2015-05-24 04:32:32 +00:00
|
|
|
// Copyright 2010 Dolphin Emulator Project
|
|
|
|
// Licensed under GPLv2+
|
|
|
|
// Refer to the license.txt file included.
|
|
|
|
|
2016-06-24 08:43:46 +00:00
|
|
|
#include "VideoCommon/FramebufferManagerBase.h"
|
2017-02-03 17:31:20 +00:00
|
|
|
|
2015-09-01 20:54:40 +00:00
|
|
|
#include <algorithm>
|
2015-12-21 19:11:01 +00:00
|
|
|
#include <array>
|
|
|
|
#include <memory>
|
2017-02-03 17:31:20 +00:00
|
|
|
#include <tuple>
|
|
|
|
|
2014-02-17 10:18:15 +00:00
|
|
|
#include "VideoCommon/RenderBase.h"
|
|
|
|
#include "VideoCommon/VideoConfig.h"
|
2010-11-14 23:56:26 +00:00
|
|
|
|
2015-12-22 23:47:20 +00:00
|
|
|
std::unique_ptr<FramebufferManagerBase> g_framebuffer_manager;
|
2010-11-14 23:56:26 +00:00
|
|
|
|
2016-06-24 08:43:46 +00:00
|
|
|
std::unique_ptr<XFBSourceBase>
|
|
|
|
FramebufferManagerBase::m_realXFBSource; // Only used in Real XFB mode
|
|
|
|
FramebufferManagerBase::VirtualXFBListType
|
|
|
|
FramebufferManagerBase::m_virtualXFBList; // Only used in Virtual XFB mode
|
|
|
|
std::array<const XFBSourceBase*, FramebufferManagerBase::MAX_VIRTUAL_XFB>
|
|
|
|
FramebufferManagerBase::m_overlappingXFBArray;
|
2010-11-14 23:56:26 +00:00
|
|
|
|
2014-11-06 10:41:39 +00:00
|
|
|
unsigned int FramebufferManagerBase::m_EFBLayers = 1;
|
|
|
|
|
2010-11-14 23:56:26 +00:00
|
|
|
FramebufferManagerBase::FramebufferManagerBase()
|
|
|
|
{
|
2016-06-24 08:43:46 +00:00
|
|
|
// Can't hurt
|
|
|
|
m_overlappingXFBArray.fill(nullptr);
|
2010-11-14 23:56:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
FramebufferManagerBase::~FramebufferManagerBase()
|
|
|
|
{
|
2016-06-24 08:43:46 +00:00
|
|
|
// Necessary, as these are static members
|
|
|
|
// (they really shouldn't be and should be refactored at some point).
|
|
|
|
m_virtualXFBList.clear();
|
|
|
|
m_realXFBSource.reset();
|
2010-11-14 23:56:26 +00:00
|
|
|
}
|
|
|
|
|
2016-06-24 08:43:46 +00:00
|
|
|
void FramebufferManagerBase::CopyToXFB(u32 xfbAddr, u32 fbStride, u32 fbHeight,
|
|
|
|
const EFBRectangle& sourceRc, float Gamma)
|
2010-11-14 23:56:26 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2016-06-24 08:43:46 +00:00
|
|
|
void FramebufferManagerBase::CopyToVirtualXFB(u32 xfbAddr, u32 fbStride, u32 fbHeight,
|
|
|
|
const EFBRectangle& sourceRc, float Gamma)
|
2010-11-14 23:56:26 +00:00
|
|
|
{
|
2016-06-24 08:43:46 +00:00
|
|
|
if (!g_framebuffer_manager)
|
|
|
|
return;
|
|
|
|
|
|
|
|
VirtualXFBListType::iterator vxfb = FindVirtualXFB(xfbAddr, sourceRc.GetWidth(), fbHeight);
|
|
|
|
|
|
|
|
if (m_virtualXFBList.end() == vxfb)
|
|
|
|
{
|
|
|
|
if (m_virtualXFBList.size() < MAX_VIRTUAL_XFB)
|
|
|
|
{
|
|
|
|
// create a new Virtual XFB and place it at the front of the list
|
|
|
|
m_virtualXFBList.emplace_front();
|
|
|
|
vxfb = m_virtualXFBList.begin();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// Replace the last virtual XFB
|
|
|
|
--vxfb;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// else // replace existing virtual XFB
|
|
|
|
|
|
|
|
// move this Virtual XFB to the front of the list.
|
|
|
|
if (m_virtualXFBList.begin() != vxfb)
|
|
|
|
m_virtualXFBList.splice(m_virtualXFBList.begin(), m_virtualXFBList, vxfb);
|
|
|
|
|
2017-02-03 17:31:20 +00:00
|
|
|
u32 target_width, target_height;
|
|
|
|
std::tie(target_width, target_height) = g_framebuffer_manager->GetTargetSize();
|
2016-06-24 08:43:46 +00:00
|
|
|
|
|
|
|
// recreate if needed
|
|
|
|
if (vxfb->xfbSource &&
|
|
|
|
(vxfb->xfbSource->texWidth != target_width || vxfb->xfbSource->texHeight != target_height))
|
|
|
|
vxfb->xfbSource.reset();
|
|
|
|
|
|
|
|
if (!vxfb->xfbSource)
|
|
|
|
{
|
|
|
|
vxfb->xfbSource =
|
|
|
|
g_framebuffer_manager->CreateXFBSource(target_width, target_height, m_EFBLayers);
|
|
|
|
if (!vxfb->xfbSource)
|
|
|
|
return;
|
|
|
|
|
|
|
|
vxfb->xfbSource->texWidth = target_width;
|
|
|
|
vxfb->xfbSource->texHeight = target_height;
|
|
|
|
}
|
|
|
|
|
|
|
|
vxfb->xfbSource->srcAddr = vxfb->xfbAddr = xfbAddr;
|
|
|
|
vxfb->xfbSource->srcWidth = vxfb->xfbWidth = sourceRc.GetWidth();
|
|
|
|
vxfb->xfbSource->srcHeight = vxfb->xfbHeight = fbHeight;
|
|
|
|
|
|
|
|
vxfb->xfbSource->sourceRc = g_renderer->ConvertEFBRectangle(sourceRc);
|
|
|
|
|
|
|
|
// keep stale XFB data from being used
|
|
|
|
ReplaceVirtualXFB();
|
|
|
|
|
|
|
|
// Copy EFB data to XFB and restore render target again
|
|
|
|
vxfb->xfbSource->CopyEFB(Gamma);
|
2010-11-14 23:56:26 +00:00
|
|
|
}
|
|
|
|
|
2016-06-24 08:43:46 +00:00
|
|
|
FramebufferManagerBase::VirtualXFBListType::iterator
|
|
|
|
FramebufferManagerBase::FindVirtualXFB(u32 xfbAddr, u32 width, u32 height)
|
2010-11-14 23:56:26 +00:00
|
|
|
{
|
2016-06-24 08:43:46 +00:00
|
|
|
const u32 srcLower = xfbAddr;
|
|
|
|
const u32 srcUpper = xfbAddr + 2 * width * height;
|
2010-11-14 23:56:26 +00:00
|
|
|
|
2016-06-24 08:43:46 +00:00
|
|
|
return std::find_if(m_virtualXFBList.begin(), m_virtualXFBList.end(),
|
|
|
|
[srcLower, srcUpper](const VirtualXFB& xfb) {
|
|
|
|
const u32 dstLower = xfb.xfbAddr;
|
|
|
|
const u32 dstUpper = xfb.xfbAddr + 2 * xfb.xfbWidth * xfb.xfbHeight;
|
2010-11-14 23:56:26 +00:00
|
|
|
|
2016-06-24 08:43:46 +00:00
|
|
|
return dstLower >= srcLower && dstUpper <= srcUpper;
|
|
|
|
});
|
2010-11-14 23:56:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void FramebufferManagerBase::ReplaceVirtualXFB()
|
|
|
|
{
|
2016-06-24 08:43:46 +00:00
|
|
|
VirtualXFBListType::iterator it = m_virtualXFBList.begin();
|
|
|
|
|
|
|
|
const s32 srcLower = it->xfbAddr;
|
|
|
|
const s32 srcUpper = it->xfbAddr + 2 * it->xfbWidth * it->xfbHeight;
|
|
|
|
const s32 lineSize = 2 * it->xfbWidth;
|
|
|
|
|
|
|
|
++it;
|
|
|
|
|
|
|
|
for (; it != m_virtualXFBList.end(); ++it)
|
|
|
|
{
|
|
|
|
s32 dstLower = it->xfbAddr;
|
|
|
|
s32 dstUpper = it->xfbAddr + 2 * it->xfbWidth * it->xfbHeight;
|
|
|
|
|
|
|
|
if (dstLower >= srcLower && dstUpper <= srcUpper)
|
|
|
|
{
|
|
|
|
// Invalidate the data
|
|
|
|
it->xfbAddr = 0;
|
|
|
|
it->xfbHeight = 0;
|
|
|
|
it->xfbWidth = 0;
|
|
|
|
}
|
|
|
|
else if (AddressRangesOverlap(srcLower, srcUpper, dstLower, dstUpper))
|
|
|
|
{
|
|
|
|
s32 upperOverlap = (srcUpper - dstLower) / lineSize;
|
|
|
|
s32 lowerOverlap = (dstUpper - srcLower) / lineSize;
|
|
|
|
|
|
|
|
if (upperOverlap > 0 && lowerOverlap < 0)
|
|
|
|
{
|
|
|
|
it->xfbAddr += lineSize * upperOverlap;
|
|
|
|
it->xfbHeight -= upperOverlap;
|
|
|
|
}
|
|
|
|
else if (lowerOverlap > 0)
|
|
|
|
{
|
|
|
|
it->xfbHeight -= lowerOverlap;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2010-11-14 23:56:26 +00:00
|
|
|
}
|