summaryrefslogtreecommitdiff
path: root/Source/Plugins/Plugin_VideoOGL/Src/FramebufferManager.cpp
diff options
context:
space:
mode:
authorNolan Check <Nolan.Check@gmail.com>2009-06-29 07:30:48 +0000
committerNolan Check <Nolan.Check@gmail.com>2009-06-29 07:30:48 +0000
commitc2e0225aa39a0e98a65f5ebbd600cd9f2aa05e9c (patch)
tree080275a318d8f639e20ffd49218ff18aa9053b0d /Source/Plugins/Plugin_VideoOGL/Src/FramebufferManager.cpp
parent188fa9b2cb9ba5f5d37faab40a906112905e7aa9 (diff)
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
Diffstat (limited to 'Source/Plugins/Plugin_VideoOGL/Src/FramebufferManager.cpp')
-rw-r--r--Source/Plugins/Plugin_VideoOGL/Src/FramebufferManager.cpp210
1 files changed, 209 insertions, 1 deletions
diff --git a/Source/Plugins/Plugin_VideoOGL/Src/FramebufferManager.cpp b/Source/Plugins/Plugin_VideoOGL/Src/FramebufferManager.cpp
index 1c531db68d..529c7fe876 100644
--- a/Source/Plugins/Plugin_VideoOGL/Src/FramebufferManager.cpp
+++ b/Source/Plugins/Plugin_VideoOGL/Src/FramebufferManager.cpp
@@ -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;
+}