From 24885907d8a1e0a4a92fe1a9710fe99b5b1119fe Mon Sep 17 00:00:00 2001 From: Sergey Lipskiy Date: Sun, 27 Sep 2015 10:10:05 +0600 Subject: [PATCH] Add hack_ZeldaCamera to fix camera in Zelda MM, #577 The game copies current frame buffer to the area, which initially allocated for depth buffer. Game read camera data from that area, not from normal frame buffer. That's why 'copy color buffer to RDRAM' option does not help there. Special code needed to process that. Looks ugly, but works. --- src/Config.h | 1 + src/FrameBuffer.cpp | 12 +++++++++++- src/FrameBuffer.h | 6 +++++- src/RSP.cpp | 2 +- src/gSP.cpp | 5 +++++ 5 files changed, 23 insertions(+), 3 deletions(-) diff --git a/src/Config.h b/src/Config.h index 864dedd9..918b0606 100644 --- a/src/Config.h +++ b/src/Config.h @@ -121,6 +121,7 @@ struct Config #define hack_ignoreVIHeightChange (1<<9) //Do not reset FBO when VI height is changed. Space Invaders need it. #define hack_VIUpdateOnCIChange (1<<10) //Update frame if color buffer changed. Needed for Quake II underwater. #define hack_skipVIChangeCheck (1<<11) //Don't reset FBO when VI parameters changed. Zelda MM +#define hack_ZeldaCamera (1<<12) //Special hack to detect and process Zelda MM camera. extern Config config; diff --git a/src/FrameBuffer.cpp b/src/FrameBuffer.cpp index 9914519d..73f61d01 100644 --- a/src/FrameBuffer.cpp +++ b/src/FrameBuffer.cpp @@ -357,11 +357,13 @@ FrameBufferList & FrameBufferList::get() void FrameBufferList::init() { m_pCurrent = NULL; + m_pCopy = NULL; } void FrameBufferList::destroy() { m_list.clear(); m_pCurrent = NULL; + m_pCopy = NULL; } void FrameBufferList::setBufferChanged() @@ -1184,7 +1186,15 @@ bool DepthBufferToRDRAM::CopyToRDRAM( u32 _address) { bool FrameBuffer_CopyDepthBuffer( u32 address ) { #ifndef GLES2 - return g_dbToRDRAM.CopyToRDRAM(address); + FrameBuffer * pCopyBuffer = frameBufferList().getCopyBuffer(); + if (pCopyBuffer != NULL) { + // This code is mainly to emulate Zelda MM camera. + g_fbToRDRAM.CopyToRDRAM(pCopyBuffer->m_startAddress); + pCopyBuffer->m_RdramCopy.resize(0); // To disable validity check by RDRAM content. CPU may change content of the buffer for some unknown reason. + frameBufferList().setCopyBuffer(NULL); + return true; + } else + return g_dbToRDRAM.CopyToRDRAM(address); #else return false; #endif diff --git a/src/FrameBuffer.h b/src/FrameBuffer.h index c8574932..e931ed94 100644 --- a/src/FrameBuffer.h +++ b/src/FrameBuffer.h @@ -71,10 +71,13 @@ public: void correctHeight(); void clearBuffersChanged(); + FrameBuffer * getCopyBuffer() const { return m_pCopy; } + void setCopyBuffer(FrameBuffer * _pBuffer) { m_pCopy = _pBuffer; } + static FrameBufferList & get(); private: - FrameBufferList() : m_pCurrent(NULL) {} + FrameBufferList() : m_pCurrent(NULL), m_pCopy(NULL) {} FrameBufferList(const FrameBufferList &); FrameBuffer * _findBuffer(u32 _startAddress, u32 _endAddress, u32 _width); @@ -82,6 +85,7 @@ private: typedef std::list FrameBuffers; FrameBuffers m_list; FrameBuffer * m_pCurrent; + FrameBuffer * m_pCopy; }; struct PBOBinder { diff --git a/src/RSP.cpp b/src/RSP.cpp index a2724fce..46126b62 100644 --- a/src/RSP.cpp +++ b/src/RSP.cpp @@ -338,7 +338,7 @@ void RSP_Init() ) config.generalEmulation.hacks |= hack_VIUpdateOnCIChange; else if (strstr(RSP.romname, (const char *)"MASK") != NULL) // Zelda MM - config.generalEmulation.hacks |= hack_skipVIChangeCheck; + config.generalEmulation.hacks |= hack_skipVIChangeCheck | hack_ZeldaCamera; api().FindPluginPath(RSP.pluginpath); diff --git a/src/gSP.cpp b/src/gSP.cpp index e34c4c03..cf41db5e 100644 --- a/src/gSP.cpp +++ b/src/gSP.cpp @@ -2114,6 +2114,11 @@ void _loadBGImage(const uObjScaleBg * _bgInfo, bool _loadScale) gDP.tiles[0].textureMode = TEXTUREMODE_FRAMEBUFFER_BG; gDP.tiles[0].loadType = LOADTYPE_TILE; gDP.changed |= CHANGED_TMEM; + + if ((config.generalEmulation.hacks & hack_ZeldaCamera) != 0) { + if (gDP.colorImage.address == gDP.depthImageAddress) + frameBufferList().setCopyBuffer(frameBufferList().getCurrent()); + } } } }