summaryrefslogtreecommitdiff
path: root/Source/Core/VideoBackends/OGL/BoundingBox.cpp
diff options
context:
space:
mode:
authorMarkus Wick <degasus@users.noreply.github.com>2017-03-16 21:39:17 +0100
committerGitHub <noreply@github.com>2017-03-16 21:39:17 +0100
commita0acdfc070d5bed422d3cdafd7675fc28af4eed5 (patch)
tree0edd5873022cafad1caf3c9588ae6fda8e201d75 /Source/Core/VideoBackends/OGL/BoundingBox.cpp
parentb2ab713ad93f8734fc65e104f4dc6c1c9a3e9411 (diff)
parent134317e07f7c371000389e7c3f45ceaf046eea69 (diff)
Merge pull request #5029 from ligfx/bboximagemask
OGL: implement Bounding Box on systems w/o SSBO
Diffstat (limited to 'Source/Core/VideoBackends/OGL/BoundingBox.cpp')
-rw-r--r--Source/Core/VideoBackends/OGL/BoundingBox.cpp149
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();
}
};