diff options
Diffstat (limited to 'Source/Core/VideoBackends/OGL/BoundingBox.cpp')
| -rw-r--r-- | Source/Core/VideoBackends/OGL/BoundingBox.cpp | 149 |
1 files changed, 127 insertions, 22 deletions
diff --git a/Source/Core/VideoBackends/OGL/BoundingBox.cpp b/Source/Core/VideoBackends/OGL/BoundingBox.cpp index 0ee4bd2afe..ebf8433d92 100644 --- a/Source/Core/VideoBackends/OGL/BoundingBox.cpp +++ b/Source/Core/VideoBackends/OGL/BoundingBox.cpp @@ -2,22 +2,47 @@ // Licensed under GPLv2+ // Refer to the license.txt file included. +#include <algorithm> +#include <array> #include <cstring> #include "Common/GL/GLUtil.h" #include "VideoBackends/OGL/BoundingBox.h" +#include "VideoBackends/OGL/FramebufferManager.h" #include "VideoCommon/DriverDetails.h" #include "VideoCommon/VideoConfig.h" static GLuint s_bbox_buffer_id; +static GLuint s_pbo; + +static std::array<int, 4> s_stencil_bounds; +static bool s_stencil_updated; +static bool s_stencil_cleared; + +static int s_target_width; +static int s_target_height; namespace OGL { -void BoundingBox::Init() +void BoundingBox::SetTargetSizeChanged(int target_width, int target_height) { - if (g_ActiveConfig.backend_info.bSupportsBBox) + if (g_ActiveConfig.BBoxUseFragmentShaderImplementation()) + return; + + s_target_width = target_width; + s_target_height = target_height; + s_stencil_updated = false; + + glBindBuffer(GL_PIXEL_PACK_BUFFER, s_pbo); + glBufferData(GL_PIXEL_PACK_BUFFER, s_target_width * s_target_height, nullptr, GL_STREAM_READ); + glBindBuffer(GL_PIXEL_PACK_BUFFER, 0); +} + +void BoundingBox::Init(int target_width, int target_height) +{ + if (g_ActiveConfig.BBoxUseFragmentShaderImplementation()) { int initial_values[4] = {0, 0, 0, 0}; glGenBuffers(1, &s_bbox_buffer_id); @@ -25,46 +50,126 @@ void BoundingBox::Init() glBufferData(GL_SHADER_STORAGE_BUFFER, 4 * sizeof(s32), initial_values, GL_DYNAMIC_DRAW); glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, s_bbox_buffer_id); } + else + { + s_stencil_bounds = {{0, 0, 0, 0}}; + glGenBuffers(1, &s_pbo); + SetTargetSizeChanged(target_width, target_height); + } } void BoundingBox::Shutdown() { - if (g_ActiveConfig.backend_info.bSupportsBBox) + if (g_ActiveConfig.BBoxUseFragmentShaderImplementation()) + { glDeleteBuffers(1, &s_bbox_buffer_id); + } + else + { + glDeleteBuffers(1, &s_pbo); + } } void BoundingBox::Set(int index, int value) { - glBindBuffer(GL_SHADER_STORAGE_BUFFER, s_bbox_buffer_id); - glBufferSubData(GL_SHADER_STORAGE_BUFFER, index * sizeof(int), sizeof(int), &value); - glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0); + if (g_ActiveConfig.BBoxUseFragmentShaderImplementation()) + { + glBindBuffer(GL_SHADER_STORAGE_BUFFER, s_bbox_buffer_id); + glBufferSubData(GL_SHADER_STORAGE_BUFFER, index * sizeof(int), sizeof(int), &value); + glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0); + } + else + { + s_stencil_bounds[index] = value; + + if (!s_stencil_cleared) + { + // Assumes that the EFB framebuffer is currently bound + glClearStencil(0); + glClear(GL_STENCIL_BUFFER_BIT); + s_stencil_updated = false; + s_stencil_cleared = true; + } + } } int BoundingBox::Get(int index) { - int data = 0; - glBindBuffer(GL_SHADER_STORAGE_BUFFER, s_bbox_buffer_id); - - if (!DriverDetails::HasBug(DriverDetails::BUG_SLOW_GETBUFFERSUBDATA)) + if (g_ActiveConfig.BBoxUseFragmentShaderImplementation()) { - // Using glMapBufferRange to read back the contents of the SSBO is extremely slow - // on nVidia drivers. This is more noticeable at higher internal resolutions. - // Using glGetBufferSubData instead does not seem to exhibit this slowdown. - glGetBufferSubData(GL_SHADER_STORAGE_BUFFER, index * sizeof(int), sizeof(int), &data); + int data = 0; + glBindBuffer(GL_SHADER_STORAGE_BUFFER, s_bbox_buffer_id); + if (!DriverDetails::HasBug(DriverDetails::BUG_SLOW_GETBUFFERSUBDATA)) + { + // Using glMapBufferRange to read back the contents of the SSBO is extremely slow + // on nVidia drivers. This is more noticeable at higher internal resolutions. + // Using glGetBufferSubData instead does not seem to exhibit this slowdown. + glGetBufferSubData(GL_SHADER_STORAGE_BUFFER, index * sizeof(int), sizeof(int), &data); + } + else + { + // Using glMapBufferRange is faster on AMD cards by a measurable margin. + void* ptr = glMapBufferRange(GL_SHADER_STORAGE_BUFFER, index * sizeof(int), sizeof(int), + GL_MAP_READ_BIT); + if (ptr) + { + memcpy(&data, ptr, sizeof(int)); + glUnmapBuffer(GL_SHADER_STORAGE_BUFFER); + } + } + glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0); + return data; } else { - // Using glMapBufferRange is faster on AMD cards by a measurable margin. - void* ptr = glMapBufferRange(GL_SHADER_STORAGE_BUFFER, index * sizeof(int), sizeof(int), - GL_MAP_READ_BIT); - if (ptr) + if (s_stencil_updated) { - memcpy(&data, ptr, sizeof(int)); - glUnmapBuffer(GL_SHADER_STORAGE_BUFFER); + s_stencil_updated = false; + + FramebufferManager::ResolveEFBStencilTexture(); + glBindFramebuffer(GL_READ_FRAMEBUFFER, FramebufferManager::GetResolvedFramebuffer()); + glBindBuffer(GL_PIXEL_PACK_BUFFER, s_pbo); + glPixelStorei(GL_PACK_ALIGNMENT, 1); + glReadPixels(0, 0, s_target_width, s_target_height, GL_STENCIL_INDEX, GL_UNSIGNED_BYTE, 0); + glBindFramebuffer(GL_READ_FRAMEBUFFER, FramebufferManager::GetEFBFramebuffer()); + + // Eke every bit of performance out of the compiler that we can + std::array<int, 4> bounds = s_stencil_bounds; + + u8* data = static_cast<u8*>(glMapBufferRange( + GL_PIXEL_PACK_BUFFER, 0, s_target_height * s_target_width, GL_MAP_READ_BIT)); + + for (int row = 0; row < s_target_height; row++) + { + for (int col = 0; col < s_target_width; col++) + { + if (data[row * s_target_width + col] == 0) + continue; + bounds[0] = std::min(bounds[0], col); + bounds[1] = std::max(bounds[1], col); + bounds[2] = std::min(bounds[2], row); + bounds[3] = std::max(bounds[3], row); + } + } + + s_stencil_bounds = bounds; + + glUnmapBuffer(GL_PIXEL_PACK_BUFFER); + glBindBuffer(GL_PIXEL_PACK_BUFFER, 0); } + + return s_stencil_bounds[index]; } +} - glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0); - return data; +void BoundingBox::StencilWasUpdated() +{ + s_stencil_updated = true; + s_stencil_cleared = false; +} + +bool BoundingBox::NeedsStencilBuffer() +{ + return g_ActiveConfig.bBBoxEnable && !g_ActiveConfig.BBoxUseFragmentShaderImplementation(); } }; |
