mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2024-11-15 05:47:56 -07:00
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:
parent
fd47eb7b44
commit
07a767691d
@ -736,6 +736,14 @@
|
||||
<Filter
|
||||
Name="Render"
|
||||
>
|
||||
<File
|
||||
RelativePath=".\Src\FramebufferManager.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\Src\FramebufferManager.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\Src\OnScreenDisplay.cpp"
|
||||
>
|
||||
|
222
Source/Plugins/Plugin_VideoOGL/Src/FramebufferManager.cpp
Normal file
222
Source/Plugins/Plugin_VideoOGL/Src/FramebufferManager.cpp
Normal 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;
|
||||
}
|
||||
}
|
68
Source/Plugins/Plugin_VideoOGL/Src/FramebufferManager.h
Normal file
68
Source/Plugins/Plugin_VideoOGL/Src/FramebufferManager.h
Normal 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
|
@ -54,6 +54,7 @@
|
||||
#include "OnScreenDisplay.h"
|
||||
#include "Timer.h"
|
||||
#include "StringUtil.h"
|
||||
#include "FramebufferManager.h"
|
||||
|
||||
#include "main.h" // Local
|
||||
#ifdef _WIN32
|
||||
@ -92,37 +93,7 @@ static FILE* f_pFrameDump;
|
||||
static int s_MSAASamples = 1;
|
||||
static int s_MSAACoverageSamples = 0;
|
||||
|
||||
// Normal Mode
|
||||
//
|
||||
// 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;
|
||||
|
||||
// TODO: Move these to FramebufferManager
|
||||
static TRectangle s_efbSourceRc;
|
||||
static GLuint s_xfbFramebuffer = 0; // Only used when multisampling is on
|
||||
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_targetheight;
|
||||
|
||||
static FramebufferManager s_framebufferManager;
|
||||
|
||||
#ifndef _WIN32
|
||||
int OSDChoice = 0 , OSDTime = 0, OSDInternalW = 0, OSDInternalH = 0;
|
||||
#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.");
|
||||
}
|
||||
|
||||
// The size of the framebuffer targets should really NOT be the size of the OpenGL viewport.
|
||||
// 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;
|
||||
if (g_Config.bNativeResolution)
|
||||
{
|
||||
s_targetwidth = g_Config.b2xResolution ? EFB_WIDTH * 2 : EFB_WIDTH;
|
||||
s_targetheight = g_Config.b2xResolution ? EFB_HEIGHT * 2 : EFB_HEIGHT;
|
||||
}
|
||||
else
|
||||
{
|
||||
// The size of the framebuffer targets should really NOT be the size of the OpenGL viewport.
|
||||
// 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
|
||||
// vertical pixels.
|
||||
s_targetheight *= 528.0 / 480.0;
|
||||
// Compensate height of render target for scaling, so that we get something close to the correct number of
|
||||
// vertical pixels.
|
||||
s_targetheight *= 528.0 / 480.0;
|
||||
}
|
||||
|
||||
// Ensure a minimum target size so that the native res target always fits.
|
||||
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);
|
||||
SetDefaultRectTexParams();
|
||||
|
||||
glGenFramebuffersEXT(1, (GLuint *)&s_uFramebuffer);
|
||||
if (s_uFramebuffer == 0) {
|
||||
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
|
||||
// Bind it to an XFB framebuffer if MSAA is used
|
||||
if (s_MSAASamples > 1)
|
||||
{
|
||||
// Create XFB framebuffer for transferring the multisampled EFB to the
|
||||
// XFB texture
|
||||
glGenFramebuffersEXT(1, &s_xfbFramebuffer);
|
||||
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, s_xfbFramebuffer);
|
||||
|
||||
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_RECTANGLE_ARB, s_xfbTexture, 0);
|
||||
|
||||
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)
|
||||
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);
|
||||
|
||||
if (GL_REPORT_ERROR() != GL_NO_ERROR)
|
||||
@ -501,17 +382,10 @@ void Renderer::Shutdown(void)
|
||||
g_cgcontext = 0;
|
||||
}
|
||||
|
||||
s_framebufferManager.Shutdown();
|
||||
|
||||
// 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);
|
||||
s_xfbFramebuffer = 0;
|
||||
|
||||
@ -574,14 +448,12 @@ bool Renderer::InitializeGL()
|
||||
// Return the rendering window width and height
|
||||
int Renderer::GetTargetWidth()
|
||||
{
|
||||
return (s_bNativeResolution || g_Config.b2xResolution) ?
|
||||
(s_bNativeResolution ? EFB_WIDTH : EFB_WIDTH * 2) : s_targetwidth;
|
||||
return s_targetwidth;
|
||||
}
|
||||
|
||||
int Renderer::GetTargetHeight()
|
||||
{
|
||||
return (s_bNativeResolution || g_Config.b2xResolution) ?
|
||||
(s_bNativeResolution ? EFB_HEIGHT : EFB_HEIGHT * 2) : s_targetheight;
|
||||
return s_targetheight;
|
||||
}
|
||||
|
||||
float Renderer::GetTargetScaleX()
|
||||
@ -594,22 +466,9 @@ float Renderer::GetTargetScaleY()
|
||||
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)
|
||||
{
|
||||
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb != 0 ? fb : s_uFramebuffer);
|
||||
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb != 0 ? fb : s_framebufferManager.GetEFBFramebuffer());
|
||||
}
|
||||
|
||||
void Renderer::ResetGLState()
|
||||
@ -701,60 +560,12 @@ void Renderer::SetBlendMode(bool forceUpdate)
|
||||
// Apply AA if enabled
|
||||
GLuint Renderer::ResolveAndGetRenderTarget(const TRectangle &source_rect)
|
||||
{
|
||||
if (s_MSAASamples > 1)
|
||||
{
|
||||
// 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;
|
||||
}
|
||||
return s_framebufferManager.GetEFBColorTexture(source_rect);
|
||||
}
|
||||
|
||||
GLuint Renderer::ResolveAndGetDepthTarget(const TRectangle &source_rect)
|
||||
{
|
||||
// This logic should be moved elsewhere.
|
||||
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;
|
||||
}
|
||||
return s_framebufferManager.GetEFBDepthTexture(source_rect);
|
||||
}
|
||||
|
||||
|
||||
@ -891,6 +702,7 @@ void Renderer::RenderToXFB(u8* xfbInRam, const TRectangle& sourceRc, u32 dstWidt
|
||||
Video_UpdateXFB(NULL, 0, 0, 0, FALSE);
|
||||
}
|
||||
|
||||
// TODO: Move this logic to FramebufferManager
|
||||
if (g_Config.bUseXFB)
|
||||
{
|
||||
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
|
||||
// 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);
|
||||
|
||||
glBlitFramebufferEXT(
|
||||
@ -1033,11 +845,8 @@ void Renderer::Swap()
|
||||
// Save screenshot
|
||||
if (s_bScreenshot)
|
||||
{
|
||||
// Select source
|
||||
if (s_MSAASamples > 1)
|
||||
glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, s_uResolvedFramebuffer);
|
||||
else
|
||||
glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, s_uFramebuffer);
|
||||
// TODO: Wrong. The EFB may contain something else by now. We want to read from the XFB.
|
||||
glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, s_framebufferManager.GetEFBFramebuffer());
|
||||
|
||||
s_criticalScreenshot.Enter();
|
||||
// Save screenshot
|
||||
@ -1055,11 +864,8 @@ void Renderer::Swap()
|
||||
#ifdef _WIN32
|
||||
if (g_Config.bDumpFrames)
|
||||
{
|
||||
// Select source
|
||||
if (s_MSAASamples > 1)
|
||||
glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, s_uResolvedFramebuffer);
|
||||
else
|
||||
glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, s_uFramebuffer);
|
||||
// TODO: Wrong. The EFB may contain something else by now. We want to read from the XFB.
|
||||
glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, s_framebufferManager.GetEFBFramebuffer());
|
||||
|
||||
s_criticalScreenshot.Enter();
|
||||
int w = s_efbSourceRc.right;
|
||||
|
@ -69,7 +69,6 @@ public:
|
||||
static float GetTargetScaleY();
|
||||
|
||||
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.
|
||||
// Thus, this call may be expensive. Don't repeat it unnecessarily.
|
||||
|
@ -710,7 +710,9 @@ void TextureMngr::CopyRenderTargetToTexture(u32 address, bool bFromZBuffer, bool
|
||||
glGenFramebuffersEXT(1, (GLuint *)&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();
|
||||
|
||||
glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
|
||||
@ -734,6 +736,10 @@ void TextureMngr::CopyRenderTargetToTexture(u32 address, bool bFromZBuffer, bool
|
||||
|
||||
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::RestoreGLState();
|
||||
VertexShaderManager::SetViewportChanged();
|
||||
|
@ -414,7 +414,7 @@ void Video_AddMessage(const char* pstr, u32 milliseconds)
|
||||
}
|
||||
|
||||
|
||||
|
||||
// TODO: Protect this structure with a mutex.
|
||||
static volatile struct
|
||||
{
|
||||
u8* pXFB;
|
||||
@ -441,16 +441,18 @@ void Video_UpdateXFB(u8* _pXFB, u32 _dwWidth, u32 _dwHeight, s32 _dwYOffset, boo
|
||||
{
|
||||
g_XFBUpdateRequested = FALSE;
|
||||
|
||||
if (g_Config.bUseXFB)
|
||||
if (!_pXFB)
|
||||
{
|
||||
if (!_pXFB)
|
||||
// From graphics thread in DC mode
|
||||
Renderer::DecodeFromXFB(tUpdateXFBArgs.pXFB, tUpdateXFBArgs.width, tUpdateXFBArgs.height, tUpdateXFBArgs.yOffset);
|
||||
else
|
||||
// From CPU in SC mode
|
||||
Renderer::DecodeFromXFB(_pXFB, _dwWidth, _dwHeight, _dwYOffset);
|
||||
// From graphics thread in DC mode
|
||||
_pXFB = tUpdateXFBArgs.pXFB;
|
||||
_dwWidth = tUpdateXFBArgs.width;
|
||||
_dwHeight = tUpdateXFBArgs.height;
|
||||
_dwYOffset = tUpdateXFBArgs.yOffset;
|
||||
}
|
||||
|
||||
if (g_Config.bUseXFB)
|
||||
Renderer::DecodeFromXFB(_pXFB, _dwWidth, _dwHeight, _dwYOffset);
|
||||
|
||||
// TODO: Use real XFB source parameters based on VI settings
|
||||
Renderer::Swap();
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user