diff --git a/FrameBuffer.cpp b/FrameBuffer.cpp index 77759c9d..674eec8b 100644 --- a/FrameBuffer.cpp +++ b/FrameBuffer.cpp @@ -93,7 +93,7 @@ void FrameBuffer_RemoveBuffer( u32 address ) { if (current->startAddress == address) { - current->texture = NULL; + //current->texture = NULL; FrameBuffer_Remove( current ); return; } @@ -159,8 +159,12 @@ void FrameBuffer_SaveBuffer( u32 address, u16 format, u16 size, u16 width, u16 h frameBuffer.drawBuffer = GL_DRAW_FRAMEBUFFER; FrameBuffer *current = frameBuffer.top; - if (current != NULL && gDP.colorImage.height > 1) + if (current != NULL && gDP.colorImage.height > 1) { current->endAddress = current->startAddress + ((current->width * gDP.colorImage.height << current->size >> 1) - 1); + if (!current->cleared) + gDPFillRDRAM(current->startAddress, 0, 0, current->width, gDP.colorImage.height, current->width, current->size, frameBuffer.top->fillcolor); + } + // Search through saved frame buffers while (current != NULL) { @@ -205,6 +209,7 @@ void FrameBuffer_SaveBuffer( u32 address, u16 format, u16 size, u16 width, u16 h current->size = size; current->scaleX = OGL.scaleX; current->scaleY = OGL.scaleY; + current->fillcolor = 0; current->texture->width = (u32)(current->width * OGL.scaleX); current->texture->height = (u32)(current->height * OGL.scaleY); @@ -254,7 +259,7 @@ void FrameBuffer_SaveBuffer( u32 address, u16 format, u16 size, u16 width, u16 h #endif *(u32*)&RDRAM[current->startAddress] = current->startAddress; - current->changed = TRUE; + current->cleared = false; gSP.changed |= CHANGED_TEXTURE; } diff --git a/FrameBuffer.h b/FrameBuffer.h index 2b0585e5..a7721107 100644 --- a/FrameBuffer.h +++ b/FrameBuffer.h @@ -13,7 +13,8 @@ struct FrameBuffer GLuint fbo; u32 startAddress, endAddress; - u32 size, width, height, changed; + u32 size, width, height, fillcolor; + bool cleared; gDPTile *loadTile; float scaleX, scaleY; }; diff --git a/gDP.cpp b/gDP.cpp index 41b5130c..2047bccf 100644 --- a/gDP.cpp +++ b/gDP.cpp @@ -588,37 +588,61 @@ void gDPSetTileSize( u32 tile, u32 uls, u32 ult, u32 lrs, u32 lrt ) } static -bool CheckForFrameBufferTexture(u32 _address) +bool CheckForFrameBufferTexture(u32 _address, u32 _bytes) { - if (OGL.frameBufferTextures) { - FrameBuffer *pBuffer = FrameBuffer_FindBuffer( _address ); - if ((pBuffer != NULL) - //&& ((*(u32*)&RDRAM[pBuffer->startAddress] & 0xFFFEFFFE) == (pBuffer->startAddress & 0xFFFEFFFE)) // Does not work for Jet Force Gemini - ) - { - if (gDP.textureImage.width != pBuffer->width && gDP.textureImage.size != pBuffer->size) { - //FrameBuffer_RemoveBuffer(pBuffer->startAddress); // Does not work with Zelda MM - return false; + gDP.loadTile->textureMode = TEXTUREMODE_NORMAL; + gDP.loadTile->frameBuffer = NULL; + gDP.changed |= CHANGED_TMEM; + if (!OGL.frameBufferTextures) + return false; + + FrameBuffer *pBuffer = FrameBuffer_FindBuffer( _address ); + bool bRes = pBuffer != NULL; + if ((bRes) + //&& ((*(u32*)&RDRAM[pBuffer->startAddress] & 0xFFFEFFFE) == (pBuffer->startAddress & 0xFFFEFFFE)) // Does not work for Jet Force Gemini + ) + { + + const u32 texEndAddress = _address + _bytes - 1; + if (_address > pBuffer->startAddress && texEndAddress > pBuffer->endAddress) { +// FrameBuffer_RemoveBuffer(pBuffer->startAddress); + bRes = false; + } + + if (bRes && gDP.textureImage.width != pBuffer->width && gDP.textureImage.size != pBuffer->size) { + //FrameBuffer_RemoveBuffer(pBuffer->startAddress); // Does not work with Zelda MM + bRes = false; + } + + if (bRes && pBuffer->cleared && pBuffer->size == 2) { + const u32 endAddress = min(texEndAddress, pBuffer->endAddress); + const u32 color = pBuffer->fillcolor&0xFFFEFFFE; + for (u32 i = _address + 4; i < endAddress; i+=4) { + if (((*(u32*)&RDRAM[i])&0xFFFEFFFE) != color) { + FrameBuffer_RemoveBuffer(pBuffer->startAddress); + bRes = false; + break; + } } + } + + if (bRes) { pBuffer->loadTile = gDP.loadTile; gDP.loadTile->frameBuffer = pBuffer; gDP.loadTile->textureMode = TEXTUREMODE_FRAMEBUFFER; - gDP.changed |= CHANGED_TMEM; - - for (int nTile = gSP.texture.tile; nTile < 6; ++nTile) { - if (gDP.tiles[nTile].tmem == gDP.loadTile->tmem) { - gDPTile & curTile = gDP.tiles[nTile]; - curTile.textureMode = gDP.loadTile->textureMode; - curTile.loadType = gDP.loadTile->loadType; - curTile.frameBuffer = gDP.loadTile->frameBuffer; - curTile.imageAddress = gDP.loadTile->imageAddress; - } - } - - return true; } } - return false; + + for (int nTile = gSP.texture.tile; nTile < 6; ++nTile) { + if (gDP.tiles[nTile].tmem == gDP.loadTile->tmem) { + gDPTile & curTile = gDP.tiles[nTile]; + curTile.textureMode = gDP.loadTile->textureMode; + curTile.loadType = gDP.loadTile->loadType; + curTile.frameBuffer = gDP.loadTile->frameBuffer; + curTile.imageAddress = gDP.loadTile->imageAddress; + } + } + return bRes; } void gDPLoadTile( u32 tile, u32 uls, u32 ult, u32 lrs, u32 lrt ) @@ -641,10 +665,11 @@ void gDPLoadTile( u32 tile, u32 uls, u32 ult, u32 lrs, u32 lrt ) dest = &TMEM[gDP.loadTile->tmem]; bpl = (gDP.loadTile->lrs - gDP.loadTile->uls + 1) << gDP.loadTile->size >> 1; height = gDP.loadTile->lrt - gDP.loadTile->ult + 1; + const u32 bytes = height * bpl; src = &RDRAM[address]; - if (((address + height * bpl) > RDRAMSize) || - (((gDP.loadTile->tmem << 3) + bpl * height) > 4096)) // Stay within TMEM + if (((address + bytes) > RDRAMSize) || + (((gDP.loadTile->tmem << 3) + bytes) > 4096)) // Stay within TMEM { #ifdef DEBUG DebugMsg( DEBUG_HIGH | DEBUG_ERROR | DEBUG_TEXTURE, "// Attempting to load texture tile out of range\n" ); @@ -654,7 +679,7 @@ void gDPLoadTile( u32 tile, u32 uls, u32 ult, u32 lrs, u32 lrt ) return; } - if (CheckForFrameBufferTexture(address)) + if (CheckForFrameBufferTexture(address, bytes)) return; // Line given for 32-bit is half what it seems it should since they split the @@ -679,10 +704,6 @@ void gDPLoadTile( u32 tile, u32 uls, u32 ult, u32 lrs, u32 lrt ) dest += line; } - gDP.loadTile->textureMode = TEXTUREMODE_NORMAL; - gDP.loadTile->frameBuffer = NULL; - gDP.changed |= CHANGED_TMEM; - #ifdef DEBUG DebugMsg( DEBUG_HIGH | DEBUG_HANDLED | DEBUG_TEXTURE, "gDPLoadTile( %i, %i, %i, %i, %i );\n", tile, gDP.loadTile->uls, gDP.loadTile->ult, gDP.loadTile->lrs, gDP.loadTile->lrt ); @@ -712,7 +733,10 @@ void gDPLoadBlock( u32 tile, u32 uls, u32 ult, u32 lrs, u32 dxt ) return; } - if (CheckForFrameBufferTexture(address)) + gDP.loadTile->textureMode = TEXTUREMODE_NORMAL; + gDP.loadTile->frameBuffer = NULL; + gDP.changed |= CHANGED_TMEM; + if (CheckForFrameBufferTexture(address, bytes)) return; u64* src = (u64*)&RDRAM[address]; @@ -743,10 +767,6 @@ void gDPLoadBlock( u32 tile, u32 uls, u32 ult, u32 lrs, u32 dxt ) else UnswapCopy( src, dest, bytes ); - gDP.loadTile->textureMode = TEXTUREMODE_NORMAL; - gDP.loadTile->frameBuffer = NULL; - gDP.changed |= CHANGED_TMEM; - #ifdef DEBUG DebugMsg( DEBUG_HIGH | DEBUG_HANDLED | DEBUG_TEXTURE, "gDPLoadBlock( %i, %i, %i, %i, %i );\n", tile, uls, ult, lrs, dxt ); @@ -814,19 +834,51 @@ void gDPSetScissor( u32 mode, f32 ulx, f32 uly, f32 lrx, f32 lry ) #endif } +#define DEPTH_CLEAR_COLOR 0xfffcfffc // The value usually used to clear depth buffer +const bool g_bDepthClearOnly = false; +void gDPFillRDRAM(u32 address, s32 ulx, s32 uly, s32 lrx, s32 lry, u32 width, u32 size, u32 color ) +{ + if (g_bDepthClearOnly && color != DEPTH_CLEAR_COLOR) + return; + if (frameBuffer.drawBuffer == GL_DRAW_FRAMEBUFFER) { + frameBuffer.top->cleared = true; + frameBuffer.top->fillcolor = color; + } + ulx = min(max(ulx, gDP.scissor.ulx), gDP.scissor.lrx); + lrx = min(max(lrx, gDP.scissor.ulx), gDP.scissor.lrx); + uly = min(max(uly, gDP.scissor.uly), gDP.scissor.lry); + lry = min(max(lry, gDP.scissor.uly), gDP.scissor.lry); + u32 ci_width_in_dwords = width >> (3 - size); + ulx >>= (3 - size); + lrx >>= (3 - size); + u32 * dst = (u32*)(RDRAM + address); + dst += uly * ci_width_in_dwords; + for (u32 y = uly; y < lry; ++y) { + for (u32 x = ulx; x < lrx; ++x) + dst[x] = color; + dst += ci_width_in_dwords; + } + *(u32*)&RDRAM[address] = address; +} + void gDPFillRectangle( s32 ulx, s32 uly, s32 lrx, s32 lry ) { -#define DEPTH_CLAER_COLOR 0xfffcfffc // The value usually used to clear depth buffer - + if (gDP.otherMode.cycleType == G_CYC_FILL) + { + lrx++; + lry++; + } if (gDP.depthImageAddress == gDP.colorImage.address) { // Game may use depth texture as auxilary color texture. Example: Mario Tennis // If color is not depth clear color, that is most likely the case - if (gDP.fillColor.color == DEPTH_CLAER_COLOR) { + if (gDP.fillColor.color == DEPTH_CLEAR_COLOR) { + gDPFillRDRAM(gDP.colorImage.address, ulx, uly, lrx, lry, gDP.colorImage.width, gDP.colorImage.size, gDP.fillColor.color); OGL_ClearDepthBuffer(); return; } - } else if (gDP.fillColor.color == DEPTH_CLAER_COLOR) { + } else if (gDP.fillColor.color == DEPTH_CLEAR_COLOR) { DepthBuffer_SetBuffer( gDP.colorImage.address ); + gDPFillRDRAM(gDP.colorImage.address, ulx, uly, lrx, lry, gDP.colorImage.width, gDP.colorImage.size, gDP.fillColor.color); OGL_ClearDepthBuffer(); return; } @@ -835,14 +887,9 @@ void gDPFillRectangle( s32 ulx, s32 uly, s32 lrx, s32 lry ) gDPGetFillColor(fillColor); if (gDP.otherMode.cycleType == G_CYC_FILL) { - //if (gDP.fillColor.a == 0.0f) - // return; - - lrx++; - lry++; - - if ((ulx == 0) && (uly == 0) && (lrx == VI.width) && (lry == VI.height)) + if ((ulx == 0) && (uly == 0) && (lrx == gDP.scissor.lrx) && (lry == gDP.scissor.lry)) { + gDPFillRDRAM(gDP.colorImage.address, ulx, uly, lrx, lry, gDP.colorImage.width, gDP.colorImage.size, gDP.fillColor.color); OGL_ClearColorBuffer( fillColor ); return; } @@ -932,7 +979,10 @@ void gDPTextureRectangle( f32 ulx, f32 uly, f32 lrx, f32 lry, s32 tile, f32 s, f gSP.textureTile[1] = &gDP.tiles[gSP.texture.tile < 7 ? gSP.texture.tile + 1 : gSP.texture.tile]; gDP.colorImage.changed = TRUE; - gDP.colorImage.height = max( gDP.colorImage.height, (u32)gDP.scissor.lry ); + if (gDP.colorImage.width < 64) + gDP.colorImage.height = (u32)max( (s32)gDP.colorImage.height, lry ); + else + gDP.colorImage.height = max( gDP.colorImage.height, (u32)gDP.scissor.lry ); #ifdef DEBUG DebugMsg( DEBUG_HIGH | DEBUG_HANDLED, "gDPTextureRectangle( %f, %f, %f, %f, %i, %i, %f, %f, %f, %f );\n", diff --git a/gDP.h b/gDP.h index d2be44d8..b355eb99 100644 --- a/gDP.h +++ b/gDP.h @@ -280,5 +280,7 @@ void gDPPipeSync(); void gDPLoadSync(); void gDPNoOp(); +void gDPFillRDRAM( u32 address, s32 ulx, s32 uly, s32 lrx, s32 lry, u32 width, u32 size, u32 color ); + #endif