From 53224d41d05a9ec70d0a2715e1a7601a0e60bb14 Mon Sep 17 00:00:00 2001 From: Michael Maltese Date: Thu, 9 Mar 2017 15:33:10 -0800 Subject: [PATCH] OGL: only create stencil buffer when needed --- Source/Core/VideoBackends/OGL/BoundingBox.cpp | 6 +++ Source/Core/VideoBackends/OGL/BoundingBox.h | 6 ++- .../VideoBackends/OGL/FramebufferManager.cpp | 54 ++++++++++++++----- .../VideoBackends/OGL/FramebufferManager.h | 9 +++- Source/Core/VideoBackends/OGL/Render.cpp | 53 +++++++++--------- 5 files changed, 86 insertions(+), 42 deletions(-) diff --git a/Source/Core/VideoBackends/OGL/BoundingBox.cpp b/Source/Core/VideoBackends/OGL/BoundingBox.cpp index 44ba0ab118..2d370a115d 100644 --- a/Source/Core/VideoBackends/OGL/BoundingBox.cpp +++ b/Source/Core/VideoBackends/OGL/BoundingBox.cpp @@ -167,4 +167,10 @@ void BoundingBox::StencilWasUpdated() s_stencil_updated = true; s_stencil_cleared = false; } + +bool BoundingBox::NeedsStencilBuffer() +{ + return g_ActiveConfig.bBBoxEnable && + !g_ActiveConfig.backend_info.bSupportsFragmentStoresAndAtomics; +} }; diff --git a/Source/Core/VideoBackends/OGL/BoundingBox.h b/Source/Core/VideoBackends/OGL/BoundingBox.h index 033ea56cd5..44365c9fbc 100644 --- a/Source/Core/VideoBackends/OGL/BoundingBox.h +++ b/Source/Core/VideoBackends/OGL/BoundingBox.h @@ -15,8 +15,10 @@ public: static void SetTargetSizeChanged(int target_width, int target_height); // When SSBO isn't available, the bounding box is calculated directly from the - // stencil buffer. When the stencil buffer is changed, this function needs to - // be called to invalidate the cached bounding box data. + // stencil buffer. + static bool NeedsStencilBuffer(); + // When the stencil buffer is changed, this function needs to be called to + // invalidate the cached bounding box data. static void StencilWasUpdated(); static void Set(int index, int value); diff --git a/Source/Core/VideoBackends/OGL/FramebufferManager.cpp b/Source/Core/VideoBackends/OGL/FramebufferManager.cpp index 13b6759a01..17244db24e 100644 --- a/Source/Core/VideoBackends/OGL/FramebufferManager.cpp +++ b/Source/Core/VideoBackends/OGL/FramebufferManager.cpp @@ -29,6 +29,7 @@ namespace OGL int FramebufferManager::m_targetWidth; int FramebufferManager::m_targetHeight; int FramebufferManager::m_msaaSamples; +bool FramebufferManager::m_enable_stencil_buffer; GLenum FramebufferManager::m_textureType; std::vector FramebufferManager::m_efbFramebuffer; @@ -88,18 +89,26 @@ GLuint FramebufferManager::CreateTexture(GLenum texture_type, GLenum internal_fo return texture; } -void FramebufferManager::BindLayeredTexture(GLuint texture, const std::vector& framebuffers, GLenum attachment, GLenum texture_type) +void FramebufferManager::BindLayeredTexture(GLuint texture, const std::vector& framebuffers, + GLenum attachment, GLenum texture_type) { glBindFramebuffer(GL_FRAMEBUFFER, framebuffers[0]); FramebufferTexture(GL_FRAMEBUFFER, attachment, texture_type, texture, 0); // Bind all the other layers as separate FBOs for blitting. - for (unsigned int i = 1; i < m_EFBLayers; i++) { + for (unsigned int i = 1; i < m_EFBLayers; i++) + { glBindFramebuffer(GL_FRAMEBUFFER, m_resolvedFramebuffer[i]); glFramebufferTextureLayer(GL_FRAMEBUFFER, attachment, texture, 0, i); } } -FramebufferManager::FramebufferManager(int targetWidth, int targetHeight, int msaaSamples) +bool FramebufferManager::HasStencilBuffer() +{ + return m_enable_stencil_buffer; +} + +FramebufferManager::FramebufferManager(int targetWidth, int targetHeight, int msaaSamples, + bool enable_stencil_buffer) { m_xfbFramebuffer = 0; m_efbColor = 0; @@ -110,8 +119,8 @@ FramebufferManager::FramebufferManager(int targetWidth, int targetHeight, int ms m_targetWidth = targetWidth; m_targetHeight = targetHeight; - m_msaaSamples = msaaSamples; + m_enable_stencil_buffer = enable_stencil_buffer; // The EFB can be set to different pixel formats by the game through the // BPMEM_ZCOMPARE register (which should probably have a different name). @@ -130,6 +139,16 @@ FramebufferManager::FramebufferManager(int targetWidth, int targetHeight, int ms m_efbFramebuffer.resize(m_EFBLayers); m_resolvedFramebuffer.resize(m_EFBLayers); + GLenum depth_internal_format = GL_DEPTH_COMPONENT32F; + GLenum depth_pixel_format = GL_DEPTH_COMPONENT; + GLenum depth_data_type = GL_FLOAT; + if (m_enable_stencil_buffer) + { + depth_internal_format = GL_DEPTH32F_STENCIL8; + depth_pixel_format = GL_DEPTH_STENCIL; + depth_data_type = GL_FLOAT_32_UNSIGNED_INT_24_8_REV; + } + if (m_msaaSamples <= 1) { m_textureType = GL_TEXTURE_2D_ARRAY; @@ -152,18 +171,22 @@ FramebufferManager::FramebufferManager(int targetWidth, int targetHeight, int ms m_resolvedColorTexture = CreateTexture(resolvedType, GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE); m_resolvedDepthTexture = - CreateTexture(resolvedType, GL_DEPTH32F_STENCIL8, GL_DEPTH_STENCIL, GL_FLOAT_32_UNSIGNED_INT_24_8_REV); + CreateTexture(resolvedType, depth_internal_format, depth_pixel_format, depth_data_type); // Bind resolved textures to resolved framebuffer. glGenFramebuffers(m_EFBLayers, m_resolvedFramebuffer.data()); - BindLayeredTexture(m_resolvedColorTexture, m_resolvedFramebuffer, GL_COLOR_ATTACHMENT0, resolvedType); - BindLayeredTexture(m_resolvedDepthTexture, m_resolvedFramebuffer, GL_DEPTH_ATTACHMENT, resolvedType); - BindLayeredTexture(m_resolvedDepthTexture, m_resolvedFramebuffer, GL_STENCIL_ATTACHMENT, resolvedType); + BindLayeredTexture(m_resolvedColorTexture, m_resolvedFramebuffer, GL_COLOR_ATTACHMENT0, + resolvedType); + BindLayeredTexture(m_resolvedDepthTexture, m_resolvedFramebuffer, GL_DEPTH_ATTACHMENT, + resolvedType); + if (m_enable_stencil_buffer) + BindLayeredTexture(m_resolvedDepthTexture, m_resolvedFramebuffer, GL_STENCIL_ATTACHMENT, + resolvedType); } m_efbColor = CreateTexture(m_textureType, GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE); - m_efbDepth = CreateTexture(m_textureType, GL_DEPTH32F_STENCIL8, GL_DEPTH_STENCIL, - GL_FLOAT_32_UNSIGNED_INT_24_8_REV); + m_efbDepth = + CreateTexture(m_textureType, depth_internal_format, depth_pixel_format, depth_data_type); m_efbColorSwap = CreateTexture(m_textureType, GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE); // Create XFB framebuffer; targets will be created elsewhere. @@ -173,15 +196,20 @@ FramebufferManager::FramebufferManager(int targetWidth, int targetHeight, int ms glGenFramebuffers(m_EFBLayers, m_efbFramebuffer.data()); BindLayeredTexture(m_efbColor, m_efbFramebuffer, GL_COLOR_ATTACHMENT0, m_textureType); BindLayeredTexture(m_efbDepth, m_efbFramebuffer, GL_DEPTH_ATTACHMENT, m_textureType); - BindLayeredTexture(m_efbDepth, m_efbFramebuffer, GL_STENCIL_ATTACHMENT, m_textureType); + if (m_enable_stencil_buffer) + BindLayeredTexture(m_efbDepth, m_efbFramebuffer, GL_STENCIL_ATTACHMENT, m_textureType); // EFB framebuffer is currently bound, make sure to clear it before use. glViewport(0, 0, m_targetWidth, m_targetHeight); glScissor(0, 0, m_targetWidth, m_targetHeight); glClearColor(0.f, 0.f, 0.f, 0.f); glClearDepthf(1.0f); - glClearStencil(0); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + if (m_enable_stencil_buffer) + { + glClearStencil(0); + glClear(GL_STENCIL_BUFFER_BIT); + } // reinterpret pixel format const char* vs = m_EFBLayers > 1 ? "void main(void) {\n" diff --git a/Source/Core/VideoBackends/OGL/FramebufferManager.h b/Source/Core/VideoBackends/OGL/FramebufferManager.h index 93f8e5bad3..62b2f5ce3c 100644 --- a/Source/Core/VideoBackends/OGL/FramebufferManager.h +++ b/Source/Core/VideoBackends/OGL/FramebufferManager.h @@ -63,7 +63,8 @@ struct XFBSource : public XFBSourceBase class FramebufferManager : public FramebufferManagerBase { public: - FramebufferManager(int targetWidth, int targetHeight, int msaaSamples); + FramebufferManager(int targetWidth, int targetHeight, int msaaSamples, + bool enable_stencil_buffer); ~FramebufferManager(); // To get the EFB in texture form, these functions may have to transfer @@ -101,11 +102,13 @@ public: static void ReinterpretPixelData(unsigned int convtype); static void PokeEFB(EFBAccessType type, const EfbPokeData* points, size_t num_points); + static bool HasStencilBuffer(); private: GLuint CreateTexture(GLenum texture_type, GLenum internal_format, GLenum pixel_format, GLenum data_type); - void BindLayeredTexture(GLuint texture, const std::vector& framebuffers, GLenum attachment, GLenum texture_type); + void BindLayeredTexture(GLuint texture, const std::vector& framebuffers, + GLenum attachment, GLenum texture_type); std::unique_ptr CreateXFBSource(unsigned int target_width, unsigned int target_height, unsigned int layers) override; @@ -126,6 +129,8 @@ private: static GLuint m_efbColorSwap; // will be hot swapped with m_efbColor when reinterpreting EFB pixel formats + static bool m_enable_stencil_buffer; + // Only used in MSAA mode, TODO: try to avoid them static std::vector m_resolvedFramebuffer; static GLuint m_resolvedColorTexture; diff --git a/Source/Core/VideoBackends/OGL/Render.cpp b/Source/Core/VideoBackends/OGL/Render.cpp index d2124c6c5c..69554269cb 100644 --- a/Source/Core/VideoBackends/OGL/Render.cpp +++ b/Source/Core/VideoBackends/OGL/Render.cpp @@ -734,8 +734,8 @@ void Renderer::Shutdown() void Renderer::Init() { // Initialize the FramebufferManager - g_framebuffer_manager = - std::make_unique(m_target_width, m_target_height, s_MSAASamples); + g_framebuffer_manager = std::make_unique( + m_target_width, m_target_height, s_MSAASamples, BoundingBox::NeedsStencilBuffer()); m_post_processor = std::make_unique(); s_raster_font = std::make_unique(); @@ -1338,35 +1338,38 @@ void Renderer::SwapImpl(u32 xfbAddr, u32 fbWidth, u32 fbStride, u32 fbHeight, } bool target_size_changed = CalculateTargetSize(); - if (target_size_changed || xfbchanged || window_resized || - (s_last_multisamples != g_ActiveConfig.iMultisamples) || - (s_last_stereo_mode != (g_ActiveConfig.iStereoMode > 0))) + bool stencil_buffer_enabled = + static_cast(g_framebuffer_manager.get())->HasStencilBuffer(); + + bool fb_needs_update = target_size_changed || + s_last_multisamples != g_ActiveConfig.iMultisamples || + stencil_buffer_enabled != BoundingBox::NeedsStencilBuffer() || + s_last_stereo_mode != (g_ActiveConfig.iStereoMode > 0); + + if (xfbchanged || window_resized || fb_needs_update) { s_last_xfb_mode = g_ActiveConfig.bUseRealXFB; - UpdateDrawRectangle(); + } + if (fb_needs_update) + { + s_last_stereo_mode = g_ActiveConfig.iStereoMode > 0; + s_last_multisamples = g_ActiveConfig.iMultisamples; + s_MSAASamples = s_last_multisamples; - if (target_size_changed || s_last_multisamples != g_ActiveConfig.iMultisamples || - s_last_stereo_mode != (g_ActiveConfig.iStereoMode > 0)) + if (s_MSAASamples > 1 && s_MSAASamples > g_ogl_config.max_samples) { - s_last_stereo_mode = g_ActiveConfig.iStereoMode > 0; - s_last_multisamples = g_ActiveConfig.iMultisamples; - s_MSAASamples = s_last_multisamples; - - if (s_MSAASamples > 1 && s_MSAASamples > g_ogl_config.max_samples) - { - s_MSAASamples = g_ogl_config.max_samples; - OSD::AddMessage(StringFromFormat( - "%d Anti Aliasing samples selected, but only %d supported by your GPU.", - s_last_multisamples, g_ogl_config.max_samples), - 10000); - } - - g_framebuffer_manager.reset(); - g_framebuffer_manager = - std::make_unique(m_target_width, m_target_height, s_MSAASamples); - BoundingBox::SetTargetSizeChanged(m_target_width, m_target_height); + s_MSAASamples = g_ogl_config.max_samples; + OSD::AddMessage( + StringFromFormat("%d Anti Aliasing samples selected, but only %d supported by your GPU.", + s_last_multisamples, g_ogl_config.max_samples), + 10000); } + + g_framebuffer_manager.reset(); + g_framebuffer_manager = std::make_unique( + m_target_width, m_target_height, s_MSAASamples, BoundingBox::NeedsStencilBuffer()); + BoundingBox::SetTargetSizeChanged(m_target_width, m_target_height); } // ---------------------------------------------------------------------