Clean up OpenGL code and introduce the Framebuffer Manager. More work is forthcoming; I plan to implement resolution switching (while the game is running) and also multiple virtual XFBs for game-controlled buffer swapping.

git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@3587 8ced0084-cf51-0410-be5f-012b33b47a6e
This commit is contained in:
Nolan Check 2009-06-28 23:35:08 +00:00
parent fd47eb7b44
commit 07a767691d
7 changed files with 357 additions and 246 deletions

View File

@ -736,6 +736,14 @@
<Filter <Filter
Name="Render" Name="Render"
> >
<File
RelativePath=".\Src\FramebufferManager.cpp"
>
</File>
<File
RelativePath=".\Src\FramebufferManager.h"
>
</File>
<File <File
RelativePath=".\Src\OnScreenDisplay.cpp" RelativePath=".\Src\OnScreenDisplay.cpp"
> >

View File

@ -0,0 +1,222 @@
// Copyright (C) 2003-2009 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#include "Globals.h"
#include "FramebufferManager.h"
void FramebufferManager::Init(int targetWidth, int targetHeight, int msaaSamples, int msaaCoverageSamples)
{
m_targetWidth = targetWidth;
m_targetHeight = targetHeight;
m_msaaSamples = msaaSamples;
m_msaaCoverageSamples = msaaCoverageSamples;
// Create EFB target.
glGenFramebuffersEXT(1, &m_efbFramebuffer);
if (m_msaaSamples <= 1)
{
// EFB targets will be textures in non-MSAA mode.
GLuint glObj[2];
glGenTextures(2, glObj);
m_efbColor = glObj[0];
m_efbDepth = glObj[1];
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, m_efbColor);
glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA8, m_targetWidth, m_targetHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, m_efbDepth);
glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_DEPTH_COMPONENT24, m_targetWidth, m_targetHeight, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, NULL);
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0);
// Bind target textures to the EFB framebuffer.
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_efbFramebuffer);
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_RECTANGLE_ARB, m_efbColor, 0);
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_RECTANGLE_ARB, m_efbDepth, 0);
GL_REPORT_FBO_ERROR();
}
else
{
// EFB targets will be renderbuffers in MSAA mode (required by OpenGL).
// Resolve targets will be created to transfer EFB to RAM textures.
// XFB framebuffer will be created to transfer EFB to XFB texture.
// Create EFB target renderbuffers.
GLuint glObj[2];
glGenRenderbuffersEXT(2, glObj);
m_efbColor = glObj[0];
m_efbDepth = glObj[1];
glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, m_efbColor);
if (m_msaaCoverageSamples)
glRenderbufferStorageMultisampleCoverageNV(GL_RENDERBUFFER_EXT, m_msaaCoverageSamples, m_msaaSamples, GL_RGBA8, m_targetWidth, m_targetHeight);
else
glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, m_msaaSamples, GL_RGBA8, m_targetWidth, m_targetHeight);
glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, m_efbDepth);
if (m_msaaCoverageSamples)
glRenderbufferStorageMultisampleCoverageNV(GL_RENDERBUFFER_EXT, m_msaaCoverageSamples, m_msaaSamples, GL_DEPTH_COMPONENT24, m_targetWidth, m_targetHeight);
else
glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, m_msaaSamples, GL_DEPTH_COMPONENT24, m_targetWidth, m_targetHeight);
glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0);
// Bind target renderbuffers to EFB framebuffer.
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_efbFramebuffer);
glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_RENDERBUFFER_EXT, m_efbColor);
glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, m_efbDepth);
GL_REPORT_FBO_ERROR();
// Create XFB framebuffer; targets will be created elsewhere.
glGenFramebuffersEXT(1, &m_xfbFramebuffer);
// Create resolved targets for transferring multisampled EFB to texture.
glGenFramebuffersEXT(1, &m_resolvedFramebuffer);
glGenTextures(2, glObj);
m_resolvedColorTexture = glObj[0];
m_resolvedDepthTexture = glObj[1];
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, m_resolvedColorTexture);
glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA8, m_targetWidth, m_targetHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, m_resolvedDepthTexture);
glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_DEPTH_COMPONENT24, m_targetWidth, m_targetHeight, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, NULL);
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0);
// Bind resolved textures to resolved framebuffer.
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_resolvedFramebuffer);
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_RECTANGLE_ARB, m_resolvedColorTexture, 0);
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_RECTANGLE_ARB, m_resolvedDepthTexture, 0);
GL_REPORT_FBO_ERROR();
// Return to EFB framebuffer.
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_efbFramebuffer);
}
// EFB framebuffer is currently bound.
}
void FramebufferManager::Shutdown()
{
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
GLuint glObj[3];
// Note: OpenGL deletion functions silently ignore parameters of "0".
glObj[0] = m_efbFramebuffer;
glObj[1] = m_resolvedFramebuffer;
glObj[2] = m_xfbFramebuffer;
glDeleteFramebuffersEXT(3, glObj);
m_efbFramebuffer = 0;
m_xfbFramebuffer = 0;
glObj[0] = m_resolvedColorTexture;
glObj[1] = m_resolvedDepthTexture;
glDeleteTextures(2, glObj);
glObj[0] = m_efbColor;
glObj[1] = m_efbDepth;
if (m_msaaSamples <= 1)
glDeleteTextures(2, glObj);
else
glDeleteRenderbuffersEXT(2, glObj);
m_efbColor = 0;
m_efbDepth = 0;
}
GLuint FramebufferManager::GetEFBColorTexture(const TRectangle& sourceRc) const
{
if (m_msaaSamples <= 1)
{
return m_efbColor;
}
else
{
// Transfer the EFB to a resolved texture. EXT_framebuffer_blit is
// required.
// Flip source rectangle upside-down for OpenGL.
TRectangle glRect;
sourceRc.FlipYPosition(m_targetHeight, &glRect);
glRect.Clamp(0, 0, m_targetWidth, m_targetHeight);
// Resolve.
glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, m_efbFramebuffer);
glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, m_resolvedFramebuffer);
glBlitFramebufferEXT(
glRect.left, glRect.top, glRect.right, glRect.bottom,
glRect.left, glRect.top, glRect.right, glRect.bottom,
GL_COLOR_BUFFER_BIT, GL_NEAREST
);
// Return to EFB.
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_efbFramebuffer);
return m_resolvedColorTexture;
}
}
GLuint FramebufferManager::GetEFBDepthTexture(const TRectangle& sourceRc) const
{
if (m_msaaSamples <= 1)
{
return m_efbDepth;
}
else
{
// Transfer the EFB to a resolved texture. EXT_framebuffer_blit is
// required.
// Flip source rectangle upside-down for OpenGL.
TRectangle glRect;
sourceRc.FlipYPosition(m_targetHeight, &glRect);
glRect.Clamp(0, 0, m_targetWidth, m_targetHeight);
// Resolve.
glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, m_efbFramebuffer);
glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, m_resolvedFramebuffer);
glBlitFramebufferEXT(
glRect.left, glRect.top, glRect.right, glRect.bottom,
glRect.left, glRect.top, glRect.right, glRect.bottom,
GL_DEPTH_BUFFER_BIT, GL_NEAREST
);
// Return to EFB.
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_efbFramebuffer);
return m_resolvedDepthTexture;
}
}

