diff --git a/src/DepthBuffer.cpp b/src/DepthBuffer.cpp index 74977336..f27bcfc6 100644 --- a/src/DepthBuffer.cpp +++ b/src/DepthBuffer.cpp @@ -442,7 +442,11 @@ void DepthBufferList::saveBuffer(u32 _address) if (pFrameBuffer != nullptr) pFrameBuffer->m_isDepthBuffer = true; - DepthBuffer * pDepthBuffer = findBuffer(_address); + DepthBuffer * pDepthBuffer = nullptr; + if (pFrameBuffer != nullptr && pFrameBuffer->m_startAddress != _address) + pDepthBuffer = findBuffer(pFrameBuffer->m_startAddress); + else + pDepthBuffer = findBuffer(_address); if (pDepthBuffer != nullptr && pFrameBuffer != nullptr && pDepthBuffer->m_width != pFrameBuffer->m_width) { removeBuffer(_address); diff --git a/src/FrameBuffer.cpp b/src/FrameBuffer.cpp index f0822991..2e2829af 100644 --- a/src/FrameBuffer.cpp +++ b/src/FrameBuffer.cpp @@ -36,7 +36,9 @@ FrameBuffer::FrameBuffer() , m_size(0) , m_width(0) , m_height(0) - , m_validityChecked(0) + , m_originX(0) + , m_originY(0) + , m_swapCount(0) , m_scale(0) , m_copiedToRdram(false) , m_fingerprint(false) @@ -56,6 +58,7 @@ FrameBuffer::FrameBuffer() , m_copied(false) , m_pFrameBufferCopyTexture(nullptr) , m_copyFBO(ObjectHandle::defaultFramebuffer) + , m_validityChecked(0) { m_loadTileOrigin.uls = m_loadTileOrigin.ult = 0; m_pTexture = textureCache().addFrameBufferTexture(config.video.multisampling != 0); @@ -189,6 +192,7 @@ void FrameBuffer::init(u32 _address, u16 _format, u16 _size, u16 _width, bool _c m_cfb = _cfb; m_cleared = false; m_fingerprint = false; + m_swapCount = dwnd().getBuffersSwapCount(); const u16 maxHeight = VI_GetMaxBufferHeight(_width); _initTexture(_width, maxHeight, _format, _size, m_pTexture); @@ -716,17 +720,63 @@ void FrameBufferList::saveBuffer(u32 _address, u16 _format, u16 _size, u16 _widt removeIntersections(); } + const float scaleX = config.frameBufferEmulation.nativeResFactor == 0 ? + wnd.getScaleX() : + static_cast(config.frameBufferEmulation.nativeResFactor); + if (m_pCurrent == nullptr || m_pCurrent->m_startAddress != _address || m_pCurrent->m_width != _width) m_pCurrent = findBuffer(_address); - const float scaleX = config.frameBufferEmulation.nativeResFactor == 0 ? - wnd.getScaleX() : - static_cast(config.frameBufferEmulation.nativeResFactor); - if (m_pCurrent != nullptr) { - if ((m_pCurrent->m_startAddress != _address) || - (m_pCurrent->m_width != _width) || - (m_pCurrent->m_size < _size) || - (m_pCurrent->m_scale != scaleX)) + + auto isSubBuffer = [_address, _width, _size, &wnd](const FrameBuffer * _pBuffer) -> bool + { + if (_pBuffer->m_swapCount == wnd.getBuffersSwapCount() && + !_pBuffer->m_cfb && + _pBuffer->m_width == _width && + _pBuffer->m_size == _size) { + const u32 stride = _width << _size >> 1; + const u32 diffFromStart = _address - _pBuffer->m_startAddress; + if (diffFromStart % stride != 0) + return true; + const u32 diffFromEnd = _pBuffer->m_endAddress - _address + 1; + if ((diffFromEnd / stride > 5)) + return true; + } + return false; + }; + + auto isOverlappingBuffer = [_address, _width, _size](const FrameBuffer * _pBuffer) -> bool + { + if (_pBuffer->m_width == _width && _pBuffer->m_size == _size) { + const u32 stride = _width << _size >> 1; + const u32 diffEnd = _pBuffer->m_endAddress - _address + 1; + if ((diffEnd / stride < 5)) + return true; + } + return false; + }; + + if (m_pCurrent != nullptr) { + m_pCurrent->m_originX = m_pCurrent->m_originY = 0; + if ((m_pCurrent->m_startAddress != _address)) { + if (isSubBuffer(m_pCurrent)) { + const u32 stride = _width << _size >> 1; + const u32 addrOffset = _address - m_pCurrent->m_startAddress; + m_pCurrent->m_originX = (addrOffset % stride) >> (_size - 1); + m_pCurrent->m_originY = addrOffset / stride; + gSP.changed |= CHANGED_VIEWPORT; + gDP.changed |= CHANGED_SCISSOR; + return; + } else if (isOverlappingBuffer(m_pCurrent)) { + m_pCurrent->m_endAddress = _address - 1; + m_pCurrent = nullptr; + } else { + removeBuffer(m_pCurrent->m_startAddress); + m_pCurrent = nullptr; + } + } else if ((m_pCurrent->m_width != _width) || + (m_pCurrent->m_size < _size) || + (m_pCurrent->m_scale != scaleX)) { removeBuffer(m_pCurrent->m_startAddress); m_pCurrent = nullptr; } else { @@ -780,6 +830,7 @@ void FrameBufferList::saveBuffer(u32 _address, u16 _format, u16 _size, u16 _widt m_pCurrent->m_isDepthBuffer = _address == gDP.depthImageAddress; m_pCurrent->m_isPauseScreen = m_pCurrent->m_isOBScreen = false; m_pCurrent->m_copied = false; + m_pCurrent->m_swapCount = wnd.getBuffersSwapCount(); } void FrameBufferList::copyAux() diff --git a/src/FrameBuffer.h b/src/FrameBuffer.h index b9164efc..d6a8aaa3 100644 --- a/src/FrameBuffer.h +++ b/src/FrameBuffer.h @@ -29,8 +29,14 @@ struct FrameBuffer bool _isMarioTennisScoreboard() const; bool isAuxiliary() const; - u32 m_startAddress, m_endAddress; - u32 m_size, m_width, m_height; + u32 m_startAddress; + u32 m_endAddress; + u32 m_size; + u32 m_width; + u32 m_height; + u32 m_originX; + u32 m_originY; + u32 m_swapCount; float m_scale; bool m_copiedToRdram; bool m_fingerprint; @@ -83,6 +89,7 @@ private: void _initCopyTexture(); CachedTexture * _copyFrameBufferTexture(); CachedTexture * _getSubTexture(u32 _t); + mutable u32 m_validityChecked; }; diff --git a/src/GraphicsDrawer.cpp b/src/GraphicsDrawer.cpp index e4b97136..29066204 100644 --- a/src/GraphicsDrawer.cpp +++ b/src/GraphicsDrawer.cpp @@ -192,18 +192,21 @@ void GraphicsDrawer::updateScissor(FrameBuffer * _pBuffer) const { DisplayWindow & wnd = DisplayWindow::get(); f32 scaleX, scaleY; + f32 offsetX = 0.0f, offsetY = 0.0f; if (_pBuffer == nullptr) { scaleX = wnd.getScaleX(); scaleY = wnd.getScaleY(); } else { scaleX = _pBuffer->m_scale; scaleY = _pBuffer->m_scale; + offsetX = f32(_pBuffer->m_originX); + offsetY = f32(_pBuffer->m_originY); } - f32 SX0 = gDP.scissor.ulx; - f32 SX1 = gDP.scissor.lrx; - f32 SY0 = gDP.scissor.uly; - f32 SY1 = gDP.scissor.lry; + f32 SX0 = gDP.scissor.ulx + offsetX; + f32 SX1 = gDP.scissor.lrx + offsetX; + f32 SY0 = gDP.scissor.uly + offsetY; + f32 SY1 = gDP.scissor.lry + offsetY; if (u32(SX1) == 512 && (config.generalEmulation.hacks & hack_RE2) != 0) { SX1 = f32(*REG.VI_WIDTH); @@ -245,10 +248,13 @@ void GraphicsDrawer::_updateViewport() const const f32 scaleX = pCurrentBuffer->m_scale; const f32 scaleY = pCurrentBuffer->m_scale; float Xf = gSP.viewport.vscale[0] < 0 ? (gSP.viewport.x + gSP.viewport.vscale[0] * 2.0f) : gSP.viewport.x; + Xf += f32(pCurrentBuffer->m_originX); if (_needAdjustCoordinate(wnd)) Xf = _adjustViewportX(Xf); const s32 X = (s32)(Xf * scaleX); - const s32 Y = gSP.viewport.vscale[1] < 0 ? (s32)((gSP.viewport.y + gSP.viewport.vscale[1] * 2.0f) * scaleY) : (s32)(gSP.viewport.y * scaleY); + float Yf = gSP.viewport.vscale[1] < 0 ? (gSP.viewport.y + gSP.viewport.vscale[1] * 2.0f) : gSP.viewport.y; + Yf += f32(pCurrentBuffer->m_originY); + const s32 Y = (s32)(Yf * scaleY); gfxContext.setViewport(X, Y, std::max((s32)(gSP.viewport.width * scaleX), 0), std::max((s32)(gSP.viewport.height * scaleY), 0)); } @@ -262,6 +268,7 @@ void GraphicsDrawer::_updateScreenCoordsViewport(const FrameBuffer * _pBuffer) c u32 bufferWidth, bufferHeight; f32 viewportScaleX, viewportScaleY; + s32 X = 0, Y = 0; if (pCurrentBuffer == nullptr) { bufferWidth = VI.width; bufferHeight = VI.height; @@ -271,9 +278,11 @@ void GraphicsDrawer::_updateScreenCoordsViewport(const FrameBuffer * _pBuffer) c bufferWidth = pCurrentBuffer->m_width; bufferHeight = VI_GetMaxBufferHeight(bufferWidth); viewportScaleX = viewportScaleY = pCurrentBuffer->m_scale; + X = static_cast(pCurrentBuffer->m_originX * viewportScaleX); + Y = static_cast(pCurrentBuffer->m_originY * viewportScaleY); } - gfxContext.setViewport(0, 0, (s32)(bufferWidth * viewportScaleX), (s32)(bufferHeight * viewportScaleY)); + gfxContext.setViewport(X, Y, (s32)(bufferWidth * viewportScaleX), (s32)(bufferHeight * viewportScaleY)); gSP.changed |= CHANGED_VIEWPORT; }