summaryrefslogtreecommitdiff
path: root/Source/Core/VideoBackends/OGL
diff options
context:
space:
mode:
authorTilka <tilkax@gmail.com>2019-02-26 04:21:05 +0000
committerGitHub <noreply@github.com>2019-02-26 04:21:05 +0000
commit6ce7f44b8a0bb3b95d3f12ebffbef7a71a443fdd (patch)
tree98380ce3a3284c52597a6fba86589c847219ecd5 /Source/Core/VideoBackends/OGL
parent19673ce79af814ca3b77d7f8ea60458e564bfa51 (diff)
parentf039149198657c1891e1c6462ed30c31ed4b8486 (diff)
Merge pull request #7753 from stenzek/videocommon-all-the-things
Move a significant amount of video backend logic to VideoCommon
Diffstat (limited to 'Source/Core/VideoBackends/OGL')
-rw-r--r--Source/Core/VideoBackends/OGL/BoundingBox.cpp172
-rw-r--r--Source/Core/VideoBackends/OGL/BoundingBox.h13
-rw-r--r--Source/Core/VideoBackends/OGL/CMakeLists.txt4
-rw-r--r--Source/Core/VideoBackends/OGL/FramebufferManager.cpp634
-rw-r--r--Source/Core/VideoBackends/OGL/FramebufferManager.h127
-rw-r--r--Source/Core/VideoBackends/OGL/NativeVertexFormat.cpp21
-rw-r--r--Source/Core/VideoBackends/OGL/OGL.vcxproj8
-rw-r--r--Source/Core/VideoBackends/OGL/OGL.vcxproj.filters24
-rw-r--r--Source/Core/VideoBackends/OGL/OGLShader.cpp15
-rw-r--r--Source/Core/VideoBackends/OGL/OGLShader.h14
-rw-r--r--Source/Core/VideoBackends/OGL/OGLTexture.cpp254
-rw-r--r--Source/Core/VideoBackends/OGL/OGLTexture.h23
-rw-r--r--Source/Core/VideoBackends/OGL/PostProcessing.cpp273
-rw-r--r--Source/Core/VideoBackends/OGL/PostProcessing.h44
-rw-r--r--Source/Core/VideoBackends/OGL/ProgramShaderCache.cpp54
-rw-r--r--Source/Core/VideoBackends/OGL/ProgramShaderCache.h15
-rw-r--r--Source/Core/VideoBackends/OGL/Render.cpp780
-rw-r--r--Source/Core/VideoBackends/OGL/Render.h64
-rw-r--r--Source/Core/VideoBackends/OGL/StreamBuffer.h4
-rw-r--r--Source/Core/VideoBackends/OGL/TextureCache.cpp574
-rw-r--r--Source/Core/VideoBackends/OGL/TextureCache.h108
-rw-r--r--Source/Core/VideoBackends/OGL/TextureConverter.cpp170
-rw-r--r--Source/Core/VideoBackends/OGL/TextureConverter.h33
-rw-r--r--Source/Core/VideoBackends/OGL/VertexManager.cpp186
-rw-r--r--Source/Core/VideoBackends/OGL/VertexManager.h27
-rw-r--r--Source/Core/VideoBackends/OGL/main.cpp37
26 files changed, 661 insertions, 3017 deletions
diff --git a/Source/Core/VideoBackends/OGL/BoundingBox.cpp b/Source/Core/VideoBackends/OGL/BoundingBox.cpp
index c50f831524..18ef7802cc 100644
--- a/Source/Core/VideoBackends/OGL/BoundingBox.cpp
+++ b/Source/Core/VideoBackends/OGL/BoundingBox.cpp
@@ -2,175 +2,77 @@
// 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 "VideoBackends/OGL/Render.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::SetTargetSizeChanged(int target_width, int target_height)
+void BoundingBox::Init()
{
- if (g_ActiveConfig.BBoxUseFragmentShaderImplementation())
+ if (!g_ActiveConfig.backend_info.bSupportsBBox)
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);
- glBindBuffer(GL_SHADER_STORAGE_BUFFER, s_bbox_buffer_id);
- 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);
- }
+ int initial_values[4] = {0, 0, 0, 0};
+ glGenBuffers(1, &s_bbox_buffer_id);
+ glBindBuffer(GL_SHADER_STORAGE_BUFFER, s_bbox_buffer_id);
+ glBufferData(GL_SHADER_STORAGE_BUFFER, 4 * sizeof(s32), initial_values, GL_DYNAMIC_DRAW);
+ glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, s_bbox_buffer_id);
}
void BoundingBox::Shutdown()
{
- if (g_ActiveConfig.BBoxUseFragmentShaderImplementation())
- {
- glDeleteBuffers(1, &s_bbox_buffer_id);
- }
- else
- {
- glDeleteBuffers(1, &s_pbo);
- }
+ if (!g_ActiveConfig.backend_info.bSupportsBBox)
+ return;
+
+ glDeleteBuffers(1, &s_bbox_buffer_id);
}
void BoundingBox::Set(int index, int value)
{
- 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 (!g_ActiveConfig.backend_info.bSupportsBBox)
+ return;
- 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;
- }
- }
+ 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);
}
int BoundingBox::Get(int index)
{
- if (g_ActiveConfig.BBoxUseFragmentShaderImplementation())
+ if (!g_ActiveConfig.backend_info.bSupportsBBox)
+ return 0;
+
+ int data = 0;
+ glBindBuffer(GL_SHADER_STORAGE_BUFFER, s_bbox_buffer_id);
+ if (!DriverDetails::HasBug(DriverDetails::BUG_SLOW_GETBUFFERSUBDATA) &&
+ !static_cast<Renderer*>(g_renderer.get())->IsGLES())
{
- int data = 0;
- glBindBuffer(GL_SHADER_STORAGE_BUFFER, s_bbox_buffer_id);
- if (!DriverDetails::HasBug(DriverDetails::BUG_SLOW_GETBUFFERSUBDATA) &&
- !static_cast<Renderer*>(g_renderer.get())->IsGLES())
- {
- // 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;
+ // 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
{
- if (s_stencil_updated)
+ // 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)
{
- 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);
+ memcpy(&data, ptr, sizeof(int));
+ glUnmapBuffer(GL_SHADER_STORAGE_BUFFER);
}
-
- 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();
-}
-};
+}; // namespace OGL
diff --git a/Source/Core/VideoBackends/OGL/BoundingBox.h b/Source/Core/VideoBackends/OGL/BoundingBox.h
index 44365c9fbc..cbf54074ab 100644
--- a/Source/Core/VideoBackends/OGL/BoundingBox.h
+++ b/Source/Core/VideoBackends/OGL/BoundingBox.h
@@ -9,19 +9,10 @@ namespace OGL
class BoundingBox
{
public:
- static void Init(int target_width, int target_height);
+ static void Init();
static void Shutdown();
- static void SetTargetSizeChanged(int target_width, int target_height);
-
- // When SSBO isn't available, the bounding box is calculated directly from the
- // 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);
static int Get(int index);
};
-};
+}; // namespace OGL
diff --git a/Source/Core/VideoBackends/OGL/CMakeLists.txt b/Source/Core/VideoBackends/OGL/CMakeLists.txt
index c786ba671f..da091c8e9b 100644
--- a/Source/Core/VideoBackends/OGL/CMakeLists.txt
+++ b/Source/Core/VideoBackends/OGL/CMakeLists.txt
@@ -1,19 +1,15 @@
add_library(videoogl
BoundingBox.cpp
- FramebufferManager.cpp
main.cpp
NativeVertexFormat.cpp
OGLPipeline.cpp
OGLShader.cpp
OGLTexture.cpp
PerfQuery.cpp
- PostProcessing.cpp
ProgramShaderCache.cpp
Render.cpp
SamplerCache.cpp
StreamBuffer.cpp
- TextureCache.cpp
- TextureConverter.cpp
VertexManager.cpp
)
diff --git a/Source/Core/VideoBackends/OGL/FramebufferManager.cpp b/Source/Core/VideoBackends/OGL/FramebufferManager.cpp
deleted file mode 100644
index 12de898ff5..0000000000
--- a/Source/Core/VideoBackends/OGL/FramebufferManager.cpp
+++ /dev/null
@@ -1,634 +0,0 @@
-// Copyright 2009 Dolphin Emulator Project
-// Licensed under GPLv2+
-// Refer to the license.txt file included.
-
-#include "VideoBackends/OGL/FramebufferManager.h"
-
-#include <memory>
-#include <vector>
-
-#include "Common/Common.h"
-#include "Common/CommonTypes.h"
-#include "Common/Logging/Log.h"
-#include "Common/MsgHandler.h"
-
-#include "Core/HW/Memmap.h"
-
-#include "VideoBackends/OGL/Render.h"
-#include "VideoBackends/OGL/SamplerCache.h"
-#include "VideoBackends/OGL/TextureConverter.h"
-#include "VideoBackends/OGL/VertexManager.h"
-
-#include "VideoCommon/OnScreenDisplay.h"
-#include "VideoCommon/VertexShaderGen.h"
-#include "VideoCommon/VideoBackendBase.h"
-
-constexpr const char* GLSL_REINTERPRET_PIXELFMT_VS = R"GLSL(
-flat out int layer;
-void main(void) {
- layer = 0;
- vec2 rawpos = vec2(gl_VertexID & 1, gl_VertexID & 2);
- gl_Position = vec4(rawpos* 2.0 - 1.0, 0.0, 1.0);
-})GLSL";
-
-constexpr const char* GLSL_SHADER_FS = R"GLSL(
-#define MULTILAYER %d
-#define MSAA %d
-
-#if MSAA
-
-#if MULTILAYER
-SAMPLER_BINDING(9) uniform sampler2DMSArray samp9;
-#else
-SAMPLER_BINDING(9) uniform sampler2DMS samp9;
-#endif
-
-#else
-SAMPLER_BINDING(9) uniform sampler2DArray samp9;
-#endif
-
-vec4 sampleEFB(ivec3 pos) {
-#if MSAA
-
-#if MULTILAYER
- return texelFetch(samp9, pos, gl_SampleID);
-#else
- return texelFetch(samp9, pos.xy, gl_SampleID);
-#endif
-
-#else
- return texelFetch(samp9, pos, 0);
-#endif
-})GLSL";
-
-constexpr const char* GLSL_SAMPLE_EFB_FS = R"GLSL(
-#define MULTILAYER %d
-
-#if MULTILAYER
-SAMPLER_BINDING(9) uniform sampler2DMSArray samp9;
-#else
-SAMPLER_BINDING(9) uniform sampler2DMS samp9;
-#endif
-vec4 sampleEFB(ivec3 pos) {
- vec4 color = vec4(0.0, 0.0, 0.0, 0.0);
- for (int i = 0; i < %d; i++)
-#if MULTILAYER
- color += texelFetch(samp9, pos, i);
-#else
- color += texelFetch(samp9, pos.xy, i);
-#endif
-
- return color / %d;
-})GLSL";
-
-constexpr const char* GLSL_RGBA6_TO_RGB8_FS = R"GLSL(
-flat in int layer;
-out vec4 ocol0;
-void main() {
- ivec4 src6 = ivec4(round(sampleEFB(ivec3(gl_FragCoord.xy, layer)) * 63.f));
- ivec4 dst8;
-
- dst8.r = (src6.r << 2) | (src6.g >> 4);
- dst8.g = ((src6.g & 0xF) << 4) | (src6.b >> 2);
- dst8.b = ((src6.b & 0x3) << 6) | src6.a;
- dst8.a = 255;
-
- ocol0 = float4(dst8) / 255.f;
-})GLSL";
-
-constexpr const char* GLSL_RGB8_TO_RGBA6_FS = R"GLSL(
-flat in int layer;
-out vec4 ocol0;
-void main() {
- ivec4 src8 = ivec4(round(sampleEFB(ivec3(gl_FragCoord.xy, layer)) * 255.f));
- ivec4 dst6;
-
- dst6.r = src8.r >> 2;
- dst6.g = ((src8.r & 0x3) << 4) | (src8.g >> 4);
- dst6.b = ((src8.g & 0xF) << 2) | (src8.b >> 6);
- dst6.a = src8.b & 0x3F;
- ocol0 = float4(dst6) / 63.f;
-})GLSL";
-
-constexpr const char* GLSL_GS = R"GLSL(
-layout(triangles) in;
-layout(triangle_strip, max_vertices = %d) out;
-flat out int layer;
-void main() {
- for (int j = 0; j < %d; ++j) {
- for (int i = 0; i < 3; ++i) {
- layer = j;
- gl_Layer = j;
- gl_Position = gl_in[i].gl_Position;
- EmitVertex();
- }
- EndPrimitive();
- }
-})GLSL";
-
-constexpr const char* GLSL_EFB_POKE_VERTEX_VS = R"GLSL(
-in vec2 rawpos;
-in vec4 rawcolor0; // color
-in int rawcolor1; // depth
-out vec4 v_c;
-out float v_z;
-void main(void) {
- gl_Position = vec4(((rawpos + 0.5) / vec2(640.0, 528.0) * 2.0 - 1.0) * vec2(1.0, -1.0), 0.0, 1.0);
- gl_PointSize = %d.0 / 640.0;
-
- v_c = rawcolor0.bgra;
- v_z = float(rawcolor1 & 0xFFFFFF) / 16777216.0;
-})GLSL";
-
-constexpr const char* GLSL_EFB_POKE_PIXEL_FS = R"GLSL(
-in vec4 %s_c;
-in float %s_z;
-out vec4 ocol0;
-void main(void) {
- ocol0 = %s_c;
- gl_FragDepth = %s_z;
-})GLSL";
-
-constexpr const char* GLSL_EFB_POKE_GEOMETRY_GS = R"GLSL(
-layout(points) in;
-layout(points, max_vertices = %d) out;
-in vec4 v_c[1];
-in float v_z[1];
-out vec4 g_c;
-out float g_z;
-void main() {
- for (int j = 0; j < %d; ++j) {
- gl_Layer = j;
- gl_Position = gl_in[0].gl_Position;
- gl_PointSize = %d.0 / 640.0;
- g_c = v_c[0];
- g_z = v_z[0];
-
- EmitVertex();
- EndPrimitive();
- }
-})GLSL";
-
-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<GLuint> FramebufferManager::m_efbFramebuffer;
-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.
-std::vector<GLuint> FramebufferManager::m_resolvedFramebuffer;
-GLuint FramebufferManager::m_resolvedColorTexture;
-GLuint FramebufferManager::m_resolvedDepthTexture;
-
-// reinterpret pixel format
-SHADER FramebufferManager::m_pixel_format_shaders[2];
-
-// EFB pokes
-GLuint FramebufferManager::m_EfbPokes_VBO;
-GLuint FramebufferManager::m_EfbPokes_VAO;
-SHADER FramebufferManager::m_EfbPokes;
-
-GLuint FramebufferManager::CreateTexture(GLenum texture_type, GLenum internal_format,
- GLenum pixel_format, GLenum data_type)
-{
- GLuint texture;
- glActiveTexture(GL_TEXTURE9);
- glGenTextures(1, &texture);
- glBindTexture(texture_type, texture);
- if (texture_type == GL_TEXTURE_2D_ARRAY)
- {
- glTexParameteri(texture_type, GL_TEXTURE_MAX_LEVEL, 0);
- glTexImage3D(texture_type, 0, internal_format, m_targetWidth, m_targetHeight, m_EFBLayers, 0,
- pixel_format, data_type, nullptr);
- }
- else if (texture_type == GL_TEXTURE_2D_MULTISAMPLE_ARRAY)
- {
- if (g_ogl_config.bSupports3DTextureStorageMultisample)
- glTexStorage3DMultisample(texture_type, m_msaaSamples, internal_format, m_targetWidth,
- m_targetHeight, m_EFBLayers, false);
- else
- glTexImage3DMultisample(texture_type, m_msaaSamples, internal_format, m_targetWidth,
- m_targetHeight, m_EFBLayers, false);
- }
- else if (texture_type == GL_TEXTURE_2D_MULTISAMPLE)
- {
- if (g_ogl_config.bSupports2DTextureStorageMultisample)
- glTexStorage2DMultisample(texture_type, m_msaaSamples, internal_format, m_targetWidth,
- m_targetHeight, false);
- else
- glTexImage2DMultisample(texture_type, m_msaaSamples, internal_format, m_targetWidth,
- m_targetHeight, false);
- }
- else
- {
- PanicAlert("Unhandled texture type %d", texture_type);
- }
- glBindTexture(texture_type, 0);
- return texture;
-}
-
-void FramebufferManager::BindLayeredTexture(GLuint texture, const std::vector<GLuint>& 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++)
- {
- glBindFramebuffer(GL_FRAMEBUFFER, framebuffers[i]);
- glFramebufferTextureLayer(GL_FRAMEBUFFER, attachment, texture, 0, i);
- }
-}
-
-bool FramebufferManager::HasStencilBuffer()
-{
- return m_enable_stencil_buffer;
-}
-
-FramebufferManager::FramebufferManager(int targetWidth, int targetHeight, int msaaSamples,
- bool enable_stencil_buffer)
-{
- m_efbColor = 0;
- m_efbDepth = 0;
- m_efbColorSwap = 0;
- m_resolvedColorTexture = 0;
- m_resolvedDepthTexture = 0;
-
- 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).
- // They are:
- // - 24-bit RGB (8-bit components) with 24-bit Z
- // - 24-bit RGBA (6-bit components) with 24-bit Z
- // - Multisampled 16-bit RGB (5-6-5 format) with 16-bit Z
- // We only use one EFB format here: 32-bit ARGB with 24-bit Z.
- // Multisampling depends on user settings.
- // The distinction becomes important for certain operations, i.e. the
- // alpha channel should be ignored if the EFB does not have one.
-
- glActiveTexture(GL_TEXTURE9);
-
- m_EFBLayers = (g_ActiveConfig.stereo_mode != StereoMode::Off) ? 2 : 1;
- 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;
- }
-
- const bool multilayer = m_EFBLayers > 1;
-
- if (m_msaaSamples <= 1)
- {
- m_textureType = GL_TEXTURE_2D_ARRAY;
- }
- else
- {
- // Only use a layered multisample texture if needed. Some drivers
- // slow down significantly with single-layered multisample textures.
- m_textureType = multilayer ? GL_TEXTURE_2D_MULTISAMPLE_ARRAY : GL_TEXTURE_2D_MULTISAMPLE;
-
- // 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. This would lead to an unneeded copy of the EFB, so we are going to
- // avoid it. But as this job isn't done right now, we do need that texture for resolving:
- GLenum resolvedType = GL_TEXTURE_2D_ARRAY;
-
- m_resolvedColorTexture = CreateTexture(resolvedType, GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE);
- m_resolvedDepthTexture =
- 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);
- 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, depth_internal_format, depth_pixel_format, depth_data_type);
- m_efbColorSwap = CreateTexture(m_textureType, GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE);
-
- // Bind target textures to EFB framebuffer.
- 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);
- 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);
- glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
- if (m_enable_stencil_buffer)
- {
- glClearStencil(0);
- glClear(GL_STENCIL_BUFFER_BIT);
- }
-
- // reinterpret pixel format
- std::string vs = GLSL_REINTERPRET_PIXELFMT_VS;
-
- // The way to sample the EFB is based on the on the current configuration.
- // As we use the same sampling way for both interpreting shaders, the sampling
- // shader are generated first:
- std::string sampler;
-
- if (m_msaaSamples <= 1)
- {
- // non-msaa, so just fetch the pixel
- sampler = StringFromFormat(GLSL_SHADER_FS, multilayer, false);
- }
- else if (g_ActiveConfig.backend_info.bSupportsSSAA)
- {
- // msaa + sample shading available, so just fetch the sample
- // This will lead to sample shading, but it's the only way to not loose
- // the values of each sample.
- sampler = StringFromFormat(GLSL_SHADER_FS, multilayer, true);
- }
- else
- {
- // msaa without sample shading: calculate the mean value of the pixel
- sampler = StringFromFormat(GLSL_SAMPLE_EFB_FS, multilayer, m_msaaSamples, m_msaaSamples);
- }
-
- std::string ps_rgba6_to_rgb8 = sampler + GLSL_RGBA6_TO_RGB8_FS;
-
- std::string ps_rgb8_to_rgba6 = sampler + GLSL_RGB8_TO_RGBA6_FS;
-
- std::string gs = StringFromFormat(GLSL_GS, m_EFBLayers * 3, m_EFBLayers);
-
- ProgramShaderCache::CompileShader(m_pixel_format_shaders[0], vs, ps_rgb8_to_rgba6,
- multilayer ? gs : "");
- ProgramShaderCache::CompileShader(m_pixel_format_shaders[1], vs, ps_rgba6_to_rgb8,
- multilayer ? gs : "");
-
- const auto prefix = multilayer ? "g" : "v";
-
- ProgramShaderCache::CompileShader(
- m_EfbPokes, StringFromFormat(GLSL_EFB_POKE_VERTEX_VS, m_targetWidth),
-
- StringFromFormat(GLSL_EFB_POKE_PIXEL_FS, prefix, prefix, prefix, prefix),
-
- multilayer ?
- StringFromFormat(GLSL_EFB_POKE_GEOMETRY_GS, m_EFBLayers, m_EFBLayers, m_targetWidth) :
- "");
- glGenBuffers(1, &m_EfbPokes_VBO);
- glGenVertexArrays(1, &m_EfbPokes_VAO);
- glBindBuffer(GL_ARRAY_BUFFER, m_EfbPokes_VBO);
- glBindVertexArray(m_EfbPokes_VAO);
- glEnableVertexAttribArray(SHADER_POSITION_ATTRIB);
- glVertexAttribPointer(SHADER_POSITION_ATTRIB, 2, GL_UNSIGNED_SHORT, 0, sizeof(EfbPokeData),
- (void*)offsetof(EfbPokeData, x));
- glEnableVertexAttribArray(SHADER_COLOR0_ATTRIB);
- glVertexAttribPointer(SHADER_COLOR0_ATTRIB, 4, GL_UNSIGNED_BYTE, 1, sizeof(EfbPokeData),
- (void*)offsetof(EfbPokeData, data));
- glEnableVertexAttribArray(SHADER_COLOR1_ATTRIB);
- glVertexAttribIPointer(SHADER_COLOR1_ATTRIB, 1, GL_INT, sizeof(EfbPokeData),
- (void*)offsetof(EfbPokeData, data));
- glBindBuffer(GL_ARRAY_BUFFER,
- static_cast<VertexManager*>(g_vertex_manager.get())->GetVertexBufferHandle());
-
- if (!static_cast<Renderer*>(g_renderer.get())->IsGLES())
- glEnable(GL_PROGRAM_POINT_SIZE);
-}
-
-FramebufferManager::~FramebufferManager()
-{
- glBindFramebuffer(GL_FRAMEBUFFER, 0);
-
- GLuint glObj[3];
-
- // Note: OpenGL deletion functions silently ignore parameters of "0".
-
- glDeleteFramebuffers(m_EFBLayers, m_efbFramebuffer.data());
- glDeleteFramebuffers(m_EFBLayers, m_resolvedFramebuffer.data());
-
- // Required, as these are static class members
- m_efbFramebuffer.clear();
- m_resolvedFramebuffer.clear();
-
- glObj[0] = m_resolvedColorTexture;
- glObj[1] = m_resolvedDepthTexture;
- glDeleteTextures(2, glObj);
- m_resolvedColorTexture = 0;
- m_resolvedDepthTexture = 0;
-
- glObj[0] = m_efbColor;
- glObj[1] = m_efbDepth;
- glObj[2] = m_efbColorSwap;
- glDeleteTextures(3, glObj);
- m_efbColor = 0;
- m_efbDepth = 0;
- m_efbColorSwap = 0;
-
- // reinterpret pixel format
- m_pixel_format_shaders[0].Destroy();
- m_pixel_format_shaders[1].Destroy();
-
- // EFB pokes
- glDeleteBuffers(1, &m_EfbPokes_VBO);
- glDeleteVertexArrays(1, &m_EfbPokes_VAO);
- m_EfbPokes_VBO = 0;
- m_EfbPokes_VAO = 0;
- m_EfbPokes.Destroy();
-}
-
-GLuint FramebufferManager::GetEFBColorTexture(const EFBRectangle& sourceRc)
-{
- if (m_msaaSamples <= 1)
- {
- return m_efbColor;
- }
- else
- {
- // Transfer the EFB to a resolved texture. EXT_framebuffer_blit is
- // required.
-
- TargetRectangle targetRc = g_renderer->ConvertEFBRectangle(sourceRc);
- targetRc.ClampUL(0, 0, m_targetWidth, m_targetHeight);
-
- // Resolve.
- 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[0]);
-
- return m_resolvedColorTexture;
- }
-}
-
-GLuint FramebufferManager::GetEFBDepthTexture(const EFBRectangle& sourceRc)
-{
- if (m_msaaSamples <= 1)
- {
- return m_efbDepth;
- }
- else
- {
- // Transfer the EFB to a resolved texture.
-
- TargetRectangle targetRc = g_renderer->ConvertEFBRectangle(sourceRc);
- targetRc.ClampUL(0, 0, m_targetWidth, m_targetHeight);
-
- // Resolve.
- 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[0]);
-
- return m_resolvedDepthTexture;
- }
-}
-
-void FramebufferManager::ResolveEFBStencilTexture()
-{
- if (m_msaaSamples <= 1)
- return;
-
- // Resolve.
- for (unsigned int i = 0; i < m_EFBLayers; i++)
- {
- glBindFramebuffer(GL_READ_FRAMEBUFFER, m_efbFramebuffer[i]);
- glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_resolvedFramebuffer[i]);
- glBlitFramebuffer(0, 0, m_targetWidth, m_targetHeight, 0, 0, m_targetWidth, m_targetHeight,
- GL_STENCIL_BUFFER_BIT, GL_NEAREST);
- }
-
- // Return to EFB.
- glBindFramebuffer(GL_FRAMEBUFFER, m_efbFramebuffer[0]);
-}
-
-GLuint FramebufferManager::GetResolvedFramebuffer()
-{
- if (m_msaaSamples <= 1)
- return m_efbFramebuffer[0];
- return m_resolvedFramebuffer[0];
-}
-
-void FramebufferManager::SetFramebuffer(GLuint fb)
-{
- glBindFramebuffer(GL_FRAMEBUFFER, fb != 0 ? fb : GetEFBFramebuffer());
-}
-
-void FramebufferManager::FramebufferTexture(GLenum target, GLenum attachment, GLenum textarget,
- GLuint texture, GLint level)
-{
- if (textarget == GL_TEXTURE_2D_ARRAY || textarget == GL_TEXTURE_2D_MULTISAMPLE_ARRAY)
- {
- if (m_EFBLayers > 1)
- glFramebufferTexture(target, attachment, texture, level);
- else
- glFramebufferTextureLayer(target, attachment, texture, level, 0);
- }
- else
- {
- glFramebufferTexture2D(target, attachment, textarget, texture, level);
- }
-}
-
-// Apply AA if enabled
-GLuint FramebufferManager::ResolveAndGetRenderTarget(const EFBRectangle& source_rect)
-{
- return GetEFBColorTexture(source_rect);
-}
-
-GLuint FramebufferManager::ResolveAndGetDepthTarget(const EFBRectangle& source_rect)
-{
- return GetEFBDepthTexture(source_rect);
-}
-
-void FramebufferManager::ReinterpretPixelData(unsigned int convtype)
-{
- g_renderer->ResetAPIState();
-
- GLuint src_texture = 0;
-
- // We aren't allowed to render and sample the same texture in one draw call,
- // so we have to create a new texture and overwrite it completely.
- // To not allocate one big texture every time, we've allocated two on
- // initialization and just swap them here:
- src_texture = m_efbColor;
- m_efbColor = m_efbColorSwap;
- m_efbColorSwap = src_texture;
- FramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, m_textureType, m_efbColor, 0);
-
- glViewport(0, 0, m_targetWidth, m_targetHeight);
- glActiveTexture(GL_TEXTURE9);
- glBindTexture(m_textureType, src_texture);
- g_sampler_cache->BindNearestSampler(9);
-
- m_pixel_format_shaders[convtype ? 1 : 0].Bind();
- ProgramShaderCache::BindVertexFormat(nullptr);
- glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
- glBindTexture(m_textureType, 0);
-
- g_renderer->RestoreAPIState();
-}
-
-void FramebufferManager::PokeEFB(EFBAccessType type, const EfbPokeData* points, size_t num_points)
-{
- g_renderer->ResetAPIState();
-
- if (type == EFBAccessType::PokeZ)
- {
- glDepthMask(GL_TRUE);
- glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
- glEnable(GL_DEPTH_TEST);
- glDepthFunc(GL_ALWAYS);
- }
-
- glBindVertexArray(m_EfbPokes_VAO);
- glBindBuffer(GL_ARRAY_BUFFER, m_EfbPokes_VBO);
- glBufferData(GL_ARRAY_BUFFER, sizeof(EfbPokeData) * num_points, points, GL_STREAM_DRAW);
- m_EfbPokes.Bind();
- glViewport(0, 0, m_targetWidth, m_targetHeight);
- glDrawArrays(GL_POINTS, 0, (GLsizei)num_points);
-
- glBindBuffer(GL_ARRAY_BUFFER,
- static_cast<VertexManager*>(g_vertex_manager.get())->GetVertexBufferHandle());
- g_renderer->RestoreAPIState();
-
- // TODO: Could just update the EFB cache with the new value
- ClearEFBCache();
-}
-
-} // namespace OGL
diff --git a/Source/Core/VideoBackends/OGL/FramebufferManager.h b/Source/Core/VideoBackends/OGL/FramebufferManager.h
deleted file mode 100644
index f68556bf90..0000000000
--- a/Source/Core/VideoBackends/OGL/FramebufferManager.h
+++ /dev/null
@@ -1,127 +0,0 @@
-// Copyright 2009 Dolphin Emulator Project
-// Licensed under GPLv2+
-// Refer to the license.txt file included.
-
-#pragma once
-
-#include <memory>
-#include <utility>
-#include <vector>
-
-#include "Common/CommonTypes.h"
-#include "Common/GL/GLUtil.h"
-#include "VideoBackends/OGL/ProgramShaderCache.h"
-#include "VideoBackends/OGL/Render.h"
-#include "VideoCommon/FramebufferManagerBase.h"
-
-// On the GameCube, the game sends a request for the graphics processor to
-// transfer its internal EFB (Embedded Framebuffer) to an area in GameCube RAM
-// called the XFB (External Framebuffer). The size and location of the XFB is
-// decided at the time of the copy, and the format is always YUYV. The video
-// interface is given a pointer to the XFB, which will be decoded and
-// displayed on the TV.
-//
-// There are two ways for Dolphin to emulate this:
-//
-// Real XFB mode:
-//
-// Dolphin will behave like the GameCube and encode the EFB to
-// a portion of GameCube RAM. The emulated video interface will decode the data
-// for output to the screen.
-//
-// Advantages: Behaves exactly like the GameCube.
-// Disadvantages: Resolution will be limited.
-//
-// Virtual XFB mode:
-//
-// When a request is made to copy the EFB to an XFB, Dolphin
-// will remember the RAM location and size of the XFB in a Virtual XFB list.
-// The video interface will look up the XFB in the list and use the enhanced
-// data stored there, if available.
-//
-// Advantages: Enables high resolution graphics, better than real hardware.
-// Disadvantages: If the GameCube CPU writes directly to the XFB (which is
-// possible but uncommon), the Virtual XFB will not capture this information.
-
-// There may be multiple XFBs in GameCube RAM. This is the maximum number to
-// virtualize.
-
-namespace OGL
-{
-class FramebufferManager : public FramebufferManagerBase
-{
-public:
- 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
- // the EFB to a resolved texture first.
- static GLuint GetEFBColorTexture(const EFBRectangle& sourceRc);
- static GLuint GetEFBDepthTexture(const EFBRectangle& sourceRc);
- static void ResolveEFBStencilTexture();
-
- static GLuint GetEFBFramebuffer(unsigned int layer = 0)
- {
- return (layer < m_EFBLayers) ? m_efbFramebuffer[layer] : m_efbFramebuffer.back();
- }
- // Resolved framebuffer is only used in MSAA mode.
- static GLuint GetResolvedFramebuffer();
- static void SetFramebuffer(GLuint fb);
- static void FramebufferTexture(GLenum target, GLenum attachment, GLenum textarget, GLuint texture,
- GLint level);
-
- // 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.
- // If not in MSAA mode, will just return the render target texture ID.
- // After calling this, before you render anything else, you MUST bind the framebuffer you want to
- // draw to.
- static GLuint ResolveAndGetRenderTarget(const EFBRectangle& rect);
-
- // Same as above but for the depth Target.
- // After calling this, before you render anything else, you MUST bind the framebuffer you want to
- // draw to.
- static GLuint ResolveAndGetDepthTarget(const EFBRectangle& rect);
-
- // Convert EFB content on pixel format change.
- // convtype=0 -> rgb8->rgba6, convtype=2 -> rgba6->rgb8
- 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<GLuint>& framebuffers,
- GLenum attachment, GLenum texture_type);
-
- static int m_targetWidth;
- static int m_targetHeight;
- static int m_msaaSamples;
-
- static GLenum m_textureType;
- static std::vector<GLuint> m_efbFramebuffer;
- static GLuint m_efbColor;
- static GLuint m_efbDepth;
- 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<GLuint> m_resolvedFramebuffer;
- static GLuint m_resolvedColorTexture;
- static GLuint m_resolvedDepthTexture;
-
- // For pixel format draw
- static SHADER m_pixel_format_shaders[2];
-
- // For EFB pokes
- static GLuint m_EfbPokes_VBO;
- static GLuint m_EfbPokes_VAO;
- static SHADER m_EfbPokes;
-};
-
-} // namespace OGL
diff --git a/Source/Core/VideoBackends/OGL/NativeVertexFormat.cpp b/Source/Core/VideoBackends/OGL/NativeVertexFormat.cpp
index df24809ae0..50a6276c72 100644
--- a/Source/Core/VideoBackends/OGL/NativeVertexFormat.cpp
+++ b/Source/Core/VideoBackends/OGL/NativeVertexFormat.cpp
@@ -7,6 +7,7 @@
#include "Common/MsgHandler.h"
#include "VideoBackends/OGL/ProgramShaderCache.h"
+#include "VideoBackends/OGL/Render.h"
#include "VideoBackends/OGL/VertexManager.h"
#include "VideoCommon/NativeVertexFormat.h"
@@ -18,7 +19,7 @@
namespace OGL
{
std::unique_ptr<NativeVertexFormat>
-VertexManager::CreateNativeVertexFormat(const PortableVertexDeclaration& vtx_decl)
+Renderer::CreateNativeVertexFormat(const PortableVertexDeclaration& vtx_decl)
{
return std::make_unique<GLVertexFormat>(vtx_decl);
}
@@ -44,10 +45,10 @@ static void SetPointer(u32 attrib, u32 stride, const AttributeFormat& format)
(u8*)nullptr + format.offset);
}
-GLVertexFormat::GLVertexFormat(const PortableVertexDeclaration& _vtx_decl)
+GLVertexFormat::GLVertexFormat(const PortableVertexDeclaration& vtx_decl)
+ : NativeVertexFormat(vtx_decl)
{
- this->vtx_decl = _vtx_decl;
- u32 vertex_stride = _vtx_decl.stride;
+ u32 vertex_stride = vtx_decl.stride;
// We will not allow vertex components causing uneven strides.
if (vertex_stride & 3)
@@ -63,22 +64,22 @@ GLVertexFormat::GLVertexFormat(const PortableVertexDeclaration& _vtx_decl)
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vm->GetIndexBufferHandle());
glBindBuffer(GL_ARRAY_BUFFER, vm->GetVertexBufferHandle());
- SetPointer(SHADER_POSITION_ATTRIB, vertex_stride, _vtx_decl.position);
+ SetPointer(SHADER_POSITION_ATTRIB, vertex_stride, vtx_decl.position);
for (int i = 0; i < 3; i++)
- SetPointer(SHADER_NORM0_ATTRIB + i, vertex_stride, _vtx_decl.normals[i]);
+ SetPointer(SHADER_NORM0_ATTRIB + i, vertex_stride, vtx_decl.normals[i]);
for (int i = 0; i < 2; i++)
- SetPointer(SHADER_COLOR0_ATTRIB + i, vertex_stride, _vtx_decl.colors[i]);
+ SetPointer(SHADER_COLOR0_ATTRIB + i, vertex_stride, vtx_decl.colors[i]);
for (int i = 0; i < 8; i++)
- SetPointer(SHADER_TEXTURE0_ATTRIB + i, vertex_stride, _vtx_decl.texcoords[i]);
+ SetPointer(SHADER_TEXTURE0_ATTRIB + i, vertex_stride, vtx_decl.texcoords[i]);
- SetPointer(SHADER_POSMTX_ATTRIB, vertex_stride, _vtx_decl.posmtx);
+ SetPointer(SHADER_POSMTX_ATTRIB, vertex_stride, vtx_decl.posmtx);
}
GLVertexFormat::~GLVertexFormat()
{
glDeleteVertexArrays(1, &VAO);
}
-}
+} // namespace OGL
diff --git a/Source/Core/VideoBackends/OGL/OGL.vcxproj b/Source/Core/VideoBackends/OGL/OGL.vcxproj
index 38ea16b42e..7395b6ef2b 100644
--- a/Source/Core/VideoBackends/OGL/OGL.vcxproj
+++ b/Source/Core/VideoBackends/OGL/OGL.vcxproj
@@ -40,17 +40,13 @@
<ClCompile Include="OGLShader.cpp" />
<ClCompile Include="OGLTexture.cpp" />
<ClCompile Include="BoundingBox.cpp" />
- <ClCompile Include="FramebufferManager.cpp" />
<ClCompile Include="main.cpp" />
<ClCompile Include="NativeVertexFormat.cpp" />
<ClCompile Include="PerfQuery.cpp" />
- <ClCompile Include="PostProcessing.cpp" />
<ClCompile Include="ProgramShaderCache.cpp" />
<ClCompile Include="Render.cpp" />
<ClCompile Include="SamplerCache.cpp" />
<ClCompile Include="StreamBuffer.cpp" />
- <ClCompile Include="TextureCache.cpp" />
- <ClCompile Include="TextureConverter.cpp" />
<ClCompile Include="VertexManager.cpp" />
</ItemGroup>
<ItemGroup>
@@ -58,16 +54,12 @@
<ClInclude Include="OGLShader.h" />
<ClInclude Include="OGLTexture.h" />
<ClInclude Include="BoundingBox.h" />
- <ClInclude Include="FramebufferManager.h" />
<ClInclude Include="GPUTimer.h" />
<ClInclude Include="PerfQuery.h" />
- <ClInclude Include="PostProcessing.h" />
<ClInclude Include="ProgramShaderCache.h" />
<ClInclude Include="Render.h" />
<ClInclude Include="SamplerCache.h" />
<ClInclude Include="StreamBuffer.h" />
- <ClInclude Include="TextureCache.h" />
- <ClInclude Include="TextureConverter.h" />
<ClInclude Include="VertexManager.h" />
<ClInclude Include="VideoBackend.h" />
</ItemGroup>
diff --git a/Source/Core/VideoBackends/OGL/OGL.vcxproj.filters b/Source/Core/VideoBackends/OGL/OGL.vcxproj.filters
index fbede5caf6..4077f05a37 100644
--- a/Source/Core/VideoBackends/OGL/OGL.vcxproj.filters
+++ b/Source/Core/VideoBackends/OGL/OGL.vcxproj.filters
@@ -18,21 +18,12 @@
<ClCompile Include="VertexManager.cpp">
<Filter>Decoder</Filter>
</ClCompile>
- <ClCompile Include="TextureConverter.cpp">
- <Filter>GLUtil</Filter>
- </ClCompile>
<ClCompile Include="BoundingBox.cpp">
<Filter>Render</Filter>
</ClCompile>
- <ClCompile Include="FramebufferManager.cpp">
- <Filter>Render</Filter>
- </ClCompile>
<ClCompile Include="PerfQuery.cpp">
<Filter>Render</Filter>
</ClCompile>
- <ClCompile Include="PostProcessing.cpp">
- <Filter>Render</Filter>
- </ClCompile>
<ClCompile Include="ProgramShaderCache.cpp">
<Filter>Render</Filter>
</ClCompile>
@@ -42,9 +33,6 @@
<ClCompile Include="StreamBuffer.cpp">
<Filter>Render</Filter>
</ClCompile>
- <ClCompile Include="TextureCache.cpp">
- <Filter>Render</Filter>
- </ClCompile>
<ClCompile Include="main.cpp" />
<ClCompile Include="SamplerCache.cpp" />
<ClCompile Include="OGLTexture.cpp">
@@ -61,21 +49,12 @@
<ClInclude Include="VertexManager.h">
<Filter>Decoder</Filter>
</ClInclude>
- <ClInclude Include="TextureConverter.h">
- <Filter>GLUtil</Filter>
- </ClInclude>
<ClInclude Include="BoundingBox.h">
<Filter>Render</Filter>
</ClInclude>
- <ClInclude Include="FramebufferManager.h">
- <Filter>Render</Filter>
- </ClInclude>
<ClInclude Include="PerfQuery.h">
<Filter>Render</Filter>
</ClInclude>
- <ClInclude Include="PostProcessing.h">
- <Filter>Render</Filter>
- </ClInclude>
<ClInclude Include="ProgramShaderCache.h">
<Filter>Render</Filter>
</ClInclude>
@@ -85,9 +64,6 @@
<ClInclude Include="StreamBuffer.h">
<Filter>Render</Filter>
</ClInclude>
- <ClInclude Include="TextureCache.h">
- <Filter>Render</Filter>
- </ClInclude>
<ClInclude Include="SamplerCache.h" />
<ClInclude Include="VideoBackend.h" />
<ClInclude Include="GPUTimer.h">
diff --git a/Source/Core/VideoBackends/OGL/OGLShader.cpp b/Source/Core/VideoBackends/OGL/OGLShader.cpp
index e881269524..340d79f244 100644
--- a/Source/Core/VideoBackends/OGL/OGLShader.cpp
+++ b/Source/Core/VideoBackends/OGL/OGLShader.cpp
@@ -24,23 +24,24 @@ static GLenum GetGLShaderTypeForStage(ShaderStage stage)
}
}
-OGLShader::OGLShader(ShaderStage stage, GLenum gl_type, GLuint shader_id)
- : AbstractShader(stage), m_type(gl_type), m_id(shader_id)
+OGLShader::OGLShader(ShaderStage stage, GLenum gl_type, GLuint gl_id)
+ : AbstractShader(stage), m_id(ProgramShaderCache::GenerateShaderID()), m_type(gl_type),
+ m_gl_id(gl_id)
{
}
-OGLShader::OGLShader(GLuint compute_program_id)
- : AbstractShader(ShaderStage::Compute), m_type(GL_COMPUTE_SHADER),
- m_compute_program_id(compute_program_id)
+OGLShader::OGLShader(GLuint gl_compute_program_id)
+ : AbstractShader(ShaderStage::Compute), m_id(ProgramShaderCache::GenerateShaderID()),
+ m_type(GL_COMPUTE_SHADER), m_gl_compute_program_id(gl_compute_program_id)
{
}
OGLShader::~OGLShader()
{
if (m_stage != ShaderStage::Compute)
- glDeleteShader(m_id);
+ glDeleteShader(m_gl_id);
else
- glDeleteProgram(m_compute_program_id);
+ glDeleteProgram(m_gl_compute_program_id);
}
bool OGLShader::HasBinary() const
diff --git a/Source/Core/VideoBackends/OGL/OGLShader.h b/Source/Core/VideoBackends/OGL/OGLShader.h
index e3036044f6..a703d60696 100644
--- a/Source/Core/VideoBackends/OGL/OGLShader.h
+++ b/Source/Core/VideoBackends/OGL/OGLShader.h
@@ -16,13 +16,14 @@ namespace OGL
class OGLShader final : public AbstractShader
{
public:
- explicit OGLShader(ShaderStage stage, GLenum gl_type, GLuint shader_id);
- explicit OGLShader(GLuint compute_program_id);
+ explicit OGLShader(ShaderStage stage, GLenum gl_type, GLuint gl_id);
+ explicit OGLShader(GLuint gl_compute_program_id);
~OGLShader() override;
+ u64 GetID() const { return m_id; }
GLenum GetGLShaderType() const { return m_type; }
- GLuint GetGLShaderID() const { return m_id; }
- GLuint GetGLComputeProgramID() const { return m_compute_program_id; }
+ GLuint GetGLShaderID() const { return m_gl_id; }
+ GLuint GetGLComputeProgramID() const { return m_gl_compute_program_id; }
bool HasBinary() const override;
BinaryData GetBinary() const override;
@@ -30,9 +31,10 @@ public:
size_t length);
private:
+ u64 m_id;
GLenum m_type;
- GLuint m_id = 0;
- GLuint m_compute_program_id = 0;
+ GLuint m_gl_id = 0;
+ GLuint m_gl_compute_program_id = 0;
};
} // namespace OGL
diff --git a/Source/Core/VideoBackends/OGL/OGLTexture.cpp b/Source/Core/VideoBackends/OGL/OGLTexture.cpp
index fbe7f576c7..3cdbaca301 100644
--- a/Source/Core/VideoBackends/OGL/OGLTexture.cpp
+++ b/Source/Core/VideoBackends/OGL/OGLTexture.cpp
@@ -6,13 +6,8 @@
#include "Common/CommonTypes.h"
#include "Common/MsgHandler.h"
-#include "VideoBackends/OGL/FramebufferManager.h"
#include "VideoBackends/OGL/OGLTexture.h"
#include "VideoBackends/OGL/SamplerCache.h"
-#include "VideoBackends/OGL/TextureCache.h"
-
-#include "VideoCommon/ImageWrite.h"
-#include "VideoCommon/TextureConfig.h"
namespace OGL
{
@@ -115,10 +110,9 @@ OGLTexture::OGLTexture(const TextureConfig& tex_config) : AbstractTexture(tex_co
DEBUG_ASSERT_MSG(VIDEO, !tex_config.IsMultisampled() || tex_config.levels == 1,
"OpenGL does not support multisampled textures with mip levels");
- GLenum target =
- tex_config.IsMultisampled() ? GL_TEXTURE_2D_MULTISAMPLE_ARRAY : GL_TEXTURE_2D_ARRAY;
+ const GLenum target = GetGLTarget();
glGenTextures(1, &m_texId);
- glActiveTexture(GL_TEXTURE9);
+ glActiveTexture(GL_MUTABLE_TEXTURE_INDEX);
glBindTexture(target, m_texId);
glTexParameteri(target, GL_TEXTURE_MAX_LEVEL, m_config.levels - 1);
@@ -139,7 +133,7 @@ OGLTexture::OGLTexture(const TextureConfig& tex_config) : AbstractTexture(tex_co
m_config.layers);
}
- if (m_config.rendertarget)
+ if (m_config.IsRenderTarget())
{
// We can't render to compressed formats.
ASSERT(!IsCompressedFormat(m_config.format));
@@ -147,40 +141,19 @@ OGLTexture::OGLTexture(const TextureConfig& tex_config) : AbstractTexture(tex_co
{
for (u32 level = 0; level < m_config.levels; level++)
{
- glTexImage3D(target, level, GL_RGBA, std::max(m_config.width >> level, 1u),
- std::max(m_config.height >> level, 1u), m_config.layers, 0, GL_RGBA,
- GL_UNSIGNED_BYTE, nullptr);
+ glTexImage3D(target, level, gl_internal_format, std::max(m_config.width >> level, 1u),
+ std::max(m_config.height >> level, 1u), m_config.layers, 0,
+ GetGLFormatForTextureFormat(m_config.format),
+ GetGLTypeForTextureFormat(m_config.format), nullptr);
}
}
- glGenFramebuffers(1, &m_framebuffer);
- FramebufferManager::SetFramebuffer(m_framebuffer);
- FramebufferManager::FramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, target, m_texId,
- 0);
-
- // We broke the framebuffer binding here, and need to restore it, as the CreateTexture
- // method is in the base renderer class and can be called by VideoCommon.
- FramebufferManager::SetFramebuffer(0);
}
}
OGLTexture::~OGLTexture()
{
- g_renderer->UnbindTexture(this);
- if (m_texId)
- glDeleteTextures(1, &m_texId);
-
- if (m_framebuffer)
- glDeleteFramebuffers(1, &m_framebuffer);
-}
-
-GLuint OGLTexture::GetRawTexIdentifier() const
-{
- return m_texId;
-}
-
-GLuint OGLTexture::GetFramebuffer() const
-{
- return m_framebuffer;
+ Renderer::GetInstance()->UnbindTexture(this);
+ glDeleteTextures(1, &m_texId);
}
void OGLTexture::CopyRectangleFromTexture(const AbstractTexture* src,
@@ -188,19 +161,18 @@ void OGLTexture::CopyRectangleFromTexture(const AbstractTexture* src,
u32 src_level, const MathUtil::Rectangle<int>& dst_rect,
u32 dst_layer, u32 dst_level)
{
- const OGLTexture* srcentry = static_cast<const OGLTexture*>(src);
+ const OGLTexture* src_gltex = static_cast<const OGLTexture*>(src);
ASSERT(src_rect.GetWidth() == dst_rect.GetWidth() &&
src_rect.GetHeight() == dst_rect.GetHeight());
if (g_ogl_config.bSupportsCopySubImage)
{
- glCopyImageSubData(srcentry->m_texId, GL_TEXTURE_2D_ARRAY, src_level, src_rect.left,
- src_rect.top, src_layer, m_texId, GL_TEXTURE_2D_ARRAY, dst_level,
- dst_rect.left, dst_rect.top, dst_layer, dst_rect.GetWidth(),
- dst_rect.GetHeight(), 1);
+ glCopyImageSubData(src_gltex->m_texId, src_gltex->GetGLTarget(), src_level, src_rect.left,
+ src_rect.top, src_layer, m_texId, GetGLTarget(), dst_level, dst_rect.left,
+ dst_rect.top, dst_layer, dst_rect.GetWidth(), dst_rect.GetHeight(), 1);
}
else
{
- BlitFramebuffer(const_cast<OGLTexture*>(srcentry), src_rect, src_layer, src_level, dst_rect,
+ BlitFramebuffer(const_cast<OGLTexture*>(src_gltex), src_rect, src_layer, src_level, dst_rect,
dst_layer, dst_level);
}
}
@@ -210,28 +182,12 @@ void OGLTexture::BlitFramebuffer(OGLTexture* srcentry, const MathUtil::Rectangle
const MathUtil::Rectangle<int>& dst_rect, u32 dst_layer,
u32 dst_level)
{
- // If it isn't a single leveled/layered texture, we need to update the framebuffer.
- bool update_src_framebuffer =
- srcentry->m_framebuffer == 0 || srcentry->m_config.layers != 0 || src_level != 0;
- bool update_dst_framebuffer = m_framebuffer == 0 || m_config.layers != 0 || dst_level != 0;
- if (!m_framebuffer)
- glGenFramebuffers(1, &m_framebuffer);
- if (!srcentry->m_framebuffer)
- glGenFramebuffers(1, &const_cast<OGLTexture*>(srcentry)->m_framebuffer);
-
- glBindFramebuffer(GL_READ_FRAMEBUFFER, srcentry->m_framebuffer);
- if (update_src_framebuffer)
- {
- glFramebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, srcentry->m_texId,
- src_level, src_layer);
- }
-
- glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_framebuffer);
- if (update_dst_framebuffer)
- {
- glFramebufferTextureLayer(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, m_texId, dst_level,
- dst_layer);
- }
+ Renderer::GetInstance()->BindSharedReadFramebuffer();
+ glFramebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, srcentry->m_texId, src_level,
+ src_layer);
+ Renderer::GetInstance()->BindSharedDrawFramebuffer();
+ glFramebufferTextureLayer(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, m_texId, dst_level,
+ dst_layer);
// glBlitFramebuffer is still affected by the scissor test, which is enabled by default.
glDisable(GL_SCISSOR_TEST);
@@ -239,50 +195,10 @@ void OGLTexture::BlitFramebuffer(OGLTexture* srcentry, const MathUtil::Rectangle
glBlitFramebuffer(src_rect.left, src_rect.top, src_rect.right, src_rect.bottom, dst_rect.left,
dst_rect.top, dst_rect.right, dst_rect.bottom, GL_COLOR_BUFFER_BIT, GL_NEAREST);
- if (update_src_framebuffer)
- {
- FramebufferManager::FramebufferTexture(
- GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
- srcentry->m_config.IsMultisampled() ? GL_TEXTURE_2D_MULTISAMPLE_ARRAY : GL_TEXTURE_2D_ARRAY,
- srcentry->m_texId, 0);
- }
- if (update_dst_framebuffer)
- {
- FramebufferManager::FramebufferTexture(
- GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
- m_config.IsMultisampled() ? GL_TEXTURE_2D_MULTISAMPLE_ARRAY : GL_TEXTURE_2D_ARRAY, m_texId,
- 0);
- }
-
// The default state for the scissor test is enabled. We don't need to do a full state
// restore, as the framebuffer and scissor test are the only things we changed.
glEnable(GL_SCISSOR_TEST);
- FramebufferManager::SetFramebuffer(0);
-}
-
-void OGLTexture::ScaleRectangleFromTexture(const AbstractTexture* source,
- const MathUtil::Rectangle<int>& srcrect,
- const MathUtil::Rectangle<int>& dstrect)
-{
- const OGLTexture* srcentry = static_cast<const OGLTexture*>(source);
- if (!m_framebuffer)
- {
- glGenFramebuffers(1, &m_framebuffer);
- FramebufferManager::SetFramebuffer(m_framebuffer);
- FramebufferManager::FramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
- GL_TEXTURE_2D_ARRAY, m_texId, 0);
- }
- g_renderer->ResetAPIState();
- FramebufferManager::SetFramebuffer(m_framebuffer);
- glActiveTexture(GL_TEXTURE9);
- glBindTexture(GL_TEXTURE_2D_ARRAY, srcentry->m_texId);
- g_sampler_cache->BindLinearSampler(9);
- glViewport(dstrect.left, dstrect.top, dstrect.GetWidth(), dstrect.GetHeight());
- TextureCache::GetInstance()->GetColorCopyProgram().Bind();
- glUniform4f(TextureCache::GetInstance()->GetColorCopyPositionUniform(), float(srcrect.left),
- float(srcrect.top), float(srcrect.GetWidth()), float(srcrect.GetHeight()));
- glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
- g_renderer->RestoreAPIState();
+ Renderer::GetInstance()->RestoreFramebufferBinding();
}
void OGLTexture::ResolveFromTexture(const AbstractTexture* src,
@@ -307,8 +223,9 @@ void OGLTexture::Load(u32 level, u32 width, u32 height, u32 row_length, const u8
std::max(1u, m_config.width >> level), std::max(1u, m_config.height >> level), width,
height);
- glActiveTexture(GL_TEXTURE9);
- glBindTexture(GL_TEXTURE_2D_ARRAY, m_texId);
+ const GLenum target = GetGLTarget();
+ glActiveTexture(GL_MUTABLE_TEXTURE_INDEX);
+ glBindTexture(target, m_texId);
if (row_length != width)
glPixelStorei(GL_UNPACK_ROW_LENGTH, row_length);
@@ -318,12 +235,12 @@ void OGLTexture::Load(u32 level, u32 width, u32 height, u32 row_length, const u8
{
if (g_ogl_config.bSupportsTextureStorage)
{
- glCompressedTexSubImage3D(GL_TEXTURE_2D_ARRAY, level, 0, 0, 0, width, height, 1,
- gl_internal_format, static_cast<GLsizei>(buffer_size), buffer);
+ glCompressedTexSubImage3D(target, level, 0, 0, 0, width, height, 1, gl_internal_format,
+ static_cast<GLsizei>(buffer_size), buffer);
}
else
{
- glCompressedTexImage3D(GL_TEXTURE_2D_ARRAY, level, gl_internal_format, width, height, 1, 0,
+ glCompressedTexImage3D(target, level, gl_internal_format, width, height, 1, 0,
static_cast<GLsizei>(buffer_size), buffer);
}
}
@@ -333,13 +250,12 @@ void OGLTexture::Load(u32 level, u32 width, u32 height, u32 row_length, const u8
GLenum gl_type = GetGLTypeForTextureFormat(m_config.format);
if (g_ogl_config.bSupportsTextureStorage)
{
- glTexSubImage3D(GL_TEXTURE_2D_ARRAY, level, 0, 0, 0, width, height, 1, gl_format, gl_type,
- buffer);
+ glTexSubImage3D(target, level, 0, 0, 0, width, height, 1, gl_format, gl_type, buffer);
}
else
{
- glTexImage3D(GL_TEXTURE_2D_ARRAY, level, gl_internal_format, width, height, 1, 0, gl_format,
- gl_type, buffer);
+ glTexImage3D(target, level, gl_internal_format, width, height, 1, 0, gl_format, gl_type,
+ buffer);
}
}
@@ -347,6 +263,11 @@ void OGLTexture::Load(u32 level, u32 width, u32 height, u32 row_length, const u8
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
}
+GLenum OGLTexture::GetGLFormatForImageTexture() const
+{
+ return GetGLInternalFormatForTextureFormat(m_config.format, true);
+}
+
OGLStagingTexture::OGLStagingTexture(StagingTextureType type, const TextureConfig& config,
GLenum target, GLuint buffer_name, size_t buffer_size,
char* map_ptr, size_t map_stride)
@@ -405,8 +326,7 @@ std::unique_ptr<OGLStagingTexture> OGLStagingTexture::Create(StagingTextureType
}
glBufferStorage(target, buffer_size, nullptr, buffer_flags);
- buffer_ptr =
- reinterpret_cast<char*>(glMapBufferRange(GL_PIXEL_PACK_BUFFER, 0, buffer_size, map_flags));
+ buffer_ptr = reinterpret_cast<char*>(glMapBufferRange(target, 0, buffer_size, map_flags));
ASSERT(buffer_ptr != nullptr);
}
else
@@ -426,7 +346,7 @@ void OGLStagingTexture::CopyFromTexture(const AbstractTexture* src,
const MathUtil::Rectangle<int>& src_rect, u32 src_layer,
u32 src_level, const MathUtil::Rectangle<int>& dst_rect)
{
- ASSERT(m_type == StagingTextureType::Readback);
+ ASSERT(m_type == StagingTextureType::Readback || m_type == StagingTextureType::Mutable);
ASSERT(src_rect.GetWidth() == dst_rect.GetWidth() &&
src_rect.GetHeight() == dst_rect.GetHeight());
ASSERT(src_rect.left >= 0 && static_cast<u32>(src_rect.right) <= src->GetConfig().width &&
@@ -443,40 +363,37 @@ void OGLStagingTexture::CopyFromTexture(const AbstractTexture* src,
glPixelStorei(GL_PACK_ROW_LENGTH, m_config.width);
const OGLTexture* gltex = static_cast<const OGLTexture*>(src);
- size_t dst_offset = dst_rect.top * m_config.GetStride() + dst_rect.left * m_texel_size;
+ const size_t dst_offset = dst_rect.top * m_config.GetStride() + dst_rect.left * m_texel_size;
- // If we don't have a FBO associated with this texture, we need to use a slow path.
- if (gltex->GetFramebuffer() != 0 && src_layer == 0 && src_level == 0)
+ // Prefer glGetTextureSubImage(), when available.
+ if (g_ogl_config.bSupportsTextureSubImage)
{
- // This texture has a framebuffer, so we can use glReadPixels().
- glBindFramebuffer(GL_READ_FRAMEBUFFER, gltex->GetFramebuffer());
- glReadPixels(src_rect.left, src_rect.top, src_rect.GetWidth(), src_rect.GetHeight(),
- GetGLFormatForTextureFormat(m_config.format),
- GetGLTypeForTextureFormat(m_config.format), reinterpret_cast<void*>(dst_offset));
-
- // Reset both read/draw framebuffers.
- glBindFramebuffer(GL_FRAMEBUFFER, FramebufferManager::GetEFBFramebuffer());
+ glGetTextureSubImage(
+ gltex->GetGLTextureId(), src_level, src_rect.left, src_rect.top, src_layer,
+ src_rect.GetWidth(), src_rect.GetHeight(), 1, GetGLFormatForTextureFormat(src->GetFormat()),
+ GetGLTypeForTextureFormat(src->GetFormat()),
+ static_cast<GLsizei>(m_buffer_size - dst_offset), reinterpret_cast<void*>(dst_offset));
}
else
{
- if (g_ogl_config.bSupportsTextureSubImage)
+ // Mutate the shared framebuffer.
+ Renderer::GetInstance()->BindSharedReadFramebuffer();
+ if (AbstractTexture::IsDepthFormat(gltex->GetFormat()))
{
- glGetTextureSubImage(
- gltex->GetRawTexIdentifier(), src_level, src_rect.left, src_rect.top, src_layer,
- src_rect.GetWidth(), src_rect.GetHeight(), 1,
- GetGLFormatForTextureFormat(m_config.format), GetGLTypeForTextureFormat(m_config.format),
- static_cast<GLsizei>(m_buffer_size - dst_offset), reinterpret_cast<void*>(dst_offset));
+ glFramebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, 0, 0, 0);
+ glFramebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, gltex->GetGLTextureId(),
+ src_level, src_layer);
}
else
{
- // TODO: Investigate whether it's faster to use glReadPixels() with a framebuffer, since we're
- // copying the whole texture, which may waste bandwidth. So we're trading CPU work in creating
- // the framebuffer for GPU work in copying potentially redundant texels.
- glActiveTexture(GL_TEXTURE9);
- glBindTexture(GL_TEXTURE_2D_ARRAY, gltex->GetRawTexIdentifier());
- glGetTexImage(GL_TEXTURE_2D_ARRAY, src_level, GetGLFormatForTextureFormat(m_config.format),
- GetGLTypeForTextureFormat(m_config.format), nullptr);
+ glFramebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, gltex->GetGLTextureId(),
+ src_level, src_layer);
+ glFramebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, 0, 0, 0);
}
+ glReadPixels(src_rect.left, src_rect.top, src_rect.GetWidth(), src_rect.GetHeight(),
+ GetGLFormatForTextureFormat(src->GetFormat()),
+ GetGLTypeForTextureFormat(src->GetFormat()), reinterpret_cast<void*>(dst_offset));
+ Renderer::GetInstance()->RestoreFramebufferBinding();
}
glPixelStorei(GL_PACK_ROW_LENGTH, 0);
@@ -501,7 +418,7 @@ void OGLStagingTexture::CopyToTexture(const MathUtil::Rectangle<int>& src_rect,
const MathUtil::Rectangle<int>& dst_rect, u32 dst_layer,
u32 dst_level)
{
- ASSERT(m_type == StagingTextureType::Upload);
+ ASSERT(m_type == StagingTextureType::Upload || m_type == StagingTextureType::Mutable);
ASSERT(src_rect.GetWidth() == dst_rect.GetWidth() &&
src_rect.GetHeight() == dst_rect.GetHeight());
ASSERT(src_rect.left >= 0 && static_cast<u32>(src_rect.right) <= m_config.width &&
@@ -509,8 +426,9 @@ void OGLStagingTexture::CopyToTexture(const MathUtil::Rectangle<int>& src_rect,
ASSERT(dst_rect.left >= 0 && static_cast<u32>(dst_rect.right) <= dst->GetConfig().width &&
dst_rect.top >= 0 && static_cast<u32>(dst_rect.bottom) <= dst->GetConfig().height);
- size_t src_offset = src_rect.top * m_config.GetStride() + src_rect.left * m_texel_size;
- size_t copy_size = src_rect.GetHeight() * m_config.GetStride();
+ const OGLTexture* gltex = static_cast<const OGLTexture*>(dst);
+ const size_t src_offset = src_rect.top * m_config.GetStride() + src_rect.left * m_texel_size;
+ const size_t copy_size = src_rect.GetHeight() * m_config.GetStride();
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, m_buffer_name);
glPixelStorei(GL_UNPACK_ROW_LENGTH, m_config.width);
@@ -533,12 +451,12 @@ void OGLStagingTexture::CopyToTexture(const MathUtil::Rectangle<int>& src_rect,
}
// Copy from the staging buffer to the texture object.
- glActiveTexture(GL_TEXTURE9);
- glBindTexture(GL_TEXTURE_2D_ARRAY, static_cast<const OGLTexture*>(dst)->GetRawTexIdentifier());
- glTexSubImage3D(GL_TEXTURE_2D_ARRAY, 0, dst_rect.left, dst_rect.top, dst_layer,
- dst_rect.GetWidth(), dst_rect.GetHeight(), 1,
- GetGLFormatForTextureFormat(m_config.format),
- GetGLTypeForTextureFormat(m_config.format), reinterpret_cast<void*>(src_offset));
+ const GLenum target = gltex->GetGLTarget();
+ glActiveTexture(GL_MUTABLE_TEXTURE_INDEX);
+ glBindTexture(target, gltex->GetGLTextureId());
+ glTexSubImage3D(target, 0, dst_rect.left, dst_rect.top, dst_layer, dst_rect.GetWidth(),
+ dst_rect.GetHeight(), 1, GetGLFormatForTextureFormat(dst->GetFormat()),
+ GetGLTypeForTextureFormat(dst->GetFormat()), reinterpret_cast<void*>(src_offset));
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
@@ -602,10 +520,13 @@ void OGLStagingTexture::Unmap()
m_map_pointer = nullptr;
}
-OGLFramebuffer::OGLFramebuffer(AbstractTextureFormat color_format,
+OGLFramebuffer::OGLFramebuffer(AbstractTexture* color_attachment, AbstractTexture* depth_attachment,
+ AbstractTextureFormat color_format,
AbstractTextureFormat depth_format, u32 width, u32 height,
u32 layers, u32 samples, GLuint fbo)
- : AbstractFramebuffer(color_format, depth_format, width, height, layers, samples), m_fbo(fbo)
+ : AbstractFramebuffer(color_attachment, depth_attachment, color_format, depth_format, width,
+ height, layers, samples),
+ m_fbo(fbo)
{
}
@@ -614,8 +535,8 @@ OGLFramebuffer::~OGLFramebuffer()
glDeleteFramebuffers(1, &m_fbo);
}
-std::unique_ptr<OGLFramebuffer> OGLFramebuffer::Create(const OGLTexture* color_attachment,
- const OGLTexture* depth_attachment)
+std::unique_ptr<OGLFramebuffer> OGLFramebuffer::Create(OGLTexture* color_attachment,
+ OGLTexture* depth_attachment)
{
if (!ValidateConfig(color_attachment, depth_attachment))
return nullptr;
@@ -638,13 +559,13 @@ std::unique_ptr<OGLFramebuffer> OGLFramebuffer::Create(const OGLTexture* color_a
{
if (color_attachment->GetConfig().layers > 1)
{
- glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
- color_attachment->GetRawTexIdentifier(), 0);
+ glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, color_attachment->GetGLTextureId(),
+ 0);
}
else
{
glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
- color_attachment->GetRawTexIdentifier(), 0, 0);
+ color_attachment->GetGLTextureId(), 0, 0);
}
}
@@ -655,19 +576,26 @@ std::unique_ptr<OGLFramebuffer> OGLFramebuffer::Create(const OGLTexture* color_a
GL_DEPTH_ATTACHMENT;
if (depth_attachment->GetConfig().layers > 1)
{
- glFramebufferTexture(GL_FRAMEBUFFER, attachment, depth_attachment->GetRawTexIdentifier(), 0);
+ glFramebufferTexture(GL_FRAMEBUFFER, attachment, depth_attachment->GetGLTextureId(), 0);
}
else
{
- glFramebufferTextureLayer(GL_FRAMEBUFFER, attachment, depth_attachment->GetRawTexIdentifier(),
- 0, 0);
+ glFramebufferTextureLayer(GL_FRAMEBUFFER, attachment, depth_attachment->GetGLTextureId(), 0,
+ 0);
}
}
DEBUG_ASSERT(glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE);
- FramebufferManager::SetFramebuffer(0);
- return std::make_unique<OGLFramebuffer>(color_format, depth_format, width, height, layers,
- samples, fbo);
+ Renderer::GetInstance()->RestoreFramebufferBinding();
+
+ return std::make_unique<OGLFramebuffer>(color_attachment, depth_attachment, color_format,
+ depth_format, width, height, layers, samples, fbo);
+}
+
+void OGLFramebuffer::UpdateDimensions(u32 width, u32 height)
+{
+ m_width = width;
+ m_height = height;
}
} // namespace OGL
diff --git a/Source/Core/VideoBackends/OGL/OGLTexture.h b/Source/Core/VideoBackends/OGL/OGLTexture.h
index 60c5c932b3..bd6a6918e2 100644
--- a/Source/Core/VideoBackends/OGL/OGLTexture.h
+++ b/Source/Core/VideoBackends/OGL/OGLTexture.h
@@ -25,16 +25,17 @@ public:
const MathUtil::Rectangle<int>& src_rect, u32 src_layer,
u32 src_level, const MathUtil::Rectangle<int>& dst_rect,
u32 dst_layer, u32 dst_level) override;
- void ScaleRectangleFromTexture(const AbstractTexture* source,
- const MathUtil::Rectangle<int>& srcrect,
- const MathUtil::Rectangle<int>& dstrect) override;
void ResolveFromTexture(const AbstractTexture* src, const MathUtil::Rectangle<int>& rect,
u32 layer, u32 level) override;
void Load(u32 level, u32 width, u32 height, u32 row_length, const u8* buffer,
size_t buffer_size) override;
- GLuint GetRawTexIdentifier() const;
- GLuint GetFramebuffer() const;
+ GLuint GetGLTextureId() const { return m_texId; }
+ GLenum GetGLTarget() const
+ {
+ return IsMultisampled() ? GL_TEXTURE_2D_MULTISAMPLE_ARRAY : GL_TEXTURE_2D_ARRAY;
+ }
+ GLenum GetGLFormatForImageTexture() const;
private:
void BlitFramebuffer(OGLTexture* srcentry, const MathUtil::Rectangle<int>& src_rect,
@@ -42,7 +43,6 @@ private:
u32 dst_layer, u32 dst_level);
GLuint m_texId;
- GLuint m_framebuffer = 0;
};
class OGLStagingTexture final : public AbstractStagingTexture
@@ -79,13 +79,18 @@ private:
class OGLFramebuffer final : public AbstractFramebuffer
{
public:
- OGLFramebuffer(AbstractTextureFormat color_format, AbstractTextureFormat depth_format, u32 width,
+ OGLFramebuffer(AbstractTexture* color_attachment, AbstractTexture* depth_attachment,
+ AbstractTextureFormat color_format, AbstractTextureFormat depth_format, u32 width,
u32 height, u32 layers, u32 samples, GLuint fbo);
~OGLFramebuffer() override;
+ static std::unique_ptr<OGLFramebuffer> Create(OGLTexture* color_attachment,
+ OGLTexture* depth_attachment);
+
GLuint GetFBO() const { return m_fbo; }
- static std::unique_ptr<OGLFramebuffer> Create(const OGLTexture* color_attachment,
- const OGLTexture* depth_attachment);
+
+ // Used for updating the dimensions of the system/window framebuffer.
+ void UpdateDimensions(u32 width, u32 height);
protected:
GLuint m_fbo;
diff --git a/Source/Core/VideoBackends/OGL/PostProcessing.cpp b/Source/Core/VideoBackends/OGL/PostProcessing.cpp
deleted file mode 100644
index 57d8f7c8f8..0000000000
--- a/Source/Core/VideoBackends/OGL/PostProcessing.cpp
+++ /dev/null
@@ -1,273 +0,0 @@
-// Copyright 2009 Dolphin Emulator Project
-// Licensed under GPLv2+
-// Refer to the license.txt file included.
-
-#include "VideoBackends/OGL/PostProcessing.h"
-
-#include "Common/CommonTypes.h"
-#include "Common/Logging/Log.h"
-#include "Common/StringUtil.h"
-
-#include "Core/Config/GraphicsSettings.h"
-
-#include "VideoBackends/OGL/FramebufferManager.h"
-#include "VideoBackends/OGL/OGLTexture.h"
-#include "VideoBackends/OGL/ProgramShaderCache.h"
-#include "VideoBackends/OGL/SamplerCache.h"
-
-#include "VideoCommon/VideoCommon.h"
-#include "VideoCommon/VideoConfig.h"
-
-namespace OGL
-{
-static const char s_vertex_shader[] = "out vec2 uv0;\n"
- "uniform vec4 src_rect;\n"
- "void main(void) {\n"
- " vec2 rawpos = vec2(gl_VertexID&1, gl_VertexID&2);\n"
- " gl_Position = vec4(rawpos*2.0-1.0, 0.0, 1.0);\n"
- " uv0 = vec2(mix(src_rect.xy, src_rect.zw, rawpos));\n"
- "}\n";
-
-OpenGLPostProcessing::OpenGLPostProcessing() : m_initialized(false)
-{
- CreateHeader();
-}
-
-OpenGLPostProcessing::~OpenGLPostProcessing()
-{
- m_shader.Destroy();
-}
-
-void OpenGLPostProcessing::BlitFromTexture(TargetRectangle src, TargetRectangle dst,
- int src_texture, int src_width, int src_height,
- int layer)
-{
- ApplyShader();
-
- glViewport(dst.left, dst.bottom, dst.GetWidth(), dst.GetHeight());
-
- ProgramShaderCache::BindVertexFormat(nullptr);
-
- m_shader.Bind();
-
- glUniform4f(m_uniform_resolution, (float)src_width, (float)src_height, 1.0f / (float)src_width,
- 1.0f / (float)src_height);
- glUniform4f(m_uniform_src_rect, src.left / (float)src_width, src.top / (float)src_height,
- src.right / (float)src_width, src.bottom / (float)src_height);
- glUniform1ui(m_uniform_time, (GLuint)m_timer.GetTimeElapsed());
- glUniform1i(m_uniform_layer, layer);
-
- if (m_config.IsDirty())
- {
- for (auto& it : m_config.GetOptions())
- {
- if (it.second.m_dirty)
- {
- switch (it.second.m_type)
- {
- case PostProcessingShaderConfiguration::ConfigurationOption::OptionType::OPTION_BOOL:
- glUniform1i(m_uniform_bindings[it.first], it.second.m_bool_value);
- break;
- case PostProcessingShaderConfiguration::ConfigurationOption::OptionType::OPTION_INTEGER:
- switch (it.second.m_integer_values.size())
- {
- case 1:
- glUniform1i(m_uniform_bindings[it.first], it.second.m_integer_values[0]);
- break;
- case 2:
- glUniform2i(m_uniform_bindings[it.first], it.second.m_integer_values[0],
- it.second.m_integer_values[1]);
- break;
- case 3:
- glUniform3i(m_uniform_bindings[it.first], it.second.m_integer_values[0],
- it.second.m_integer_values[1], it.second.m_integer_values[2]);
- break;
- case 4:
- glUniform4i(m_uniform_bindings[it.first], it.second.m_integer_values[0],
- it.second.m_integer_values[1], it.second.m_integer_values[2],
- it.second.m_integer_values[3]);
- break;
- }
- break;
- case PostProcessingShaderConfiguration::ConfigurationOption::OptionType::OPTION_FLOAT:
- switch (it.second.m_float_values.size())
- {
- case 1:
- glUniform1f(m_uniform_bindings[it.first], it.second.m_float_values[0]);
- break;
- case 2:
- glUniform2f(m_uniform_bindings[it.first], it.second.m_float_values[0],
- it.second.m_float_values[1]);
- break;
- case 3:
- glUniform3f(m_uniform_bindings[it.first], it.second.m_float_values[0],
- it.second.m_float_values[1], it.second.m_float_values[2]);
- break;
- case 4:
- glUniform4f(m_uniform_bindings[it.first], it.second.m_float_values[0],
- it.second.m_float_values[1], it.second.m_float_values[2],
- it.second.m_float_values[3]);
- break;
- }
- break;
- }
- it.second.m_dirty = false;
- }
- }
- m_config.SetDirty(false);
- }
-
- glActiveTexture(GL_TEXTURE9);
- glBindTexture(GL_TEXTURE_2D_ARRAY, src_texture);
- g_sampler_cache->BindLinearSampler(9);
- glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
-}
-
-void OpenGLPostProcessing::ApplyShader()
-{
- // shader didn't changed
- if (m_initialized && m_config.GetShader() == g_ActiveConfig.sPostProcessingShader)
- return;
-
- m_shader.Destroy();
- m_uniform_bindings.clear();
-
- // load shader code
- std::string main_code = m_config.LoadShader();
- std::string options_code = LoadShaderOptions();
- std::string code = m_glsl_header + options_code + main_code;
-
- // and compile it
- if (!ProgramShaderCache::CompileShader(m_shader, s_vertex_shader, code))
- {
- ERROR_LOG(VIDEO, "Failed to compile post-processing shader %s", m_config.GetShader().c_str());
- Config::SetCurrent(Config::GFX_ENHANCE_POST_SHADER, "");
- code = m_config.LoadShader();
- ProgramShaderCache::CompileShader(m_shader, s_vertex_shader, code);
- }
-
- // read uniform locations
- m_uniform_resolution = glGetUniformLocation(m_shader.glprogid, "resolution");
- m_uniform_time = glGetUniformLocation(m_shader.glprogid, "time");
- m_uniform_src_rect = glGetUniformLocation(m_shader.glprogid, "src_rect");
- m_uniform_layer = glGetUniformLocation(m_shader.glprogid, "layer");
-
- for (const auto& it : m_config.GetOptions())
- {
- std::string glsl_name = "options." + it.first;
- m_uniform_bindings[it.first] = glGetUniformLocation(m_shader.glprogid, glsl_name.c_str());
- }
- m_initialized = true;
-}
-
-void OpenGLPostProcessing::CreateHeader()
-{
- m_glsl_header =
- // Required variables
- // Shouldn't be accessed directly by the PP shader
- // Texture sampler
- "SAMPLER_BINDING(8) uniform sampler2D samp8;\n"
- "SAMPLER_BINDING(9) uniform sampler2DArray samp9;\n"
-
- // Output variable
- "out float4 ocol0;\n"
- // Input coordinates
- "in float2 uv0;\n"
- // Resolution
- "uniform float4 resolution;\n"
- // Time
- "uniform uint time;\n"
- // Layer
- "uniform int layer;\n"
-
- // Interfacing functions
- "float4 Sample()\n"
- "{\n"
- "\treturn texture(samp9, float3(uv0, layer));\n"
- "}\n"
-
- "float4 SampleLocation(float2 location)\n"
- "{\n"
- "\treturn texture(samp9, float3(location, layer));\n"
- "}\n"
-
- "float4 SampleLayer(int layer)\n"
- "{\n"
- "\treturn texture(samp9, float3(uv0, layer));\n"
- "}\n"
-
- "#define SampleOffset(offset) textureOffset(samp9, float3(uv0, layer), offset)\n"
-
- "float2 GetResolution()\n"
- "{\n"
- "\treturn resolution.xy;\n"
- "}\n"
-
- "float2 GetInvResolution()\n"
- "{\n"
- "\treturn resolution.zw;\n"
- "}\n"
-
- "float2 GetCoordinates()\n"
- "{\n"
- "\treturn uv0;\n"
- "}\n"
-
- "uint GetTime()\n"
- "{\n"
- "\treturn time;\n"
- "}\n"
-
- "void SetOutput(float4 color)\n"
- "{\n"
- "\tocol0 = color;\n"
- "}\n"
-
- "#define GetOption(x) (options.x)\n"
- "#define OptionEnabled(x) (options.x != 0)\n";
-}
-
-std::string OpenGLPostProcessing::LoadShaderOptions()
-{
- m_uniform_bindings.clear();
- if (m_config.GetOptions().empty())
- return "";
-
- std::string glsl_options = "struct Options\n{\n";
-
- for (const auto& it : m_config.GetOptions())
- {
- if (it.second.m_type ==
- PostProcessingShaderConfiguration::ConfigurationOption::OptionType::OPTION_BOOL)
- {
- glsl_options += StringFromFormat("int %s;\n", it.first.c_str());
- }
- else if (it.second.m_type ==
- PostProcessingShaderConfiguration::ConfigurationOption::OptionType::OPTION_INTEGER)
- {
- u32 count = static_cast<u32>(it.second.m_integer_values.size());
- if (count == 1)
- glsl_options += StringFromFormat("int %s;\n", it.first.c_str());
- else
- glsl_options += StringFromFormat("int%d %s;\n", count, it.first.c_str());
- }
- else if (it.second.m_type ==
- PostProcessingShaderConfiguration::ConfigurationOption::OptionType::OPTION_FLOAT)
- {
- u32 count = static_cast<u32>(it.second.m_float_values.size());
- if (count == 1)
- glsl_options += StringFromFormat("float %s;\n", it.first.c_str());
- else
- glsl_options += StringFromFormat("float%d %s;\n", count, it.first.c_str());
- }
-
- m_uniform_bindings[it.first] = 0;
- }
-
- glsl_options += "};\n";
- glsl_options += "uniform Options options;\n";
-
- return glsl_options;
-}
-
-} // namespace OGL
diff --git a/Source/Core/VideoBackends/OGL/PostProcessing.h b/Source/Core/VideoBackends/OGL/PostProcessing.h
deleted file mode 100644
index 1c8c8ecf52..0000000000
--- a/Source/Core/VideoBackends/OGL/PostProcessing.h
+++ /dev/null
@@ -1,44 +0,0 @@
-// Copyright 2008 Dolphin Emulator Project
-// Licensed under GPLv2+
-// Refer to the license.txt file included.
-
-#pragma once
-
-#include <string>
-#include <unordered_map>
-
-#include "Common/GL/GLUtil.h"
-
-#include "VideoBackends/OGL/ProgramShaderCache.h"
-
-#include "VideoCommon/PostProcessing.h"
-#include "VideoCommon/VideoCommon.h"
-
-namespace OGL
-{
-class OpenGLPostProcessing : public PostProcessingShaderImplementation
-{
-public:
- OpenGLPostProcessing();
- ~OpenGLPostProcessing();
-
- void BlitFromTexture(TargetRectangle src, TargetRectangle dst, int src_texture, int src_width,
- int src_height, int layer);
- void ApplyShader();
-
-private:
- bool m_initialized;
- SHADER m_shader;
- GLuint m_uniform_resolution;
- GLuint m_uniform_src_rect;
- GLuint m_uniform_time;
- GLuint m_uniform_layer;
- std::string m_glsl_header;
-
- std::unordered_map<std::string, GLuint> m_uniform_bindings;
-
- void CreateHeader();
- std::string LoadShaderOptions();
-};
-
-} // namespace
diff --git a/Source/Core/VideoBackends/OGL/ProgramShaderCache.cpp b/Source/Core/VideoBackends/OGL/ProgramShaderCache.cpp
index c8d54acd5a..e06491b986 100644
--- a/Source/Core/VideoBackends/OGL/ProgramShaderCache.cpp
+++ b/Source/Core/VideoBackends/OGL/ProgramShaderCache.cpp
@@ -4,6 +4,7 @@
#include "VideoBackends/OGL/ProgramShaderCache.h"
+#include <atomic>
#include <limits>
#include <memory>
#include <string>
@@ -27,7 +28,6 @@
#include "VideoBackends/OGL/VertexManager.h"
#include "VideoCommon/AsyncShaderCompiler.h"
-#include "VideoCommon/Debugger.h"
#include "VideoCommon/DriverDetails.h"
#include "VideoCommon/GeometryShaderManager.h"
#include "VideoCommon/ImageWrite.h"
@@ -54,6 +54,7 @@ static GLuint CurrentProgram = 0;
ProgramShaderCache::PipelineProgramMap ProgramShaderCache::s_pipeline_programs;
std::mutex ProgramShaderCache::s_pipeline_program_lock;
static std::string s_glsl_header = "";
+static std::atomic<u64> s_shader_counter{0};
static thread_local bool s_is_shared_context = false;
static std::string GetGLSLVersionString()
@@ -109,13 +110,13 @@ void SHADER::SetProgramVariables()
glUniformBlockBinding(glprogid, UBERBlock_id, 4);
// Bind Texture Samplers
- for (int a = 0; a < 10; ++a)
+ for (int a = 0; a < 8; ++a)
{
- std::string name = StringFromFormat(a < 8 ? "samp[%d]" : "samp%d", a);
-
// Still need to get sampler locations since we aren't binding them statically in the shaders
- int loc = glGetUniformLocation(glprogid, name.c_str());
- if (loc != -1)
+ int loc = glGetUniformLocation(glprogid, StringFromFormat("samp[%d]", a).c_str());
+ if (loc < 0)
+ loc = glGetUniformLocation(glprogid, StringFromFormat("samp%d", a).c_str());
+ if (loc >= 0)
glUniform1i(loc, a);
}
@@ -191,21 +192,22 @@ bool PipelineProgramKey::operator!=(const PipelineProgramKey& rhs) const
bool PipelineProgramKey::operator==(const PipelineProgramKey& rhs) const
{
- return std::tie(vertex_shader, geometry_shader, pixel_shader) ==
- std::tie(rhs.vertex_shader, rhs.geometry_shader, rhs.pixel_shader);
+ return std::tie(vertex_shader_id, geometry_shader_id, pixel_shader_id) ==
+ std::tie(rhs.vertex_shader_id, rhs.geometry_shader_id, rhs.pixel_shader_id);
}
bool PipelineProgramKey::operator<(const PipelineProgramKey& rhs) const
{
- return std::tie(vertex_shader, geometry_shader, pixel_shader) <
- std::tie(rhs.vertex_shader, rhs.geometry_shader, rhs.pixel_shader);
+ return std::tie(vertex_shader_id, geometry_shader_id, pixel_shader_id) <
+ std::tie(rhs.vertex_shader_id, rhs.geometry_shader_id, rhs.pixel_shader_id);
}
std::size_t PipelineProgramKeyHash::operator()(const PipelineProgramKey& key) const
{
// We would really want std::hash_combine for this..
- std::hash<const void*> hasher;
- return hasher(key.vertex_shader) + hasher(key.geometry_shader) + hasher(key.pixel_shader);
+ std::hash<u64> hasher;
+ return hasher(key.vertex_shader_id) + hasher(key.geometry_shader_id) +
+ hasher(key.pixel_shader_id);
}
StreamBuffer* ProgramShaderCache::GetUniformBuffer()
@@ -218,13 +220,6 @@ u32 ProgramShaderCache::GetUniformBufferAlignment()
return s_ubo_align;
}
-void ProgramShaderCache::InvalidateConstants()
-{
- VertexShaderManager::dirty = true;
- GeometryShaderManager::dirty = true;
- PixelShaderManager::dirty = true;
-}
-
void ProgramShaderCache::UploadConstants()
{
if (PixelShaderManager::dirty || VertexShaderManager::dirty || GeometryShaderManager::dirty)
@@ -574,7 +569,9 @@ const PipelineProgram* ProgramShaderCache::GetPipelineProgram(const GLVertexForm
const OGLShader* geometry_shader,
const OGLShader* pixel_shader)
{
- PipelineProgramKey key = {vertex_shader, geometry_shader, pixel_shader};
+ PipelineProgramKey key = {vertex_shader ? vertex_shader->GetID() : 0,
+ geometry_shader ? geometry_shader->GetID() : 0,
+ pixel_shader ? pixel_shader->GetID() : 0};
{
std::lock_guard<std::mutex> guard(s_pipeline_program_lock);
auto iter = s_pipeline_programs.find(key);
@@ -750,6 +747,7 @@ void ProgramShaderCache::CreateHeader()
"%s\n"
// Silly differences
+ "#define API_OPENGL 1\n"
"#define float2 vec2\n"
"#define float3 vec3\n"
"#define float4 vec4\n"
@@ -759,8 +757,6 @@ void ProgramShaderCache::CreateHeader()
"#define int2 ivec2\n"
"#define int3 ivec3\n"
"#define int4 ivec4\n"
-
- // hlsl to glsl function translation
"#define frac fract\n"
"#define lerp mix\n"
@@ -782,12 +778,17 @@ void ProgramShaderCache::CreateHeader()
"#define FRAGMENT_OUTPUT_LOCATION_INDEXED(x, y)\n"
"#define UBO_BINDING(packing, x) layout(packing, binding = x)\n"
"#define SAMPLER_BINDING(x) layout(binding = x)\n"
- "#define SSBO_BINDING(x) layout(binding = x)\n" :
+ "#define TEXEL_BUFFER_BINDING(x) layout(binding = x)\n"
+ "#define SSBO_BINDING(x) layout(binding = x)\n"
+ "#define IMAGE_BINDING(format, x) layout(format, binding = x)\n" :
"#define ATTRIBUTE_LOCATION(x)\n"
"#define FRAGMENT_OUTPUT_LOCATION(x)\n"
"#define FRAGMENT_OUTPUT_LOCATION_INDEXED(x, y)\n"
"#define UBO_BINDING(packing, x) layout(packing)\n"
- "#define SAMPLER_BINDING(x)\n",
+ "#define SAMPLER_BINDING(x)\n"
+ "#define TEXEL_BUFFER_BINDING(x)\n"
+ "#define SSBO_BINDING(x)\n"
+ "#define IMAGE_BINDING(format, x) layout(format)\n",
// Input/output blocks are matched by name during program linking
"#define VARYING_LOCATION(x)\n",
!is_glsles && g_ActiveConfig.backend_info.bSupportsFragmentStoresAndAtomics ?
@@ -823,6 +824,11 @@ void ProgramShaderCache::CreateHeader()
v >= GlslEs310 ? "precision highp image2DArray;" : "");
}
+u64 ProgramShaderCache::GenerateShaderID()
+{
+ return s_shader_counter++;
+}
+
bool SharedContextAsyncShaderCompiler::WorkerThreadInitMainThread(void** param)
{
std::unique_ptr<GLContext> context =
diff --git a/Source/Core/VideoBackends/OGL/ProgramShaderCache.h b/Source/Core/VideoBackends/OGL/ProgramShaderCache.h
index b94e733167..7fc267dc5d 100644
--- a/Source/Core/VideoBackends/OGL/ProgramShaderCache.h
+++ b/Source/Core/VideoBackends/OGL/ProgramShaderCache.h
@@ -44,9 +44,9 @@ struct SHADER
struct PipelineProgramKey
{
- const OGLShader* vertex_shader;
- const OGLShader* geometry_shader;
- const OGLShader* pixel_shader;
+ u64 vertex_shader_id;
+ u64 geometry_shader_id;
+ u64 pixel_shader_id;
bool operator==(const PipelineProgramKey& rhs) const;
bool operator!=(const PipelineProgramKey& rhs) const;
@@ -82,7 +82,6 @@ public:
const std::string& gcode);
static StreamBuffer* GetUniformBuffer();
static u32 GetUniformBufferAlignment();
- static void InvalidateConstants();
static void UploadConstants();
static void UploadConstants(const void* data, u32 data_size);
@@ -90,6 +89,14 @@ public:
static void Shutdown();
static void CreateHeader();
+ // This counter increments with each shader object allocated, in order to give it a unique ID.
+ // Since the shaders can be destroyed after a pipeline is created, we can't use the shader pointer
+ // as a key for GL programs. For the same reason, we can't use the GL objects either. This ID is
+ // guaranteed to be unique for the emulation session, even if the memory allocator or GL driver
+ // re-uses pointers, therefore we won't have any collisions where the shaders attached to a
+ // pipeline do not match the pipeline configuration.
+ static u64 GenerateShaderID();
+
static const PipelineProgram* GetPipelineProgram(const GLVertexFormat* vertex_format,
const OGLShader* vertex_shader,
const OGLShader* geometry_shader,
diff --git a/Source/Core/VideoBackends/OGL/Render.cpp b/Source/Core/VideoBackends/OGL/Render.cpp
index b72941583e..baeb9f877c 100644
--- a/Source/Core/VideoBackends/OGL/Render.cpp
+++ b/Source/Core/VideoBackends/OGL/Render.cpp
@@ -27,22 +27,21 @@
#include "Core/Core.h"
#include "VideoBackends/OGL/BoundingBox.h"
-#include "VideoBackends/OGL/FramebufferManager.h"
#include "VideoBackends/OGL/OGLPipeline.h"
#include "VideoBackends/OGL/OGLShader.h"
#include "VideoBackends/OGL/OGLTexture.h"
-#include "VideoBackends/OGL/PostProcessing.h"
#include "VideoBackends/OGL/ProgramShaderCache.h"
#include "VideoBackends/OGL/SamplerCache.h"
#include "VideoBackends/OGL/StreamBuffer.h"
-#include "VideoBackends/OGL/TextureCache.h"
#include "VideoBackends/OGL/VertexManager.h"
#include "VideoCommon/BPFunctions.h"
#include "VideoCommon/DriverDetails.h"
+#include "VideoCommon/FramebufferManager.h"
#include "VideoCommon/IndexGenerator.h"
#include "VideoCommon/OnScreenDisplay.h"
#include "VideoCommon/PixelEngine.h"
+#include "VideoCommon/PostProcessing.h"
#include "VideoCommon/RenderState.h"
#include "VideoCommon/ShaderGenCommon.h"
#include "VideoCommon/VertexShaderManager.h"
@@ -54,22 +53,6 @@ namespace OGL
{
VideoConfig g_ogl_config;
-// Declarations and definitions
-// ----------------------------
-
-// 1 for no MSAA. Use s_MSAASamples > 1 to check for MSAA.
-static int s_MSAASamples = 1;
-
-// EFB cache related
-static const u32 EFB_CACHE_RECT_SIZE = 64; // Cache 64x64 blocks.
-static const u32 EFB_CACHE_WIDTH =
- (EFB_WIDTH + EFB_CACHE_RECT_SIZE - 1) / EFB_CACHE_RECT_SIZE; // round up
-static const u32 EFB_CACHE_HEIGHT = (EFB_HEIGHT + EFB_CACHE_RECT_SIZE - 1) / EFB_CACHE_RECT_SIZE;
-static bool s_efbCacheValid[2][EFB_CACHE_WIDTH * EFB_CACHE_HEIGHT];
-static bool s_efbCacheIsCleared = false;
-static std::vector<u32>
- s_efbCache[2][EFB_CACHE_WIDTH * EFB_CACHE_HEIGHT]; // 2 for PeekZ and PeekColor
-
static void APIENTRY ErrorCallback(GLenum source, GLenum type, GLuint id, GLenum severity,
GLsizei length, const char* message, const void* userParam)
{
@@ -356,6 +339,16 @@ Renderer::Renderer(std::unique_ptr<GLContext> main_gl_context, float backbuffer_
m_current_depth_state(RenderState::GetInvalidDepthState()),
m_current_blend_state(RenderState::GetInvalidBlendingState())
{
+ // Create the window framebuffer.
+ if (!m_main_gl_context->IsHeadless())
+ {
+ m_system_framebuffer = std::make_unique<OGLFramebuffer>(
+ nullptr, nullptr, AbstractTextureFormat::RGBA8, AbstractTextureFormat::Undefined,
+ std::max(m_main_gl_context->GetBackBufferWidth(), 1u),
+ std::max(m_main_gl_context->GetBackBufferHeight(), 1u), 1, 1, 0);
+ m_current_framebuffer = m_system_framebuffer.get();
+ }
+
bool bSuccess = true;
g_ogl_config.gl_vendor = (const char*)glGetString(GL_VENDOR);
@@ -437,9 +430,9 @@ Renderer::Renderer(std::unique_ptr<GLContext> main_gl_context, float backbuffer_
g_Config.backend_info.bSupportsPrimitiveRestart =
!DriverDetails::HasBug(DriverDetails::BUG_PRIMITIVE_RESTART) &&
((GLExtensions::Version() >= 310) || GLExtensions::Supports("GL_NV_primitive_restart"));
- g_Config.backend_info.bSupportsBBox = true;
g_Config.backend_info.bSupportsFragmentStoresAndAtomics =
GLExtensions::Supports("GL_ARB_shader_storage_buffer_object");
+ g_Config.backend_info.bSupportsBBox = g_Config.backend_info.bSupportsFragmentStoresAndAtomics;
g_Config.backend_info.bSupportsGSInstancing = GLExtensions::Supports("GL_ARB_gpu_shader5");
g_Config.backend_info.bSupportsSSAA = GLExtensions::Supports("GL_ARB_gpu_shader5") &&
GLExtensions::Supports("GL_ARB_sample_shading");
@@ -692,9 +685,13 @@ Renderer::Renderer(std::unique_ptr<GLContext> main_gl_context, float backbuffer_
glDebugMessageCallbackARB(ErrorCallback, nullptr);
}
if (LogManager::GetInstance()->IsEnabled(LogTypes::HOST_GPU, LogTypes::LERROR))
+ {
glEnable(GL_DEBUG_OUTPUT);
+ }
else
+ {
glDisable(GL_DEBUG_OUTPUT);
+ }
}
int samples;
@@ -753,23 +750,9 @@ Renderer::Renderer(std::unique_ptr<GLContext> main_gl_context, float backbuffer_
if (!DriverDetails::HasBug(DriverDetails::BUG_BROKEN_VSYNC))
m_main_gl_context->SwapInterval(g_ActiveConfig.bVSyncActive);
- // Because of the fixed framebuffer size we need to disable the resolution
- // options while running
-
- // The stencil is used for bounding box emulation when SSBOs are not available
- glDisable(GL_STENCIL_TEST);
- glStencilFunc(GL_ALWAYS, 1, 0xFF);
- glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
-
- // Reset The Current Viewport
- glViewport(0, 0, GetTargetWidth(), GetTargetHeight());
if (g_ActiveConfig.backend_info.bSupportsClipControl)
glClipControl(GL_LOWER_LEFT, GL_ZERO_TO_ONE);
- glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
- glClearDepthf(1.0f);
- glEnable(GL_DEPTH_TEST);
- glDepthFunc(GL_LEQUAL);
if (g_ActiveConfig.backend_info.bSupportsDepthClamp)
{
glEnable(GL_CLIP_DISTANCE0);
@@ -779,18 +762,14 @@ Renderer::Renderer(std::unique_ptr<GLContext> main_gl_context, float backbuffer_
glPixelStorei(GL_UNPACK_ALIGNMENT, 4); // 4-byte pixel alignment
- glEnable(GL_SCISSOR_TEST);
- glScissor(0, 0, GetTargetWidth(), GetTargetHeight());
- glBlendFunc(GL_ONE, GL_ONE);
- glBlendColor(0, 0, 0, 0.5f);
- glClearDepthf(1.0f);
+ glGenFramebuffers(1, &m_shared_read_framebuffer);
+ glGenFramebuffers(1, &m_shared_draw_framebuffer);
if (g_ActiveConfig.backend_info.bSupportsPrimitiveRestart)
GLUtil::EnablePrimitiveRestart(m_main_gl_context.get());
IndexGenerator::Init();
UpdateActiveConfig();
- ClearEFBCache();
}
Renderer::~Renderer() = default;
@@ -805,24 +784,15 @@ bool Renderer::Initialize()
if (!::Renderer::Initialize())
return false;
- // Initialize the FramebufferManager
- g_framebuffer_manager = std::make_unique<FramebufferManager>(
- m_target_width, m_target_height, s_MSAASamples, BoundingBox::NeedsStencilBuffer());
- m_current_framebuffer_width = m_target_width;
- m_current_framebuffer_height = m_target_height;
-
- m_post_processor = std::make_unique<OpenGLPostProcessing>();
return true;
}
void Renderer::Shutdown()
{
::Renderer::Shutdown();
- g_framebuffer_manager.reset();
-
- UpdateActiveConfig();
- m_post_processor.reset();
+ glDeleteFramebuffers(1, &m_shared_draw_framebuffer);
+ glDeleteFramebuffers(1, &m_shared_read_framebuffer);
}
std::unique_ptr<AbstractTexture> Renderer::CreateTexture(const TextureConfig& config)
@@ -836,12 +806,11 @@ std::unique_ptr<AbstractStagingTexture> Renderer::CreateStagingTexture(StagingTe
return OGLStagingTexture::Create(type, config);
}
-std::unique_ptr<AbstractFramebuffer>
-Renderer::CreateFramebuffer(const AbstractTexture* color_attachment,
- const AbstractTexture* depth_attachment)
+std::unique_ptr<AbstractFramebuffer> Renderer::CreateFramebuffer(AbstractTexture* color_attachment,
+ AbstractTexture* depth_attachment)
{
- return OGLFramebuffer::Create(static_cast<const OGLTexture*>(color_attachment),
- static_cast<const OGLTexture*>(depth_attachment));
+ return OGLFramebuffer::Create(static_cast<OGLTexture*>(color_attachment),
+ static_cast<OGLTexture*>(depth_attachment));
}
std::unique_ptr<AbstractShader> Renderer::CreateShaderFromSource(ShaderStage stage,
@@ -861,231 +830,9 @@ std::unique_ptr<AbstractPipeline> Renderer::CreatePipeline(const AbstractPipelin
return OGLPipeline::Create(config);
}
-TargetRectangle Renderer::ConvertEFBRectangle(const EFBRectangle& rc)
-{
- TargetRectangle result;
- result.left = EFBToScaledX(rc.left);
- result.top = EFBToScaledY(EFB_HEIGHT - rc.top);
- result.right = EFBToScaledX(rc.right);
- result.bottom = EFBToScaledY(EFB_HEIGHT - rc.bottom);
- return result;
-}
-
void Renderer::SetScissorRect(const MathUtil::Rectangle<int>& rc)
{
- glScissor(rc.left, rc.bottom, rc.GetWidth(), rc.GetHeight());
-}
-
-void ClearEFBCache()
-{
- if (!s_efbCacheIsCleared)
- {
- s_efbCacheIsCleared = true;
- memset(s_efbCacheValid, 0, sizeof(s_efbCacheValid));
- }
-}
-
-void Renderer::UpdateEFBCache(EFBAccessType type, u32 cacheRectIdx, const EFBRectangle& efbPixelRc,
- const TargetRectangle& targetPixelRc, const void* data)
-{
- const u32 cacheType = (type == EFBAccessType::PeekZ ? 0 : 1);
-
- if (s_efbCache[cacheType][cacheRectIdx].empty())
- s_efbCache[cacheType][cacheRectIdx].resize(EFB_CACHE_RECT_SIZE * EFB_CACHE_RECT_SIZE);
-
- u32 targetPixelRcWidth = targetPixelRc.right - targetPixelRc.left;
- u32 efbPixelRcHeight = efbPixelRc.bottom - efbPixelRc.top;
- u32 efbPixelRcWidth = efbPixelRc.right - efbPixelRc.left;
-
- for (u32 yCache = 0; yCache < efbPixelRcHeight; ++yCache)
- {
- u32 yEFB = efbPixelRc.top + yCache;
- u32 yPixel = (EFBToScaledY(EFB_HEIGHT - yEFB) + EFBToScaledY(EFB_HEIGHT - yEFB - 1)) / 2;
- u32 yData = yPixel - targetPixelRc.bottom;
-
- for (u32 xCache = 0; xCache < efbPixelRcWidth; ++xCache)
- {
- u32 xEFB = efbPixelRc.left + xCache;
- u32 xPixel = (EFBToScaledX(xEFB) + EFBToScaledX(xEFB + 1)) / 2;
- u32 xData = xPixel - targetPixelRc.left;
- u32 value;
- if (type == EFBAccessType::PeekZ)
- {
- float* ptr = (float*)data;
- value = MathUtil::Clamp<u32>((u32)(ptr[yData * targetPixelRcWidth + xData] * 16777216.0f),
- 0, 0xFFFFFF);
- }
- else
- {
- u32* ptr = (u32*)data;
- value = ptr[yData * targetPixelRcWidth + xData];
- }
- s_efbCache[cacheType][cacheRectIdx][yCache * EFB_CACHE_RECT_SIZE + xCache] = value;
- }
- }
-
- s_efbCacheValid[cacheType][cacheRectIdx] = true;
- s_efbCacheIsCleared = false;
-}
-
-// This function allows the CPU to directly access the EFB.
-// There are EFB peeks (which will read the color or depth of a pixel)
-// and EFB pokes (which will change the color or depth of a pixel).
-//
-// The behavior of EFB peeks can only be modified by:
-// - GX_PokeAlphaRead
-// The behavior of EFB pokes can be modified by:
-// - GX_PokeAlphaMode (TODO)
-// - GX_PokeAlphaUpdate (TODO)
-// - GX_PokeBlendMode (TODO)
-// - GX_PokeColorUpdate (TODO)
-// - GX_PokeDither (TODO)
-// - GX_PokeDstAlpha (TODO)
-// - GX_PokeZMode (TODO)
-u32 Renderer::AccessEFB(EFBAccessType type, u32 x, u32 y, u32 poke_data)
-{
- u32 cacheRectIdx = (y / EFB_CACHE_RECT_SIZE) * EFB_CACHE_WIDTH + (x / EFB_CACHE_RECT_SIZE);
-
- EFBRectangle efbPixelRc;
-
- if (type == EFBAccessType::PeekColor || type == EFBAccessType::PeekZ)
- {
- // Get the rectangular target region containing the EFB pixel
- efbPixelRc.left = (x / EFB_CACHE_RECT_SIZE) * EFB_CACHE_RECT_SIZE;
- efbPixelRc.top = (y / EFB_CACHE_RECT_SIZE) * EFB_CACHE_RECT_SIZE;
- efbPixelRc.right = std::min(efbPixelRc.left + EFB_CACHE_RECT_SIZE, (u32)EFB_WIDTH);
- efbPixelRc.bottom = std::min(efbPixelRc.top + EFB_CACHE_RECT_SIZE, (u32)EFB_HEIGHT);
- }
- else
- {
- efbPixelRc.left = x;
- efbPixelRc.top = y;
- efbPixelRc.right = x + 1;
- efbPixelRc.bottom = y + 1;
- }
-
- TargetRectangle targetPixelRc = ConvertEFBRectangle(efbPixelRc);
- u32 targetPixelRcWidth = targetPixelRc.right - targetPixelRc.left;
- u32 targetPixelRcHeight = targetPixelRc.top - targetPixelRc.bottom;
-
- // TODO (FIX) : currently, AA path is broken/offset and doesn't return the correct pixel
- switch (type)
- {
- case EFBAccessType::PeekZ:
- {
- if (!s_efbCacheValid[0][cacheRectIdx])
- {
- if (s_MSAASamples > 1)
- {
- ResetAPIState();
-
- // Resolve our rectangle.
- FramebufferManager::GetEFBDepthTexture(efbPixelRc);
- glBindFramebuffer(GL_READ_FRAMEBUFFER, FramebufferManager::GetResolvedFramebuffer());
- }
-
- std::unique_ptr<float[]> depthMap(new float[targetPixelRcWidth * targetPixelRcHeight]);
-
- glReadPixels(targetPixelRc.left, targetPixelRc.bottom, targetPixelRcWidth,
- targetPixelRcHeight, GL_DEPTH_COMPONENT, GL_FLOAT, depthMap.get());
-
- UpdateEFBCache(type, cacheRectIdx, efbPixelRc, targetPixelRc, depthMap.get());
-
- if (s_MSAASamples > 1)
- RestoreAPIState();
- }
-
- u32 xRect = x % EFB_CACHE_RECT_SIZE;
- u32 yRect = y % EFB_CACHE_RECT_SIZE;
- u32 z = s_efbCache[0][cacheRectIdx][yRect * EFB_CACHE_RECT_SIZE + xRect];
-
- // if Z is in 16 bit format you must return a 16 bit integer
- if (bpmem.zcontrol.pixel_format == PEControl::RGB565_Z16)
- z = z >> 8;
-
- return z;
- }
-
- case EFBAccessType::PeekColor: // GXPeekARGB
- {
- // Although it may sound strange, this really is A8R8G8B8 and not RGBA or 24-bit...
-
- // Tested in Killer 7, the first 8bits represent the alpha value which is used to
- // determine if we're aiming at an enemy (0x80 / 0x88) or not (0x70)
- // Wind Waker is also using it for the pictograph to determine the color of each pixel
- if (!s_efbCacheValid[1][cacheRectIdx])
- {
- if (s_MSAASamples > 1)
- {
- ResetAPIState();
-
- // Resolve our rectangle.
- FramebufferManager::GetEFBColorTexture(efbPixelRc);
- glBindFramebuffer(GL_READ_FRAMEBUFFER, FramebufferManager::GetResolvedFramebuffer());
- }
-
- std::unique_ptr<u32[]> colorMap(new u32[targetPixelRcWidth * targetPixelRcHeight]);
-
- if (IsGLES())
- // XXX: Swap colours
- glReadPixels(targetPixelRc.left, targetPixelRc.bottom, targetPixelRcWidth,
- targetPixelRcHeight, GL_RGBA, GL_UNSIGNED_BYTE, colorMap.get());
- else
- glReadPixels(targetPixelRc.left, targetPixelRc.bottom, targetPixelRcWidth,
- targetPixelRcHeight, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, colorMap.get());
-
- UpdateEFBCache(type, cacheRectIdx, efbPixelRc, targetPixelRc, colorMap.get());
-
- if (s_MSAASamples > 1)
- RestoreAPIState();
- }
-
- u32 xRect = x % EFB_CACHE_RECT_SIZE;
- u32 yRect = y % EFB_CACHE_RECT_SIZE;
- u32 color = s_efbCache[1][cacheRectIdx][yRect * EFB_CACHE_RECT_SIZE + xRect];
-
- // check what to do with the alpha channel (GX_PokeAlphaRead)
- PixelEngine::UPEAlphaReadReg alpha_read_mode = PixelEngine::GetAlphaReadMode();
-
- if (bpmem.zcontrol.pixel_format == PEControl::RGBA6_Z24)
- {
- color = RGBA8ToRGBA6ToRGBA8(color);
- }
- else if (bpmem.zcontrol.pixel_format == PEControl::RGB565_Z16)
- {
- color = RGBA8ToRGB565ToRGBA8(color);
- }
- if (bpmem.zcontrol.pixel_format != PEControl::RGBA6_Z24)
- {
- color |= 0xFF000000;
- }
- if (alpha_read_mode.ReadMode == 2)
- {
- // GX_READ_NONE
- return color;
- }
- else if (alpha_read_mode.ReadMode == 1)
- {
- // GX_READ_FF
- return (color | 0xFF000000);
- }
- else /*if(alpha_read_mode.ReadMode == 0)*/
- {
- // GX_READ_00
- return (color & 0x00FFFFFF);
- }
- }
-
- default:
- break;
- }
-
- return 0;
-}
-
-void Renderer::PokeEFB(EFBAccessType type, const EfbPokeData* points, size_t num_points)
-{
- FramebufferManager::PokeEFB(type, points, num_points);
+ glScissor(rc.left, rc.top, rc.GetWidth(), rc.GetHeight());
}
u16 Renderer::BBoxRead(int index)
@@ -1138,9 +885,6 @@ void Renderer::BBoxWrite(int index, u16 _value)
void Renderer::SetViewport(float x, float y, float width, float height, float near_depth,
float far_depth)
{
- // The x/y parameters here assume a upper-left origin. glViewport takes an offset from the
- // lower-left of the framebuffer, so we must set y to the distance from the lower-left.
- y = static_cast<float>(m_current_framebuffer_height) - y - height;
if (g_ogl_config.bSupportViewportFloat)
{
glViewportIndexedf(0, x, y, width, height);
@@ -1156,7 +900,7 @@ void Renderer::SetViewport(float x, float y, float width, float height, float ne
void Renderer::Draw(u32 base_vertex, u32 num_vertices)
{
- glDrawArrays(static_cast<const OGLPipeline*>(m_graphics_pipeline)->GetGLPrimitive(), base_vertex,
+ glDrawArrays(static_cast<const OGLPipeline*>(m_current_pipeline)->GetGLPrimitive(), base_vertex,
num_vertices);
}
@@ -1164,135 +908,112 @@ void Renderer::DrawIndexed(u32 base_index, u32 num_indices, u32 base_vertex)
{
if (g_ogl_config.bSupportsGLBaseVertex)
{
- glDrawElementsBaseVertex(static_cast<const OGLPipeline*>(m_graphics_pipeline)->GetGLPrimitive(),
+ glDrawElementsBaseVertex(static_cast<const OGLPipeline*>(m_current_pipeline)->GetGLPrimitive(),
num_indices, GL_UNSIGNED_SHORT,
static_cast<u16*>(nullptr) + base_index, base_vertex);
}
else
{
- glDrawElements(static_cast<const OGLPipeline*>(m_graphics_pipeline)->GetGLPrimitive(),
+ glDrawElements(static_cast<const OGLPipeline*>(m_current_pipeline)->GetGLPrimitive(),
num_indices, GL_UNSIGNED_SHORT, static_cast<u16*>(nullptr) + base_index);
}
}
-void Renderer::ClearScreen(const EFBRectangle& rc, bool colorEnable, bool alphaEnable, bool zEnable,
- u32 color, u32 z)
+void Renderer::DispatchComputeShader(const AbstractShader* shader, u32 groups_x, u32 groups_y,
+ u32 groups_z)
{
- ResetAPIState();
+ glUseProgram(static_cast<const OGLShader*>(shader)->GetGLComputeProgramID());
+ glDispatchCompute(groups_x, groups_y, groups_z);
- // color
- GLboolean const color_mask = colorEnable ? GL_TRUE : GL_FALSE,
- alpha_mask = alphaEnable ? GL_TRUE : GL_FALSE;
- glColorMask(color_mask, color_mask, color_mask, alpha_mask);
+ // We messed up the program binding, so restore it.
+ ProgramShaderCache::InvalidateLastProgram();
+ if (m_current_pipeline)
+ static_cast<const OGLPipeline*>(m_current_pipeline)->GetProgram()->shader.Bind();
- glClearColor(float((color >> 16) & 0xFF) / 255.0f, float((color >> 8) & 0xFF) / 255.0f,
- float((color >> 0) & 0xFF) / 255.0f, float((color >> 24) & 0xFF) / 255.0f);
+ // Barrier to texture can be used for reads.
+ if (m_bound_image_texture)
+ glMemoryBarrier(GL_TEXTURE_UPDATE_BARRIER_BIT);
+}
- // depth
- glDepthMask(zEnable ? GL_TRUE : GL_FALSE);
+void Renderer::ClearScreen(const EFBRectangle& rc, bool colorEnable, bool alphaEnable, bool zEnable,
+ u32 color, u32 z)
+{
+ g_framebuffer_manager->FlushEFBPokes();
+ g_framebuffer_manager->InvalidatePeekCache();
- glClearDepthf(float(z & 0xFFFFFF) / 16777216.0f);
+ u32 clear_mask = 0;
+ if (colorEnable || alphaEnable)
+ {
+ glColorMask(colorEnable, colorEnable, colorEnable, alphaEnable);
+ glClearColor(float((color >> 16) & 0xFF) / 255.0f, float((color >> 8) & 0xFF) / 255.0f,
+ float((color >> 0) & 0xFF) / 255.0f, float((color >> 24) & 0xFF) / 255.0f);
+ clear_mask = GL_COLOR_BUFFER_BIT;
+ }
+ if (zEnable)
+ {
+ glDepthMask(zEnable ? GL_TRUE : GL_FALSE);
+ glClearDepthf(float(z & 0xFFFFFF) / 16777216.0f);
+ clear_mask |= GL_DEPTH_BUFFER_BIT;
+ }
// Update rect for clearing the picture
- glEnable(GL_SCISSOR_TEST);
-
- TargetRectangle const targetRc = ConvertEFBRectangle(rc);
- glScissor(targetRc.left, targetRc.bottom, targetRc.GetWidth(), targetRc.GetHeight());
-
// glColorMask/glDepthMask/glScissor affect glClear (glViewport does not)
- glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+ const auto converted_target_rc =
+ ConvertFramebufferRectangle(ConvertEFBRectangle(rc), m_current_framebuffer);
+ SetScissorRect(converted_target_rc);
- RestoreAPIState();
+ glClear(clear_mask);
- ClearEFBCache();
+ // Restore color/depth mask.
+ if (colorEnable || alphaEnable)
+ {
+ glColorMask(m_current_blend_state.colorupdate, m_current_blend_state.colorupdate,
+ m_current_blend_state.colorupdate, m_current_blend_state.alphaupdate);
+ }
+ if (zEnable)
+ glDepthMask(m_current_depth_state.updateenable);
+
+ // Scissor rect must be restored.
+ BPFunctions::SetScissor();
}
void Renderer::RenderXFBToScreen(const AbstractTexture* texture, const EFBRectangle& rc)
{
- TargetRectangle source_rc = rc;
- source_rc.top = rc.GetHeight();
- source_rc.bottom = 0;
-
- // Check if we need to render to a new surface.
- TargetRectangle flipped_trc = GetTargetRectangle();
- std::swap(flipped_trc.top, flipped_trc.bottom);
-
- // Copy the framebuffer to screen.
- OpenGLPostProcessing* post_processor = static_cast<OpenGLPostProcessing*>(m_post_processor.get());
- if (g_ActiveConfig.stereo_mode == StereoMode::SBS ||
- g_ActiveConfig.stereo_mode == StereoMode::TAB)
- {
- TargetRectangle left_rc, right_rc;
+ // Quad-buffered stereo is annoying on GL.
+ if (g_ActiveConfig.stereo_mode != StereoMode::QuadBuffer)
+ return ::Renderer::RenderXFBToScreen(texture, rc);
- // Top-and-Bottom mode needs to compensate for inverted vertical screen coordinates.
- if (g_ActiveConfig.stereo_mode == StereoMode::TAB)
- std::tie(right_rc, left_rc) = ConvertStereoRectangle(flipped_trc);
- else
- std::tie(left_rc, right_rc) = ConvertStereoRectangle(flipped_trc);
-
- post_processor->BlitFromTexture(source_rc, left_rc,
- static_cast<const OGLTexture*>(texture)->GetRawTexIdentifier(),
- texture->GetWidth(), texture->GetHeight(), 0);
- post_processor->BlitFromTexture(source_rc, right_rc,
- static_cast<const OGLTexture*>(texture)->GetRawTexIdentifier(),
- texture->GetWidth(), texture->GetHeight(), 1);
- }
- else if (g_ActiveConfig.stereo_mode == StereoMode::QuadBuffer)
- {
- glDrawBuffer(GL_BACK_LEFT);
- post_processor->BlitFromTexture(source_rc, flipped_trc,
- static_cast<const OGLTexture*>(texture)->GetRawTexIdentifier(),
- texture->GetWidth(), texture->GetHeight(), 0);
+ const auto target_rc = GetTargetRectangle();
- glDrawBuffer(GL_BACK_RIGHT);
- post_processor->BlitFromTexture(source_rc, flipped_trc,
- static_cast<const OGLTexture*>(texture)->GetRawTexIdentifier(),
- texture->GetWidth(), texture->GetHeight(), 1);
+ glDrawBuffer(GL_BACK_LEFT);
+ m_post_processor->BlitFromTexture(target_rc, rc, texture, 0);
- glDrawBuffer(GL_BACK);
- }
- else
- {
- post_processor->BlitFromTexture(source_rc, flipped_trc,
- static_cast<const OGLTexture*>(texture)->GetRawTexIdentifier(),
- texture->GetWidth(), texture->GetHeight(), 0);
- }
-}
+ glDrawBuffer(GL_BACK_RIGHT);
+ m_post_processor->BlitFromTexture(target_rc, rc, texture, 1);
-void Renderer::ReinterpretPixelData(unsigned int convtype)
-{
- if (convtype == 0 || convtype == 2)
- {
- FramebufferManager::ReinterpretPixelData(convtype);
- }
- else
- {
- ERROR_LOG(VIDEO, "Trying to reinterpret pixel data with unsupported conversion type %d",
- convtype);
- }
+ glDrawBuffer(GL_BACK);
}
-void Renderer::SetFramebuffer(const AbstractFramebuffer* framebuffer)
+void Renderer::SetFramebuffer(AbstractFramebuffer* framebuffer)
{
- glBindFramebuffer(GL_FRAMEBUFFER, static_cast<const OGLFramebuffer*>(framebuffer)->GetFBO());
+ if (m_current_framebuffer == framebuffer)
+ return;
+
+ glBindFramebuffer(GL_FRAMEBUFFER, static_cast<OGLFramebuffer*>(framebuffer)->GetFBO());
m_current_framebuffer = framebuffer;
- m_current_framebuffer_width = framebuffer->GetWidth();
- m_current_framebuffer_height = framebuffer->GetHeight();
}
-void Renderer::SetAndDiscardFramebuffer(const AbstractFramebuffer* framebuffer)
+void Renderer::SetAndDiscardFramebuffer(AbstractFramebuffer* framebuffer)
{
// EXT_discard_framebuffer could be used here to save bandwidth on tilers.
SetFramebuffer(framebuffer);
}
-void Renderer::SetAndClearFramebuffer(const AbstractFramebuffer* framebuffer,
+void Renderer::SetAndClearFramebuffer(AbstractFramebuffer* framebuffer,
const ClearColor& color_value, float depth_value)
{
SetFramebuffer(framebuffer);
- // NOTE: This disturbs the current scissor/mask setting.
- // This won't be an issue when we implement proper state tracking.
glDisable(GL_SCISSOR_TEST);
GLbitfield clear_mask = 0;
if (framebuffer->HasColorBuffer())
@@ -1304,103 +1025,27 @@ void Renderer::SetAndClearFramebuffer(const AbstractFramebuffer* framebuffer,
if (framebuffer->HasDepthBuffer())
{
glDepthMask(GL_TRUE);
- glClearDepth(depth_value);
+ glClearDepthf(depth_value);
clear_mask |= GL_DEPTH_BUFFER_BIT;
}
glClear(clear_mask);
-}
-
-void Renderer::ApplyBlendingState(const BlendingState state, bool force)
-{
- if (!force && m_current_blend_state == state)
- return;
-
- bool useDualSource =
- state.usedualsrc && g_ActiveConfig.backend_info.bSupportsDualSourceBlend &&
- (!DriverDetails::HasBug(DriverDetails::BUG_BROKEN_DUAL_SOURCE_BLENDING) || state.dstalpha);
- // Only use shader blend if we need to and we don't support dual-source blending directly
- bool useShaderBlend = !useDualSource && state.usedualsrc && state.dstalpha &&
- g_ActiveConfig.backend_info.bSupportsFramebufferFetch;
-
- if (useShaderBlend)
- {
- glDisable(GL_BLEND);
- }
- else
- {
- const GLenum src_factors[8] = {GL_ZERO,
- GL_ONE,
- GL_DST_COLOR,
- GL_ONE_MINUS_DST_COLOR,
- useDualSource ? GL_SRC1_ALPHA : (GLenum)GL_SRC_ALPHA,
- useDualSource ? GL_ONE_MINUS_SRC1_ALPHA :
- (GLenum)GL_ONE_MINUS_SRC_ALPHA,
- GL_DST_ALPHA,
- GL_ONE_MINUS_DST_ALPHA};
- const GLenum dst_factors[8] = {GL_ZERO,
- GL_ONE,
- GL_SRC_COLOR,
- GL_ONE_MINUS_SRC_COLOR,
- useDualSource ? GL_SRC1_ALPHA : (GLenum)GL_SRC_ALPHA,
- useDualSource ? GL_ONE_MINUS_SRC1_ALPHA :
- (GLenum)GL_ONE_MINUS_SRC_ALPHA,
- GL_DST_ALPHA,
- GL_ONE_MINUS_DST_ALPHA};
-
- if (state.blendenable)
- {
- glEnable(GL_BLEND);
- }
- else
- {
- glDisable(GL_BLEND);
- }
-
- // Always call glBlendEquationSeparate and glBlendFuncSeparate, even when
- // GL_BLEND is disabled, as a workaround for some bugs (possibly graphics
- // driver issues?). See https://bugs.dolphin-emu.org/issues/10120 : "Sonic
- // Adventure 2 Battle: graphics crash when loading first Dark level"
- GLenum equation = state.subtract ? GL_FUNC_REVERSE_SUBTRACT : GL_FUNC_ADD;
- GLenum equationAlpha = state.subtractAlpha ? GL_FUNC_REVERSE_SUBTRACT : GL_FUNC_ADD;
- glBlendEquationSeparate(equation, equationAlpha);
- glBlendFuncSeparate(src_factors[state.srcfactor], dst_factors[state.dstfactor],
- src_factors[state.srcfactoralpha], dst_factors[state.dstfactoralpha]);
- }
-
- const GLenum logic_op_codes[16] = {
- GL_CLEAR, GL_AND, GL_AND_REVERSE, GL_COPY, GL_AND_INVERTED, GL_NOOP,
- GL_XOR, GL_OR, GL_NOR, GL_EQUIV, GL_INVERT, GL_OR_REVERSE,
- GL_COPY_INVERTED, GL_OR_INVERTED, GL_NAND, GL_SET};
+ glEnable(GL_SCISSOR_TEST);
- if (IsGLES())
- {
- // Logic ops aren't available in GLES3
- }
- else if (state.logicopenable)
- {
- glEnable(GL_COLOR_LOGIC_OP);
- glLogicOp(logic_op_codes[state.logicmode]);
- }
- else
+ // Restore color/depth mask.
+ if (framebuffer->HasColorBuffer())
{
- glDisable(GL_COLOR_LOGIC_OP);
+ glColorMask(m_current_blend_state.colorupdate, m_current_blend_state.colorupdate,
+ m_current_blend_state.colorupdate, m_current_blend_state.alphaupdate);
}
-
- glColorMask(state.colorupdate, state.colorupdate, state.colorupdate, state.alphaupdate);
- m_current_blend_state = state;
+ if (framebuffer->HasDepthBuffer())
+ glDepthMask(m_current_depth_state.updateenable);
}
void Renderer::BindBackbuffer(const ClearColor& clear_color)
{
CheckForSurfaceChange();
CheckForSurfaceResize();
-
- glBindFramebuffer(GL_FRAMEBUFFER, 0);
- glClearColor(0, 0, 0, 0);
- glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
- m_current_framebuffer = nullptr;
- m_current_framebuffer_width = m_backbuffer_width;
- m_current_framebuffer_height = m_backbuffer_height;
+ SetAndClearFramebuffer(m_system_framebuffer.get(), clear_color);
}
void Renderer::PresentBackbuffer()
@@ -1419,25 +1064,6 @@ void Renderer::PresentBackbuffer()
void Renderer::OnConfigChanged(u32 bits)
{
- if (bits & (CONFIG_CHANGE_BIT_TARGET_SIZE | CONFIG_CHANGE_BIT_MULTISAMPLES |
- CONFIG_CHANGE_BIT_STEREO_MODE | CONFIG_CHANGE_BIT_BBOX))
- {
- s_MSAASamples = g_ActiveConfig.iMultisamples;
- 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_MSAASamples, g_ogl_config.max_samples),
- 10000);
- }
-
- g_framebuffer_manager.reset();
- g_framebuffer_manager = std::make_unique<FramebufferManager>(
- m_target_width, m_target_height, s_MSAASamples, BoundingBox::NeedsStencilBuffer());
- BoundingBox::SetTargetSizeChanged(m_target_width, m_target_height);
- }
-
if (bits & CONFIG_CHANGE_BIT_VSYNC && !DriverDetails::HasBug(DriverDetails::BUG_BROKEN_VSYNC))
m_main_gl_context->SwapInterval(g_ActiveConfig.bVSyncActive);
@@ -1448,10 +1074,15 @@ void Renderer::OnConfigChanged(u32 bits)
void Renderer::Flush()
{
// ensure all commands are sent to the GPU.
- // Otherwise the driver could batch several frames togehter.
+ // Otherwise the driver could batch several frames together.
glFlush();
}
+void Renderer::WaitForGPUIdle()
+{
+ glFinish();
+}
+
void Renderer::CheckForSurfaceChange()
{
if (!m_surface_changed.TestAndClear())
@@ -1463,6 +1094,7 @@ void Renderer::CheckForSurfaceChange()
// With a surface change, the window likely has new dimensions.
m_backbuffer_width = m_main_gl_context->GetBackBufferWidth();
m_backbuffer_height = m_main_gl_context->GetBackBufferHeight();
+ m_system_framebuffer->UpdateDimensions(m_backbuffer_width, m_backbuffer_height);
}
void Renderer::CheckForSurfaceResize()
@@ -1473,52 +1105,36 @@ void Renderer::CheckForSurfaceResize()
m_main_gl_context->Update();
m_backbuffer_width = m_main_gl_context->GetBackBufferWidth();
m_backbuffer_height = m_main_gl_context->GetBackBufferHeight();
+ m_system_framebuffer->UpdateDimensions(m_backbuffer_width, m_backbuffer_height);
}
-// ALWAYS call RestoreAPIState for each ResetAPIState call you're doing
-void Renderer::ResetAPIState()
+void Renderer::BeginUtilityDrawing()
{
- // Gets us to a reasonably sane state where it's possible to do things like
- // image copies with textured quads, etc.
- glDisable(GL_SCISSOR_TEST);
- glDisable(GL_DEPTH_TEST);
- glDisable(GL_CULL_FACE);
- glDisable(GL_BLEND);
- if (!IsGLES())
- glDisable(GL_COLOR_LOGIC_OP);
+ ::Renderer::BeginUtilityDrawing();
+
+ glEnable(GL_PROGRAM_POINT_SIZE);
if (g_ActiveConfig.backend_info.bSupportsDepthClamp)
{
glDisable(GL_CLIP_DISTANCE0);
glDisable(GL_CLIP_DISTANCE1);
}
- glDepthMask(GL_FALSE);
- glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
- m_current_rasterization_state = RenderState::GetInvalidRasterizationState();
- m_current_depth_state = RenderState::GetInvalidDepthState();
- m_current_blend_state = RenderState::GetInvalidBlendingState();
}
-void Renderer::RestoreAPIState()
+void Renderer::EndUtilityDrawing()
{
- m_current_framebuffer = nullptr;
- m_current_framebuffer_width = m_target_width;
- m_current_framebuffer_height = m_target_height;
- FramebufferManager::SetFramebuffer(0);
+ ::Renderer::EndUtilityDrawing();
- // Gets us back into a more game-like state.
- glEnable(GL_SCISSOR_TEST);
+ glDisable(GL_PROGRAM_POINT_SIZE);
if (g_ActiveConfig.backend_info.bSupportsDepthClamp)
{
glEnable(GL_CLIP_DISTANCE0);
glEnable(GL_CLIP_DISTANCE1);
}
- BPFunctions::SetScissor();
- BPFunctions::SetViewport();
}
-void Renderer::ApplyRasterizationState(const RasterizationState state, bool force)
+void Renderer::ApplyRasterizationState(const RasterizationState state)
{
- if (!force && m_current_rasterization_state == state)
+ if (m_current_rasterization_state == state)
return;
// none, ccw, cw, ccw
@@ -1536,9 +1152,9 @@ void Renderer::ApplyRasterizationState(const RasterizationState state, bool forc
m_current_rasterization_state = state;
}
-void Renderer::ApplyDepthState(const DepthState state, bool force)
+void Renderer::ApplyDepthState(const DepthState state)
{
- if (!force && m_current_depth_state == state)
+ if (m_current_depth_state == state)
return;
const GLenum glCmpFuncs[8] = {GL_NEVER, GL_LESS, GL_EQUAL, GL_LEQUAL,
@@ -1562,30 +1178,116 @@ void Renderer::ApplyDepthState(const DepthState state, bool force)
m_current_depth_state = state;
}
+void Renderer::ApplyBlendingState(const BlendingState state)
+{
+ if (m_current_blend_state == state)
+ return;
+
+ bool useDualSource =
+ state.usedualsrc && g_ActiveConfig.backend_info.bSupportsDualSourceBlend &&
+ (!DriverDetails::HasBug(DriverDetails::BUG_BROKEN_DUAL_SOURCE_BLENDING) || state.dstalpha);
+ // Only use shader blend if we need to and we don't support dual-source blending directly
+ bool useShaderBlend = !useDualSource && state.usedualsrc && state.dstalpha &&
+ g_ActiveConfig.backend_info.bSupportsFramebufferFetch;
+
+ if (useShaderBlend)
+ {
+ glDisable(GL_BLEND);
+ }
+ else
+ {
+ const GLenum src_factors[8] = {GL_ZERO,
+ GL_ONE,
+ GL_DST_COLOR,
+ GL_ONE_MINUS_DST_COLOR,
+ useDualSource ? GL_SRC1_ALPHA : (GLenum)GL_SRC_ALPHA,
+ useDualSource ? GL_ONE_MINUS_SRC1_ALPHA :
+ (GLenum)GL_ONE_MINUS_SRC_ALPHA,
+ GL_DST_ALPHA,
+ GL_ONE_MINUS_DST_ALPHA};
+ const GLenum dst_factors[8] = {GL_ZERO,
+ GL_ONE,
+ GL_SRC_COLOR,
+ GL_ONE_MINUS_SRC_COLOR,
+ useDualSource ? GL_SRC1_ALPHA : (GLenum)GL_SRC_ALPHA,
+ useDualSource ? GL_ONE_MINUS_SRC1_ALPHA :
+ (GLenum)GL_ONE_MINUS_SRC_ALPHA,
+ GL_DST_ALPHA,
+ GL_ONE_MINUS_DST_ALPHA};
+
+ if (state.blendenable)
+ glEnable(GL_BLEND);
+ else
+ glDisable(GL_BLEND);
+
+ // Always call glBlendEquationSeparate and glBlendFuncSeparate, even when
+ // GL_BLEND is disabled, as a workaround for some bugs (possibly graphics
+ // driver issues?). See https://bugs.dolphin-emu.org/issues/10120 : "Sonic
+ // Adventure 2 Battle: graphics crash when loading first Dark level"
+ GLenum equation = state.subtract ? GL_FUNC_REVERSE_SUBTRACT : GL_FUNC_ADD;
+ GLenum equationAlpha = state.subtractAlpha ? GL_FUNC_REVERSE_SUBTRACT : GL_FUNC_ADD;
+ glBlendEquationSeparate(equation, equationAlpha);
+ glBlendFuncSeparate(src_factors[state.srcfactor], dst_factors[state.dstfactor],
+ src_factors[state.srcfactoralpha], dst_factors[state.dstfactoralpha]);
+ }
+
+ const GLenum logic_op_codes[16] = {
+ GL_CLEAR, GL_AND, GL_AND_REVERSE, GL_COPY, GL_AND_INVERTED, GL_NOOP,
+ GL_XOR, GL_OR, GL_NOR, GL_EQUIV, GL_INVERT, GL_OR_REVERSE,
+ GL_COPY_INVERTED, GL_OR_INVERTED, GL_NAND, GL_SET};
+
+ // Logic ops aren't available in GLES3
+ if (!IsGLES())
+ {
+ if (state.logicopenable)
+ {
+ glEnable(GL_COLOR_LOGIC_OP);
+ glLogicOp(logic_op_codes[state.logicmode]);
+ }
+ else
+ {
+ glDisable(GL_COLOR_LOGIC_OP);
+ }
+ }
+
+ glColorMask(state.colorupdate, state.colorupdate, state.colorupdate, state.alphaupdate);
+ m_current_blend_state = state;
+}
+
void Renderer::SetPipeline(const AbstractPipeline* pipeline)
{
- // Not all shader changes currently go through SetPipeline, so we can't
- // test if the pipeline hasn't changed and skip these applications. Yet.
- m_graphics_pipeline = static_cast<const OGLPipeline*>(pipeline);
- if (!m_graphics_pipeline)
+ if (m_current_pipeline == pipeline)
return;
- ApplyRasterizationState(m_graphics_pipeline->GetRasterizationState());
- ApplyDepthState(m_graphics_pipeline->GetDepthState());
- ApplyBlendingState(m_graphics_pipeline->GetBlendingState());
- ProgramShaderCache::BindVertexFormat(m_graphics_pipeline->GetVertexFormat());
- m_graphics_pipeline->GetProgram()->shader.Bind();
+ if (pipeline)
+ {
+ ApplyRasterizationState(static_cast<const OGLPipeline*>(pipeline)->GetRasterizationState());
+ ApplyDepthState(static_cast<const OGLPipeline*>(pipeline)->GetDepthState());
+ ApplyBlendingState(static_cast<const OGLPipeline*>(pipeline)->GetBlendingState());
+ ProgramShaderCache::BindVertexFormat(
+ static_cast<const OGLPipeline*>(pipeline)->GetVertexFormat());
+ static_cast<const OGLPipeline*>(pipeline)->GetProgram()->shader.Bind();
+ }
+ else
+ {
+ ProgramShaderCache::InvalidateLastProgram();
+ glUseProgram(0);
+ }
+ m_current_pipeline = pipeline;
}
void Renderer::SetTexture(u32 index, const AbstractTexture* texture)
{
- if (m_bound_textures[index] == texture)
+ const OGLTexture* gl_texture = static_cast<const OGLTexture*>(texture);
+ if (m_bound_textures[index] == gl_texture)
return;
glActiveTexture(GL_TEXTURE0 + index);
- glBindTexture(GL_TEXTURE_2D_ARRAY,
- texture ? static_cast<const OGLTexture*>(texture)->GetRawTexIdentifier() : 0);
- m_bound_textures[index] = texture;
+ if (gl_texture)
+ glBindTexture(gl_texture->GetGLTarget(), gl_texture->GetGLTextureId());
+ else
+ glBindTexture(GL_TEXTURE_2D_ARRAY, 0);
+ m_bound_textures[index] = gl_texture;
}
void Renderer::SetSamplerState(u32 index, const SamplerState& state)
@@ -1593,6 +1295,25 @@ void Renderer::SetSamplerState(u32 index, const SamplerState& state)
g_sampler_cache->SetSamplerState(index, state);
}
+void Renderer::SetComputeImageTexture(AbstractTexture* texture, bool read, bool write)
+{
+ if (m_bound_image_texture == texture)
+ return;
+
+ if (texture)
+ {
+ const GLenum access = read ? (write ? GL_READ_WRITE : GL_READ_ONLY) : GL_WRITE_ONLY;
+ glBindImageTexture(0, static_cast<OGLTexture*>(texture)->GetGLTextureId(), 0, GL_TRUE, 0,
+ access, static_cast<OGLTexture*>(texture)->GetGLFormatForImageTexture());
+ }
+ else
+ {
+ glBindImageTexture(0, 0, 0, GL_FALSE, 0, GL_READ_ONLY, GL_RGBA8);
+ }
+
+ m_bound_image_texture = texture;
+}
+
void Renderer::UnbindTexture(const AbstractTexture* texture)
{
for (size_t i = 0; i < m_bound_textures.size(); i++)
@@ -1604,15 +1325,34 @@ void Renderer::UnbindTexture(const AbstractTexture* texture)
glBindTexture(GL_TEXTURE_2D_ARRAY, 0);
m_bound_textures[i] = nullptr;
}
-}
-void Renderer::SetInterlacingMode()
-{
- // TODO
+ if (m_bound_image_texture == texture)
+ {
+ glBindImageTexture(0, 0, 0, GL_FALSE, 0, GL_READ_ONLY, GL_RGBA8);
+ m_bound_image_texture = nullptr;
+ }
}
std::unique_ptr<VideoCommon::AsyncShaderCompiler> Renderer::CreateAsyncShaderCompiler()
{
return std::make_unique<SharedContextAsyncShaderCompiler>();
}
+
+void Renderer::BindSharedReadFramebuffer()
+{
+ glBindFramebuffer(GL_READ_FRAMEBUFFER, m_shared_read_framebuffer);
+}
+
+void Renderer::BindSharedDrawFramebuffer()
+{
+ glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_shared_draw_framebuffer);
+}
+
+void Renderer::RestoreFramebufferBinding()
+{
+ glBindFramebuffer(
+ GL_FRAMEBUFFER,
+ m_current_framebuffer ? static_cast<OGLFramebuffer*>(m_current_framebuffer)->GetFBO() : 0);
+}
+
} // namespace OGL
diff --git a/Source/Core/VideoBackends/OGL/Render.h b/Source/Core/VideoBackends/OGL/Render.h
index 398a49377d..442a31d5c0 100644
--- a/Source/Core/VideoBackends/OGL/Render.h
+++ b/Source/Core/VideoBackends/OGL/Render.h
@@ -11,12 +11,11 @@
#include "Common/GL/GLExtensions/GLExtensions.h"
#include "VideoCommon/RenderBase.h"
-struct XFBSourceBase;
-
namespace OGL
{
+class OGLFramebuffer;
class OGLPipeline;
-void ClearEFBCache();
+class OGLTexture;
enum GlslVersion
{
@@ -86,6 +85,8 @@ public:
Renderer(std::unique_ptr<GLContext> main_gl_context, float backbuffer_scale);
~Renderer() override;
+ static Renderer* GetInstance() { return static_cast<Renderer*>(g_renderer.get()); }
+
bool IsHeadless() const override;
bool Initialize() override;
@@ -98,73 +99,80 @@ public:
size_t length) override;
std::unique_ptr<AbstractShader> CreateShaderFromBinary(ShaderStage stage, const void* data,
size_t length) override;
+ std::unique_ptr<NativeVertexFormat>
+ CreateNativeVertexFormat(const PortableVertexDeclaration& vtx_decl) override;
std::unique_ptr<AbstractPipeline> CreatePipeline(const AbstractPipelineConfig& config) override;
std::unique_ptr<AbstractFramebuffer>
- CreateFramebuffer(const AbstractTexture* color_attachment,
- const AbstractTexture* depth_attachment) override;
+ CreateFramebuffer(AbstractTexture* color_attachment, AbstractTexture* depth_attachment) override;
void SetPipeline(const AbstractPipeline* pipeline) override;
- void SetFramebuffer(const AbstractFramebuffer* framebuffer) override;
- void SetAndDiscardFramebuffer(const AbstractFramebuffer* framebuffer) override;
- void SetAndClearFramebuffer(const AbstractFramebuffer* framebuffer,
- const ClearColor& color_value = {},
+ void SetFramebuffer(AbstractFramebuffer* framebuffer) override;
+ void SetAndDiscardFramebuffer(AbstractFramebuffer* framebuffer) override;
+ void SetAndClearFramebuffer(AbstractFramebuffer* framebuffer, const ClearColor& color_value = {},
float depth_value = 0.0f) override;
void SetScissorRect(const MathUtil::Rectangle<int>& rc) override;
void SetTexture(u32 index, const AbstractTexture* texture) override;
void SetSamplerState(u32 index, const SamplerState& state) override;
+ void SetComputeImageTexture(AbstractTexture* texture, bool read, bool write) override;
void UnbindTexture(const AbstractTexture* texture) override;
- void SetInterlacingMode() override;
void SetViewport(float x, float y, float width, float height, float near_depth,
float far_depth) override;
void Draw(u32 base_vertex, u32 num_vertices) override;
void DrawIndexed(u32 base_index, u32 num_indices, u32 base_vertex) override;
+ void DispatchComputeShader(const AbstractShader* shader, u32 groups_x, u32 groups_y,
+ u32 groups_z) override;
void BindBackbuffer(const ClearColor& clear_color = {}) override;
void PresentBackbuffer() override;
- u32 AccessEFB(EFBAccessType type, u32 x, u32 y, u32 poke_data) override;
- void PokeEFB(EFBAccessType type, const EfbPokeData* points, size_t num_points) override;
-
u16 BBoxRead(int index) override;
void BBoxWrite(int index, u16 value) override;
- void ResetAPIState() override;
- void RestoreAPIState() override;
-
- TargetRectangle ConvertEFBRectangle(const EFBRectangle& rc) override;
+ void BeginUtilityDrawing() override;
+ void EndUtilityDrawing() override;
void Flush() override;
+ void WaitForGPUIdle() override;
void RenderXFBToScreen(const AbstractTexture* texture, const EFBRectangle& rc) override;
void OnConfigChanged(u32 bits) override;
void ClearScreen(const EFBRectangle& rc, bool colorEnable, bool alphaEnable, bool zEnable,
u32 color, u32 z) override;
- void ReinterpretPixelData(unsigned int convtype) override;
-
std::unique_ptr<VideoCommon::AsyncShaderCompiler> CreateAsyncShaderCompiler() override;
// Only call methods from this on the GPU thread.
GLContext* GetMainGLContext() const { return m_main_gl_context.get(); }
bool IsGLES() const { return m_main_gl_context->IsGLES(); }
- const OGLPipeline* GetCurrentGraphicsPipeline() const { return m_graphics_pipeline; }
+ // Invalidates a cached texture binding. Required for texel buffers when they borrow the units.
+ void InvalidateTextureBinding(u32 index) { m_bound_textures[index] = nullptr; }
-private:
- void UpdateEFBCache(EFBAccessType type, u32 cacheRectIdx, const EFBRectangle& efbPixelRc,
- const TargetRectangle& targetPixelRc, const void* data);
+ // The shared framebuffer exists for copying textures when extensions are not available. It is
+ // slower, but the only way to do these things otherwise.
+ GLuint GetSharedReadFramebuffer() const { return m_shared_read_framebuffer; }
+ GLuint GetSharedDrawFramebuffer() const { return m_shared_draw_framebuffer; }
+ void BindSharedReadFramebuffer();
+ void BindSharedDrawFramebuffer();
+ // Restores FBO binding after it's been changed.
+ void RestoreFramebufferBinding();
+
+private:
void CheckForSurfaceChange();
void CheckForSurfaceResize();
- void ApplyBlendingState(const BlendingState state, bool force = false);
- void ApplyRasterizationState(const RasterizationState state, bool force = false);
- void ApplyDepthState(const DepthState state, bool force = false);
+ void ApplyRasterizationState(const RasterizationState state);
+ void ApplyDepthState(const DepthState state);
+ void ApplyBlendingState(const BlendingState state);
std::unique_ptr<GLContext> m_main_gl_context;
- std::array<const AbstractTexture*, 8> m_bound_textures{};
- const OGLPipeline* m_graphics_pipeline = nullptr;
+ std::unique_ptr<OGLFramebuffer> m_system_framebuffer;
+ std::array<const OGLTexture*, 8> m_bound_textures{};
+ AbstractTexture* m_bound_image_texture = nullptr;
RasterizationState m_current_rasterization_state;
DepthState m_current_depth_state;
BlendingState m_current_blend_state;
+ GLuint m_shared_read_framebuffer = 0;
+ GLuint m_shared_draw_framebuffer = 0;
};
} // namespace OGL
diff --git a/Source/Core/VideoBackends/OGL/StreamBuffer.h b/Source/Core/VideoBackends/OGL/StreamBuffer.h
index 2a8efba1af..9946f3d33e 100644
--- a/Source/Core/VideoBackends/OGL/StreamBuffer.h
+++ b/Source/Core/VideoBackends/OGL/StreamBuffer.h
@@ -19,6 +19,8 @@ public:
static std::unique_ptr<StreamBuffer> Create(u32 type, u32 size);
virtual ~StreamBuffer();
+ u32 GetGLBufferId() const { return m_buffer; }
+ u32 GetSize() const { return m_size; }
u32 GetCurrentOffset() const { return m_iterator; }
/* This mapping function will return a pair of:
@@ -64,4 +66,4 @@ private:
std::array<GLsync, SYNC_POINTS> m_fences{};
};
-}
+} // namespace OGL
diff --git a/Source/Core/VideoBackends/OGL/TextureCache.cpp b/Source/Core/VideoBackends/OGL/TextureCache.cpp
deleted file mode 100644
index 9b0699587b..0000000000
--- a/Source/Core/VideoBackends/OGL/TextureCache.cpp
+++ /dev/null
@@ -1,574 +0,0 @@
-// Copyright 2008 Dolphin Emulator Project
-// Licensed under GPLv2+
-// Refer to the license.txt file included.
-
-#include <algorithm>
-#include <cmath>
-#include <cstring>
-#include <fstream>
-#include <memory>
-#include <vector>
-
-#include "Common/Assert.h"
-#include "Common/MsgHandler.h"
-#include "Common/StringUtil.h"
-
-#include "VideoBackends/OGL/FramebufferManager.h"
-#include "VideoBackends/OGL/GPUTimer.h"
-#include "VideoBackends/OGL/OGLTexture.h"
-#include "VideoBackends/OGL/ProgramShaderCache.h"
-#include "VideoBackends/OGL/Render.h"
-#include "VideoBackends/OGL/SamplerCache.h"
-#include "VideoBackends/OGL/StreamBuffer.h"
-#include "VideoBackends/OGL/TextureCache.h"
-#include "VideoBackends/OGL/TextureConverter.h"
-
-#include "VideoCommon/ImageWrite.h"
-#include "VideoCommon/TextureConversionShader.h"
-#include "VideoCommon/TextureConverterShaderGen.h"
-#include "VideoCommon/TextureDecoder.h"
-#include "VideoCommon/VideoCommon.h"
-#include "VideoCommon/VideoConfig.h"
-
-namespace OGL
-{
-constexpr const char GLSL_PROGRAM_VS[] = R"GLSL(
-out vec3 %c_uv0;
-SAMPLER_BINDING(9) uniform sampler2DArray samp9;
-uniform vec4 copy_position; // left, top, right, bottom
-
-void main()
-{
- vec2 rawpos = vec2(gl_VertexID&1, gl_VertexID&2);
- %c_uv0 = vec3(mix(copy_position.xy, copy_position.zw, rawpos) / vec2(textureSize(samp9, 0).xy), 0.0);
- gl_Position = vec4(rawpos*2.0-1.0, 0.0, 1.0);
-}
-)GLSL";
-
-constexpr const char GLSL_PROGRAM_GS[] = R"GLSL(
-layout(triangles) in;
-layout(triangle_strip, max_vertices = 6) out;
-in vec3 v_uv0[3];
-out vec3 f_uv0;
-SAMPLER_BINDING(9) uniform sampler2DArray samp9;
-
-void main()
-{
- int layers = textureSize(samp9, 0).z;
- for (int layer = 0; layer < layers; ++layer) {
- for (int i = 0; i < 3; ++i) {
- f_uv0 = vec3(v_uv0[i].xy, layer);
- gl_Position = gl_in[i].gl_Position;
- gl_Layer = layer;
- EmitVertex();
- }
- }
- EndPrimitive();
-}
-)GLSL";
-
-constexpr const char GLSL_COLOR_COPY_FS[] = R"GLSL(
-SAMPLER_BINDING(9) uniform sampler2DArray samp9;
-in vec3 f_uv0;
-out vec4 ocol0;
-
-void main()
-{
- vec4 texcol = texture(samp9, f_uv0);
- ocol0 = texcol;
-}
-)GLSL";
-
-constexpr const char GLSL_PALETTE_FS[] = R"GLSL(
-uniform int texture_buffer_offset;
-uniform float multiplier;
-SAMPLER_BINDING(9) uniform sampler2DArray samp9;
-SAMPLER_BINDING(10) uniform usamplerBuffer samp10;
-
-in vec3 f_uv0;
-out vec4 ocol0;
-
-int Convert3To8(int v)
-{
- // Swizzle bits: 00000123 -> 12312312
- return (v << 5) | (v << 2) | (v >> 1);
-}
-
-int Convert4To8(int v)
-{
- // Swizzle bits: 00001234 -> 12341234
- return (v << 4) | v;
-}
-
-int Convert5To8(int v)
-{
- // Swizzle bits: 00012345 -> 12345123
- return (v << 3) | (v >> 2);
-}
-
-int Convert6To8(int v)
-{
- // Swizzle bits: 00123456 -> 12345612
- return (v << 2) | (v >> 4);
-}
-
-float4 DecodePixel_RGB5A3(int val)
-{
- int r,g,b,a;
- if ((val&0x8000) > 0)
- {
- r=Convert5To8((val>>10) & 0x1f);
- g=Convert5To8((val>>5 ) & 0x1f);
- b=Convert5To8((val ) & 0x1f);
- a=0xFF;
- }
- else
- {
- a=Convert3To8((val>>12) & 0x7);
- r=Convert4To8((val>>8 ) & 0xf);
- g=Convert4To8((val>>4 ) & 0xf);
- b=Convert4To8((val ) & 0xf);
- }
- return float4(r, g, b, a) / 255.0;
-}
-
-float4 DecodePixel_RGB565(int val)
-{
- int r, g, b, a;
- r = Convert5To8((val >> 11) & 0x1f);
- g = Convert6To8((val >> 5) & 0x3f);
- b = Convert5To8((val) & 0x1f);
- a = 0xFF;
- return float4(r, g, b, a) / 255.0;
-}
-
-float4 DecodePixel_IA8(int val)
-{
- int i = val & 0xFF;
- int a = val >> 8;
- return float4(i, i, i, a) / 255.0;
-}
-
-void main()
-{
- int src = int(round(texture(samp9, f_uv0).r * multiplier));
- src = int(texelFetch(samp10, src + texture_buffer_offset).r);
- src = ((src << 8) & 0xFF00) | (src >> 8);
- ocol0 = DecodePixel_%s(src);
-}
-)GLSL";
-
-//#define TIME_TEXTURE_DECODING 1
-
-void TextureCache::CopyEFB(AbstractStagingTexture* dst, const EFBCopyParams& params,
- u32 native_width, u32 bytes_per_row, u32 num_blocks_y, u32 memory_stride,
- const EFBRectangle& src_rect, bool scale_by_half, float y_scale,
- float gamma, bool clamp_top, bool clamp_bottom,
- const CopyFilterCoefficientArray& filter_coefficients)
-{
- // Flip top/bottom due to lower-left coordinate system.
- float clamp_top_val =
- clamp_bottom ? (1.0f - src_rect.bottom / static_cast<float>(EFB_HEIGHT)) : 0.0f;
- float clamp_bottom_val =
- clamp_top ? (1.0f - src_rect.top / static_cast<float>(EFB_HEIGHT)) : 1.0f;
- TextureConverter::EncodeToRamFromTexture(dst, params, native_width, bytes_per_row, num_blocks_y,
- memory_stride, src_rect, scale_by_half, y_scale, gamma,
- clamp_top_val, clamp_bottom_val, filter_coefficients);
-}
-
-TextureCache::TextureCache()
-{
- CompileShaders();
-
- if (g_ActiveConfig.backend_info.bSupportsPaletteConversion)
- {
- s32 buffer_size_mb = (g_ActiveConfig.backend_info.bSupportsGPUTextureDecoding ? 32 : 1);
- s32 buffer_size = buffer_size_mb * 1024 * 1024;
- s32 max_buffer_size = 0;
-
- // The minimum MAX_TEXTURE_BUFFER_SIZE that the spec mandates is 65KB, we are asking for a 1MB
- // buffer here. This buffer is also used as storage for undecoded textures when compute shader
- // texture decoding is enabled, in which case the requested size is 32MB.
- glGetIntegerv(GL_MAX_TEXTURE_BUFFER_SIZE, &max_buffer_size);
-
- // Clamp the buffer size to the maximum size that the driver supports.
- buffer_size = std::min(buffer_size, max_buffer_size);
-
- m_palette_stream_buffer = StreamBuffer::Create(GL_TEXTURE_BUFFER, buffer_size);
- glGenTextures(1, &m_palette_resolv_texture);
- glBindTexture(GL_TEXTURE_BUFFER, m_palette_resolv_texture);
- glTexBuffer(GL_TEXTURE_BUFFER, GL_R16UI, m_palette_stream_buffer->m_buffer);
-
- if (g_ActiveConfig.backend_info.bSupportsGPUTextureDecoding)
- CreateTextureDecodingResources();
- }
-}
-
-TextureCache::~TextureCache()
-{
- DeleteShaders();
- if (g_ActiveConfig.backend_info.bSupportsGPUTextureDecoding)
- DestroyTextureDecodingResources();
-
- if (g_ActiveConfig.backend_info.bSupportsPaletteConversion)
- {
- glDeleteTextures(1, &m_palette_resolv_texture);
- }
-}
-
-TextureCache* TextureCache::GetInstance()
-{
- return static_cast<TextureCache*>(g_texture_cache.get());
-}
-
-const SHADER& TextureCache::GetColorCopyProgram() const
-{
- return m_colorCopyProgram;
-}
-
-GLuint TextureCache::GetColorCopyPositionUniform() const
-{
- return m_colorCopyPositionUniform;
-}
-
-bool TextureCache::CompilePaletteShader(TLUTFormat tlutfmt, const std::string& vcode,
- const std::string& pcode, const std::string& gcode)
-{
- ASSERT(IsValidTLUTFormat(tlutfmt));
- PaletteShader& shader = m_palette_shaders[static_cast<int>(tlutfmt)];
-
- if (!ProgramShaderCache::CompileShader(shader.shader, vcode, pcode, gcode))
- return false;
-
- shader.buffer_offset_uniform =
- glGetUniformLocation(shader.shader.glprogid, "texture_buffer_offset");
- shader.multiplier_uniform = glGetUniformLocation(shader.shader.glprogid, "multiplier");
- shader.copy_position_uniform = glGetUniformLocation(shader.shader.glprogid, "copy_position");
-
- return true;
-}
-
-bool TextureCache::CompileShaders()
-{
- std::string geo_program = "";
- char prefix = 'f';
- if (g_ActiveConfig.stereo_mode != StereoMode::Off)
- {
- geo_program = GLSL_PROGRAM_GS;
- prefix = 'v';
- }
-
- if (!ProgramShaderCache::CompileShader(m_colorCopyProgram,
- StringFromFormat(GLSL_PROGRAM_VS, prefix, prefix),
- GLSL_COLOR_COPY_FS, geo_program))
- {
- return false;
- }
-
- m_colorCopyPositionUniform = glGetUniformLocation(m_colorCopyProgram.glprogid, "copy_position");
-
- if (g_ActiveConfig.backend_info.bSupportsPaletteConversion)
- {
- if (!CompilePaletteShader(TLUTFormat::IA8, StringFromFormat(GLSL_PROGRAM_VS, prefix, prefix),
- StringFromFormat(GLSL_PALETTE_FS, "IA8"), geo_program))
- return false;
-
- if (!CompilePaletteShader(TLUTFormat::RGB565, StringFromFormat(GLSL_PROGRAM_VS, prefix, prefix),
- StringFromFormat(GLSL_PALETTE_FS, "RGB565"), geo_program))
- return false;
-
- if (!CompilePaletteShader(TLUTFormat::RGB5A3, StringFromFormat(GLSL_PROGRAM_VS, prefix, prefix),
- StringFromFormat(GLSL_PALETTE_FS, "RGB5A3"), geo_program))
- return false;
- }
-
- return true;
-}
-
-void TextureCache::DeleteShaders()
-{
- for (auto& it : m_efb_copy_programs)
- it.second.shader.Destroy();
- m_efb_copy_programs.clear();
-
- if (g_ActiveConfig.backend_info.bSupportsPaletteConversion)
- for (auto& shader : m_palette_shaders)
- shader.shader.Destroy();
-}
-
-void TextureCache::ConvertTexture(TCacheEntry* destination, TCacheEntry* source,
- const void* palette, TLUTFormat tlutfmt)
-{
- if (!g_ActiveConfig.backend_info.bSupportsPaletteConversion)
- return;
-
- ASSERT(IsValidTLUTFormat(tlutfmt));
- const PaletteShader& palette_shader = m_palette_shaders[static_cast<int>(tlutfmt)];
-
- g_renderer->ResetAPIState();
-
- OGLTexture* source_texture = static_cast<OGLTexture*>(source->texture.get());
- OGLTexture* destination_texture = static_cast<OGLTexture*>(destination->texture.get());
-
- glActiveTexture(GL_TEXTURE9);
- glBindTexture(GL_TEXTURE_2D_ARRAY, source_texture->GetRawTexIdentifier());
- g_sampler_cache->BindNearestSampler(9);
-
- FramebufferManager::SetFramebuffer(destination_texture->GetFramebuffer());
- glViewport(0, 0, destination->GetWidth(), destination->GetHeight());
- palette_shader.shader.Bind();
-
- // C14 textures are currently unsupported
- int size = source->format == TextureFormat::I4 ? 32 : 512;
- auto buffer = m_palette_stream_buffer->Map(size);
- memcpy(buffer.first, palette, size);
- m_palette_stream_buffer->Unmap(size);
- glUniform1i(palette_shader.buffer_offset_uniform, buffer.second / 2);
- glUniform1f(palette_shader.multiplier_uniform,
- source->format == TextureFormat::I4 ? 15.0f : 255.0f);
- glUniform4f(palette_shader.copy_position_uniform, 0.0f, 0.0f,
- static_cast<float>(source->GetWidth()), static_cast<float>(source->GetHeight()));
-
- glActiveTexture(GL_TEXTURE10);
- glBindTexture(GL_TEXTURE_BUFFER, m_palette_resolv_texture);
- g_sampler_cache->BindNearestSampler(10);
-
- ProgramShaderCache::BindVertexFormat(nullptr);
- glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
-
- g_renderer->RestoreAPIState();
-}
-
-static const std::string decoding_vertex_shader = R"(
-void main()
-{
- vec2 rawpos = vec2(gl_VertexID&1, gl_VertexID&2);
- gl_Position = vec4(rawpos*2.0-1.0, 0.0, 1.0);
-}
-)";
-
-void TextureCache::CreateTextureDecodingResources()
-{
- static const GLenum gl_view_types[TextureConversionShaderTiled::BUFFER_FORMAT_COUNT] = {
- GL_R8UI, // BUFFER_FORMAT_R8_UINT
- GL_R16UI, // BUFFER_FORMAT_R16_UINT
- GL_RG32UI, // BUFFER_FORMAT_R32G32_UINT
- GL_RGBA8UI, // BUFFER_FORMAT_RGBA8_UINT
- };
-
- glGenTextures(TextureConversionShaderTiled::BUFFER_FORMAT_COUNT,
- m_texture_decoding_buffer_views.data());
- for (size_t i = 0; i < TextureConversionShaderTiled::BUFFER_FORMAT_COUNT; i++)
- {
- glBindTexture(GL_TEXTURE_BUFFER, m_texture_decoding_buffer_views[i]);
- glTexBuffer(GL_TEXTURE_BUFFER, gl_view_types[i], m_palette_stream_buffer->m_buffer);
- }
-}
-
-void TextureCache::DestroyTextureDecodingResources()
-{
- glDeleteTextures(TextureConversionShaderTiled::BUFFER_FORMAT_COUNT,
- m_texture_decoding_buffer_views.data());
- m_texture_decoding_buffer_views.fill(0);
- m_texture_decoding_program_info.clear();
-}
-
-bool TextureCache::SupportsGPUTextureDecode(TextureFormat format, TLUTFormat palette_format)
-{
- auto key = std::make_pair(static_cast<u32>(format), static_cast<u32>(palette_format));
- auto iter = m_texture_decoding_program_info.find(key);
- if (iter != m_texture_decoding_program_info.end())
- return iter->second.valid;
-
- TextureDecodingProgramInfo info;
- info.base_info = TextureConversionShaderTiled::GetDecodingShaderInfo(format);
- if (!info.base_info)
- {
- m_texture_decoding_program_info.emplace(key, info);
- return false;
- }
-
- std::string shader_source =
- TextureConversionShaderTiled::GenerateDecodingShader(format, palette_format, APIType::OpenGL);
- if (shader_source.empty())
- {
- m_texture_decoding_program_info.emplace(key, info);
- return false;
- }
-
- if (!ProgramShaderCache::CompileComputeShader(info.program, shader_source))
- {
- m_texture_decoding_program_info.emplace(key, info);
- return false;
- }
-
- info.uniform_dst_size = glGetUniformLocation(info.program.glprogid, "u_dst_size");
- info.uniform_src_size = glGetUniformLocation(info.program.glprogid, "u_src_size");
- info.uniform_src_offset = glGetUniformLocation(info.program.glprogid, "u_src_offset");
- info.uniform_src_row_stride = glGetUniformLocation(info.program.glprogid, "u_src_row_stride");
- info.uniform_palette_offset = glGetUniformLocation(info.program.glprogid, "u_palette_offset");
- info.valid = true;
- m_texture_decoding_program_info.emplace(key, info);
- return true;
-}
-
-void TextureCache::DecodeTextureOnGPU(TCacheEntry* entry, u32 dst_level, const u8* data,
- size_t data_size, TextureFormat format, u32 width, u32 height,
- u32 aligned_width, u32 aligned_height, u32 row_stride,
- const u8* palette, TLUTFormat palette_format)
-{
- auto key = std::make_pair(static_cast<u32>(format), static_cast<u32>(palette_format));
- auto iter = m_texture_decoding_program_info.find(key);
- if (iter == m_texture_decoding_program_info.end())
- return;
-
-#ifdef TIME_TEXTURE_DECODING
- GPUTimer timer;
-#endif
-
- // Copy to GPU-visible buffer, aligned to the data type.
- auto info = iter->second;
- u32 bytes_per_buffer_elem =
- TextureConversionShaderTiled::GetBytesPerBufferElement(info.base_info->buffer_format);
-
- // Only copy palette if it is required.
- bool has_palette = info.base_info->palette_size > 0;
- u32 total_upload_size = static_cast<u32>(data_size);
- u32 palette_offset = total_upload_size;
- if (has_palette)
- {
- // Align to u16.
- if ((total_upload_size % sizeof(u16)) != 0)
- {
- total_upload_size++;
- palette_offset++;
- }
-
- total_upload_size += info.base_info->palette_size;
- }
-
- // Allocate space in stream buffer, and copy texture + palette across.
- auto buffer = m_palette_stream_buffer->Map(total_upload_size, bytes_per_buffer_elem);
- memcpy(buffer.first, data, data_size);
- if (has_palette)
- memcpy(buffer.first + palette_offset, palette, info.base_info->palette_size);
- m_palette_stream_buffer->Unmap(total_upload_size);
-
- info.program.Bind();
-
- // Calculate stride in buffer elements
- u32 row_stride_in_elements = row_stride / bytes_per_buffer_elem;
- u32 offset_in_elements = buffer.second / bytes_per_buffer_elem;
- u32 palette_offset_in_elements = (buffer.second + palette_offset) / sizeof(u16);
- if (info.uniform_dst_size >= 0)
- glUniform2ui(info.uniform_dst_size, width, height);
- if (info.uniform_src_size >= 0)
- glUniform2ui(info.uniform_src_size, aligned_width, aligned_height);
- if (info.uniform_src_offset >= 0)
- glUniform1ui(info.uniform_src_offset, offset_in_elements);
- if (info.uniform_src_row_stride >= 0)
- glUniform1ui(info.uniform_src_row_stride, row_stride_in_elements);
- if (info.uniform_palette_offset >= 0)
- glUniform1ui(info.uniform_palette_offset, palette_offset_in_elements);
-
- glActiveTexture(GL_TEXTURE9);
- glBindTexture(GL_TEXTURE_BUFFER, m_texture_decoding_buffer_views[info.base_info->buffer_format]);
-
- if (has_palette)
- {
- // Use an R16UI view for the palette.
- glActiveTexture(GL_TEXTURE10);
- glBindTexture(GL_TEXTURE_BUFFER, m_palette_resolv_texture);
- }
-
- auto dispatch_groups =
- TextureConversionShaderTiled::GetDispatchCount(info.base_info, aligned_width, aligned_height);
- glBindImageTexture(0, static_cast<OGLTexture*>(entry->texture.get())->GetRawTexIdentifier(),
- dst_level, GL_TRUE, 0, GL_WRITE_ONLY, GL_RGBA8);
- glDispatchCompute(dispatch_groups.first, dispatch_groups.second, 1);
- glMemoryBarrier(GL_TEXTURE_UPDATE_BARRIER_BIT);
-
-#ifdef TIME_TEXTURE_DECODING
- WARN_LOG(VIDEO, "Decode texture format %u size %ux%u took %.4fms", static_cast<u32>(format),
- width, height, timer.GetTimeMilliseconds());
-#endif
-}
-
-void TextureCache::CopyEFBToCacheEntry(TCacheEntry* entry, bool is_depth_copy,
- const EFBRectangle& src_rect, bool scale_by_half,
- EFBCopyFormat dst_format, bool is_intensity, float gamma,
- bool clamp_top, bool clamp_bottom,
- const CopyFilterCoefficientArray& filter_coefficients)
-{
- auto* destination_texture = static_cast<OGLTexture*>(entry->texture.get());
- g_renderer->ResetAPIState(); // reset any game specific settings
-
- // Make sure to resolve anything we need to read from.
- const GLuint read_texture = is_depth_copy ?
- FramebufferManager::ResolveAndGetDepthTarget(src_rect) :
- FramebufferManager::ResolveAndGetRenderTarget(src_rect);
-
- FramebufferManager::SetFramebuffer(destination_texture->GetFramebuffer());
-
- glActiveTexture(GL_TEXTURE9);
- glBindTexture(GL_TEXTURE_2D_ARRAY, read_texture);
- if (scale_by_half)
- g_sampler_cache->BindLinearSampler(9);
- else
- g_sampler_cache->BindNearestSampler(9);
-
- glViewport(0, 0, destination_texture->GetConfig().width, destination_texture->GetConfig().height);
-
- auto uid = TextureConversionShaderGen::GetShaderUid(dst_format, is_depth_copy, is_intensity,
- scale_by_half,
- NeedsCopyFilterInShader(filter_coefficients));
-
- auto it = m_efb_copy_programs.emplace(uid, EFBCopyShader());
- EFBCopyShader& shader = it.first->second;
- bool created = it.second;
-
- if (created)
- {
- ShaderCode code = TextureConversionShaderGen::GenerateShader(APIType::OpenGL, uid.GetUidData());
-
- std::string geo_program = "";
- char prefix = 'f';
- if (g_ActiveConfig.stereo_mode != StereoMode::Off)
- {
- geo_program = GLSL_PROGRAM_GS;
- prefix = 'v';
- }
-
- ProgramShaderCache::CompileShader(shader.shader,
- StringFromFormat(GLSL_PROGRAM_VS, prefix, prefix),
- code.GetBuffer(), geo_program);
-
- shader.position_uniform = glGetUniformLocation(shader.shader.glprogid, "copy_position");
- shader.pixel_height_uniform = glGetUniformLocation(shader.shader.glprogid, "pixel_height");
- shader.gamma_rcp_uniform = glGetUniformLocation(shader.shader.glprogid, "gamma_rcp");
- shader.clamp_tb_uniform = glGetUniformLocation(shader.shader.glprogid, "clamp_tb");
- shader.filter_coefficients_uniform =
- glGetUniformLocation(shader.shader.glprogid, "filter_coefficients");
- }
-
- shader.shader.Bind();
-
- TargetRectangle R = g_renderer->ConvertEFBRectangle(src_rect);
- glUniform4f(shader.position_uniform, static_cast<float>(R.left), static_cast<float>(R.top),
- static_cast<float>(R.right), static_cast<float>(R.bottom));
- glUniform1f(shader.pixel_height_uniform, g_ActiveConfig.bCopyEFBScaled ?
- 1.0f / g_renderer->GetTargetHeight() :
- 1.0f / EFB_HEIGHT);
- glUniform1f(shader.gamma_rcp_uniform, 1.0f / gamma);
- glUniform2f(shader.clamp_tb_uniform,
- clamp_bottom ? (1.0f - src_rect.bottom / static_cast<float>(EFB_HEIGHT)) : 0.0f,
- clamp_top ? (1.0f - src_rect.top / static_cast<float>(EFB_HEIGHT)) : 1.0f);
- glUniform3f(shader.filter_coefficients_uniform, filter_coefficients[0], filter_coefficients[1],
- filter_coefficients[2]);
-
- ProgramShaderCache::BindVertexFormat(nullptr);
- glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
-
- g_renderer->RestoreAPIState();
-}
-} // namespace OGL
diff --git a/Source/Core/VideoBackends/OGL/TextureCache.h b/Source/Core/VideoBackends/OGL/TextureCache.h
deleted file mode 100644
index 89fc82ee9d..0000000000
--- a/Source/Core/VideoBackends/OGL/TextureCache.h
+++ /dev/null
@@ -1,108 +0,0 @@
-// Copyright 2008 Dolphin Emulator Project
-// Licensed under GPLv2+
-// Refer to the license.txt file included.
-
-#pragma once
-
-#include <map>
-#include <utility>
-
-#include "Common/CommonTypes.h"
-#include "Common/GL/GLUtil.h"
-#include "VideoBackends/OGL/ProgramShaderCache.h"
-
-#include "VideoCommon/TextureCacheBase.h"
-#include "VideoCommon/TextureConversionShader.h"
-#include "VideoCommon/TextureConverterShaderGen.h"
-#include "VideoCommon/VideoCommon.h"
-
-class AbstractTexture;
-class StreamBuffer;
-struct TextureConfig;
-
-namespace OGL
-{
-class TextureCache : public TextureCacheBase
-{
-public:
- TextureCache();
- ~TextureCache();
-
- static TextureCache* GetInstance();
-
- bool SupportsGPUTextureDecode(TextureFormat format, TLUTFormat palette_format) override;
- void DecodeTextureOnGPU(TCacheEntry* entry, u32 dst_level, const u8* data, size_t data_size,
- TextureFormat format, u32 width, u32 height, u32 aligned_width,
- u32 aligned_height, u32 row_stride, const u8* palette,
- TLUTFormat palette_format) override;
-
- const SHADER& GetColorCopyProgram() const;
- GLuint GetColorCopyPositionUniform() const;
-
-private:
- struct PaletteShader
- {
- SHADER shader;
- GLuint buffer_offset_uniform;
- GLuint multiplier_uniform;
- GLuint copy_position_uniform;
- };
-
- struct TextureDecodingProgramInfo
- {
- const TextureConversionShaderTiled::DecodingShaderInfo* base_info = nullptr;
- SHADER program;
- GLint uniform_dst_size = -1;
- GLint uniform_src_size = -1;
- GLint uniform_src_row_stride = -1;
- GLint uniform_src_offset = -1;
- GLint uniform_palette_offset = -1;
- bool valid = false;
- };
-
- void ConvertTexture(TCacheEntry* destination, TCacheEntry* source, const void* palette,
- TLUTFormat format) override;
-
- void CopyEFB(AbstractStagingTexture* dst, const EFBCopyParams& params, u32 native_width,
- u32 bytes_per_row, u32 num_blocks_y, u32 memory_stride, const EFBRectangle& src_rect,
- bool scale_by_half, float y_scale, float gamma, bool clamp_top, bool clamp_bottom,
- const CopyFilterCoefficientArray& filter_coefficients) override;
-
- void CopyEFBToCacheEntry(TCacheEntry* entry, bool is_depth_copy, const EFBRectangle& src_rect,
- bool scale_by_half, EFBCopyFormat dst_format, bool is_intensity,
- float gamma, bool clamp_top, bool clamp_bottom,
- const CopyFilterCoefficientArray& filter_coefficients) override;
-
- bool CompileShaders() override;
- void DeleteShaders() override;
-
- bool CompilePaletteShader(TLUTFormat tlutfmt, const std::string& vcode, const std::string& pcode,
- const std::string& gcode);
-
- void CreateTextureDecodingResources();
- void DestroyTextureDecodingResources();
-
- struct EFBCopyShader
- {
- SHADER shader;
- GLuint position_uniform;
- GLuint pixel_height_uniform;
- GLuint gamma_rcp_uniform;
- GLuint clamp_tb_uniform;
- GLuint filter_coefficients_uniform;
- };
-
- std::map<TextureConversionShaderGen::TCShaderUid, EFBCopyShader> m_efb_copy_programs;
-
- SHADER m_colorCopyProgram;
- GLuint m_colorCopyPositionUniform;
-
- std::array<PaletteShader, 3> m_palette_shaders;
- std::unique_ptr<StreamBuffer> m_palette_stream_buffer;
- GLuint m_palette_resolv_texture = 0;
-
- std::map<std::pair<u32, u32>, TextureDecodingProgramInfo> m_texture_decoding_program_info;
- std::array<GLuint, TextureConversionShaderTiled::BUFFER_FORMAT_COUNT>
- m_texture_decoding_buffer_views;
-};
-}
diff --git a/Source/Core/VideoBackends/OGL/TextureConverter.cpp b/Source/Core/VideoBackends/OGL/TextureConverter.cpp
deleted file mode 100644
index 095365140f..0000000000
--- a/Source/Core/VideoBackends/OGL/TextureConverter.cpp
+++ /dev/null
@@ -1,170 +0,0 @@
-// Copyright 2008 Dolphin Emulator Project
-// Licensed under GPLv2+
-// Refer to the license.txt file included.
-
-// Fast image conversion using OpenGL shaders.
-
-#include "VideoBackends/OGL/TextureConverter.h"
-
-#include <string>
-
-#include "Common/CommonTypes.h"
-#include "Common/FileUtil.h"
-#include "Common/Logging/Log.h"
-#include "Common/MsgHandler.h"
-#include "Common/StringUtil.h"
-
-#include "Core/HW/Memmap.h"
-
-#include "VideoBackends/OGL/FramebufferManager.h"
-#include "VideoBackends/OGL/OGLTexture.h"
-#include "VideoBackends/OGL/ProgramShaderCache.h"
-#include "VideoBackends/OGL/Render.h"
-#include "VideoBackends/OGL/SamplerCache.h"
-#include "VideoBackends/OGL/TextureCache.h"
-
-#include "VideoCommon/ImageWrite.h"
-#include "VideoCommon/TextureConversionShader.h"
-#include "VideoCommon/VideoCommon.h"
-#include "VideoCommon/VideoConfig.h"
-
-namespace OGL
-{
-namespace TextureConverter
-{
-namespace
-{
-struct EncodingProgram
-{
- SHADER program;
- GLint copy_position_uniform;
- GLint y_scale_uniform;
- GLint gamma_rcp_uniform;
- GLint clamp_tb_uniform;
- GLint filter_coefficients_uniform;
-};
-
-std::map<EFBCopyParams, EncodingProgram> s_encoding_programs;
-std::unique_ptr<AbstractTexture> s_encoding_render_texture;
-
-const int renderBufferWidth = EFB_WIDTH * 4;
-const int renderBufferHeight = 1024;
-} // namespace
-
-static EncodingProgram& GetOrCreateEncodingShader(const EFBCopyParams& params)
-{
- auto iter = s_encoding_programs.find(params);
- if (iter != s_encoding_programs.end())
- return iter->second;
-
- const char* shader =
- TextureConversionShaderTiled::GenerateEncodingShader(params, APIType::OpenGL);
-
-#if defined(_DEBUG) || defined(DEBUGFAST)
- if (g_ActiveConfig.iLog & CONF_SAVESHADERS && shader)
- {
- static int counter = 0;
- std::string filename =
- StringFromFormat("%senc_%04i.txt", File::GetUserPath(D_DUMP_IDX).c_str(), counter++);
-
- SaveData(filename, shader);
- }
-#endif
-
- const char* VProgram = "void main()\n"
- "{\n"
- " vec2 rawpos = vec2(gl_VertexID&1, gl_VertexID&2);\n"
- " gl_Position = vec4(rawpos*2.0-1.0, 0.0, 1.0);\n"
- "}\n";
-
- EncodingProgram program;
- if (!ProgramShaderCache::CompileShader(program.program, VProgram, shader))
- PanicAlert("Failed to compile texture encoding shader.");
-
- program.copy_position_uniform = glGetUniformLocation(program.program.glprogid, "position");
- program.y_scale_uniform = glGetUniformLocation(program.program.glprogid, "y_scale");
- program.gamma_rcp_uniform = glGetUniformLocation(program.program.glprogid, "gamma_rcp");
- program.clamp_tb_uniform = glGetUniformLocation(program.program.glprogid, "clamp_tb");
- program.filter_coefficients_uniform =
- glGetUniformLocation(program.program.glprogid, "filter_coefficients");
- return s_encoding_programs.emplace(params, program).first->second;
-}
-
-void Init()
-{
- s_encoding_render_texture = g_renderer->CreateTexture(TextureCache::GetEncodingTextureConfig());
-}
-
-void Shutdown()
-{
- s_encoding_render_texture.reset();
-
- for (auto& program : s_encoding_programs)
- program.second.program.Destroy();
- s_encoding_programs.clear();
-}
-
-// dst_line_size, writeStride in bytes
-
-static void EncodeToRamUsingShader(GLuint srcTexture, AbstractStagingTexture* destAddr,
- u32 dst_line_size, u32 dstHeight, u32 writeStride,
- bool linearFilter, float y_scale)
-{
- FramebufferManager::SetFramebuffer(
- static_cast<OGLTexture*>(s_encoding_render_texture.get())->GetFramebuffer());
-
- // set source texture
- glActiveTexture(GL_TEXTURE9);
- glBindTexture(GL_TEXTURE_2D_ARRAY, srcTexture);
-
- // We also linear filtering for both box filtering and downsampling higher resolutions to 1x
- // TODO: This only produces perfect downsampling for 2x IR, other resolutions will need more
- // complex down filtering to average all pixels and produce the correct result.
- // Also, box filtering won't be correct for anything other than 1x IR
- if (linearFilter || g_renderer->GetEFBScale() != 1 || y_scale > 1.0f)
- g_sampler_cache->BindLinearSampler(9);
- else
- g_sampler_cache->BindNearestSampler(9);
-
- glViewport(0, 0, (GLsizei)(dst_line_size / 4), (GLsizei)dstHeight);
-
- ProgramShaderCache::BindVertexFormat(nullptr);
- glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
-
- MathUtil::Rectangle<int> copy_rect(0, 0, dst_line_size / 4, dstHeight);
-
- destAddr->CopyFromTexture(s_encoding_render_texture.get(), copy_rect, 0, 0, copy_rect);
-}
-
-void EncodeToRamFromTexture(AbstractStagingTexture* dest, const EFBCopyParams& params,
- u32 native_width, u32 bytes_per_row, u32 num_blocks_y,
- u32 memory_stride, const EFBRectangle& src_rect, bool scale_by_half,
- float y_scale, float gamma, float clamp_top, float clamp_bottom,
- const TextureCacheBase::CopyFilterCoefficientArray& filter_coefficients)
-{
- g_renderer->ResetAPIState();
-
- EncodingProgram& texconv_shader = GetOrCreateEncodingShader(params);
-
- texconv_shader.program.Bind();
- glUniform4i(texconv_shader.copy_position_uniform, src_rect.left, src_rect.top, native_width,
- scale_by_half ? 2 : 1);
- glUniform1f(texconv_shader.y_scale_uniform, y_scale);
- glUniform1f(texconv_shader.gamma_rcp_uniform, 1.0f / gamma);
- glUniform2f(texconv_shader.clamp_tb_uniform, clamp_top, clamp_bottom);
- glUniform3f(texconv_shader.filter_coefficients_uniform, filter_coefficients[0],
- filter_coefficients[1], filter_coefficients[2]);
-
- const GLuint read_texture = params.depth ?
- FramebufferManager::ResolveAndGetDepthTarget(src_rect) :
- FramebufferManager::ResolveAndGetRenderTarget(src_rect);
-
- EncodeToRamUsingShader(read_texture, dest, bytes_per_row, num_blocks_y, memory_stride,
- scale_by_half && !params.depth, y_scale);
-
- g_renderer->RestoreAPIState();
-}
-
-} // namespace TextureConverter
-
-} // namespace OGL
diff --git a/Source/Core/VideoBackends/OGL/TextureConverter.h b/Source/Core/VideoBackends/OGL/TextureConverter.h
deleted file mode 100644
index 575fbf5bd0..0000000000
--- a/Source/Core/VideoBackends/OGL/TextureConverter.h
+++ /dev/null
@@ -1,33 +0,0 @@
-// Copyright 2008 Dolphin Emulator Project
-// Licensed under GPLv2+
-// Refer to the license.txt file included.
-
-#pragma once
-
-#include "Common/CommonTypes.h"
-#include "Common/GL/GLUtil.h"
-
-#include "VideoCommon/TextureCacheBase.h"
-#include "VideoCommon/VideoCommon.h"
-
-struct EFBCopyParams;
-class AbstractStagingTexture;
-
-namespace OGL
-{
-// Converts textures between formats using shaders
-// TODO: support multiple texture formats
-namespace TextureConverter
-{
-void Init();
-void Shutdown();
-
-// returns size of the encoded data (in bytes)
-void EncodeToRamFromTexture(
- AbstractStagingTexture* dest, const EFBCopyParams& params, u32 native_width, u32 bytes_per_row,
- u32 num_blocks_y, u32 memory_stride, const EFBRectangle& src_rect, bool scale_by_half,
- float y_scale, float gamma, float clamp_top, float clamp_bottom,
- const TextureCacheBase::CopyFilterCoefficientArray& filter_coefficients);
-}
-
-} // namespace OGL
diff --git a/Source/Core/VideoBackends/OGL/VertexManager.cpp b/Source/Core/VideoBackends/OGL/VertexManager.cpp
index 3883a13595..543a85dac8 100644
--- a/Source/Core/VideoBackends/OGL/VertexManager.cpp
+++ b/Source/Core/VideoBackends/OGL/VertexManager.cpp
@@ -9,17 +9,14 @@
#include <string>
#include <vector>
+#include "Common/Align.h"
#include "Common/CommonTypes.h"
-#include "Common/FileUtil.h"
#include "Common/GL/GLExtensions/GLExtensions.h"
-#include "Common/StringUtil.h"
-#include "VideoBackends/OGL/BoundingBox.h"
#include "VideoBackends/OGL/OGLPipeline.h"
#include "VideoBackends/OGL/ProgramShaderCache.h"
#include "VideoBackends/OGL/Render.h"
#include "VideoBackends/OGL/StreamBuffer.h"
-#include "VideoCommon/BoundingBox.h"
#include "VideoCommon/IndexGenerator.h"
#include "VideoCommon/Statistics.h"
@@ -28,79 +25,147 @@
namespace OGL
{
-// This are the initially requested size for the buffers expressed in bytes
-const u32 MAX_IBUFFER_SIZE = 2 * 1024 * 1024;
-const u32 MAX_VBUFFER_SIZE = 32 * 1024 * 1024;
-
-VertexManager::VertexManager() : m_cpu_v_buffer(MAX_VBUFFER_SIZE), m_cpu_i_buffer(MAX_IBUFFER_SIZE)
+static void CheckBufferBinding()
{
- CreateDeviceObjects();
+ // The index buffer is part of the VAO state, therefore we need to bind it first.
+ if (!ProgramShaderCache::IsValidVertexFormatBound())
+ {
+ ProgramShaderCache::BindVertexFormat(
+ static_cast<GLVertexFormat*>(VertexLoaderManager::GetCurrentVertexFormat()));
+ }
}
+VertexManager::VertexManager() = default;
+
VertexManager::~VertexManager()
{
- DestroyDeviceObjects();
-}
+ if (g_ActiveConfig.backend_info.bSupportsPaletteConversion)
+ {
+ glDeleteTextures(static_cast<GLsizei>(m_texel_buffer_views.size()),
+ m_texel_buffer_views.data());
+ }
-void VertexManager::CreateDeviceObjects()
-{
- m_vertex_buffer = StreamBuffer::Create(GL_ARRAY_BUFFER, MAX_VBUFFER_SIZE);
- m_index_buffer = StreamBuffer::Create(GL_ELEMENT_ARRAY_BUFFER, MAX_IBUFFER_SIZE);
+ // VAO must be found when destroying the index buffer.
+ CheckBufferBinding();
+ m_texel_buffer.reset();
+ m_index_buffer.reset();
+ m_vertex_buffer.reset();
}
-void VertexManager::DestroyDeviceObjects()
+bool VertexManager::Initialize()
{
- m_vertex_buffer.reset();
- m_index_buffer.reset();
+ if (!VertexManagerBase::Initialize())
+ return false;
+
+ m_vertex_buffer = StreamBuffer::Create(GL_ARRAY_BUFFER, VERTEX_STREAM_BUFFER_SIZE);
+ m_index_buffer = StreamBuffer::Create(GL_ELEMENT_ARRAY_BUFFER, INDEX_STREAM_BUFFER_SIZE);
+
+ if (g_ActiveConfig.backend_info.bSupportsPaletteConversion)
+ {
+ // The minimum MAX_TEXTURE_BUFFER_SIZE that the spec mandates is 65KB, we are asking for a 1MB
+ // buffer here. This buffer is also used as storage for undecoded textures when compute shader
+ // texture decoding is enabled, in which case the requested size is 32MB.
+ GLint max_buffer_size;
+ glGetIntegerv(GL_MAX_TEXTURE_BUFFER_SIZE, &max_buffer_size);
+ m_texel_buffer = StreamBuffer::Create(
+ GL_TEXTURE_BUFFER, std::min(max_buffer_size, static_cast<GLint>(TEXEL_STREAM_BUFFER_SIZE)));
+
+ // Allocate texture views backed by buffer.
+ static constexpr std::array<std::pair<TexelBufferFormat, GLenum>, NUM_TEXEL_BUFFER_FORMATS>
+ format_mapping = {{
+ {TEXEL_BUFFER_FORMAT_R8_UINT, GL_R8UI},
+ {TEXEL_BUFFER_FORMAT_R16_UINT, GL_R16UI},
+ {TEXEL_BUFFER_FORMAT_RGBA8_UINT, GL_RGBA8},
+ {TEXEL_BUFFER_FORMAT_R32G32_UINT, GL_RG32UI},
+ }};
+ glGenTextures(static_cast<GLsizei>(m_texel_buffer_views.size()), m_texel_buffer_views.data());
+ glActiveTexture(GL_MUTABLE_TEXTURE_INDEX);
+ for (const auto& it : format_mapping)
+ {
+ glBindTexture(GL_TEXTURE_BUFFER, m_texel_buffer_views[it.first]);
+ glTexBuffer(GL_TEXTURE_BUFFER, it.second, m_texel_buffer->GetGLBufferId());
+ }
+ }
+
+ return true;
}
void VertexManager::UploadUtilityUniforms(const void* uniforms, u32 uniforms_size)
{
- ProgramShaderCache::InvalidateConstants();
+ InvalidateConstants();
ProgramShaderCache::UploadConstants(uniforms, uniforms_size);
}
-GLuint VertexManager::GetVertexBufferHandle() const
+bool VertexManager::UploadTexelBuffer(const void* data, u32 data_size, TexelBufferFormat format,
+ u32* out_offset)
{
- return m_vertex_buffer->m_buffer;
+ if (data_size > m_texel_buffer->GetSize())
+ return false;
+
+ const u32 elem_size = GetTexelBufferElementSize(format);
+ const auto dst = m_texel_buffer->Map(data_size, elem_size);
+ std::memcpy(dst.first, data, data_size);
+ ADDSTAT(stats.thisFrame.bytesUniformStreamed, data_size);
+ *out_offset = dst.second / elem_size;
+ m_texel_buffer->Unmap(data_size);
+
+ // Bind the correct view to the texel buffer slot.
+ glActiveTexture(GL_TEXTURE0);
+ glBindTexture(GL_TEXTURE_BUFFER, m_texel_buffer_views[static_cast<u32>(format)]);
+ Renderer::GetInstance()->InvalidateTextureBinding(0);
+ return true;
}
-GLuint VertexManager::GetIndexBufferHandle() const
+bool VertexManager::UploadTexelBuffer(const void* data, u32 data_size, TexelBufferFormat format,
+ u32* out_offset, const void* palette_data, u32 palette_size,
+ TexelBufferFormat palette_format, u32* out_palette_offset)
{
- return m_index_buffer->m_buffer;
+ const u32 elem_size = GetTexelBufferElementSize(format);
+ const u32 palette_elem_size = GetTexelBufferElementSize(palette_format);
+ const u32 reserve_size = data_size + palette_size + palette_elem_size;
+ if (reserve_size > m_texel_buffer->GetSize())
+ return false;
+
+ const auto dst = m_texel_buffer->Map(reserve_size, elem_size);
+ const u32 palette_byte_offset = Common::AlignUp(data_size, palette_elem_size);
+ std::memcpy(dst.first, data, data_size);
+ std::memcpy(dst.first + palette_byte_offset, palette_data, palette_size);
+ ADDSTAT(stats.thisFrame.bytesUniformStreamed, palette_byte_offset + palette_size);
+ *out_offset = dst.second / elem_size;
+ *out_palette_offset = (dst.second + palette_byte_offset) / palette_elem_size;
+ m_texel_buffer->Unmap(palette_byte_offset + palette_size);
+
+ glActiveTexture(GL_TEXTURE0);
+ glBindTexture(GL_TEXTURE_BUFFER, m_texel_buffer_views[static_cast<u32>(format)]);
+ Renderer::GetInstance()->InvalidateTextureBinding(0);
+
+ glActiveTexture(GL_TEXTURE1);
+ glBindTexture(GL_TEXTURE_BUFFER, m_texel_buffer_views[static_cast<u32>(palette_format)]);
+ Renderer::GetInstance()->InvalidateTextureBinding(1);
+
+ return true;
}
-static void CheckBufferBinding()
+GLuint VertexManager::GetVertexBufferHandle() const
{
- // The index buffer is part of the VAO state, therefore we need to bind it first.
- if (!ProgramShaderCache::IsValidVertexFormatBound())
- {
- ProgramShaderCache::BindVertexFormat(
- static_cast<GLVertexFormat*>(VertexLoaderManager::GetCurrentVertexFormat()));
- }
+ return m_vertex_buffer->m_buffer;
}
-void VertexManager::ResetBuffer(u32 vertex_stride, bool cull_all)
+GLuint VertexManager::GetIndexBufferHandle() const
{
- if (cull_all)
- {
- // This buffer isn't getting sent to the GPU. Just allocate it on the cpu.
- m_cur_buffer_pointer = m_base_buffer_pointer = m_cpu_v_buffer.data();
- m_end_buffer_pointer = m_base_buffer_pointer + m_cpu_v_buffer.size();
+ return m_index_buffer->m_buffer;
+}
- IndexGenerator::Start((u16*)m_cpu_i_buffer.data());
- }
- else
- {
- CheckBufferBinding();
+void VertexManager::ResetBuffer(u32 vertex_stride)
+{
+ CheckBufferBinding();
- auto buffer = m_vertex_buffer->Map(MAXVBUFFERSIZE, vertex_stride);
- m_cur_buffer_pointer = m_base_buffer_pointer = buffer.first;
- m_end_buffer_pointer = buffer.first + MAXVBUFFERSIZE;
+ auto buffer = m_vertex_buffer->Map(MAXVBUFFERSIZE, vertex_stride);
+ m_cur_buffer_pointer = m_base_buffer_pointer = buffer.first;
+ m_end_buffer_pointer = buffer.first + MAXVBUFFERSIZE;
- buffer = m_index_buffer->Map(MAXIBUFFERSIZE * sizeof(u16));
- IndexGenerator::Start((u16*)buffer.first);
- }
+ buffer = m_index_buffer->Map(MAXIBUFFERSIZE * sizeof(u16));
+ IndexGenerator::Start((u16*)buffer.first);
}
void VertexManager::CommitBuffer(u32 num_vertices, u32 vertex_stride, u32 num_indices,
@@ -120,31 +185,8 @@ void VertexManager::CommitBuffer(u32 num_vertices, u32 vertex_stride, u32 num_in
ADDSTAT(stats.thisFrame.bytesIndexStreamed, index_data_size);
}
-void VertexManager::UploadConstants()
+void VertexManager::UploadUniforms()
{
ProgramShaderCache::UploadConstants();
}
-
-void VertexManager::DrawCurrentBatch(u32 base_index, u32 num_indices, u32 base_vertex)
-{
- if (::BoundingBox::active && !g_Config.BBoxUseFragmentShaderImplementation())
- {
- glEnable(GL_STENCIL_TEST);
- }
-
- if (m_current_pipeline_object)
- {
- static_cast<Renderer*>(g_renderer.get())->SetPipeline(m_current_pipeline_object);
- static_cast<Renderer*>(g_renderer.get())->DrawIndexed(base_index, num_indices, base_vertex);
- }
-
- if (::BoundingBox::active && !g_Config.BBoxUseFragmentShaderImplementation())
- {
- OGL::BoundingBox::StencilWasUpdated();
- glDisable(GL_STENCIL_TEST);
- }
-
- g_Config.iSaveTargetId++;
- ClearEFBCache();
-}
} // namespace OGL
diff --git a/Source/Core/VideoBackends/OGL/VertexManager.h b/Source/Core/VideoBackends/OGL/VertexManager.h
index 388c559716..b9b410855c 100644
--- a/Source/Core/VideoBackends/OGL/VertexManager.h
+++ b/Source/Core/VideoBackends/OGL/VertexManager.h
@@ -4,8 +4,8 @@
#pragma once
+#include <array>
#include <memory>
-#include <vector>
#include "Common/CommonTypes.h"
#include "Common/GL/GLUtil.h"
@@ -26,35 +26,34 @@ public:
// Handles the OpenGL details of drawing lots of vertices quickly.
// Other functionality is moving out.
-class VertexManager : public VertexManagerBase
+class VertexManager final : public VertexManagerBase
{
public:
VertexManager();
- ~VertexManager();
+ ~VertexManager() override;
- std::unique_ptr<NativeVertexFormat>
- CreateNativeVertexFormat(const PortableVertexDeclaration& vtx_decl) override;
+ bool Initialize() override;
void UploadUtilityUniforms(const void* uniforms, u32 uniforms_size) override;
+ bool UploadTexelBuffer(const void* data, u32 data_size, TexelBufferFormat format,
+ u32* out_offset) override;
+ bool UploadTexelBuffer(const void* data, u32 data_size, TexelBufferFormat format, u32* out_offset,
+ const void* palette_data, u32 palette_size,
+ TexelBufferFormat palette_format, u32* out_palette_offset) override;
GLuint GetVertexBufferHandle() const;
GLuint GetIndexBufferHandle() const;
protected:
- void CreateDeviceObjects() override;
- void DestroyDeviceObjects() override;
- void ResetBuffer(u32 vertex_stride, bool cull_all) override;
+ void ResetBuffer(u32 vertex_stride) override;
void CommitBuffer(u32 num_vertices, u32 vertex_stride, u32 num_indices, u32* out_base_vertex,
u32* out_base_index) override;
- void UploadConstants() override;
- void DrawCurrentBatch(u32 base_index, u32 num_indices, u32 base_vertex) override;
+ void UploadUniforms() override;
private:
std::unique_ptr<StreamBuffer> m_vertex_buffer;
std::unique_ptr<StreamBuffer> m_index_buffer;
-
- // Alternative buffers in CPU memory for primatives we are going to discard.
- std::vector<u8> m_cpu_v_buffer;
- std::vector<u16> m_cpu_i_buffer;
+ std::unique_ptr<StreamBuffer> m_texel_buffer;
+ std::array<GLuint, NUM_TEXEL_BUFFER_FORMATS> m_texel_buffer_views{};
};
} // namespace OGL
diff --git a/Source/Core/VideoBackends/OGL/main.cpp b/Source/Core/VideoBackends/OGL/main.cpp
index 3624a7fd7a..76cd7b2ca6 100644
--- a/Source/Core/VideoBackends/OGL/main.cpp
+++ b/Source/Core/VideoBackends/OGL/main.cpp
@@ -50,13 +50,11 @@ Make AA apply instantly during gameplay if possible
#include "VideoBackends/OGL/ProgramShaderCache.h"
#include "VideoBackends/OGL/Render.h"
#include "VideoBackends/OGL/SamplerCache.h"
-#include "VideoBackends/OGL/TextureCache.h"
-#include "VideoBackends/OGL/TextureConverter.h"
#include "VideoBackends/OGL/VertexManager.h"
#include "VideoBackends/OGL/VideoBackend.h"
-#include "VideoCommon/OnScreenDisplay.h"
-#include "VideoCommon/VideoCommon.h"
+#include "VideoCommon/FramebufferManager.h"
+#include "VideoCommon/TextureCacheBase.h"
#include "VideoCommon/VideoConfig.h"
namespace OGL
@@ -78,6 +76,7 @@ void VideoBackend::InitBackendInfo()
{
g_Config.backend_info.api_type = APIType::OpenGL;
g_Config.backend_info.MaxTextureSize = 16384;
+ g_Config.backend_info.bUsesLowerLeftOrigin = true;
g_Config.backend_info.bSupportsExclusiveFullscreen = false;
g_Config.backend_info.bSupportsOversizedViewports = true;
g_Config.backend_info.bSupportsGeometryShaders = true;
@@ -89,6 +88,7 @@ void VideoBackend::InitBackendInfo()
g_Config.backend_info.bSupportsLogicOp = true;
g_Config.backend_info.bSupportsMultithreading = false;
g_Config.backend_info.bSupportsCopyToVram = true;
+ g_Config.backend_info.bSupportsLargePoints = true;
// TODO: There is a bug here, if texel buffers are not supported the graphics options
// will show the option when it is not supported. The only way around this would be
@@ -173,17 +173,26 @@ bool VideoBackend::Initialize(const WindowSystemInfo& wsi)
return false;
g_renderer = std::make_unique<Renderer>(std::move(main_gl_context), wsi.render_surface_scale);
+ ProgramShaderCache::Init();
g_vertex_manager = std::make_unique<VertexManager>();
+ g_shader_cache = std::make_unique<VideoCommon::ShaderCache>();
+ g_framebuffer_manager = std::make_unique<FramebufferManager>();
g_perf_query = GetPerfQuery();
- ProgramShaderCache::Init();
- g_texture_cache = std::make_unique<TextureCache>();
+ g_texture_cache = std::make_unique<TextureCacheBase>();
g_sampler_cache = std::make_unique<SamplerCache>();
- g_shader_cache = std::make_unique<VideoCommon::ShaderCache>();
- if (!g_renderer->Initialize())
+ BoundingBox::Init();
+
+ if (!g_vertex_manager->Initialize() || !g_shader_cache->Initialize() ||
+ !g_renderer->Initialize() || !g_framebuffer_manager->Initialize() ||
+ !g_texture_cache->Initialize())
+ {
+ PanicAlert("Failed to initialize renderer classes");
+ Shutdown();
return false;
- TextureConverter::Init();
- BoundingBox::Init(g_renderer->GetTargetWidth(), g_renderer->GetTargetHeight());
- return g_shader_cache->Initialize();
+ }
+
+ g_shader_cache->InitializeShaderCache();
+ return true;
}
void VideoBackend::Shutdown()
@@ -191,13 +200,13 @@ void VideoBackend::Shutdown()
g_shader_cache->Shutdown();
g_renderer->Shutdown();
BoundingBox::Shutdown();
- TextureConverter::Shutdown();
- g_shader_cache.reset();
g_sampler_cache.reset();
g_texture_cache.reset();
- ProgramShaderCache::Shutdown();
g_perf_query.reset();
g_vertex_manager.reset();
+ g_framebuffer_manager.reset();
+ g_shader_cache.reset();
+ ProgramShaderCache::Shutdown();
g_renderer.reset();
ShutdownShared();
}