From 45d9d63564c3a744571fae6cf5d1be55d41c5159 Mon Sep 17 00:00:00 2001 From: Sergey Lipskiy Date: Sun, 8 May 2016 15:58:19 +0600 Subject: [PATCH] Implement frame buffer subimage copy. When N64 game needs to apply frame buffer texture to a polygon, it copies part of frame buffer data to texture memory. The plugin does not copy frame buffer texture, since frame buffer texture already in video memory and thus can be used directly. However, sometimes polygons with frame buffer texture use texture coordinates wrap. Wrap can't be done correct when whole frame buffer texture is used. Thus, frame buffer subimage copy is implemented. Part of texture copied to a new texture, which can be correctly wrapped. Fixed PD cloacking effect, #839 --- src/FrameBuffer.cpp | 211 +++++++++++++++++++++++++++++++------------- src/FrameBuffer.h | 18 ++-- 2 files changed, 163 insertions(+), 66 deletions(-) diff --git a/src/FrameBuffer.cpp b/src/FrameBuffer.cpp index d76d9b4b..8c849145 100644 --- a/src/FrameBuffer.cpp +++ b/src/FrameBuffer.cpp @@ -148,7 +148,8 @@ FrameBuffer::FrameBuffer() : m_copiedToRdram(false), m_fingerprint(false), m_cleared(false), m_changed(false), m_cfb(false), m_isDepthBuffer(false), m_isPauseScreen(false), m_isOBScreen(false), m_needHeightCorrection(false), m_postProcessed(0), m_pLoadTile(NULL), - m_pDepthBuffer(NULL), m_pResolveTexture(NULL), m_resolveFBO(0), m_resolved(false) + m_pDepthBuffer(NULL), m_resolveFBO(0), m_pResolveTexture(NULL), m_resolved(false), + m_SubFBO(0), m_pSubTexture(NULL) { m_pTexture = textureCache().addFrameBufferTexture(); glGenFramebuffers(1, &m_FBO); @@ -157,10 +158,14 @@ FrameBuffer::FrameBuffer() : FrameBuffer::FrameBuffer(FrameBuffer && _other) : m_startAddress(_other.m_startAddress), m_endAddress(_other.m_endAddress), m_size(_other.m_size), m_width(_other.m_width), m_height(_other.m_height), m_fillcolor(_other.m_fillcolor), - m_validityChecked(_other.m_validityChecked), m_scaleX(_other.m_scaleX), m_scaleY(_other.m_scaleY), m_copiedToRdram(_other.m_copiedToRdram), m_fingerprint(_other.m_fingerprint), m_cleared(_other.m_cleared), m_changed(_other.m_changed), - m_cfb(_other.m_cfb), m_isDepthBuffer(_other.m_isDepthBuffer), m_isPauseScreen(_other.m_isPauseScreen), m_isOBScreen(_other.m_isOBScreen), m_needHeightCorrection(_other.m_needHeightCorrection), m_postProcessed(_other.m_postProcessed), + m_validityChecked(_other.m_validityChecked), m_scaleX(_other.m_scaleX), m_scaleY(_other.m_scaleY), m_copiedToRdram(_other.m_copiedToRdram), + m_fingerprint(_other.m_fingerprint), m_cleared(_other.m_cleared), m_changed(_other.m_changed), + m_cfb(_other.m_cfb), m_isDepthBuffer(_other.m_isDepthBuffer), m_isPauseScreen(_other.m_isPauseScreen), + m_isOBScreen(_other.m_isOBScreen), m_needHeightCorrection(_other.m_needHeightCorrection), m_postProcessed(_other.m_postProcessed), m_FBO(_other.m_FBO), m_pLoadTile(_other.m_pLoadTile), m_pTexture(_other.m_pTexture), m_pDepthBuffer(_other.m_pDepthBuffer), - m_pResolveTexture(_other.m_pResolveTexture), m_resolveFBO(_other.m_resolveFBO), m_resolved(_other.m_resolved), m_RdramCopy(_other.m_RdramCopy) + m_resolveFBO(_other.m_resolveFBO), m_pResolveTexture(_other.m_pResolveTexture), m_resolved(_other.m_resolved), + m_SubFBO(_other.m_SubFBO), m_pSubTexture(_other.m_pSubTexture), + m_RdramCopy(_other.m_RdramCopy) { _other.m_FBO = 0; _other.m_pTexture = NULL; @@ -169,6 +174,8 @@ FrameBuffer::FrameBuffer(FrameBuffer && _other) : _other.m_pResolveTexture = NULL; _other.m_resolveFBO = 0; _other.m_RdramCopy.clear(); + _other.m_SubFBO = 0; + _other.m_pSubTexture = NULL; } @@ -182,19 +189,23 @@ FrameBuffer::~FrameBuffer() glDeleteFramebuffers(1, &m_resolveFBO); if (m_pResolveTexture != NULL) textureCache().removeFrameBufferTexture(m_pResolveTexture); + if (m_SubFBO != 0) + glDeleteFramebuffers(1, &m_SubFBO); + if (m_pSubTexture != NULL) + textureCache().removeFrameBufferTexture(m_pSubTexture); } -void FrameBuffer::_initTexture(u16 _format, u16 _size, CachedTexture *_pTexture) +void FrameBuffer::_initTexture(u16 _width, u16 _height, u16 _format, u16 _size, CachedTexture *_pTexture) { - _pTexture->width = (u32)(m_width * m_scaleX); - _pTexture->height = (u32)(m_height * m_scaleY); + _pTexture->width = (u32)(_width * m_scaleX); + _pTexture->height = (u32)(_height * m_scaleY); _pTexture->format = _format; _pTexture->size = _size; _pTexture->clampS = 1; _pTexture->clampT = 1; _pTexture->address = m_startAddress; - _pTexture->clampWidth = m_width; - _pTexture->clampHeight = m_height; + _pTexture->clampWidth = _width; + _pTexture->clampHeight = _height; _pTexture->frameBufferTexture = CachedTexture::fbOneSample; _pTexture->maskS = 0; _pTexture->maskT = 0; @@ -262,7 +273,7 @@ void FrameBuffer::init(u32 _address, u32 _endAddress, u16 _format, u16 _size, u1 m_cleared = false; m_fingerprint = false; - _initTexture(_format, _size, m_pTexture); + _initTexture(_width, _height, _format, _size, m_pTexture); glBindFramebuffer(GL_FRAMEBUFFER, m_FBO); #ifdef GL_MULTISAMPLING_SUPPORT @@ -283,7 +294,7 @@ void FrameBuffer::init(u32 _address, u32 _endAddress, u16 _format, u16 _size, u1 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D_MULTISAMPLE, m_pTexture->glName, 0); m_pResolveTexture = textureCache().addFrameBufferTexture(); - _initTexture(_format, _size, m_pResolveTexture); + _initTexture(_width, _height, _format, _size, m_pResolveTexture); glGenFramebuffers(1, &m_resolveFBO); glBindFramebuffer(GL_FRAMEBUFFER, m_resolveFBO); _setAndAttachTexture(_size, m_pResolveTexture); @@ -412,15 +423,125 @@ void FrameBuffer::resolveMultisampledTexture(bool _bForce) #endif } -CachedTexture * FrameBuffer::getTexture() +bool FrameBuffer::_initSubTexture(u32 _t) { - if (config.video.multisampling == 0) - return m_pTexture; - if (m_resolved) - return m_pResolveTexture; + if (m_SubFBO == 0) + glGenFramebuffers(1, &m_SubFBO); - resolveMultisampledTexture(); - return m_pResolveTexture; + gDPTile * pTile = gSP.textureTile[_t]; + if (pTile->lrs < pTile->uls || pTile->lrt < pTile->ult) + return false; + const u32 width = pTile->lrs - pTile->uls + 1; + const u32 height = pTile->lrt - pTile->ult + 1; + + if (m_pSubTexture != NULL) { + if (m_pSubTexture->size == m_pTexture->size && + m_pSubTexture->clampWidth == width && + m_pSubTexture->clampHeight == height) + return true; + textureCache().removeFrameBufferTexture(m_pSubTexture); + } + + m_pSubTexture = textureCache().addFrameBufferTexture(); + _initTexture(width, height, m_pTexture->format, m_pTexture->size, m_pSubTexture); + + m_pSubTexture->clampS = pTile->clamps; + m_pSubTexture->clampT = pTile->clampt; + m_pSubTexture->offsetS = 0.0f; + m_pSubTexture->offsetT = m_pSubTexture->clampHeight; + + glActiveTexture(GL_TEXTURE0 + _t); + glBindTexture(GL_TEXTURE_2D, m_pSubTexture->glName); + if (m_pSubTexture->size > G_IM_SIZ_8b) + glTexImage2D(GL_TEXTURE_2D, 0, fboFormats.colorInternalFormat, m_pSubTexture->realWidth, m_pSubTexture->realHeight, 0, fboFormats.colorFormat, fboFormats.colorType, NULL); + else + glTexImage2D(GL_TEXTURE_2D, 0, fboFormats.monochromeInternalFormat, m_pSubTexture->realWidth, m_pSubTexture->realHeight, 0, fboFormats.monochromeFormat, fboFormats.monochromeType, NULL); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_SubFBO); + glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_pSubTexture->glName, 0); + return true; +} + +CachedTexture * FrameBuffer::_getSubTexture(u32 _t) +{ + if (!_initSubTexture(_t)) + return m_pTexture; + GLint x0 = (GLint)(m_pTexture->offsetS * m_scaleX); + GLint y0 = (GLint)(m_pTexture->offsetT * m_scaleY) - m_pSubTexture->realHeight; + GLint copyWidth = m_pSubTexture->realWidth; + if (x0 + copyWidth > m_pTexture->realWidth) + copyWidth = m_pTexture->realWidth - x0; + GLint copyHeight = m_pSubTexture->realHeight; + if (y0 + copyHeight > m_pTexture->realHeight) + copyHeight = m_pTexture->realHeight - y0; + +#ifdef GLES2 + glBindFramebuffer(GL_READ_FRAMEBUFFER, m_FBO); + glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, x0, y0, copyWidth, copyHeight, 0); + glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); +#else + glBindFramebuffer(GL_READ_FRAMEBUFFER, m_FBO); + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_SubFBO); + glBlitFramebuffer(x0, y0, x0 + copyWidth, y0 + copyHeight, + 0, 0, copyWidth, copyHeight, + GL_COLOR_BUFFER_BIT, GL_NEAREST); + glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); + frameBufferList().setCurrentDrawBuffer(); +#endif + + return m_pSubTexture; +} + +CachedTexture * FrameBuffer::getTexture(u32 _t) +{ + const u32 shift = (gSP.textureTile[_t]->imageAddress - m_startAddress) >> (m_size - 1); + const u32 factor = m_width; + if (gSP.textureTile[_t]->loadType == LOADTYPE_TILE) { + m_pTexture->offsetS = (float)(m_pLoadTile->uls + (shift % factor)); + m_pTexture->offsetT = (float)(m_height - (m_pLoadTile->ult + shift / factor)); + } else { + m_pTexture->offsetS = (float)(shift % factor); + m_pTexture->offsetT = (float)(m_height - shift / factor); + } + + CachedTexture *pTexture = m_pTexture; +// if (gSP.textureTile[_t]->loadType == LOADTYPE_TILE && pTexture->size > 1) + if (gSP.textureTile[_t]->clamps == 0 || gSP.textureTile[_t]->clampt == 0) + pTexture = _getSubTexture(_t); + + pTexture->scaleS = m_scaleX / (float)pTexture->realWidth; + pTexture->scaleT = m_scaleY / (float)pTexture->realHeight; + + if (gSP.textureTile[_t]->shifts > 10) + pTexture->shiftScaleS = (float)(1 << (16 - gSP.textureTile[_t]->shifts)); + else if (gSP.textureTile[_t]->shifts > 0) + pTexture->shiftScaleS = 1.0f / (float)(1 << gSP.textureTile[_t]->shifts); + else + pTexture->shiftScaleS = 1.0f; + + if (gSP.textureTile[_t]->shiftt > 10) + pTexture->shiftScaleT = (float)(1 << (16 - gSP.textureTile[_t]->shiftt)); + else if (gSP.textureTile[_t]->shiftt > 0) + pTexture->shiftScaleT = 1.0f / (float)(1 << gSP.textureTile[_t]->shiftt); + else + pTexture->shiftScaleT = 1.0f; + + return pTexture; +} + +CachedTexture * FrameBuffer::getTextureBG(u32 _t) +{ + m_pTexture->scaleS = video().getScaleX() / (float)m_pTexture->realWidth; + m_pTexture->scaleT = video().getScaleY() / (float)m_pTexture->realHeight; + + m_pTexture->shiftScaleS = 1.0f; + m_pTexture->shiftScaleT = 1.0f; + + m_pTexture->offsetS = gSP.bgImage.imageX; + m_pTexture->offsetT = (float)m_height - gSP.bgImage.imageY; + return m_pTexture; } FrameBufferList & FrameBufferList::get() @@ -958,62 +1079,30 @@ void FrameBufferList::renderBuffer(u32 _address) -void FrameBuffer_ActivateBufferTexture(s16 t, FrameBuffer *pBuffer) +void FrameBuffer_ActivateBufferTexture(u32 t, FrameBuffer *pBuffer) { - if (pBuffer == NULL || pBuffer->m_pTexture == NULL) + if (pBuffer == NULL) return; - CachedTexture *pTexture = pBuffer->m_pTexture; - - pTexture->scaleS = pBuffer->m_scaleX / (float)pTexture->realWidth; - pTexture->scaleT = pBuffer->m_scaleY / (float)pTexture->realHeight; - - if (gSP.textureTile[t]->shifts > 10) - pTexture->shiftScaleS = (float)(1 << (16 - gSP.textureTile[t]->shifts)); - else if (gSP.textureTile[t]->shifts > 0) - pTexture->shiftScaleS = 1.0f / (float)(1 << gSP.textureTile[t]->shifts); - else - pTexture->shiftScaleS = 1.0f; - - if (gSP.textureTile[t]->shiftt > 10) - pTexture->shiftScaleT = (float)(1 << (16 - gSP.textureTile[t]->shiftt)); - else if (gSP.textureTile[t]->shiftt > 0) - pTexture->shiftScaleT = 1.0f / (float)(1 << gSP.textureTile[t]->shiftt); - else - pTexture->shiftScaleT = 1.0f; - - const u32 shift = (gSP.textureTile[t]->imageAddress - pBuffer->m_startAddress) >> (pBuffer->m_size - 1); - const u32 factor = pBuffer->m_width; - if (gSP.textureTile[t]->loadType == LOADTYPE_TILE) { - pTexture->offsetS = (float)(pBuffer->m_pLoadTile->uls + (shift % factor)); - pTexture->offsetT = (float)(pBuffer->m_height - (pBuffer->m_pLoadTile->ult + shift / factor)); - } - else { - pTexture->offsetS = (float)(shift % factor); - pTexture->offsetT = (float)(pBuffer->m_height - shift / factor); - } + CachedTexture *pTexture = pBuffer->getTexture(t); + if (pTexture == NULL) + return; // frameBufferList().renderBuffer(pBuffer->m_startAddress); textureCache().activateTexture(t, pTexture); gDP.changed |= CHANGED_FB_TEXTURE; } -void FrameBuffer_ActivateBufferTextureBG(s16 t, FrameBuffer *pBuffer ) +void FrameBuffer_ActivateBufferTextureBG(u32 t, FrameBuffer *pBuffer ) { - if (pBuffer == NULL || pBuffer->m_pTexture == NULL) + if (pBuffer == NULL) return; - CachedTexture *pTexture = pBuffer->m_pTexture; - pTexture->scaleS = video().getScaleX() / (float)pTexture->realWidth; - pTexture->scaleT = video().getScaleY() / (float)pTexture->realHeight; + CachedTexture *pTexture = pBuffer->getTextureBG(t); + if (pTexture == NULL) + return; - pTexture->shiftScaleS = 1.0f; - pTexture->shiftScaleT = 1.0f; - - pTexture->offsetS = gSP.bgImage.imageX; - pTexture->offsetT = (float)pBuffer->m_height - gSP.bgImage.imageY; - - // FrameBuffer_RenderBuffer(buffer->startAddress); +// frameBufferList().renderBuffer(pBuffer->m_startAddress); textureCache().activateTexture(t, pTexture); gDP.changed |= CHANGED_FB_TEXTURE; } diff --git a/src/FrameBuffer.h b/src/FrameBuffer.h index 91fe1646..cac7107b 100644 --- a/src/FrameBuffer.h +++ b/src/FrameBuffer.h @@ -19,7 +19,8 @@ struct FrameBuffer void init(u32 _address, u32 _endAddress, u16 _format, u16 _size, u16 _width, u16 _height, bool _cfb); void reinit(u16 _height); void resolveMultisampledTexture(bool _bForce = false); - CachedTexture * getTexture(); + CachedTexture * getTexture(u32 _t); + CachedTexture * getTextureBG(u32 _t); void copyRdram(); bool isValid() const; bool _isMarioTennisScoreboard() const; @@ -43,16 +44,23 @@ struct FrameBuffer gDPTile *m_pLoadTile; CachedTexture *m_pTexture; DepthBuffer *m_pDepthBuffer; + // multisampling - CachedTexture *m_pResolveTexture; GLuint m_resolveFBO; + CachedTexture *m_pResolveTexture; bool m_resolved; + // subtexture + GLuint m_SubFBO; + CachedTexture *m_pSubTexture; + std::vector m_RdramCopy; private: - void _initTexture(u16 _format, u16 _size, CachedTexture *_pTexture); + void _initTexture(u16 _width, u16 _height, u16 _format, u16 _size, CachedTexture *_pTexture); void _setAndAttachTexture(u16 _size, CachedTexture *_pTexture); + bool _initSubTexture(u32 _t); + CachedTexture * _getSubTexture(u32 _t); }; class FrameBufferList @@ -127,7 +135,7 @@ void FrameBuffer_CopyFromRDRAM(u32 address, bool bUseAlpha); void FrameBuffer_AddAddress(u32 address, u32 _size); bool FrameBuffer_CopyDepthBuffer(u32 address); bool FrameBuffer_CopyDepthBufferChunk(u32 address); -void FrameBuffer_ActivateBufferTexture(s16 t, FrameBuffer *pBuffer); -void FrameBuffer_ActivateBufferTextureBG(s16 t, FrameBuffer *pBuffer); +void FrameBuffer_ActivateBufferTexture(u32 t, FrameBuffer *pBuffer); +void FrameBuffer_ActivateBufferTextureBG(u32 t, FrameBuffer *pBuffer); #endif