Move to new Virtual XFB system which correctly handles games which store multiple XFB's in memory. More OpenGL cleanup.

git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@3591 8ced0084-cf51-0410-be5f-012b33b47a6e
This commit is contained in:
Nolan Check 2009-06-29 07:30:48 +00:00
parent 188fa9b2cb
commit c2e0225aa3
15 changed files with 389 additions and 133 deletions

View file

@ -18,6 +18,9 @@
#include "Globals.h"
#include "FramebufferManager.h"
#include "TextureConverter.h"
#include "XFB.h"
void FramebufferManager::Init(int targetWidth, int targetHeight, int msaaSamples, int msaaCoverageSamples)
{
m_targetWidth = targetWidth;
@ -156,7 +159,11 @@ void FramebufferManager::Shutdown()
glObj[0] = m_resolvedColorTexture;
glObj[1] = m_resolvedDepthTexture;
glDeleteTextures(2, glObj);
glObj[2] = m_realXFBSource.texture;
glDeleteTextures(3, glObj);
m_resolvedColorTexture = 0;
m_resolvedDepthTexture = 0;
m_realXFBSource.texture = 0;
glObj[0] = m_efbColor;
glObj[1] = m_efbDepth;
@ -166,6 +173,28 @@ void FramebufferManager::Shutdown()
glDeleteRenderbuffersEXT(2, glObj);
m_efbColor = 0;
m_efbDepth = 0;
for (VirtualXFBListType::iterator it = m_virtualXFBList.begin(); it != m_virtualXFBList.end(); ++it)
{
glDeleteTextures(1, &it->xfbSource.texture);
}
m_virtualXFBList.clear();
}
void FramebufferManager::CopyToXFB(u32 xfbAddr, u32 dstWidth, u32 dstHeight, const TRectangle& sourceRc)
{
if (g_Config.bUseXFB)
copyToRealXFB(xfbAddr, dstWidth, dstHeight, sourceRc);
else
copyToVirtualXFB(xfbAddr, dstWidth, dstHeight, sourceRc);
}
const XFBSource* FramebufferManager::GetXFBSource(u32 xfbAddr, u32 srcWidth, u32 srcHeight)
{
if (g_Config.bUseXFB)
return getRealXFBSource(xfbAddr, srcWidth, srcHeight);
else
return getVirtualXFBSource(xfbAddr, srcWidth, srcHeight);
}
GLuint FramebufferManager::GetEFBColorTexture(const TRectangle& sourceRc) const
@ -231,3 +260,182 @@ GLuint FramebufferManager::GetEFBDepthTexture(const TRectangle& sourceRc) const
return m_resolvedDepthTexture;
}
}
FramebufferManager::VirtualXFBListType::iterator
FramebufferManager::findVirtualXFB(u32 xfbAddr, u32 width, u32 height)
{
u32 srcLower = xfbAddr;
u32 srcUpper = xfbAddr + 2 * width * height;
VirtualXFBListType::iterator it;
for (it = m_virtualXFBList.begin(); it != m_virtualXFBList.end(); ++it)
{
u32 dstLower = it->xfbAddr;
u32 dstUpper = it->xfbAddr + 2 * it->xfbWidth * it->xfbHeight;
if (addrRangesOverlap(srcLower, srcUpper, dstLower, dstUpper))
return it;
}
// That address is not in the Virtual XFB list.
return m_virtualXFBList.end();
}
void FramebufferManager::copyToRealXFB(u32 xfbAddr, u32 dstWidth, u32 dstHeight, const TRectangle& sourceRc)
{
u8* pXFB = Memory_GetPtr(xfbAddr);
if (!pXFB)
{
WARN_LOG(VIDEO, "Tried to copy to invalid XFB address");
return;
}
XFB_Write(pXFB, sourceRc, dstWidth, dstHeight);
}
void FramebufferManager::copyToVirtualXFB(u32 xfbAddr, u32 dstWidth, u32 dstHeight, const TRectangle& sourceRc)
{
GLuint xfbTexture;
VirtualXFBListType::iterator it = findVirtualXFB(xfbAddr, dstWidth, dstHeight);
if (it != m_virtualXFBList.end())
{
// Overwrite an existing Virtual XFB.
it->xfbAddr = xfbAddr;
it->xfbWidth = dstWidth;
it->xfbHeight = dstHeight;
it->xfbSource.texWidth = m_targetWidth;
it->xfbSource.texHeight = m_targetHeight;
it->xfbSource.sourceRc = sourceRc;
xfbTexture = it->xfbSource.texture;
// Move this Virtual XFB to the front of the list.
m_virtualXFBList.splice(m_virtualXFBList.begin(), m_virtualXFBList, it);
}
else
{
// Create a new Virtual XFB and place it at the front of the list.
glGenTextures(1, &xfbTexture);
if (m_msaaSamples > 1)
{
// In MSAA mode, allocate the texture image here. In non-MSAA mode,
// the image will be allocated by glCopyTexImage2D (later).
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, xfbTexture);
glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, 4, m_targetWidth, m_targetHeight, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0);
}
VirtualXFB newVirt;
newVirt.xfbAddr = xfbAddr;
newVirt.xfbWidth = dstWidth;
newVirt.xfbHeight = dstHeight;
newVirt.xfbSource.texture = xfbTexture;
newVirt.xfbSource.texWidth = m_targetWidth;
newVirt.xfbSource.texHeight = m_targetHeight;
newVirt.xfbSource.sourceRc = sourceRc;
// Add the new Virtual XFB to the list
if (m_virtualXFBList.size() >= MAX_VIRTUAL_XFB)
{
// List overflowed; delete the oldest.
glDeleteTextures(1, &m_virtualXFBList.back().xfbSource.texture);
m_virtualXFBList.pop_back();
}
m_virtualXFBList.push_front(newVirt);
}
// Copy EFB to XFB texture
if (m_msaaSamples <= 1)
{
// Just copy the EFB directly.
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_efbFramebuffer);
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, xfbTexture);
glCopyTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, 4, 0, 0, m_targetWidth, m_targetHeight, 0);
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0);
}
else
{
// OpenGL cannot copy directly from a multisampled framebuffer, so use
// EXT_framebuffer_blit.
glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, m_efbFramebuffer);
glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, m_xfbFramebuffer);
// Bind texture.
glFramebufferTexture2DEXT(GL_DRAW_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_RECTANGLE_ARB, xfbTexture, 0);
GL_REPORT_FBO_ERROR();
glBlitFramebufferEXT(
0, 0, m_targetWidth, m_targetHeight,
0, 0, m_targetWidth, m_targetHeight,
GL_COLOR_BUFFER_BIT, GL_NEAREST
);
// Unbind texture.
glFramebufferTexture2DEXT(GL_DRAW_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_RECTANGLE_ARB, 0, 0);
// Return to EFB.
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_efbFramebuffer);
}
}
const XFBSource* FramebufferManager::getRealXFBSource(u32 xfbAddr, u32 srcWidth, u32 srcHeight)
{
m_realXFBSource.texWidth = XFB_WIDTH;
m_realXFBSource.texHeight = XFB_HEIGHT;
m_realXFBSource.sourceRc.left = 0;
m_realXFBSource.sourceRc.top = 0;
m_realXFBSource.sourceRc.right = srcWidth;
m_realXFBSource.sourceRc.bottom = srcHeight;
if (!m_realXFBSource.texture)
{
glGenTextures(1, &m_realXFBSource.texture);
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, m_realXFBSource.texture);
glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, 4, XFB_WIDTH, XFB_HEIGHT, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0);
}
// Decode YUYV data from GameCube RAM
TextureConverter::DecodeToTexture(xfbAddr, srcWidth, srcHeight, m_realXFBSource.texture);
return &m_realXFBSource;
}
const XFBSource* FramebufferManager::getVirtualXFBSource(u32 xfbAddr, u32 srcWidth, u32 srcHeight)
{
if (m_virtualXFBList.size() == 0)
{
// No Virtual XFBs available.
return NULL;
}
VirtualXFBListType::iterator it = findVirtualXFB(xfbAddr, srcWidth, srcHeight);
if (it == m_virtualXFBList.end())
{
// Virtual XFB is not in the list, so return the most recently rendered
// one.
it = m_virtualXFBList.begin();
}
return &it->xfbSource;
}