summaryrefslogtreecommitdiff
path: root/Source/Plugins/Plugin_VideoMerge/Src/FramebufferManager.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Source/Plugins/Plugin_VideoMerge/Src/FramebufferManager.cpp')
-rw-r--r--Source/Plugins/Plugin_VideoMerge/Src/FramebufferManager.cpp216
1 files changed, 216 insertions, 0 deletions
diff --git a/Source/Plugins/Plugin_VideoMerge/Src/FramebufferManager.cpp b/Source/Plugins/Plugin_VideoMerge/Src/FramebufferManager.cpp
new file mode 100644
index 0000000000..023b9edf0c
--- /dev/null
+++ b/Source/Plugins/Plugin_VideoMerge/Src/FramebufferManager.cpp
@@ -0,0 +1,216 @@
+
+#include "FramebufferManager.h"
+
+#include "VideoConfig.h"
+#include "Renderer.h"
+
+#include "Main.h"
+
+FramebufferManagerBase::VirtualXFBListType FramebufferManagerBase::m_virtualXFBList; // Only used in Virtual XFB mode
+
+const XFBSourceBase* FramebufferManagerBase::m_overlappingXFBArray[];
+
+FramebufferManagerBase::~FramebufferManagerBase()
+{
+ VirtualXFBListType::iterator
+ it = m_virtualXFBList.begin(),
+ vlend = m_virtualXFBList.end();
+ for (; it != vlend; ++it)
+ delete it->xfbSource;
+}
+
+const XFBSourceBase** FramebufferManagerBase::GetXFBSource(u32 xfbAddr, u32 fbWidth, u32 fbHeight, u32 &xfbCount)
+{
+ //if (g_ActiveConfig.bUseRealXFB)
+ // return getRealXFBSource(xfbAddr, fbWidth, fbHeight, xfbCount);
+ //else
+ return getVirtualXFBSource(xfbAddr, fbWidth, fbHeight, xfbCount);
+}
+
+inline bool addrRangesOverlap(u32 aLower, u32 aUpper, u32 bLower, u32 bUpper)
+{
+ return !((aLower >= bUpper) || (bLower >= aUpper));
+}
+
+void FramebufferManagerBase::CopyToXFB(u32 xfbAddr, u32 fbWidth, u32 fbHeight, const EFBRectangle& sourceRc)
+{
+ //if (g_ActiveConfig.bUseRealXFB)
+ // copyToRealXFB(xfbAddr, fbWidth, fbHeight, sourceRc);
+ //else
+ copyToVirtualXFB(xfbAddr, fbWidth, fbHeight, sourceRc);
+}
+
+void FramebufferManagerBase::replaceVirtualXFB()
+{
+ VirtualXFBListType::iterator
+ it = m_virtualXFBList.begin(),
+ vlend = m_virtualXFBList.end();
+
+ VirtualXFB *vxfb = &*it;
+
+ const s32 srcLower = vxfb->xfbAddr;
+ const s32 srcUpper = vxfb->xfbAddr + 2 * vxfb->xfbWidth * vxfb->xfbHeight;
+ const s32 lineSize = 2 * vxfb->xfbWidth;
+
+ while (++it != vlend)
+ {
+ vxfb = &*it;
+
+ const s32 dstLower = vxfb->xfbAddr;
+ const s32 dstUpper = vxfb->xfbAddr + 2 * vxfb->xfbWidth * vxfb->xfbHeight;
+
+ if (dstLower >= srcLower && dstUpper <= srcUpper)
+ {
+ // invalidate the data
+ vxfb->xfbAddr = 0;
+ vxfb->xfbHeight = 0;
+ vxfb->xfbWidth = 0;
+ }
+ else if (addrRangesOverlap(srcLower, srcUpper, dstLower, dstUpper))
+ {
+ const s32 upperOverlap = (srcUpper - dstLower) / lineSize;
+ const s32 lowerOverlap = (dstUpper - srcLower) / lineSize;
+
+ if (upperOverlap > 0 && lowerOverlap < 0)
+ {
+ vxfb->xfbAddr += lineSize * upperOverlap;
+ vxfb->xfbHeight -= upperOverlap;
+ }
+ else if (lowerOverlap > 0)
+ {
+ vxfb->xfbHeight -= lowerOverlap;
+ }
+ }
+ }
+}
+
+FramebufferManagerBase::VirtualXFBListType::iterator
+FramebufferManagerBase::findVirtualXFB(u32 xfbAddr, u32 width, u32 height)
+{
+ const u32 srcLower = xfbAddr;
+ const u32 srcUpper = xfbAddr + 2 * width * height;
+
+ VirtualXFBListType::iterator
+ it = m_virtualXFBList.begin(),
+ vlend = m_virtualXFBList.end();
+ for (; it != vlend; ++it)
+ {
+ const VirtualXFB &vxfb = *it;
+
+ const u32 dstLower = vxfb.xfbAddr;
+ const u32 dstUpper = vxfb.xfbAddr + 2 * vxfb.xfbWidth * vxfb.xfbHeight;
+
+ if (dstLower >= srcLower && dstUpper <= srcUpper)
+ return it;
+ }
+
+ // That address is not in the Virtual XFB list.
+ return m_virtualXFBList.end();
+}
+
+void FramebufferManagerBase::copyToVirtualXFB(u32 xfbAddr, u32 fbWidth, u32 fbHeight, const EFBRectangle& sourceRc)
+{
+ const VirtualXFBListType::iterator it = findVirtualXFB(xfbAddr, fbWidth, fbHeight);
+
+ VirtualXFB *vxfb = NULL;
+
+ if (m_virtualXFBList.end() == it)
+ {
+ if (m_virtualXFBList.size() >= MAX_VIRTUAL_XFB)
+ {
+ PanicAlert("Requested creating a new virtual XFB although the maximum number has already been reached! Report this to the devs");
+ return;
+ // TODO, possible alternative to failing: just delete the oldest virtual XFB:
+ // delete m_virtualXFBList.back().xfbSource;
+ // m_virtualXFBList.pop_back();
+ }
+ else
+ {
+ // create a new Virtual XFB and place it at the front of the list
+ VirtualXFB v;
+ m_virtualXFBList.push_front(v);
+ vxfb = &m_virtualXFBList.front();
+ }
+ }
+ else
+ {
+ vxfb = &*it;
+ delete vxfb->xfbSource;
+ }
+
+ vxfb->xfbAddr = xfbAddr;
+ vxfb->xfbWidth = fbWidth;
+ vxfb->xfbHeight = fbHeight;
+
+ const float scaleX = RendererBase::GetXFBScaleX();
+ const float scaleY = RendererBase::GetXFBScaleY();
+
+ TargetRectangle targetSource;
+ targetSource.top = (int)(sourceRc.top * scaleY);
+ targetSource.bottom = (int)(sourceRc.bottom * scaleY);
+ targetSource.left = (int)(sourceRc.left * scaleX);
+ targetSource.right = (int)(sourceRc.right * scaleX);
+
+ const unsigned int target_width = targetSource.right - targetSource.left;
+ const unsigned int target_height = targetSource.bottom - targetSource.top;
+
+ vxfb->xfbSource = g_framebuffer_manager->CreateXFBSource(target_width, target_height);
+ if (NULL == vxfb->xfbSource)
+ {
+ PanicAlert("Failed to create virtual XFB");
+ return;
+ }
+
+ // why do both of these have a height/width/addr ?
+ vxfb->xfbSource->srcAddr = xfbAddr;
+ vxfb->xfbSource->srcWidth = fbWidth;
+ vxfb->xfbSource->srcHeight = fbHeight;
+
+ vxfb->xfbSource->texWidth = target_width;
+ vxfb->xfbSource->texHeight = target_height;
+
+ if (m_virtualXFBList.end() != it)
+ {
+ // move this Virtual XFB to the front of the list.
+ m_virtualXFBList.splice(m_virtualXFBList.begin(), m_virtualXFBList, it);
+
+ // keep stale XFB data from being used
+ replaceVirtualXFB();
+ }
+
+ g_renderer->ResetAPIState(); // reset any game specific settings
+
+ vxfb->xfbSource->CopyEFB(RendererBase::ConvertEFBRectangle(sourceRc));
+
+ g_renderer->RestoreAPIState();
+}
+
+const XFBSourceBase** FramebufferManagerBase::getVirtualXFBSource(u32 xfbAddr, u32 fbWidth, u32 fbHeight, u32 &xfbCount)
+{
+ xfbCount = 0;
+
+ if (0 == m_virtualXFBList.size()) // no Virtual XFBs available
+ return NULL;
+
+ u32 srcLower = xfbAddr;
+ u32 srcUpper = xfbAddr + 2 * fbWidth * fbHeight;
+
+ VirtualXFBListType::reverse_iterator
+ it = m_virtualXFBList.rbegin(),
+ vlend = m_virtualXFBList.rend();
+ for (; it != vlend; ++it)
+ {
+ VirtualXFB* vxfb = &*it;
+
+ u32 dstLower = vxfb->xfbAddr;
+ u32 dstUpper = vxfb->xfbAddr + 2 * vxfb->xfbWidth * vxfb->xfbHeight;
+
+ if (addrRangesOverlap(srcLower, srcUpper, dstLower, dstUpper))
+ {
+ m_overlappingXFBArray[xfbCount] = vxfb->xfbSource;
+ xfbCount++;
+ }
+ }
+
+ return &m_overlappingXFBArray[0];
+}