diff options
| author | Tilka <tilkax@gmail.com> | 2019-02-26 04:21:05 +0000 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2019-02-26 04:21:05 +0000 |
| commit | 6ce7f44b8a0bb3b95d3f12ebffbef7a71a443fdd (patch) | |
| tree | 98380ce3a3284c52597a6fba86589c847219ecd5 /Source/Core/VideoBackends/OGL | |
| parent | 19673ce79af814ca3b77d7f8ea60458e564bfa51 (diff) | |
| parent | f039149198657c1891e1c6462ed30c31ed4b8486 (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')
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(); } |
