From 07a767691d411a7c2a31340628adda8c92e1204d Mon Sep 17 00:00:00 2001 From: Nolan Check Date: Sun, 28 Jun 2009 23:35:08 +0000 Subject: [PATCH] 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 --- .../Plugin_VideoOGL/Plugin_VideoOGL.vcproj | 8 + .../Src/FramebufferManager.cpp | 222 ++++++++++++++ .../Plugin_VideoOGL/Src/FramebufferManager.h | 68 +++++ Source/Plugins/Plugin_VideoOGL/Src/Render.cpp | 278 +++--------------- Source/Plugins/Plugin_VideoOGL/Src/Render.h | 1 - .../Plugin_VideoOGL/Src/TextureMngr.cpp | 8 +- Source/Plugins/Plugin_VideoOGL/Src/main.cpp | 18 +- 7 files changed, 357 insertions(+), 246 deletions(-) create mode 100644 Source/Plugins/Plugin_VideoOGL/Src/FramebufferManager.cpp create mode 100644 Source/Plugins/Plugin_VideoOGL/Src/FramebufferManager.h diff --git a/Source/Plugins/Plugin_VideoOGL/Plugin_VideoOGL.vcproj b/Source/Plugins/Plugin_VideoOGL/Plugin_VideoOGL.vcproj index 316011c9f2..1b9e331761 100644 --- a/Source/Plugins/Plugin_VideoOGL/Plugin_VideoOGL.vcproj +++ b/Source/Plugins/Plugin_VideoOGL/Plugin_VideoOGL.vcproj @@ -736,6 +736,14 @@ + + + + diff --git a/Source/Plugins/Plugin_VideoOGL/Src/FramebufferManager.cpp b/Source/Plugins/Plugin_VideoOGL/Src/FramebufferManager.cpp new file mode 100644 index 0000000000..49f804b91a --- /dev/null +++ b/Source/Plugins/Plugin_VideoOGL/Src/FramebufferManager.cpp @@ -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; + } +} diff --git a/Source/Plugins/Plugin_VideoOGL/Src/FramebufferManager.h b/Source/Plugins/Plugin_VideoOGL/Src/FramebufferManager.h new file mode 100644 index 0000000000..9a8561ab37 --- /dev/null +++ b/Source/Plugins/Plugin_VideoOGL/Src/FramebufferManager.h @@ -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 diff --git a/Source/Plugins/Plugin_VideoOGL/Src/Render.cpp b/Source/Plugins/Plugin_VideoOGL/Src/Render.cpp index 5b3d86ab59..e4a5823afb 100644 --- a/Source/Plugins/Plugin_VideoOGL/Src/Render.cpp +++ b/Source/Plugins/Plugin_VideoOGL/Src/Render.cpp @@ -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; diff --git a/Source/Plugins/Plugin_VideoOGL/Src/Render.h b/Source/Plugins/Plugin_VideoOGL/Src/Render.h index 02447f0259..de187c4bdd 100644 --- a/Source/Plugins/Plugin_VideoOGL/Src/Render.h +++ b/Source/Plugins/Plugin_VideoOGL/Src/Render.h @@ -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. diff --git a/Source/Plugins/Plugin_VideoOGL/Src/TextureMngr.cpp b/Source/Plugins/Plugin_VideoOGL/Src/TextureMngr.cpp index 6ed06146bf..3af2827787 100644 --- a/Source/Plugins/Plugin_VideoOGL/Src/TextureMngr.cpp +++ b/Source/Plugins/Plugin_VideoOGL/Src/TextureMngr.cpp @@ -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(); diff --git a/Source/Plugins/Plugin_VideoOGL/Src/main.cpp b/Source/Plugins/Plugin_VideoOGL/Src/main.cpp index 19b4ddedf6..953d486ca8 100644 --- a/Source/Plugins/Plugin_VideoOGL/Src/main.cpp +++ b/Source/Plugins/Plugin_VideoOGL/Src/main.cpp @@ -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();