dolphin/Source/Plugins/Plugin_VideoMerge/Src/FramebufferManager.cpp
Jordan Woyak 194493cc04 Some work on merging the video plugins: Added a new plugin to the solution(shouldn't build by default) which combines the DX9, DX11, and OGL plugins with their common code merged (and some things temporarily removed). In it's current state the plugin is hardly usable. Perhaps someone with knowledge of the video plugins will be able to fix the things I have broken more easily than me(or point me in the right direction). I will continue to work on it as well.
Main Issues:
DX11 is functional with a ~2MB/s mem leak.
OpenGL/DirectX9 have a black display while game runs. (DirectX 9 flashes good display on emulation stop)
Too many virtual function calls. (once everything is working, I will work on removing them)
Won't build on non-Windows in its current state. (mainly EmuWindow will need changes for Linux/OS X)
Probably other stuff.

git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@6219 8ced0084-cf51-0410-be5f-012b33b47a6e
2010-09-20 21:45:47 +00:00

217 lines
6.0 KiB
C++

#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];
}