diff --git a/Source/Core/VideoBackends/OGL/FramebufferManager.cpp b/Source/Core/VideoBackends/OGL/FramebufferManager.cpp index 2567641595..e9d2ba7294 100644 --- a/Source/Core/VideoBackends/OGL/FramebufferManager.cpp +++ b/Source/Core/VideoBackends/OGL/FramebufferManager.cpp @@ -21,14 +21,14 @@ int FramebufferManager::m_targetHeight; int FramebufferManager::m_msaaSamples; GLenum FramebufferManager::m_textureType; -GLuint FramebufferManager::m_efbFramebuffer; +GLuint* FramebufferManager::m_efbFramebuffer; GLuint FramebufferManager::m_xfbFramebuffer; GLuint FramebufferManager::m_efbColor; GLuint FramebufferManager::m_efbDepth; GLuint FramebufferManager::m_efbColorSwap; // for hot swap when reinterpreting EFB pixel formats // Only used in MSAA mode. -GLuint FramebufferManager::m_resolvedFramebuffer; +GLuint* FramebufferManager::m_resolvedFramebuffer; GLuint FramebufferManager::m_resolvedColorTexture; GLuint FramebufferManager::m_resolvedDepthTexture; @@ -38,12 +38,10 @@ SHADER FramebufferManager::m_pixel_format_shaders[2]; FramebufferManager::FramebufferManager(int targetWidth, int targetHeight, int msaaSamples) { - m_efbFramebuffer = 0; m_xfbFramebuffer = 0; m_efbColor = 0; m_efbDepth = 0; m_efbColorSwap = 0; - m_resolvedFramebuffer = 0; m_resolvedColorTexture = 0; m_resolvedDepthTexture = 0; @@ -72,6 +70,8 @@ FramebufferManager::FramebufferManager(int targetWidth, int targetHeight, int ms m_efbColorSwap = glObj[2]; m_EFBLayers = (g_ActiveConfig.iStereoMode > 0) ? 2 : 1; + m_efbFramebuffer = new GLuint[m_EFBLayers](); + m_resolvedFramebuffer = new GLuint[m_EFBLayers](); // OpenGL MSAA textures are a different kind of texture type and must be allocated // with a different function, so we create them separately. @@ -99,18 +99,38 @@ FramebufferManager::FramebufferManager(int targetWidth, int targetHeight, int ms } else { - m_textureType = GL_TEXTURE_2D_MULTISAMPLE_ARRAY; GLenum resolvedType = GL_TEXTURE_2D_ARRAY; - glBindTexture(m_textureType, m_efbColor); - glTexImage3DMultisample(m_textureType, m_msaaSamples, GL_RGBA, m_targetWidth, m_targetHeight, m_EFBLayers, false); + // Only use a layered multisample texture if needed. Some drivers + // slow down significantly with single-layered multisample textures. + if (m_EFBLayers > 1) + { + m_textureType = GL_TEXTURE_2D_MULTISAMPLE_ARRAY; - glBindTexture(m_textureType, m_efbDepth); - glTexImage3DMultisample(m_textureType, m_msaaSamples, GL_DEPTH_COMPONENT24, m_targetWidth, m_targetHeight, m_EFBLayers, false); + glBindTexture(m_textureType, m_efbColor); + glTexImage3DMultisample(m_textureType, m_msaaSamples, GL_RGBA, m_targetWidth, m_targetHeight, m_EFBLayers, false); - glBindTexture(m_textureType, m_efbColorSwap); - glTexImage3DMultisample(m_textureType, m_msaaSamples, GL_RGBA, m_targetWidth, m_targetHeight, m_EFBLayers, false); - glBindTexture(m_textureType, 0); + glBindTexture(m_textureType, m_efbDepth); + glTexImage3DMultisample(m_textureType, m_msaaSamples, GL_DEPTH_COMPONENT24, m_targetWidth, m_targetHeight, m_EFBLayers, false); + + glBindTexture(m_textureType, m_efbColorSwap); + glTexImage3DMultisample(m_textureType, m_msaaSamples, GL_RGBA, m_targetWidth, m_targetHeight, m_EFBLayers, false); + glBindTexture(m_textureType, 0); + } + else + { + m_textureType = GL_TEXTURE_2D_MULTISAMPLE; + + glBindTexture(m_textureType, m_efbColor); + glTexImage2DMultisample(m_textureType, m_msaaSamples, GL_RGBA, m_targetWidth, m_targetHeight, false); + + glBindTexture(m_textureType, m_efbDepth); + glTexImage2DMultisample(m_textureType, m_msaaSamples, GL_DEPTH_COMPONENT24, m_targetWidth, m_targetHeight, false); + + glBindTexture(m_textureType, m_efbColorSwap); + glTexImage2DMultisample(m_textureType, m_msaaSamples, GL_RGBA, m_targetWidth, m_targetHeight, false); + glBindTexture(m_textureType, 0); + } // Although we are able to access the multisampled texture directly, we don't do it everywhere. // The old way is to "resolve" this multisampled texture by copying it into a non-sampled texture. @@ -133,21 +153,37 @@ FramebufferManager::FramebufferManager(int targetWidth, int targetHeight, int ms glTexImage3D(resolvedType, 0, GL_DEPTH_COMPONENT24, m_targetWidth, m_targetHeight, m_EFBLayers, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, nullptr); // Bind resolved textures to resolved framebuffer. - glGenFramebuffers(1, &m_resolvedFramebuffer); - glBindFramebuffer(GL_FRAMEBUFFER, m_resolvedFramebuffer); + glGenFramebuffers(m_EFBLayers, m_resolvedFramebuffer); + glBindFramebuffer(GL_FRAMEBUFFER, m_resolvedFramebuffer[0]); FramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, resolvedType, m_resolvedColorTexture, 0); FramebufferTexture(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, resolvedType, m_resolvedDepthTexture, 0); + + // Bind all the other layers as separate FBOs for blitting. + for (unsigned int i = 1; i < m_EFBLayers; i++) + { + glBindFramebuffer(GL_FRAMEBUFFER, m_resolvedFramebuffer[i]); + glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, m_resolvedColorTexture, 0, i); + glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, m_resolvedDepthTexture, 0, i); + } } // Create XFB framebuffer; targets will be created elsewhere. glGenFramebuffers(1, &m_xfbFramebuffer); // Bind target textures to EFB framebuffer. - glGenFramebuffers(1, &m_efbFramebuffer); - glBindFramebuffer(GL_FRAMEBUFFER, m_efbFramebuffer); + glGenFramebuffers(m_EFBLayers, m_efbFramebuffer); + glBindFramebuffer(GL_FRAMEBUFFER, m_efbFramebuffer[0]); FramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, m_textureType, m_efbColor, 0); FramebufferTexture(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, m_textureType, m_efbDepth, 0); + // Bind all the other layers as separate FBOs for blitting. + for (unsigned int i = 1; i < m_EFBLayers; i++) + { + glBindFramebuffer(GL_FRAMEBUFFER, m_efbFramebuffer[i]); + glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, m_efbColor, 0, i); + glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, m_efbDepth, 0, i); + } + // EFB framebuffer is currently bound, make sure to clear its alpha value to 1.f glViewport(0, 0, m_targetWidth, m_targetHeight); glScissor(0, 0, m_targetWidth, m_targetHeight); @@ -264,13 +300,15 @@ FramebufferManager::~FramebufferManager() // Note: OpenGL deletion functions silently ignore parameters of "0". - glObj[0] = m_efbFramebuffer; - glObj[1] = m_xfbFramebuffer; - glObj[2] = m_resolvedFramebuffer; - glDeleteFramebuffers(3, glObj); - m_efbFramebuffer = 0; + glDeleteFramebuffers(m_EFBLayers, m_efbFramebuffer); + glDeleteFramebuffers(m_EFBLayers, m_resolvedFramebuffer); + delete [] m_efbFramebuffer; + delete [] m_resolvedFramebuffer; + m_efbFramebuffer = nullptr; + m_resolvedFramebuffer = nullptr; + + glDeleteFramebuffers(1, &m_xfbFramebuffer); m_xfbFramebuffer = 0; - m_resolvedFramebuffer = 0; glObj[0] = m_resolvedColorTexture; glObj[1] = m_resolvedDepthTexture; @@ -306,16 +344,19 @@ GLuint FramebufferManager::GetEFBColorTexture(const EFBRectangle& sourceRc) targetRc.ClampLL(0, 0, m_targetWidth, m_targetHeight); // Resolve. - glBindFramebuffer(GL_READ_FRAMEBUFFER, m_efbFramebuffer); - glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_resolvedFramebuffer); - glBlitFramebuffer( - targetRc.left, targetRc.top, targetRc.right, targetRc.bottom, - targetRc.left, targetRc.top, targetRc.right, targetRc.bottom, - GL_COLOR_BUFFER_BIT, GL_NEAREST - ); + for (unsigned int i = 0; i < m_EFBLayers; i++) + { + glBindFramebuffer(GL_READ_FRAMEBUFFER, m_efbFramebuffer[i]); + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_resolvedFramebuffer[i]); + glBlitFramebuffer( + targetRc.left, targetRc.top, targetRc.right, targetRc.bottom, + targetRc.left, targetRc.top, targetRc.right, targetRc.bottom, + GL_COLOR_BUFFER_BIT, GL_NEAREST + ); + } // Return to EFB. - glBindFramebuffer(GL_FRAMEBUFFER, m_efbFramebuffer); + glBindFramebuffer(GL_FRAMEBUFFER, m_efbFramebuffer[0]); return m_resolvedColorTexture; } @@ -335,16 +376,19 @@ GLuint FramebufferManager::GetEFBDepthTexture(const EFBRectangle& sourceRc) targetRc.ClampLL(0, 0, m_targetWidth, m_targetHeight); // Resolve. - glBindFramebuffer(GL_READ_FRAMEBUFFER, m_efbFramebuffer); - glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_resolvedFramebuffer); - glBlitFramebuffer( - targetRc.left, targetRc.top, targetRc.right, targetRc.bottom, - targetRc.left, targetRc.top, targetRc.right, targetRc.bottom, - GL_DEPTH_BUFFER_BIT, GL_NEAREST - ); + for (unsigned int i = 0; i < m_EFBLayers; i++) + { + glBindFramebuffer(GL_READ_FRAMEBUFFER, m_efbFramebuffer[i]); + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_resolvedFramebuffer[i]); + glBlitFramebuffer( + targetRc.left, targetRc.top, targetRc.right, targetRc.bottom, + targetRc.left, targetRc.top, targetRc.right, targetRc.bottom, + GL_DEPTH_BUFFER_BIT, GL_NEAREST + ); + } // Return to EFB. - glBindFramebuffer(GL_FRAMEBUFFER, m_efbFramebuffer); + glBindFramebuffer(GL_FRAMEBUFFER, m_efbFramebuffer[0]); return m_resolvedDepthTexture; } diff --git a/Source/Core/VideoBackends/OGL/FramebufferManager.h b/Source/Core/VideoBackends/OGL/FramebufferManager.h index 8d42523bcc..ffc2970ee6 100644 --- a/Source/Core/VideoBackends/OGL/FramebufferManager.h +++ b/Source/Core/VideoBackends/OGL/FramebufferManager.h @@ -68,11 +68,11 @@ public: static GLuint GetEFBColorTexture(const EFBRectangle& sourceRc); static GLuint GetEFBDepthTexture(const EFBRectangle& sourceRc); - static GLuint GetEFBFramebuffer() { return m_efbFramebuffer; } + static GLuint GetEFBFramebuffer() { return m_efbFramebuffer[0]; } static GLuint GetXFBFramebuffer() { return m_xfbFramebuffer; } // Resolved framebuffer is only used in MSAA mode. - static GLuint GetResolvedFramebuffer() { return m_resolvedFramebuffer; } + static GLuint GetResolvedFramebuffer() { return m_resolvedFramebuffer[0]; } static void SetFramebuffer(GLuint fb); static void FramebufferTexture(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); @@ -102,14 +102,14 @@ private: static int m_msaaSamples; static GLenum m_textureType; - static GLuint m_efbFramebuffer; + static GLuint* m_efbFramebuffer; static GLuint m_xfbFramebuffer; static GLuint m_efbColor; static GLuint m_efbDepth; static GLuint m_efbColorSwap;// will be hot swapped with m_efbColor when reinterpreting EFB pixel formats // Only used in MSAA mode, TODO: try to avoid them - static GLuint m_resolvedFramebuffer; + static GLuint* m_resolvedFramebuffer; static GLuint m_resolvedColorTexture; static GLuint m_resolvedDepthTexture;