1
0
mirror of https://github.com/blawar/GLideN64.git synced 2024-07-02 09:03:37 +00:00

Add support for frame buffers, which are inside of some other frame buffer.

Fixed Superbowling: black screen in menu and game #116
This commit is contained in:
Sergey Lipskiy 2018-09-25 16:37:57 +07:00
parent c8b6d35597
commit 5538c7b4bb
4 changed files with 89 additions and 18 deletions

View File

@ -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);

View File

@ -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<float>(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<float>(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()

View File

@ -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;
};

View File

@ -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<s32>(pCurrentBuffer->m_originX * viewportScaleX);
Y = static_cast<s32>(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;
}