View File

@ -0,0 +1,68 @@
// Copyright (C) 2003-2009 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#ifndef _FRAMEBUFFERMANAGER_H_
#define _FRAMEBUFFERMANAGER_H_
#include "GLUtil.h"
class FramebufferManager
{
public:
FramebufferManager() :
m_efbFramebuffer(0),
m_efbColor(0),
m_efbDepth(0),
m_resolvedFramebuffer(0),
m_resolvedColorTexture(0),
m_resolvedDepthTexture(0),
m_xfbFramebuffer(0)
{}
void Init(int targetWidth, int targetHeight, int msaaSamples, int msaaCoverageSamples);
void Shutdown();
// To get the EFB in texture form, these functions may have to transfer
// the EFB to a resolved texture first.
GLuint GetEFBColorTexture(const TRectangle& sourceRc) const;
GLuint GetEFBDepthTexture(const TRectangle& sourceRc) const;
GLuint GetEFBFramebuffer() const { return m_efbFramebuffer; }
private:
int m_targetWidth;
int m_targetHeight;
int m_msaaSamples;
int m_msaaCoverageSamples;
GLuint m_efbFramebuffer;
GLuint m_efbColor; // Renderbuffer in MSAA mode; Texture otherwise
GLuint m_efbDepth; // Renderbuffer in MSAA mode; Texture otherwise
// Only used in MSAA mode.
GLuint m_resolvedFramebuffer;
GLuint m_resolvedColorTexture;
GLuint m_resolvedDepthTexture;
GLuint m_xfbFramebuffer; // Only used in MSAA mode
};
#endif

