From 57da925a14f0e28cd52a191eb770614f3864d585 Mon Sep 17 00:00:00 2001 From: Sergey Lipskiy Date: Mon, 25 Sep 2017 22:24:30 +0700 Subject: [PATCH] Check for overlapping frame buffers in FrameBufferList::removeIntersections() Fixed Mario Tennis - missing bottom half of scoreboard #1564 Problem: Top Gear Hyper Bike has overlapping frame buffers. That is start address of a buffer points on last line in previous buffer. When new buffer intersects with prevois one, plugin removes old buffer. That causes black screen in case of Top Gear Hyper Bike. FrameBuffer::updateEndAddress() was modified in commit 17eb8696ea6 to fix it. It sets buffer end address using buffer height - 1. This fix causes issue with Mario Tennis scoreboard #1564 HW buffer is not detected because end address is wrong. Solution: Add another test for intersecting buffers. It checks that the buffers are not just arbitrary intersected ones, but it is sequence of two slighly overlapping buffers. In that case buffer is not removed, but its end address is corrected, because buffers address space must not intersect. --- src/FrameBuffer.cpp | 29 ++++++++++++++++++++++++++--- 1 file changed, 26 insertions(+), 3 deletions(-) diff --git a/src/FrameBuffer.cpp b/src/FrameBuffer.cpp index e191be2c..67e7e67a 100644 --- a/src/FrameBuffer.cpp +++ b/src/FrameBuffer.cpp @@ -182,7 +182,7 @@ void FrameBuffer::init(u32 _address, u16 _format, u16 _size, u16 _width, bool _c void FrameBuffer::updateEndAddress() { - const u32 height = max(1U, m_height - 1); + const u32 height = max(1U, m_height); m_endAddress = min(RDRAMSize, m_startAddress + (((m_width * height) << m_size >> 1) - 1)); } @@ -515,6 +515,20 @@ FrameBuffer * FrameBufferList::findBuffer(u32 _startAddress) return nullptr; } +inline +bool isOverlapping(const FrameBuffer * _buf1, const FrameBuffer * _buf2) +{ + if (_buf1->m_endAddress < _buf2->m_endAddress && _buf1->m_width == _buf2->m_width && _buf1->m_size == _buf2->m_size) { + const u32 diff = _buf1->m_endAddress - _buf2->m_startAddress + 1; + const u32 stride = _buf1->m_width << _buf1->m_size >> 1; + if ((diff % stride == 0) && (diff / stride < 5)) + return true; + else + return false; + } + return false; +} + void FrameBufferList::removeIntersections() { assert(!m_list.empty()); @@ -524,8 +538,17 @@ void FrameBufferList::removeIntersections() --iter; if (&(*iter) == m_pCurrent) continue; - if ((iter->m_startAddress <= m_pCurrent->m_startAddress && iter->m_endAddress >= m_pCurrent->m_startAddress) || // [ { ] - (m_pCurrent->m_startAddress <= iter->m_startAddress && m_pCurrent->m_endAddress >= iter->m_startAddress)) { // { [ } + if (iter->m_startAddress <= m_pCurrent->m_startAddress && iter->m_endAddress >= m_pCurrent->m_startAddress) { // [ { ] + if (isOverlapping(&(*iter), m_pCurrent)) { + iter->m_endAddress = m_pCurrent->m_startAddress - 1; + continue; + } + iter = m_list.erase(iter); + } else if (m_pCurrent->m_startAddress <= iter->m_startAddress && m_pCurrent->m_endAddress >= iter->m_startAddress) { // { [ } + if (isOverlapping(m_pCurrent, &(*iter))) { + m_pCurrent->m_endAddress = iter->m_startAddress - 1; + continue; + } iter = m_list.erase(iter); } } while (iter != m_list.begin());