1
0
mirror of https://github.com/blawar/GLideN64.git synced 2024-07-04 10:03:36 +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) if (pFrameBuffer != nullptr)
pFrameBuffer->m_isDepthBuffer = true; 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) { if (pDepthBuffer != nullptr && pFrameBuffer != nullptr && pDepthBuffer->m_width != pFrameBuffer->m_width) {
removeBuffer(_address); removeBuffer(_address);

View File

@ -36,7 +36,9 @@ FrameBuffer::FrameBuffer()
, m_size(0) , m_size(0)
, m_width(0) , m_width(0)
, m_height(0) , m_height(0)
, m_validityChecked(0) , m_originX(0)
, m_originY(0)
, m_swapCount(0)
, m_scale(0) , m_scale(0)
, m_copiedToRdram(false) , m_copiedToRdram(false)
, m_fingerprint(false) , m_fingerprint(false)
@ -56,6 +58,7 @@ FrameBuffer::FrameBuffer()
, m_copied(false) , m_copied(false)
, m_pFrameBufferCopyTexture(nullptr) , m_pFrameBufferCopyTexture(nullptr)
, m_copyFBO(ObjectHandle::defaultFramebuffer) , m_copyFBO(ObjectHandle::defaultFramebuffer)
, m_validityChecked(0)
{ {
m_loadTileOrigin.uls = m_loadTileOrigin.ult = 0; m_loadTileOrigin.uls = m_loadTileOrigin.ult = 0;
m_pTexture = textureCache().addFrameBufferTexture(config.video.multisampling != 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_cfb = _cfb;
m_cleared = false; m_cleared = false;
m_fingerprint = false; m_fingerprint = false;
m_swapCount = dwnd().getBuffersSwapCount();
const u16 maxHeight = VI_GetMaxBufferHeight(_width); const u16 maxHeight = VI_GetMaxBufferHeight(_width);
_initTexture(_width, maxHeight, _format, _size, m_pTexture); _initTexture(_width, maxHeight, _format, _size, m_pTexture);
@ -716,17 +720,63 @@ void FrameBufferList::saveBuffer(u32 _address, u16 _format, u16 _size, u16 _widt
removeIntersections(); 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) if (m_pCurrent == nullptr || m_pCurrent->m_startAddress != _address || m_pCurrent->m_width != _width)
m_pCurrent = findBuffer(_address); m_pCurrent = findBuffer(_address);
const float scaleX = config.frameBufferEmulation.nativeResFactor == 0 ?
wnd.getScaleX() : auto isSubBuffer = [_address, _width, _size, &wnd](const FrameBuffer * _pBuffer) -> bool
static_cast<float>(config.frameBufferEmulation.nativeResFactor); {
if (m_pCurrent != nullptr) { if (_pBuffer->m_swapCount == wnd.getBuffersSwapCount() &&
if ((m_pCurrent->m_startAddress != _address) || !_pBuffer->m_cfb &&
(m_pCurrent->m_width != _width) || _pBuffer->m_width == _width &&
(m_pCurrent->m_size < _size) || _pBuffer->m_size == _size)
(m_pCurrent->m_scale != scaleX))
{ {
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); removeBuffer(m_pCurrent->m_startAddress);
m_pCurrent = nullptr; m_pCurrent = nullptr;
} else { } 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_isDepthBuffer = _address == gDP.depthImageAddress;
m_pCurrent->m_isPauseScreen = m_pCurrent->m_isOBScreen = false; m_pCurrent->m_isPauseScreen = m_pCurrent->m_isOBScreen = false;
m_pCurrent->m_copied = false; m_pCurrent->m_copied = false;
m_pCurrent->m_swapCount = wnd.getBuffersSwapCount();
} }
void FrameBufferList::copyAux() void FrameBufferList::copyAux()

View File

@ -29,8 +29,14 @@ struct FrameBuffer
bool _isMarioTennisScoreboard() const; bool _isMarioTennisScoreboard() const;
bool isAuxiliary() const; bool isAuxiliary() const;
u32 m_startAddress, m_endAddress; u32 m_startAddress;
u32 m_size, m_width, m_height; u32 m_endAddress;
u32 m_size;
u32 m_width;
u32 m_height;
u32 m_originX;
u32 m_originY;
u32 m_swapCount;
float m_scale; float m_scale;
bool m_copiedToRdram; bool m_copiedToRdram;
bool m_fingerprint; bool m_fingerprint;
@ -83,6 +89,7 @@ private:
void _initCopyTexture(); void _initCopyTexture();
CachedTexture * _copyFrameBufferTexture(); CachedTexture * _copyFrameBufferTexture();
CachedTexture * _getSubTexture(u32 _t); CachedTexture * _getSubTexture(u32 _t);
mutable u32 m_validityChecked; mutable u32 m_validityChecked;
}; };

View File

@ -192,18 +192,21 @@ void GraphicsDrawer::updateScissor(FrameBuffer * _pBuffer) const
{ {
DisplayWindow & wnd = DisplayWindow::get(); DisplayWindow & wnd = DisplayWindow::get();
f32 scaleX, scaleY; f32 scaleX, scaleY;
f32 offsetX = 0.0f, offsetY = 0.0f;
if (_pBuffer == nullptr) { if (_pBuffer == nullptr) {
scaleX = wnd.getScaleX(); scaleX = wnd.getScaleX();
scaleY = wnd.getScaleY(); scaleY = wnd.getScaleY();
} else { } else {
scaleX = _pBuffer->m_scale; scaleX = _pBuffer->m_scale;
scaleY = _pBuffer->m_scale; scaleY = _pBuffer->m_scale;
offsetX = f32(_pBuffer->m_originX);
offsetY = f32(_pBuffer->m_originY);
} }
f32 SX0 = gDP.scissor.ulx; f32 SX0 = gDP.scissor.ulx + offsetX;
f32 SX1 = gDP.scissor.lrx; f32 SX1 = gDP.scissor.lrx + offsetX;
f32 SY0 = gDP.scissor.uly; f32 SY0 = gDP.scissor.uly + offsetY;
f32 SY1 = gDP.scissor.lry; f32 SY1 = gDP.scissor.lry + offsetY;
if (u32(SX1) == 512 && (config.generalEmulation.hacks & hack_RE2) != 0) { if (u32(SX1) == 512 && (config.generalEmulation.hacks & hack_RE2) != 0) {
SX1 = f32(*REG.VI_WIDTH); SX1 = f32(*REG.VI_WIDTH);
@ -245,10 +248,13 @@ void GraphicsDrawer::_updateViewport() const
const f32 scaleX = pCurrentBuffer->m_scale; const f32 scaleX = pCurrentBuffer->m_scale;
const f32 scaleY = 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; 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)) if (_needAdjustCoordinate(wnd))
Xf = _adjustViewportX(Xf); Xf = _adjustViewportX(Xf);
const s32 X = (s32)(Xf * scaleX); 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, gfxContext.setViewport(X, Y,
std::max((s32)(gSP.viewport.width * scaleX), 0), std::max((s32)(gSP.viewport.height * scaleY), 0)); 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; u32 bufferWidth, bufferHeight;
f32 viewportScaleX, viewportScaleY; f32 viewportScaleX, viewportScaleY;
s32 X = 0, Y = 0;
if (pCurrentBuffer == nullptr) { if (pCurrentBuffer == nullptr) {
bufferWidth = VI.width; bufferWidth = VI.width;
bufferHeight = VI.height; bufferHeight = VI.height;
@ -271,9 +278,11 @@ void GraphicsDrawer::_updateScreenCoordsViewport(const FrameBuffer * _pBuffer) c
bufferWidth = pCurrentBuffer->m_width; bufferWidth = pCurrentBuffer->m_width;
bufferHeight = VI_GetMaxBufferHeight(bufferWidth); bufferHeight = VI_GetMaxBufferHeight(bufferWidth);
viewportScaleX = viewportScaleY = pCurrentBuffer->m_scale; 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; gSP.changed |= CHANGED_VIEWPORT;
} }