View File

@ -54,6 +54,7 @@
#include "OnScreenDisplay.h" #include "OnScreenDisplay.h"
#include "Timer.h" #include "Timer.h"
#include "StringUtil.h" #include "StringUtil.h"
#include "FramebufferManager.h"
#include "main.h" // Local #include "main.h" // Local
#ifdef _WIN32 #ifdef _WIN32
@ -92,37 +93,7 @@ static FILE* f_pFrameDump;
static int s_MSAASamples = 1; static int s_MSAASamples = 1;
static int s_MSAACoverageSamples = 0; static int s_MSAACoverageSamples = 0;
// Normal Mode // TODO: Move these to FramebufferManager
//
// By default the depth target is used
// if there is an error creating and attaching it a depth buffer will be used instead
//
// s_RenderTarget is a texture_rect
// s_DepthTarget is a texture_rect
// s_DepthBuffer is a Z renderbuffer
// MSAA mode
// s_uFramebuffer is a FBO
// s_RenderTarget is a MSAA renderbuffer
// s_DepthTarget is a MSAA renderbuffer
//
// s_ResolvedFramebuffer is a FBO
// s_ResolvedRenderTarget is a texture
// s_ResolvedDepthTarget is a texture
// A framebuffer is a set of render targets: a color and a z buffer. They can be either RenderBuffers or Textures.
static GLuint s_uFramebuffer = 0;
static GLuint s_uResolvedFramebuffer = 0;
// The size of these should be a (not necessarily even) multiple of the EFB size, 640x528, but isn't.
// These are all texture IDs. Bind them as rect arb textures.
static GLuint s_RenderTarget = 0;
static GLuint s_DepthTarget = 0;
static GLuint s_DepthBuffer = 0;
static GLuint s_ResolvedRenderTarget = 0;
static GLuint s_ResolvedDepthTarget = 0;
static TRectangle s_efbSourceRc; static TRectangle s_efbSourceRc;
static GLuint s_xfbFramebuffer = 0; // Only used when multisampling is on static GLuint s_xfbFramebuffer = 0; // Only used when multisampling is on
static GLuint s_xfbTexture = 0; static GLuint s_xfbTexture = 0;
@ -145,6 +116,8 @@ static int s_fps = 0;
static int s_targetwidth; // Size of render buffer FBO. static int s_targetwidth; // Size of render buffer FBO.
static int s_targetheight; static int s_targetheight;
static FramebufferManager s_framebufferManager;
#ifndef _WIN32 #ifndef _WIN32
int OSDChoice = 0 , OSDTime = 0, OSDInternalW = 0, OSDInternalH = 0; int OSDChoice = 0 , OSDTime = 0, OSDInternalW = 0, OSDInternalH = 0;
#endif #endif
@ -304,19 +277,27 @@ bool Renderer::Init()
WARN_LOG(VIDEO, "ARB_texture_non_power_of_two not supported. This extension is not yet used, though."); WARN_LOG(VIDEO, "ARB_texture_non_power_of_two not supported. This extension is not yet used, though.");
} }
// The size of the framebuffer targets should really NOT be the size of the OpenGL viewport. if (g_Config.bNativeResolution)
// The EFB is larger than 640x480 - in fact, it's 640x528, give or take a couple of lines. {
// So the below is wrong. s_targetwidth = g_Config.b2xResolution ? EFB_WIDTH * 2 : EFB_WIDTH;
// This should really be grabbed from config rather than from OpenGL. s_targetheight = g_Config.b2xResolution ? EFB_HEIGHT * 2 : EFB_HEIGHT;
// JP: Set these to the biggest of the 2x mode and the custom resolution so that the framebuffer }
// does not get to be too small else
int W = (int)OpenGL_GetBackbufferWidth(), H = (int)OpenGL_GetBackbufferHeight(); {
s_targetwidth = (1280 >= W) ? 1280 : W; // The size of the framebuffer targets should really NOT be the size of the OpenGL viewport.
s_targetheight = (960 >= H) ? 960 : H; // The EFB is larger than 640x480 - in fact, it's 640x528, give or take a couple of lines.
// So the below is wrong.
// This should really be grabbed from config rather than from OpenGL.
// JP: Set these to the biggest of the 2x mode and the custom resolution so that the framebuffer
// does not get to be too small
int W = (int)OpenGL_GetBackbufferWidth(), H = (int)OpenGL_GetBackbufferHeight();
s_targetwidth = (1280 >= W) ? 1280 : W;
s_targetheight = (960 >= H) ? 960 : H;
// Compensate height of render target for scaling, so that we get something close to the correct number of // Compensate height of render target for scaling, so that we get something close to the correct number of
// vertical pixels. // vertical pixels.
s_targetheight *= 528.0 / 480.0; s_targetheight *= 528.0 / 480.0;
}
// Ensure a minimum target size so that the native res target always fits. // Ensure a minimum target size so that the native res target always fits.
if (s_targetwidth < EFB_WIDTH) if (s_targetwidth < EFB_WIDTH)
@ -330,122 +311,22 @@ bool Renderer::Init()
glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, 4, s_targetwidth, s_targetheight, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL); glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, 4, s_targetwidth, s_targetheight, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
SetDefaultRectTexParams(); SetDefaultRectTexParams();
glGenFramebuffersEXT(1, (GLuint *)&s_uFramebuffer); // Bind it to an XFB framebuffer if MSAA is used
if (s_uFramebuffer == 0) { if (s_MSAASamples > 1)
ERROR_LOG(VIDEO, "failed to create the renderbufferDoes your video card support OpenGL 2.x?");
}
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, s_uFramebuffer);
if (s_MSAASamples <= 1) {
// Create the framebuffer target texture
glGenTextures(1, (GLuint *)&s_RenderTarget);
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, s_RenderTarget);
// Create our main color render target as a texture rectangle of the desired size.
glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, 4, s_targetwidth, s_targetheight, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
SetDefaultRectTexParams();
// Create the depth target texture
glGenTextures(1, &s_DepthTarget);
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, s_DepthTarget);
glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_DEPTH_COMPONENT24, s_targetwidth, s_targetheight, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, NULL);
SetDefaultRectTexParams();
// Our framebuffer object is still bound here. Attach the two render targets, color and depth, to the framebuffer object.
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_RECTANGLE_ARB, s_RenderTarget, 0);
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_RECTANGLE_ARB, s_DepthTarget, 0);
GL_REPORT_FBO_ERROR();
bool bFailed = glGetError() != GL_NO_ERROR || glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT) != GL_FRAMEBUFFER_COMPLETE_EXT;
// Check that the FBO is attached. If there is an error revert to a depth buffer.
if (bFailed) {
ERROR_LOG(VIDEO, "Disabling ztarget feature");
// detach and delete depth texture
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_RECTANGLE_ARB, 0, 0);
glDeleteTextures(1, (GLuint *)&s_DepthTarget);
s_DepthTarget = 0;
// create and attach depth buffer
glGenRenderbuffersEXT(1, (GLuint *)&s_DepthBuffer);
glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, s_DepthBuffer);
glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH24_STENCIL8_EXT, s_targetwidth, s_targetheight);
glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, s_DepthBuffer);
GL_REPORT_FBO_ERROR();
}
}
else
{ {
// Create XFB framebuffer for transferring the multisampled EFB to the
// XFB texture
glGenFramebuffersEXT(1, &s_xfbFramebuffer); glGenFramebuffersEXT(1, &s_xfbFramebuffer);
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, s_xfbFramebuffer); glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, s_xfbFramebuffer);
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_RECTANGLE_ARB, s_xfbTexture, 0); glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_RECTANGLE_ARB, s_xfbTexture, 0);
GL_REPORT_FBO_ERROR(); GL_REPORT_FBO_ERROR();
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, s_uFramebuffer);
// MSAA rendertarget init.
// First set up the boring multisampled rendertarget.
glGenRenderbuffersEXT(1, &s_RenderTarget);
glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, s_RenderTarget);
if (s_MSAACoverageSamples) {
glRenderbufferStorageMultisampleCoverageNV(GL_RENDERBUFFER_EXT, s_MSAACoverageSamples, s_MSAASamples, GL_RGBA, s_targetwidth, s_targetheight);
} else {
glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, s_MSAASamples, GL_RGBA, s_targetwidth, s_targetheight);
}
glGenRenderbuffersEXT(1, &s_DepthTarget);
glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, s_DepthTarget);
if (s_MSAACoverageSamples) {
glRenderbufferStorageMultisampleCoverageNV(GL_RENDERBUFFER_EXT, s_MSAACoverageSamples, s_MSAASamples, GL_DEPTH_COMPONENT24, s_targetwidth, s_targetheight);
} else {
glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, s_MSAASamples, GL_DEPTH_COMPONENT24, s_targetwidth, s_targetheight);
}
glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0);
// Attach them to our multisampled FBO. The multisampled FBO is still bound here.
glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_RENDERBUFFER_EXT, s_RenderTarget);
glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, s_DepthTarget);
GL_REPORT_FBO_ERROR();
bool bFailed = glGetError() != GL_NO_ERROR || glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT) != GL_FRAMEBUFFER_COMPLETE_EXT;
if (bFailed) PanicAlert("Incomplete rt");
// Create our resolve FBO, and bind it.
glGenFramebuffersEXT(1, (GLuint *)&s_uResolvedFramebuffer);
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, s_uResolvedFramebuffer);
// Generate the resolve targets.
glGenTextures(1, (GLuint *)&s_ResolvedRenderTarget);
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, s_ResolvedRenderTarget);
glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, 4, s_targetwidth, s_targetheight, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
SetDefaultRectTexParams();
// Generate the resolve targets.
glGenTextures(1, (GLuint *)&s_ResolvedDepthTarget);
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, s_ResolvedDepthTarget);
glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_DEPTH_COMPONENT24, s_targetwidth, s_targetheight, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, NULL);
SetDefaultRectTexParams();
// Attach our resolve targets to our resolved FBO.
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_RECTANGLE_ARB, s_ResolvedRenderTarget, 0);
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_RECTANGLE_ARB, s_ResolvedDepthTarget, 0);
GL_REPORT_FBO_ERROR();
bFailed = glGetError() != GL_NO_ERROR || glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT) != GL_FRAMEBUFFER_COMPLETE_EXT;
if (bFailed) PanicAlert("Incomplete rt2");
if (bFailed) {
ERROR_LOG(VIDEO, "AA rendering init failed.");
}
} }
if (GL_REPORT_ERROR() != GL_NO_ERROR) if (GL_REPORT_ERROR() != GL_NO_ERROR)
bSuccess = false; bSuccess = false;
// glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, s_uFramebuffer); // Initialize the FramebufferManager
s_framebufferManager.Init(s_targetwidth, s_targetheight, s_MSAASamples, s_MSAACoverageSamples);
glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT); glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
if (GL_REPORT_ERROR() != GL_NO_ERROR) if (GL_REPORT_ERROR() != GL_NO_ERROR)
@ -501,17 +382,10 @@ void Renderer::Shutdown(void)
g_cgcontext = 0; g_cgcontext = 0;
} }
s_framebufferManager.Shutdown();
// Note: OpenGL delete functions automatically ignore if parameter is 0 // Note: OpenGL delete functions automatically ignore if parameter is 0
glDeleteFramebuffersEXT(1, &s_uFramebuffer);
s_uFramebuffer = 0;
glDeleteTextures(1, &s_RenderTarget);
s_RenderTarget = 0;
glDeleteRenderbuffersEXT(1, &s_DepthTarget);
s_DepthTarget = 0;
glDeleteFramebuffersEXT(1, &s_xfbFramebuffer); glDeleteFramebuffersEXT(1, &s_xfbFramebuffer);
s_xfbFramebuffer = 0; s_xfbFramebuffer = 0;
@ -574,14 +448,12 @@ bool Renderer::InitializeGL()
// Return the rendering window width and height // Return the rendering window width and height
int Renderer::GetTargetWidth() int Renderer::GetTargetWidth()
{ {
return (s_bNativeResolution || g_Config.b2xResolution) ? return s_targetwidth;
(s_bNativeResolution ? EFB_WIDTH : EFB_WIDTH * 2) : s_targetwidth;
} }
int Renderer::GetTargetHeight() int Renderer::GetTargetHeight()
{ {
return (s_bNativeResolution || g_Config.b2xResolution) ? return s_targetheight;
(s_bNativeResolution ? EFB_HEIGHT : EFB_HEIGHT * 2) : s_targetheight;
} }
float Renderer::GetTargetScaleX() float Renderer::GetTargetScaleX()
@ -594,22 +466,9 @@ float Renderer::GetTargetScaleY()
return (float)GetTargetHeight() / (float)EFB_HEIGHT; return (float)GetTargetHeight() / (float)EFB_HEIGHT;
} }
// Various supporting functions
void Renderer::SetRenderTarget(GLuint targ)
{
if (!targ && s_MSAASamples > 1)
glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_RENDERBUFFER_EXT, s_RenderTarget);
else
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_RECTANGLE_ARB,
targ != 0 ? targ : s_RenderTarget, 0);
}
void Renderer::SetFramebuffer(GLuint fb) void Renderer::SetFramebuffer(GLuint fb)
{ {
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb != 0 ? fb : s_uFramebuffer); glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb != 0 ? fb : s_framebufferManager.GetEFBFramebuffer());
} }
void Renderer::ResetGLState() void Renderer::ResetGLState()
@ -701,60 +560,12 @@ void Renderer::SetBlendMode(bool forceUpdate)
// Apply AA if enabled // Apply AA if enabled
GLuint Renderer::ResolveAndGetRenderTarget(const TRectangle &source_rect) GLuint Renderer::ResolveAndGetRenderTarget(const TRectangle &source_rect)
{ {
if (s_MSAASamples > 1) return s_framebufferManager.GetEFBColorTexture(source_rect);
{
// Flip the rectangle
TRectangle flipped_rect;
source_rect.FlipYPosition(GetTargetHeight(), &flipped_rect);
flipped_rect.Clamp(0, 0, GetTargetWidth(), GetTargetHeight());
// Do the resolve.
glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, s_uFramebuffer);
glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, s_uResolvedFramebuffer);
glBlitFramebufferEXT(flipped_rect.left, flipped_rect.top, flipped_rect.right, flipped_rect.bottom,
flipped_rect.left, flipped_rect.top, flipped_rect.right, flipped_rect.bottom,
GL_COLOR_BUFFER_BIT, GL_NEAREST);
// Return the resolved target.
return s_ResolvedRenderTarget;
}
else
{
return s_RenderTarget;
}
} }
GLuint Renderer::ResolveAndGetDepthTarget(const TRectangle &source_rect) GLuint Renderer::ResolveAndGetDepthTarget(const TRectangle &source_rect)
{ {
// This logic should be moved elsewhere. return s_framebufferManager.GetEFBDepthTexture(source_rect);
if (s_MSAASamples > 1)
{
// Flip the rectangle
TRectangle flipped_rect;
//source_rect.FlipYPosition(GetTargetHeight(), &flipped_rect);
// donkopunchstania - some bug causes the offsets to be ignored. driver bug?
flipped_rect.top = 0;
flipped_rect.bottom = GetTargetHeight();
flipped_rect.left = 0;
flipped_rect.right = GetTargetWidth();
flipped_rect.Clamp(0, 0, GetTargetWidth(), GetTargetHeight());
// Do the resolve.
glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, s_uFramebuffer);
glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, s_uResolvedFramebuffer);
glBlitFramebufferEXT(flipped_rect.left, flipped_rect.top, flipped_rect.right, flipped_rect.bottom,
flipped_rect.left, flipped_rect.top, flipped_rect.right, flipped_rect.bottom,
GL_DEPTH_BUFFER_BIT, GL_NEAREST);
// Return the resolved target.
return s_ResolvedDepthTarget;
}
else
{
return s_DepthTarget;
}
} }
@ -891,6 +702,7 @@ void Renderer::RenderToXFB(u8* xfbInRam, const TRectangle& sourceRc, u32 dstWidt
Video_UpdateXFB(NULL, 0, 0, 0, FALSE); Video_UpdateXFB(NULL, 0, 0, 0, FALSE);
} }
// TODO: Move this logic to FramebufferManager
if (g_Config.bUseXFB) if (g_Config.bUseXFB)
{ {
s_efbSourceRc.left = 0; s_efbSourceRc.left = 0;
@ -909,7 +721,7 @@ void Renderer::RenderToXFB(u8* xfbInRam, const TRectangle& sourceRc, u32 dstWidt
// Cannot use glCopyTexImage2D on multisampled framebuffers, so // Cannot use glCopyTexImage2D on multisampled framebuffers, so
// EXT_framebuffer_blit must be used // EXT_framebuffer_blit must be used
glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, s_uFramebuffer); glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, s_framebufferManager.GetEFBFramebuffer());
glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, s_xfbFramebuffer); glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, s_xfbFramebuffer);
glBlitFramebufferEXT( glBlitFramebufferEXT(
@ -1033,11 +845,8 @@ void Renderer::Swap()
// Save screenshot // Save screenshot
if (s_bScreenshot) if (s_bScreenshot)
{ {
// Select source // TODO: Wrong. The EFB may contain something else by now. We want to read from the XFB.
if (s_MSAASamples > 1) glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, s_framebufferManager.GetEFBFramebuffer());
glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, s_uResolvedFramebuffer);
else
glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, s_uFramebuffer);
s_criticalScreenshot.Enter(); s_criticalScreenshot.Enter();
// Save screenshot // Save screenshot
@ -1055,11 +864,8 @@ void Renderer::Swap()
#ifdef _WIN32 #ifdef _WIN32
if (g_Config.bDumpFrames) if (g_Config.bDumpFrames)
{ {
// Select source // TODO: Wrong. The EFB may contain something else by now. We want to read from the XFB.
if (s_MSAASamples > 1) glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, s_framebufferManager.GetEFBFramebuffer());
glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, s_uResolvedFramebuffer);
else
glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, s_uFramebuffer);
s_criticalScreenshot.Enter(); s_criticalScreenshot.Enter();
int w = s_efbSourceRc.right; int w = s_efbSourceRc.right;

View File

@ -69,7 +69,6 @@ public:
static float GetTargetScaleY(); static float GetTargetScaleY();
static void SetFramebuffer(GLuint fb); static void SetFramebuffer(GLuint fb);
static void SetRenderTarget(GLuint targ); // if targ is 0, sets to original render target
// If in MSAA mode, this will perform a resolve of the specified rectangle, and return the resolve target as a texture ID. // If in MSAA mode, this will perform a resolve of the specified rectangle, and return the resolve target as a texture ID.
// Thus, this call may be expensive. Don't repeat it unnecessarily. // Thus, this call may be expensive. Don't repeat it unnecessarily.

View File

@ -710,7 +710,9 @@ void TextureMngr::CopyRenderTargetToTexture(u32 address, bool bFromZBuffer, bool
glGenFramebuffersEXT(1, (GLuint *)&s_TempFramebuffer); glGenFramebuffersEXT(1, (GLuint *)&s_TempFramebuffer);
Renderer::SetFramebuffer(s_TempFramebuffer); Renderer::SetFramebuffer(s_TempFramebuffer);
Renderer::SetRenderTarget(entry.texture); // Bind texture to temporary framebuffer
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_RECTANGLE_ARB, entry.texture, 0);
GL_REPORT_FBO_ERROR();
GL_REPORT_ERRORD(); GL_REPORT_ERRORD();
glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT); glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
@ -734,6 +736,10 @@ void TextureMngr::CopyRenderTargetToTexture(u32 address, bool bFromZBuffer, bool
GL_REPORT_ERRORD(); GL_REPORT_ERRORD();
// Unbind texture from temporary framebuffer
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_RECTANGLE_ARB, 0, 0);
// Return to the EFB.
Renderer::SetFramebuffer(0); Renderer::SetFramebuffer(0);
Renderer::RestoreGLState(); Renderer::RestoreGLState();
VertexShaderManager::SetViewportChanged(); VertexShaderManager::SetViewportChanged();

View File

@ -414,7 +414,7 @@ void Video_AddMessage(const char* pstr, u32 milliseconds)
} }
// TODO: Protect this structure with a mutex.
static volatile struct static volatile struct
{ {
u8* pXFB; u8* pXFB;
@ -441,16 +441,18 @@ void Video_UpdateXFB(u8* _pXFB, u32 _dwWidth, u32 _dwHeight, s32 _dwYOffset, boo
{ {
g_XFBUpdateRequested = FALSE; g_XFBUpdateRequested = FALSE;
if (g_Config.bUseXFB) if (!_pXFB)
{ {
if (!_pXFB) // From graphics thread in DC mode
// From graphics thread in DC mode _pXFB = tUpdateXFBArgs.pXFB;
Renderer::DecodeFromXFB(tUpdateXFBArgs.pXFB, tUpdateXFBArgs.width, tUpdateXFBArgs.height, tUpdateXFBArgs.yOffset); _dwWidth = tUpdateXFBArgs.width;
else _dwHeight = tUpdateXFBArgs.height;
// From CPU in SC mode _dwYOffset = tUpdateXFBArgs.yOffset;
Renderer::DecodeFromXFB(_pXFB, _dwWidth, _dwHeight, _dwYOffset);
} }
if (g_Config.bUseXFB)
Renderer::DecodeFromXFB(_pXFB, _dwWidth, _dwHeight, _dwYOffset);
// TODO: Use real XFB source parameters based on VI settings // TODO: Use real XFB source parameters based on VI settings
Renderer::Swap(); Renderer::Swap();