diff --git a/Source/Core/DolphinLib.props b/Source/Core/DolphinLib.props
index bc0f486082..a3d1bbacb7 100644
--- a/Source/Core/DolphinLib.props
+++ b/Source/Core/DolphinLib.props
@@ -569,9 +569,10 @@
+
+
-
@@ -1175,11 +1176,12 @@
+
+
-
diff --git a/Source/Core/VideoBackends/OGL/CMakeLists.txt b/Source/Core/VideoBackends/OGL/CMakeLists.txt
index 9a9d9caf2d..8fb8524054 100644
--- a/Source/Core/VideoBackends/OGL/CMakeLists.txt
+++ b/Source/Core/VideoBackends/OGL/CMakeLists.txt
@@ -2,14 +2,16 @@ add_library(videoogl
GPUTimer.h
OGLBoundingBox.cpp
OGLBoundingBox.h
+ OGLConfig.cpp
+ OGLConfig.h
+ OGLGfx.cpp
+ OGLGfx.h
OGLMain.cpp
OGLNativeVertexFormat.cpp
OGLPerfQuery.cpp
OGLPerfQuery.h
OGLPipeline.cpp
OGLPipeline.h
- OGLRender.cpp
- OGLRender.h
OGLShader.cpp
OGLShader.h
OGLStreamBuffer.cpp
diff --git a/Source/Core/VideoBackends/OGL/OGLBoundingBox.cpp b/Source/Core/VideoBackends/OGL/OGLBoundingBox.cpp
index b0f7139782..d21326c1f5 100644
--- a/Source/Core/VideoBackends/OGL/OGLBoundingBox.cpp
+++ b/Source/Core/VideoBackends/OGL/OGLBoundingBox.cpp
@@ -3,7 +3,7 @@
#include "VideoBackends/OGL/OGLBoundingBox.h"
-#include "VideoBackends/OGL/OGLRender.h"
+#include "VideoBackends/OGL/OGLGfx.h"
#include "VideoCommon/DriverDetails.h"
namespace OGL
@@ -35,7 +35,7 @@ std::vector OGLBoundingBox::Read(u32 index, u32 length)
// on nVidia drivers. This is more noticeable at higher internal resolutions.
// Using glGetBufferSubData instead does not seem to exhibit this slowdown.
if (!DriverDetails::HasBug(DriverDetails::BUG_SLOW_GETBUFFERSUBDATA) &&
- !static_cast(g_renderer.get())->IsGLES())
+ !static_cast(g_gfx.get())->IsGLES())
{
// We also need to ensure the the CPU does not receive stale values which have been updated by
// the GPU. Apparently the buffer here is not coherent on NVIDIA drivers. Not sure if this is a
diff --git a/Source/Core/VideoBackends/OGL/OGLRender.cpp b/Source/Core/VideoBackends/OGL/OGLConfig.cpp
similarity index 53%
rename from Source/Core/VideoBackends/OGL/OGLRender.cpp
rename to Source/Core/VideoBackends/OGL/OGLConfig.cpp
index fba72ba11b..bafc28841d 100644
--- a/Source/Core/VideoBackends/OGL/OGLRender.cpp
+++ b/Source/Core/VideoBackends/OGL/OGLConfig.cpp
@@ -1,136 +1,26 @@
-// Copyright 2008 Dolphin Emulator Project
+// Copyright 2023 Dolphin Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
-#include "VideoBackends/OGL/OGLRender.h"
+#include "VideoBackends/OGL/OGLConfig.h"
-#include
-#include
-#include
-#include
-#include
-
-#include "Common/CommonTypes.h"
#include "Common/GL/GLContext.h"
-#include "Common/GL/GLUtil.h"
+#include "Common/GL/GLExtensions/GLExtensions.h"
#include "Common/Logging/LogManager.h"
-#include "Common/MathUtil.h"
#include "Common/MsgHandler.h"
-#include "Common/StringUtil.h"
#include "Core/Config/GraphicsSettings.h"
-#include "VideoBackends/OGL/OGLBoundingBox.h"
-#include "VideoBackends/OGL/OGLPipeline.h"
-#include "VideoBackends/OGL/OGLShader.h"
-#include "VideoBackends/OGL/OGLTexture.h"
-#include "VideoBackends/OGL/OGLVertexManager.h"
-#include "VideoBackends/OGL/ProgramShaderCache.h"
-#include "VideoBackends/OGL/SamplerCache.h"
-
-#include "VideoCommon/BPFunctions.h"
#include "VideoCommon/DriverDetails.h"
-#include "VideoCommon/FramebufferManager.h"
#include "VideoCommon/OnScreenDisplay.h"
-#include "VideoCommon/PostProcessing.h"
-#include "VideoCommon/Present.h"
-#include "VideoCommon/RenderState.h"
-#include "VideoCommon/VideoCommon.h"
#include "VideoCommon/VideoConfig.h"
+#include
+#include
+#include
+
namespace OGL
{
-VideoConfig g_ogl_config;
-
-static void APIENTRY ErrorCallback(GLenum source, GLenum type, GLuint id, GLenum severity,
- GLsizei length, const char* message, const void* userParam)
-{
- const char* s_source;
- const char* s_type;
-
- // Performance - DualCore driver performance warning:
- // DualCore application thread syncing with server thread
- if (id == 0x200b0)
- return;
-
- switch (source)
- {
- case GL_DEBUG_SOURCE_API_ARB:
- s_source = "API";
- break;
- case GL_DEBUG_SOURCE_WINDOW_SYSTEM_ARB:
- s_source = "Window System";
- break;
- case GL_DEBUG_SOURCE_SHADER_COMPILER_ARB:
- s_source = "Shader Compiler";
- break;
- case GL_DEBUG_SOURCE_THIRD_PARTY_ARB:
- s_source = "Third Party";
- break;
- case GL_DEBUG_SOURCE_APPLICATION_ARB:
- s_source = "Application";
- break;
- case GL_DEBUG_SOURCE_OTHER_ARB:
- s_source = "Other";
- break;
- default:
- s_source = "Unknown";
- break;
- }
- switch (type)
- {
- case GL_DEBUG_TYPE_ERROR_ARB:
- s_type = "Error";
- break;
- case GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR_ARB:
- s_type = "Deprecated";
- break;
- case GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR_ARB:
- s_type = "Undefined";
- break;
- case GL_DEBUG_TYPE_PORTABILITY_ARB:
- s_type = "Portability";
- break;
- case GL_DEBUG_TYPE_PERFORMANCE_ARB:
- s_type = "Performance";
- break;
- case GL_DEBUG_TYPE_OTHER_ARB:
- s_type = "Other";
- break;
- default:
- s_type = "Unknown";
- break;
- }
- switch (severity)
- {
- case GL_DEBUG_SEVERITY_HIGH_ARB:
- ERROR_LOG_FMT(HOST_GPU, "id: {:x}, source: {}, type: {} - {}", id, s_source, s_type, message);
- break;
- case GL_DEBUG_SEVERITY_MEDIUM_ARB:
- WARN_LOG_FMT(HOST_GPU, "id: {:x}, source: {}, type: {} - {}", id, s_source, s_type, message);
- break;
- case GL_DEBUG_SEVERITY_LOW_ARB:
- DEBUG_LOG_FMT(HOST_GPU, "id: {:x}, source: {}, type: {} - {}", id, s_source, s_type, message);
- break;
- case GL_DEBUG_SEVERITY_NOTIFICATION:
- DEBUG_LOG_FMT(HOST_GPU, "id: {:x}, source: {}, type: {} - {}", id, s_source, s_type, message);
- break;
- default:
- ERROR_LOG_FMT(HOST_GPU, "id: {:x}, source: {}, type: {} - {}", id, s_source, s_type, message);
- break;
- }
-}
-
-// Two small Fallbacks to avoid GL_ARB_ES2_compatibility
-static void APIENTRY DepthRangef(GLfloat neardepth, GLfloat fardepth)
-{
- glDepthRange(neardepth, fardepth);
-}
-static void APIENTRY ClearDepthf(GLfloat depthval)
-{
- glClearDepth(depthval);
-}
-
-static void InitDriverInfo()
+void InitDriverInfo()
{
const std::string_view svendor(g_ogl_config.gl_vendor);
const std::string_view srenderer(g_ogl_config.gl_renderer);
@@ -320,26 +210,8 @@ static void InitDriverInfo()
DriverDetails::Init(DriverDetails::API_OPENGL, vendor, driver, version, family);
}
-// Init functions
-Renderer::Renderer(std::unique_ptr main_gl_context, float backbuffer_scale)
- : ::Renderer(static_cast(std::max(main_gl_context->GetBackBufferWidth(), 1u)),
- static_cast(std::max(main_gl_context->GetBackBufferHeight(), 1u)),
- backbuffer_scale, AbstractTextureFormat::RGBA8),
- m_main_gl_context(std::move(main_gl_context)),
- m_current_rasterization_state(RenderState::GetInvalidRasterizationState()),
- m_current_depth_state(RenderState::GetInvalidDepthState()),
- m_current_blend_state(RenderState::GetInvalidBlendingState())
+bool PopulateConfig(GLContext* m_main_gl_context)
{
- // Create the window framebuffer.
- if (!m_main_gl_context->IsHeadless())
- {
- m_system_framebuffer = std::make_unique(
- 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;
bool supports_glsl_cache = false;
@@ -347,8 +219,6 @@ Renderer::Renderer(std::unique_ptr main_gl_context, float backbuffer_
g_ogl_config.gl_renderer = (const char*)glGetString(GL_RENDERER);
g_ogl_config.gl_version = (const char*)glGetString(GL_VERSION);
- InitDriverInfo();
-
if (!m_main_gl_context->IsGLES())
{
if (!GLExtensions::Supports("GL_ARB_framebuffer_object"))
@@ -402,15 +272,6 @@ Renderer::Renderer(std::unique_ptr main_gl_context, float backbuffer_
"GPU: Does your video card support OpenGL 3.3?");
bSuccess = false;
}
-
- // OpenGL 3 doesn't provide GLES like float functions for depth.
- // They are in core in OpenGL 4.1, so almost every driver should support them.
- // But for the oldest ones, we provide fallbacks to the old double functions.
- if (!GLExtensions::Supports("GL_ARB_ES2_compatibility"))
- {
- glDepthRangef = DepthRangef;
- glClearDepthf = ClearDepthf;
- }
}
// Copy the GPU name to g_Config, so Analytics can see it.
@@ -694,29 +555,6 @@ Renderer::Renderer(std::unique_ptr main_gl_context, float backbuffer_
}
g_Config.backend_info.bSupportsPipelineCacheData = supports_glsl_cache;
- if (g_ogl_config.bSupportsDebug)
- {
- if (GLExtensions::Supports("GL_KHR_debug"))
- {
- glDebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, nullptr, true);
- glDebugMessageCallback(ErrorCallback, nullptr);
- }
- else
- {
- glDebugMessageControlARB(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, nullptr, true);
- glDebugMessageCallbackARB(ErrorCallback, nullptr);
- }
- if (Common::Log::LogManager::GetInstance()->IsEnabled(Common::Log::LogType::HOST_GPU,
- Common::Log::LogLevel::LERROR))
- {
- glEnable(GL_DEBUG_OUTPUT);
- }
- else
- {
- glDisable(GL_DEBUG_OUTPUT);
- }
- }
-
int samples;
glGetIntegerv(GL_SAMPLES, &samples);
if (samples > 1)
@@ -733,11 +571,7 @@ Renderer::Renderer(std::unique_ptr main_gl_context, float backbuffer_
}
if (!bSuccess)
- {
- // Not all needed extensions are supported, so we have to stop here.
- // Else some of the next calls might crash.
- return;
- }
+ return false;
g_Config.VerifyValidity();
UpdateActiveConfig();
@@ -772,565 +606,7 @@ Renderer::Renderer(std::unique_ptr main_gl_context, float backbuffer_
g_ogl_config.bSupportsCopySubImage ? "" : "CopyImageSubData ",
g_ActiveConfig.backend_info.bSupportsDepthClamp ? "" : "DepthClamp ");
- // Handle VSync on/off
- if (!DriverDetails::HasBug(DriverDetails::BUG_BROKEN_VSYNC))
- m_main_gl_context->SwapInterval(g_ActiveConfig.bVSyncActive);
-
- if (g_ActiveConfig.backend_info.bSupportsClipControl)
- glClipControl(GL_LOWER_LEFT, GL_ZERO_TO_ONE);
-
- if (g_ActiveConfig.backend_info.bSupportsDepthClamp)
- {
- glEnable(GL_CLIP_DISTANCE0);
- glEnable(GL_CLIP_DISTANCE1);
- glEnable(GL_DEPTH_CLAMP);
- }
-
- glPixelStorei(GL_UNPACK_ALIGNMENT, 4); // 4-byte pixel alignment
-
- 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());
-
- UpdateActiveConfig();
-}
-
-Renderer::~Renderer() = default;
-
-bool Renderer::IsHeadless() const
-{
- return m_main_gl_context->IsHeadless();
-}
-
-bool Renderer::Initialize()
-{
- if (!::Renderer::Initialize())
- return false;
-
return true;
}
-void Renderer::Shutdown()
-{
- ::Renderer::Shutdown();
-
- glDeleteFramebuffers(1, &m_shared_draw_framebuffer);
- glDeleteFramebuffers(1, &m_shared_read_framebuffer);
-}
-
-std::unique_ptr Renderer::CreateTexture(const TextureConfig& config,
- std::string_view name)
-{
- return std::make_unique(config, name);
-}
-
-std::unique_ptr Renderer::CreateStagingTexture(StagingTextureType type,
- const TextureConfig& config)
-{
- return OGLStagingTexture::Create(type, config);
-}
-
-std::unique_ptr Renderer::CreateFramebuffer(AbstractTexture* color_attachment,
- AbstractTexture* depth_attachment)
-{
- return OGLFramebuffer::Create(static_cast(color_attachment),
- static_cast(depth_attachment));
-}
-
-std::unique_ptr
-Renderer::CreateShaderFromSource(ShaderStage stage, std::string_view source, std::string_view name)
-{
- return OGLShader::CreateFromSource(stage, source, name);
-}
-
-std::unique_ptr
-Renderer::CreateShaderFromBinary(ShaderStage stage, const void* data, size_t length,
- [[maybe_unused]] std::string_view name)
-{
- return nullptr;
-}
-
-std::unique_ptr Renderer::CreatePipeline(const AbstractPipelineConfig& config,
- const void* cache_data,
- size_t cache_data_length)
-{
- return OGLPipeline::Create(config, cache_data, cache_data_length);
-}
-
-void Renderer::SetScissorRect(const MathUtil::Rectangle& rc)
-{
- glScissor(rc.left, rc.top, rc.GetWidth(), rc.GetHeight());
-}
-
-std::unique_ptr<::BoundingBox> Renderer::CreateBoundingBox() const
-{
- return std::make_unique();
-}
-
-void Renderer::SetViewport(float x, float y, float width, float height, float near_depth,
- float far_depth)
-{
- if (g_ogl_config.bSupportViewportFloat)
- {
- glViewportIndexedf(0, x, y, width, height);
- }
- else
- {
- auto iceilf = [](float f) { return static_cast(std::ceil(f)); };
- glViewport(iceilf(x), iceilf(y), iceilf(width), iceilf(height));
- }
-
- glDepthRangef(near_depth, far_depth);
-}
-
-void Renderer::Draw(u32 base_vertex, u32 num_vertices)
-{
- glDrawArrays(static_cast(m_current_pipeline)->GetGLPrimitive(), base_vertex,
- num_vertices);
-}
-
-void Renderer::DrawIndexed(u32 base_index, u32 num_indices, u32 base_vertex)
-{
- if (g_ogl_config.bSupportsGLBaseVertex)
- {
- glDrawElementsBaseVertex(static_cast(m_current_pipeline)->GetGLPrimitive(),
- num_indices, GL_UNSIGNED_SHORT,
- static_cast(nullptr) + base_index, base_vertex);
- }
- else
- {
- glDrawElements(static_cast(m_current_pipeline)->GetGLPrimitive(),
- num_indices, GL_UNSIGNED_SHORT, static_cast(nullptr) + base_index);
- }
-}
-
-void Renderer::DispatchComputeShader(const AbstractShader* shader, u32 groupsize_x, u32 groupsize_y,
- u32 groupsize_z, u32 groups_x, u32 groups_y, u32 groups_z)
-{
- glUseProgram(static_cast(shader)->GetGLComputeProgramID());
- glDispatchCompute(groups_x, groups_y, groups_z);
-
- // We messed up the program binding, so restore it.
- ProgramShaderCache::InvalidateLastProgram();
- if (m_current_pipeline)
- static_cast(m_current_pipeline)->GetProgram()->shader.Bind();
-
- // Barrier to texture can be used for reads.
- if (m_bound_image_texture)
- glMemoryBarrier(GL_TEXTURE_UPDATE_BARRIER_BIT);
-}
-
-void Renderer::ClearScreen(const MathUtil::Rectangle& rc, bool colorEnable, bool alphaEnable,
- bool zEnable, u32 color, u32 z)
-{
- g_framebuffer_manager->FlushEFBPokes();
- g_framebuffer_manager->FlagPeekCacheAsOutOfDate();
-
- 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
- // glColorMask/glDepthMask/glScissor affect glClear (glViewport does not)
- const auto converted_target_rc =
- ConvertFramebufferRectangle(ConvertEFBRectangle(rc), m_current_framebuffer);
- SetScissorRect(converted_target_rc);
-
- glClear(clear_mask);
-
- // 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::SetScissorAndViewport();
-}
-
-void Renderer::SelectLeftBuffer()
-{
- glDrawBuffer(GL_BACK_LEFT);
-}
-
-void Renderer::SelectRightBuffer()
-{
- glDrawBuffer(GL_BACK_RIGHT);
-}
-
-void Renderer::SelectMainBuffer()
-{
- glDrawBuffer(GL_BACK);
-}
-
-void Renderer::SetFramebuffer(AbstractFramebuffer* framebuffer)
-{
- if (m_current_framebuffer == framebuffer)
- return;
-
- glBindFramebuffer(GL_FRAMEBUFFER, static_cast(framebuffer)->GetFBO());
- m_current_framebuffer = framebuffer;
-}
-
-void Renderer::SetAndDiscardFramebuffer(AbstractFramebuffer* framebuffer)
-{
- // EXT_discard_framebuffer could be used here to save bandwidth on tilers.
- SetFramebuffer(framebuffer);
-}
-
-void Renderer::SetAndClearFramebuffer(AbstractFramebuffer* framebuffer,
- const ClearColor& color_value, float depth_value)
-{
- SetFramebuffer(framebuffer);
-
- glDisable(GL_SCISSOR_TEST);
- GLbitfield clear_mask = 0;
- if (framebuffer->HasColorBuffer())
- {
- glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
- glClearColor(color_value[0], color_value[1], color_value[2], color_value[3]);
- clear_mask |= GL_COLOR_BUFFER_BIT;
- }
- if (framebuffer->HasDepthBuffer())
- {
- glDepthMask(GL_TRUE);
- glClearDepthf(depth_value);
- clear_mask |= GL_DEPTH_BUFFER_BIT;
- }
- glClear(clear_mask);
- glEnable(GL_SCISSOR_TEST);
-
- // Restore color/depth mask.
- if (framebuffer->HasColorBuffer())
- {
- glColorMask(m_current_blend_state.colorupdate, m_current_blend_state.colorupdate,
- m_current_blend_state.colorupdate, m_current_blend_state.alphaupdate);
- }
- if (framebuffer->HasDepthBuffer())
- glDepthMask(m_current_depth_state.updateenable);
-}
-
-void Renderer::BindBackbuffer(const ClearColor& clear_color)
-{
- CheckForSurfaceChange();
- CheckForSurfaceResize();
- SetAndClearFramebuffer(m_system_framebuffer.get(), clear_color);
-}
-
-void Renderer::PresentBackbuffer()
-{
- if (g_ogl_config.bSupportsDebug)
- {
- if (Common::Log::LogManager::GetInstance()->IsEnabled(Common::Log::LogType::HOST_GPU,
- Common::Log::LogLevel::LERROR))
- {
- glEnable(GL_DEBUG_OUTPUT);
- }
- else
- {
- glDisable(GL_DEBUG_OUTPUT);
- }
- }
-
- // Swap the back and front buffers, presenting the image.
- m_main_gl_context->Swap();
-}
-
-void Renderer::OnConfigChanged(u32 bits)
-{
- if (bits & CONFIG_CHANGE_BIT_VSYNC && !DriverDetails::HasBug(DriverDetails::BUG_BROKEN_VSYNC))
- m_main_gl_context->SwapInterval(g_ActiveConfig.bVSyncActive);
-
- if (bits & CONFIG_CHANGE_BIT_ANISOTROPY)
- g_sampler_cache->Clear();
-}
-
-void Renderer::Flush()
-{
- // ensure all commands are sent to the GPU.
- // Otherwise the driver could batch several frames together.
- glFlush();
-}
-
-void Renderer::WaitForGPUIdle()
-{
- glFinish();
-}
-
-void Renderer::CheckForSurfaceChange()
-{
- if (!g_presenter->SurfaceChangedTestAndClear())
- return;
-
- m_main_gl_context->UpdateSurface(g_presenter->GetNewSurfaceHandle());
-
- u32 width = m_main_gl_context->GetBackBufferWidth();
- u32 height = m_main_gl_context->GetBackBufferHeight();
-
- // With a surface change, the window likely has new dimensions.
- g_presenter->SetBackbuffer(width, height);
- m_system_framebuffer->UpdateDimensions(width, height);
-}
-
-void Renderer::CheckForSurfaceResize()
-{
- if (!g_presenter->SurfaceResizedTestAndClear())
- return;
-
- m_main_gl_context->Update();
- u32 width = m_main_gl_context->GetBackBufferWidth();
- u32 height = m_main_gl_context->GetBackBufferHeight();
- g_presenter->SetBackbuffer(width, height);
- m_system_framebuffer->UpdateDimensions(width, height);
-}
-
-void Renderer::BeginUtilityDrawing()
-{
- ::Renderer::BeginUtilityDrawing();
- if (g_ActiveConfig.backend_info.bSupportsDepthClamp)
- {
- glDisable(GL_CLIP_DISTANCE0);
- glDisable(GL_CLIP_DISTANCE1);
- }
-}
-
-void Renderer::EndUtilityDrawing()
-{
- ::Renderer::EndUtilityDrawing();
- if (g_ActiveConfig.backend_info.bSupportsDepthClamp)
- {
- glEnable(GL_CLIP_DISTANCE0);
- glEnable(GL_CLIP_DISTANCE1);
- }
-}
-
-void Renderer::ApplyRasterizationState(const RasterizationState state)
-{
- if (m_current_rasterization_state == state)
- return;
-
- // none, ccw, cw, ccw
- if (state.cullmode != CullMode::None)
- {
- // TODO: GX_CULL_ALL not supported, yet!
- glEnable(GL_CULL_FACE);
- glFrontFace(state.cullmode == CullMode::Front ? GL_CCW : GL_CW);
- }
- else
- {
- glDisable(GL_CULL_FACE);
- }
-
- m_current_rasterization_state = state;
-}
-
-void Renderer::ApplyDepthState(const DepthState state)
-{
- if (m_current_depth_state == state)
- return;
-
- const GLenum glCmpFuncs[8] = {GL_NEVER, GL_LESS, GL_EQUAL, GL_LEQUAL,
- GL_GREATER, GL_NOTEQUAL, GL_GEQUAL, GL_ALWAYS};
-
- if (state.testenable)
- {
- glEnable(GL_DEPTH_TEST);
- glDepthMask(state.updateenable ? GL_TRUE : GL_FALSE);
- glDepthFunc(glCmpFuncs[u32(state.func.Value())]);
- }
- else
- {
- // if the test is disabled write is disabled too
- // TODO: When PE performance metrics are being emulated via occlusion queries, we should
- // (probably?) enable depth test with depth function ALWAYS here
- glDisable(GL_DEPTH_TEST);
- glDepthMask(GL_FALSE);
- }
-
- m_current_depth_state = state;
-}
-
-void Renderer::ApplyBlendingState(const BlendingState state)
-{
- if (m_current_blend_state == state)
- return;
-
- bool useDualSource = state.usedualsrc;
-
- 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[u32(state.srcfactor.Value())],
- dst_factors[u32(state.dstfactor.Value())],
- src_factors[u32(state.srcfactoralpha.Value())],
- dst_factors[u32(state.dstfactoralpha.Value())]);
-
- 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[u32(state.logicmode.Value())]);
- }
- 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)
-{
- if (m_current_pipeline == pipeline)
- return;
-
- if (pipeline)
- {
- ApplyRasterizationState(static_cast(pipeline)->GetRasterizationState());
- ApplyDepthState(static_cast(pipeline)->GetDepthState());
- ApplyBlendingState(static_cast(pipeline)->GetBlendingState());
- ProgramShaderCache::BindVertexFormat(
- static_cast(pipeline)->GetVertexFormat());
- static_cast(pipeline)->GetProgram()->shader.Bind();
- }
- else
- {
- ProgramShaderCache::InvalidateLastProgram();
- glUseProgram(0);
- }
- m_current_pipeline = pipeline;
-}
-
-void Renderer::SetTexture(u32 index, const AbstractTexture* texture)
-{
- const OGLTexture* gl_texture = static_cast(texture);
- if (m_bound_textures[index] == gl_texture)
- return;
-
- glActiveTexture(GL_TEXTURE0 + index);
- 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)
-{
- 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(texture)->GetGLTextureId(), 0, GL_TRUE, 0,
- access, static_cast(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++)
- {
- if (m_bound_textures[i] != texture)
- continue;
-
- glActiveTexture(static_cast(GL_TEXTURE0 + i));
- glBindTexture(GL_TEXTURE_2D_ARRAY, 0);
- m_bound_textures[i] = nullptr;
- }
-
- 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 Renderer::CreateAsyncShaderCompiler()
-{
- return std::make_unique();
-}
-
-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(m_current_framebuffer)->GetFBO() : 0);
-}
-
} // namespace OGL
diff --git a/Source/Core/VideoBackends/OGL/OGLConfig.h b/Source/Core/VideoBackends/OGL/OGLConfig.h
new file mode 100644
index 0000000000..eb3d20e70c
--- /dev/null
+++ b/Source/Core/VideoBackends/OGL/OGLConfig.h
@@ -0,0 +1,78 @@
+// Copyright 2023 Dolphin Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#pragma once
+
+#include "Common/CommonTypes.h"
+
+class GLContext;
+
+namespace OGL
+{
+enum GlslVersion
+{
+ Glsl130,
+ Glsl140,
+ Glsl150,
+ Glsl330,
+ Glsl400, // and above
+ Glsl430,
+ GlslEs300, // GLES 3.0
+ GlslEs310, // GLES 3.1
+ GlslEs320, // GLES 3.2
+};
+enum class EsTexbufType
+{
+ TexbufNone,
+ TexbufCore,
+ TexbufOes,
+ TexbufExt
+};
+
+enum class EsFbFetchType
+{
+ FbFetchNone,
+ FbFetchExt,
+ FbFetchArm,
+};
+
+// ogl-only config, so not in VideoConfig.h
+struct VideoConfig
+{
+ bool bIsES;
+ bool bSupportsGLPinnedMemory;
+ bool bSupportsGLSync;
+ bool bSupportsGLBaseVertex;
+ bool bSupportsGLBufferStorage;
+ bool bSupportsMSAA;
+ GlslVersion eSupportedGLSLVersion;
+ bool bSupportViewportFloat;
+ bool bSupportsAEP;
+ bool bSupportsDebug;
+ bool bSupportsCopySubImage;
+ u8 SupportedESPointSize;
+ EsTexbufType SupportedESTextureBuffer;
+ bool bSupportsTextureStorage;
+ bool bSupports2DTextureStorageMultisample;
+ bool bSupports3DTextureStorageMultisample;
+ bool bSupportsConservativeDepth;
+ bool bSupportsImageLoadStore;
+ bool bSupportsAniso;
+ bool bSupportsBitfield;
+ bool bSupportsTextureSubImage;
+ EsFbFetchType SupportedFramebufferFetch;
+ bool bSupportsShaderThreadShuffleNV;
+
+ const char* gl_vendor;
+ const char* gl_renderer;
+ const char* gl_version;
+
+ s32 max_samples;
+};
+
+void InitDriverInfo();
+bool PopulateConfig(GLContext* main_gl_context);
+
+extern VideoConfig g_ogl_config;
+
+} // namespace OGL
\ No newline at end of file
diff --git a/Source/Core/VideoBackends/OGL/OGLGfx.cpp b/Source/Core/VideoBackends/OGL/OGLGfx.cpp
new file mode 100644
index 0000000000..88e544c235
--- /dev/null
+++ b/Source/Core/VideoBackends/OGL/OGLGfx.cpp
@@ -0,0 +1,730 @@
+// Copyright 2023 Dolphin Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "VideoBackends/OGL/OGLGfx.h"
+
+#include "Common/GL/GLContext.h"
+#include "Common/GL/GLExtensions/GLExtensions.h"
+#include "Common/Logging/LogManager.h"
+
+#include "Core/Config/GraphicsSettings.h"
+
+#include "VideoBackends/OGL/OGLConfig.h"
+#include "VideoBackends/OGL/OGLPipeline.h"
+#include "VideoBackends/OGL/OGLShader.h"
+#include "VideoBackends/OGL/OGLTexture.h"
+#include "VideoBackends/OGL/ProgramShaderCache.h"
+#include "VideoBackends/OGL/SamplerCache.h"
+
+#include "VideoCommon/AsyncShaderCompiler.h"
+#include "VideoCommon/DriverDetails.h"
+#include "VideoCommon/OnScreenDisplay.h"
+#include "VideoCommon/Present.h"
+#include "VideoCommon/VideoConfig.h"
+
+#include
+
+namespace OGL
+{
+VideoConfig g_ogl_config;
+
+static void APIENTRY ErrorCallback(GLenum source, GLenum type, GLuint id, GLenum severity,
+ GLsizei length, const char* message, const void* userParam)
+{
+ const char* s_source;
+ const char* s_type;
+
+ // Performance - DualCore driver performance warning:
+ // DualCore application thread syncing with server thread
+ if (id == 0x200b0)
+ return;
+
+ switch (source)
+ {
+ case GL_DEBUG_SOURCE_API_ARB:
+ s_source = "API";
+ break;
+ case GL_DEBUG_SOURCE_WINDOW_SYSTEM_ARB:
+ s_source = "Window System";
+ break;
+ case GL_DEBUG_SOURCE_SHADER_COMPILER_ARB:
+ s_source = "Shader Compiler";
+ break;
+ case GL_DEBUG_SOURCE_THIRD_PARTY_ARB:
+ s_source = "Third Party";
+ break;
+ case GL_DEBUG_SOURCE_APPLICATION_ARB:
+ s_source = "Application";
+ break;
+ case GL_DEBUG_SOURCE_OTHER_ARB:
+ s_source = "Other";
+ break;
+ default:
+ s_source = "Unknown";
+ break;
+ }
+ switch (type)
+ {
+ case GL_DEBUG_TYPE_ERROR_ARB:
+ s_type = "Error";
+ break;
+ case GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR_ARB:
+ s_type = "Deprecated";
+ break;
+ case GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR_ARB:
+ s_type = "Undefined";
+ break;
+ case GL_DEBUG_TYPE_PORTABILITY_ARB:
+ s_type = "Portability";
+ break;
+ case GL_DEBUG_TYPE_PERFORMANCE_ARB:
+ s_type = "Performance";
+ break;
+ case GL_DEBUG_TYPE_OTHER_ARB:
+ s_type = "Other";
+ break;
+ default:
+ s_type = "Unknown";
+ break;
+ }
+ switch (severity)
+ {
+ case GL_DEBUG_SEVERITY_HIGH_ARB:
+ ERROR_LOG_FMT(HOST_GPU, "id: {:x}, source: {}, type: {} - {}", id, s_source, s_type, message);
+ break;
+ case GL_DEBUG_SEVERITY_MEDIUM_ARB:
+ WARN_LOG_FMT(HOST_GPU, "id: {:x}, source: {}, type: {} - {}", id, s_source, s_type, message);
+ break;
+ case GL_DEBUG_SEVERITY_LOW_ARB:
+ DEBUG_LOG_FMT(HOST_GPU, "id: {:x}, source: {}, type: {} - {}", id, s_source, s_type, message);
+ break;
+ case GL_DEBUG_SEVERITY_NOTIFICATION:
+ DEBUG_LOG_FMT(HOST_GPU, "id: {:x}, source: {}, type: {} - {}", id, s_source, s_type, message);
+ break;
+ default:
+ ERROR_LOG_FMT(HOST_GPU, "id: {:x}, source: {}, type: {} - {}", id, s_source, s_type, message);
+ break;
+ }
+}
+
+// Two small Fallbacks to avoid GL_ARB_ES2_compatibility
+static void APIENTRY DepthRangef(GLfloat neardepth, GLfloat fardepth)
+{
+ glDepthRange(neardepth, fardepth);
+}
+static void APIENTRY ClearDepthf(GLfloat depthval)
+{
+ glClearDepth(depthval);
+}
+
+OGLGfx::OGLGfx(std::unique_ptr main_gl_context, float backbuffer_scale)
+ : m_main_gl_context(std::move(main_gl_context)),
+ m_current_rasterization_state(RenderState::GetInvalidRasterizationState()),
+ m_current_depth_state(RenderState::GetInvalidDepthState()),
+ m_current_blend_state(RenderState::GetInvalidBlendingState()),
+ m_backbuffer_scale(backbuffer_scale)
+{
+ // Create the window framebuffer.
+ if (!m_main_gl_context->IsHeadless())
+ {
+ m_system_framebuffer = std::make_unique(
+ 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();
+ }
+
+ if (m_main_gl_context->IsGLES())
+ {
+ // OpenGL 3 doesn't provide GLES like float functions for depth.
+ // They are in core in OpenGL 4.1, so almost every driver should support them.
+ // But for the oldest ones, we provide fallbacks to the old double functions.
+ if (!GLExtensions::Supports("GL_ARB_ES2_compatibility"))
+ {
+ glDepthRangef = DepthRangef;
+ glClearDepthf = ClearDepthf;
+ }
+ }
+
+ if (!PopulateConfig(m_main_gl_context.get()))
+ {
+ // Not all needed extensions are supported, so we have to stop here.
+ // Else some of the next calls might crash.
+ return;
+ }
+ InitDriverInfo();
+
+ // Setup Debug logging
+ if (g_ogl_config.bSupportsDebug)
+ {
+ if (GLExtensions::Supports("GL_KHR_debug"))
+ {
+ glDebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, nullptr, true);
+ glDebugMessageCallback(ErrorCallback, nullptr);
+ }
+ else
+ {
+ glDebugMessageControlARB(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, nullptr, true);
+ glDebugMessageCallbackARB(ErrorCallback, nullptr);
+ }
+ if (Common::Log::LogManager::GetInstance()->IsEnabled(Common::Log::LogType::HOST_GPU,
+ Common::Log::LogLevel::LERROR))
+ {
+ glEnable(GL_DEBUG_OUTPUT);
+ }
+ else
+ {
+ glDisable(GL_DEBUG_OUTPUT);
+ }
+ }
+
+ // Handle VSync on/off
+ if (!DriverDetails::HasBug(DriverDetails::BUG_BROKEN_VSYNC))
+ m_main_gl_context->SwapInterval(g_ActiveConfig.bVSyncActive);
+
+ if (g_ActiveConfig.backend_info.bSupportsClipControl)
+ glClipControl(GL_LOWER_LEFT, GL_ZERO_TO_ONE);
+
+ if (g_ActiveConfig.backend_info.bSupportsDepthClamp)
+ {
+ glEnable(GL_CLIP_DISTANCE0);
+ glEnable(GL_CLIP_DISTANCE1);
+ glEnable(GL_DEPTH_CLAMP);
+ }
+
+ glPixelStorei(GL_UNPACK_ALIGNMENT, 4); // 4-byte pixel alignment
+
+ 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());
+
+ UpdateActiveConfig();
+}
+
+OGLGfx::~OGLGfx()
+{
+ glDeleteFramebuffers(1, &m_shared_draw_framebuffer);
+ glDeleteFramebuffers(1, &m_shared_read_framebuffer);
+}
+
+bool OGLGfx::IsHeadless() const
+{
+ return m_main_gl_context->IsHeadless();
+}
+
+std::unique_ptr OGLGfx::CreateTexture(const TextureConfig& config,
+ std::string_view name)
+{
+ return std::make_unique(config, name);
+}
+
+std::unique_ptr OGLGfx::CreateStagingTexture(StagingTextureType type,
+ const TextureConfig& config)
+{
+ return OGLStagingTexture::Create(type, config);
+}
+
+std::unique_ptr OGLGfx::CreateFramebuffer(AbstractTexture* color_attachment,
+ AbstractTexture* depth_attachment)
+{
+ return OGLFramebuffer::Create(static_cast(color_attachment),
+ static_cast(depth_attachment));
+}
+
+std::unique_ptr
+OGLGfx::CreateShaderFromSource(ShaderStage stage, std::string_view source, std::string_view name)
+{
+ return OGLShader::CreateFromSource(stage, source, name);
+}
+
+std::unique_ptr
+OGLGfx::CreateShaderFromBinary(ShaderStage stage, const void* data, size_t length,
+ [[maybe_unused]] std::string_view name)
+{
+ return nullptr;
+}
+
+std::unique_ptr OGLGfx::CreatePipeline(const AbstractPipelineConfig& config,
+ const void* cache_data,
+ size_t cache_data_length)
+{
+ return OGLPipeline::Create(config, cache_data, cache_data_length);
+}
+
+void OGLGfx::SetScissorRect(const MathUtil::Rectangle& rc)
+{
+ glScissor(rc.left, rc.top, rc.GetWidth(), rc.GetHeight());
+}
+
+void OGLGfx::SetViewport(float x, float y, float width, float height, float near_depth,
+ float far_depth)
+{
+ if (g_ogl_config.bSupportViewportFloat)
+ {
+ glViewportIndexedf(0, x, y, width, height);
+ }
+ else
+ {
+ auto iceilf = [](float f) { return static_cast(std::ceil(f)); };
+ glViewport(iceilf(x), iceilf(y), iceilf(width), iceilf(height));
+ }
+
+ glDepthRangef(near_depth, far_depth);
+}
+
+void OGLGfx::Draw(u32 base_vertex, u32 num_vertices)
+{
+ glDrawArrays(static_cast(m_current_pipeline)->GetGLPrimitive(), base_vertex,
+ num_vertices);
+}
+
+void OGLGfx::DrawIndexed(u32 base_index, u32 num_indices, u32 base_vertex)
+{
+ if (g_ogl_config.bSupportsGLBaseVertex)
+ {
+ glDrawElementsBaseVertex(static_cast(m_current_pipeline)->GetGLPrimitive(),
+ num_indices, GL_UNSIGNED_SHORT,
+ static_cast(nullptr) + base_index, base_vertex);
+ }
+ else
+ {
+ glDrawElements(static_cast(m_current_pipeline)->GetGLPrimitive(),
+ num_indices, GL_UNSIGNED_SHORT, static_cast(nullptr) + base_index);
+ }
+}
+
+void OGLGfx::DispatchComputeShader(const AbstractShader* shader, u32 groupsize_x, u32 groupsize_y,
+ u32 groupsize_z, u32 groups_x, u32 groups_y, u32 groups_z)
+{
+ glUseProgram(static_cast(shader)->GetGLComputeProgramID());
+ glDispatchCompute(groups_x, groups_y, groups_z);
+
+ // We messed up the program binding, so restore it.
+ ProgramShaderCache::InvalidateLastProgram();
+ if (m_current_pipeline)
+ static_cast(m_current_pipeline)->GetProgram()->shader.Bind();
+
+ // Barrier to texture can be used for reads.
+ if (m_bound_image_texture)
+ glMemoryBarrier(GL_TEXTURE_UPDATE_BARRIER_BIT);
+}
+
+void OGLGfx::SelectLeftBuffer()
+{
+ glDrawBuffer(GL_BACK_LEFT);
+}
+
+void OGLGfx::SelectRightBuffer()
+{
+ glDrawBuffer(GL_BACK_RIGHT);
+}
+
+void OGLGfx::SelectMainBuffer()
+{
+ glDrawBuffer(GL_BACK);
+}
+
+void OGLGfx::SetFramebuffer(AbstractFramebuffer* framebuffer)
+{
+ if (m_current_framebuffer == framebuffer)
+ return;
+
+ glBindFramebuffer(GL_FRAMEBUFFER, static_cast(framebuffer)->GetFBO());
+ m_current_framebuffer = framebuffer;
+}
+
+void OGLGfx::SetAndDiscardFramebuffer(AbstractFramebuffer* framebuffer)
+{
+ // EXT_discard_framebuffer could be used here to save bandwidth on tilers.
+ SetFramebuffer(framebuffer);
+}
+
+void OGLGfx::SetAndClearFramebuffer(AbstractFramebuffer* framebuffer, const ClearColor& color_value,
+ float depth_value)
+{
+ SetFramebuffer(framebuffer);
+
+ glDisable(GL_SCISSOR_TEST);
+ GLbitfield clear_mask = 0;
+ if (framebuffer->HasColorBuffer())
+ {
+ glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
+ glClearColor(color_value[0], color_value[1], color_value[2], color_value[3]);
+ clear_mask |= GL_COLOR_BUFFER_BIT;
+ }
+ if (framebuffer->HasDepthBuffer())
+ {
+ glDepthMask(GL_TRUE);
+ glClearDepthf(depth_value);
+ clear_mask |= GL_DEPTH_BUFFER_BIT;
+ }
+ glClear(clear_mask);
+ glEnable(GL_SCISSOR_TEST);
+
+ // Restore color/depth mask.
+ if (framebuffer->HasColorBuffer())
+ {
+ glColorMask(m_current_blend_state.colorupdate, m_current_blend_state.colorupdate,
+ m_current_blend_state.colorupdate, m_current_blend_state.alphaupdate);
+ }
+ if (framebuffer->HasDepthBuffer())
+ glDepthMask(m_current_depth_state.updateenable);
+}
+
+void OGLGfx::ClearRegion(const MathUtil::Rectangle& rc,
+ const MathUtil::Rectangle& target_rc, bool colorEnable,
+ bool alphaEnable, bool zEnable, u32 color, u32 z)
+{
+ 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
+ // glColorMask/glDepthMask/glScissor affect glClear (glViewport does not)
+ g_gfx->SetScissorRect(target_rc);
+
+ glClear(clear_mask);
+
+ // 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);
+}
+
+void OGLGfx::BindBackbuffer(const ClearColor& clear_color)
+{
+ CheckForSurfaceChange();
+ CheckForSurfaceResize();
+ SetAndClearFramebuffer(m_system_framebuffer.get(), clear_color);
+}
+
+void OGLGfx::PresentBackbuffer()
+{
+ if (g_ogl_config.bSupportsDebug)
+ {
+ if (Common::Log::LogManager::GetInstance()->IsEnabled(Common::Log::LogType::HOST_GPU,
+ Common::Log::LogLevel::LERROR))
+ {
+ glEnable(GL_DEBUG_OUTPUT);
+ }
+ else
+ {
+ glDisable(GL_DEBUG_OUTPUT);
+ }
+ }
+
+ // Swap the back and front buffers, presenting the image.
+ m_main_gl_context->Swap();
+}
+
+void OGLGfx::OnConfigChanged(u32 bits)
+{
+ if (bits & CONFIG_CHANGE_BIT_VSYNC && !DriverDetails::HasBug(DriverDetails::BUG_BROKEN_VSYNC))
+ m_main_gl_context->SwapInterval(g_ActiveConfig.bVSyncActive);
+
+ if (bits & CONFIG_CHANGE_BIT_ANISOTROPY)
+ g_sampler_cache->Clear();
+}
+
+void OGLGfx::Flush()
+{
+ // ensure all commands are sent to the GPU.
+ // Otherwise the driver could batch several frames together.
+ glFlush();
+}
+
+void OGLGfx::WaitForGPUIdle()
+{
+ glFinish();
+}
+
+void OGLGfx::CheckForSurfaceChange()
+{
+ if (!g_presenter->SurfaceChangedTestAndClear())
+ return;
+
+ m_main_gl_context->UpdateSurface(g_presenter->GetNewSurfaceHandle());
+
+ u32 width = m_main_gl_context->GetBackBufferWidth();
+ u32 height = m_main_gl_context->GetBackBufferHeight();
+
+ // With a surface change, the window likely has new dimensions.
+ g_presenter->SetBackbuffer(width, height);
+ m_system_framebuffer->UpdateDimensions(width, height);
+}
+
+void OGLGfx::CheckForSurfaceResize()
+{
+ if (!g_presenter->SurfaceResizedTestAndClear())
+ return;
+
+ m_main_gl_context->Update();
+ u32 width = m_main_gl_context->GetBackBufferWidth();
+ u32 height = m_main_gl_context->GetBackBufferHeight();
+ g_presenter->SetBackbuffer(width, height);
+ m_system_framebuffer->UpdateDimensions(width, height);
+}
+
+void OGLGfx::BeginUtilityDrawing()
+{
+ AbstractGfx::BeginUtilityDrawing();
+ if (g_ActiveConfig.backend_info.bSupportsDepthClamp)
+ {
+ glDisable(GL_CLIP_DISTANCE0);
+ glDisable(GL_CLIP_DISTANCE1);
+ }
+}
+
+void OGLGfx::EndUtilityDrawing()
+{
+ AbstractGfx::EndUtilityDrawing();
+ if (g_ActiveConfig.backend_info.bSupportsDepthClamp)
+ {
+ glEnable(GL_CLIP_DISTANCE0);
+ glEnable(GL_CLIP_DISTANCE1);
+ }
+}
+
+void OGLGfx::ApplyRasterizationState(const RasterizationState state)
+{
+ if (m_current_rasterization_state == state)
+ return;
+
+ // none, ccw, cw, ccw
+ if (state.cullmode != CullMode::None)
+ {
+ // TODO: GX_CULL_ALL not supported, yet!
+ glEnable(GL_CULL_FACE);
+ glFrontFace(state.cullmode == CullMode::Front ? GL_CCW : GL_CW);
+ }
+ else
+ {
+ glDisable(GL_CULL_FACE);
+ }
+
+ m_current_rasterization_state = state;
+}
+
+void OGLGfx::ApplyDepthState(const DepthState state)
+{
+ if (m_current_depth_state == state)
+ return;
+
+ const GLenum glCmpFuncs[8] = {GL_NEVER, GL_LESS, GL_EQUAL, GL_LEQUAL,
+ GL_GREATER, GL_NOTEQUAL, GL_GEQUAL, GL_ALWAYS};
+
+ if (state.testenable)
+ {
+ glEnable(GL_DEPTH_TEST);
+ glDepthMask(state.updateenable ? GL_TRUE : GL_FALSE);
+ glDepthFunc(glCmpFuncs[u32(state.func.Value())]);
+ }
+ else
+ {
+ // if the test is disabled write is disabled too
+ // TODO: When PE performance metrics are being emulated via occlusion queries, we should
+ // (probably?) enable depth test with depth function ALWAYS here
+ glDisable(GL_DEPTH_TEST);
+ glDepthMask(GL_FALSE);
+ }
+
+ m_current_depth_state = state;
+}
+
+void OGLGfx::ApplyBlendingState(const BlendingState state)
+{
+ if (m_current_blend_state == state)
+ return;
+
+ bool useDualSource = state.usedualsrc;
+
+ 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[u32(state.srcfactor.Value())],
+ dst_factors[u32(state.dstfactor.Value())],
+ src_factors[u32(state.srcfactoralpha.Value())],
+ dst_factors[u32(state.dstfactoralpha.Value())]);
+
+ 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[u32(state.logicmode.Value())]);
+ }
+ else
+ {
+ glDisable(GL_COLOR_LOGIC_OP);
+ }
+ }
+
+ glColorMask(state.colorupdate, state.colorupdate, state.colorupdate, state.alphaupdate);
+ m_current_blend_state = state;
+}
+
+void OGLGfx::SetPipeline(const AbstractPipeline* pipeline)
+{
+ if (m_current_pipeline == pipeline)
+ return;
+
+ if (pipeline)
+ {
+ ApplyRasterizationState(static_cast(pipeline)->GetRasterizationState());
+ ApplyDepthState(static_cast(pipeline)->GetDepthState());
+ ApplyBlendingState(static_cast(pipeline)->GetBlendingState());
+ ProgramShaderCache::BindVertexFormat(
+ static_cast(pipeline)->GetVertexFormat());
+ static_cast(pipeline)->GetProgram()->shader.Bind();
+ }
+ else
+ {
+ ProgramShaderCache::InvalidateLastProgram();
+ glUseProgram(0);
+ }
+ m_current_pipeline = pipeline;
+}
+
+void OGLGfx::SetTexture(u32 index, const AbstractTexture* texture)
+{
+ const OGLTexture* gl_texture = static_cast(texture);
+ if (m_bound_textures[index] == gl_texture)
+ return;
+
+ glActiveTexture(GL_TEXTURE0 + index);
+ if (gl_texture)
+ glBindTexture(gl_texture->GetGLTarget(), gl_texture->GetGLTextureId());
+ else
+ glBindTexture(GL_TEXTURE_2D_ARRAY, 0);
+ m_bound_textures[index] = gl_texture;
+}
+
+void OGLGfx::SetSamplerState(u32 index, const SamplerState& state)
+{
+ g_sampler_cache->SetSamplerState(index, state);
+}
+
+void OGLGfx::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(texture)->GetGLTextureId(), 0, GL_TRUE, 0,
+ access, static_cast(texture)->GetGLFormatForImageTexture());
+ }
+ else
+ {
+ glBindImageTexture(0, 0, 0, GL_FALSE, 0, GL_READ_ONLY, GL_RGBA8);
+ }
+
+ m_bound_image_texture = texture;
+}
+
+void OGLGfx::UnbindTexture(const AbstractTexture* texture)
+{
+ for (size_t i = 0; i < m_bound_textures.size(); i++)
+ {
+ if (m_bound_textures[i] != texture)
+ continue;
+
+ glActiveTexture(static_cast(GL_TEXTURE0 + i));
+ glBindTexture(GL_TEXTURE_2D_ARRAY, 0);
+ m_bound_textures[i] = nullptr;
+ }
+
+ 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 OGLGfx::CreateAsyncShaderCompiler()
+{
+ return std::make_unique();
+}
+
+bool OGLGfx::IsGLES() const
+{
+ return m_main_gl_context->IsGLES();
+}
+
+void OGLGfx::BindSharedReadFramebuffer()
+{
+ glBindFramebuffer(GL_READ_FRAMEBUFFER, m_shared_read_framebuffer);
+}
+
+void OGLGfx::BindSharedDrawFramebuffer()
+{
+ glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_shared_draw_framebuffer);
+}
+
+void OGLGfx::RestoreFramebufferBinding()
+{
+ glBindFramebuffer(
+ GL_FRAMEBUFFER,
+ m_current_framebuffer ? static_cast(m_current_framebuffer)->GetFBO() : 0);
+}
+
+SurfaceInfo OGLGfx::GetSurfaceInfo() const
+{
+ return {std::max(m_main_gl_context->GetBackBufferWidth(), 1u),
+ std::max(m_main_gl_context->GetBackBufferHeight(), 1u), m_backbuffer_scale,
+ AbstractTextureFormat::RGBA8};
+}
+
+} // namespace OGL
diff --git a/Source/Core/VideoBackends/OGL/OGLRender.h b/Source/Core/VideoBackends/OGL/OGLGfx.h
similarity index 65%
rename from Source/Core/VideoBackends/OGL/OGLRender.h
rename to Source/Core/VideoBackends/OGL/OGLGfx.h
index c42543a32b..8d92766387 100644
--- a/Source/Core/VideoBackends/OGL/OGLRender.h
+++ b/Source/Core/VideoBackends/OGL/OGLGfx.h
@@ -1,99 +1,25 @@
-// Copyright 2008 Dolphin Emulator Project
+// Copyright 2023 Dolphin Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
-#include
-#include
-#include
+#include "VideoCommon/AbstractGfx.h"
-#include "Common/GL/GLContext.h"
-#include "Common/GL/GLExtensions/GLExtensions.h"
-#include "VideoCommon/RenderBase.h"
-
-class BoundingBox;
+class GLContext;
namespace OGL
{
class OGLFramebuffer;
-class OGLPipeline;
class OGLTexture;
-enum GlslVersion
-{
- Glsl130,
- Glsl140,
- Glsl150,
- Glsl330,
- Glsl400, // and above
- Glsl430,
- GlslEs300, // GLES 3.0
- GlslEs310, // GLES 3.1
- GlslEs320, // GLES 3.2
-};
-enum class EsTexbufType
-{
- TexbufNone,
- TexbufCore,
- TexbufOes,
- TexbufExt
-};
-
-enum class EsFbFetchType
-{
- FbFetchNone,
- FbFetchExt,
- FbFetchArm,
-};
-
-// ogl-only config, so not in VideoConfig.h
-struct VideoConfig
-{
- bool bIsES;
- bool bSupportsGLPinnedMemory;
- bool bSupportsGLSync;
- bool bSupportsGLBaseVertex;
- bool bSupportsGLBufferStorage;
- bool bSupportsMSAA;
- GlslVersion eSupportedGLSLVersion;
- bool bSupportViewportFloat;
- bool bSupportsAEP;
- bool bSupportsDebug;
- bool bSupportsCopySubImage;
- u8 SupportedESPointSize;
- EsTexbufType SupportedESTextureBuffer;
- bool bSupportsTextureStorage;
- bool bSupports2DTextureStorageMultisample;
- bool bSupports3DTextureStorageMultisample;
- bool bSupportsConservativeDepth;
- bool bSupportsImageLoadStore;
- bool bSupportsAniso;
- bool bSupportsBitfield;
- bool bSupportsTextureSubImage;
- EsFbFetchType SupportedFramebufferFetch;
- bool bSupportsShaderThreadShuffleNV;
-
- const char* gl_vendor;
- const char* gl_renderer;
- const char* gl_version;
-
- s32 max_samples;
-};
-extern VideoConfig g_ogl_config;
-
-class Renderer : public ::Renderer
+class OGLGfx final : public AbstractGfx
{
public:
- Renderer(std::unique_ptr main_gl_context, float backbuffer_scale);
- ~Renderer() override;
-
- static Renderer* GetInstance() { return static_cast(g_renderer.get()); }
+ OGLGfx(std::unique_ptr main_gl_context, float backbuffer_scale);
+ ~OGLGfx();
bool IsHeadless() const override;
- bool Initialize() override;
- void Shutdown() override;
-
std::unique_ptr CreateTexture(const TextureConfig& config,
std::string_view name) override;
std::unique_ptr
@@ -116,6 +42,8 @@ public:
void SetAndDiscardFramebuffer(AbstractFramebuffer* framebuffer) override;
void SetAndClearFramebuffer(AbstractFramebuffer* framebuffer, const ClearColor& color_value = {},
float depth_value = 0.0f) override;
+ void ClearRegion(const MathUtil::Rectangle& rc, const MathUtil::Rectangle& target_rc,
+ bool colorEnable, bool alphaEnable, bool zEnable, u32 color, u32 z) override;
void SetScissorRect(const MathUtil::Rectangle& rc) override;
void SetTexture(u32 index, const AbstractTexture* texture) override;
void SetSamplerState(u32 index, const SamplerState& state) override;
@@ -137,34 +65,30 @@ public:
void WaitForGPUIdle() override;
void OnConfigChanged(u32 bits) override;
- void ClearScreen(const MathUtil::Rectangle& rc, bool colorEnable, bool alphaEnable,
- bool zEnable, u32 color, u32 z) override;
+ virtual void SelectLeftBuffer() override;
+ virtual void SelectRightBuffer() override;
+ virtual void SelectMainBuffer() override;
std::unique_ptr 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(); }
+ bool IsGLES() const;
// Invalidates a cached texture binding. Required for texel buffers when they borrow the units.
void InvalidateTextureBinding(u32 index) { m_bound_textures[index] = nullptr; }
// 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; }
+ u32 GetSharedReadFramebuffer() const { return m_shared_read_framebuffer; }
+ u32 GetSharedDrawFramebuffer() const { return m_shared_draw_framebuffer; }
void BindSharedReadFramebuffer();
void BindSharedDrawFramebuffer();
// Restores FBO binding after it's been changed.
void RestoreFramebufferBinding();
-protected:
- std::unique_ptr CreateBoundingBox() const override;
-
- virtual void SelectLeftBuffer() override;
- virtual void SelectRightBuffer() override;
- virtual void SelectMainBuffer() override;
+ SurfaceInfo GetSurfaceInfo() const override;
private:
void CheckForSurfaceChange();
@@ -181,7 +105,14 @@ private:
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;
+ u32 m_shared_read_framebuffer = 0;
+ u32 m_shared_draw_framebuffer = 0;
+ float m_backbuffer_scale;
};
+
+inline OGLGfx* GetOGLGfx()
+{
+ return static_cast(g_gfx.get());
+}
+
} // namespace OGL
diff --git a/Source/Core/VideoBackends/OGL/OGLMain.cpp b/Source/Core/VideoBackends/OGL/OGLMain.cpp
index f8ed07dc94..a36d9f99a4 100644
--- a/Source/Core/VideoBackends/OGL/OGLMain.cpp
+++ b/Source/Core/VideoBackends/OGL/OGLMain.cpp
@@ -46,8 +46,10 @@ Make AA apply instantly during gameplay if possible
#include "Core/Config/GraphicsSettings.h"
+#include "VideoBackends/OGL/OGLBoundingBox.h"
+#include "VideoBackends/OGL/OGLConfig.h"
+#include "VideoBackends/OGL/OGLGfx.h"
#include "VideoBackends/OGL/OGLPerfQuery.h"
-#include "VideoBackends/OGL/OGLRender.h"
#include "VideoBackends/OGL/OGLVertexManager.h"
#include "VideoBackends/OGL/ProgramShaderCache.h"
#include "VideoBackends/OGL/SamplerCache.h"
@@ -185,26 +187,16 @@ bool VideoBackend::Initialize(const WindowSystemInfo& wsi)
if (!InitializeGLExtensions(main_gl_context.get()) || !FillBackendInfo())
return false;
- InitializeShared();
- g_renderer = std::make_unique(std::move(main_gl_context), wsi.render_surface_scale);
+ g_gfx = std::make_unique(std::move(main_gl_context), wsi.render_surface_scale);
ProgramShaderCache::Init();
+
g_vertex_manager = std::make_unique();
- g_shader_cache = std::make_unique();
- g_framebuffer_manager = std::make_unique();
g_perf_query = GetPerfQuery();
- g_texture_cache = std::make_unique();
g_sampler_cache = std::make_unique();
+ g_bounding_box = std::make_unique();
- if (!g_vertex_manager->Initialize() || !g_shader_cache->Initialize() ||
- !g_renderer->Initialize() || !g_framebuffer_manager->Initialize() ||
- !g_texture_cache->Initialize())
- {
- PanicAlertFmtT("Failed to initialize renderer classes");
- Shutdown();
- return false;
- }
+ InitializeShared();
- g_shader_cache->InitializeShaderCache();
return true;
}
diff --git a/Source/Core/VideoBackends/OGL/OGLNativeVertexFormat.cpp b/Source/Core/VideoBackends/OGL/OGLNativeVertexFormat.cpp
index b77755bb12..f1213fcde5 100644
--- a/Source/Core/VideoBackends/OGL/OGLNativeVertexFormat.cpp
+++ b/Source/Core/VideoBackends/OGL/OGLNativeVertexFormat.cpp
@@ -6,7 +6,7 @@
#include "Common/GL/GLUtil.h"
#include "Common/MsgHandler.h"
-#include "VideoBackends/OGL/OGLRender.h"
+#include "VideoBackends/OGL/OGLGfx.h"
#include "VideoBackends/OGL/OGLVertexManager.h"
#include "VideoBackends/OGL/ProgramShaderCache.h"
@@ -19,7 +19,7 @@
namespace OGL
{
std::unique_ptr
-Renderer::CreateNativeVertexFormat(const PortableVertexDeclaration& vtx_decl)
+OGLGfx::CreateNativeVertexFormat(const PortableVertexDeclaration& vtx_decl)
{
return std::make_unique(vtx_decl);
}
diff --git a/Source/Core/VideoBackends/OGL/OGLPerfQuery.cpp b/Source/Core/VideoBackends/OGL/OGLPerfQuery.cpp
index 550b837de8..00816b679d 100644
--- a/Source/Core/VideoBackends/OGL/OGLPerfQuery.cpp
+++ b/Source/Core/VideoBackends/OGL/OGLPerfQuery.cpp
@@ -8,7 +8,8 @@
#include "Common/CommonTypes.h"
#include "Common/GL/GLExtensions/GLExtensions.h"
-#include "VideoBackends/OGL/OGLRender.h"
+#include "VideoBackends/OGL/OGLGfx.h"
+#include "VideoCommon/RenderBase.h"
#include "VideoCommon/VideoCommon.h"
#include "VideoCommon/VideoConfig.h"
@@ -16,7 +17,7 @@ namespace OGL
{
std::unique_ptr GetPerfQuery()
{
- const bool is_gles = static_cast(g_renderer.get())->IsGLES();
+ const bool is_gles = static_cast(g_gfx.get())->IsGLES();
if (is_gles && GLExtensions::Supports("GL_NV_occlusion_query_samples"))
return std::make_unique();
else if (is_gles)
diff --git a/Source/Core/VideoBackends/OGL/OGLPipeline.cpp b/Source/Core/VideoBackends/OGL/OGLPipeline.cpp
index b4962cf270..3f9dea623f 100644
--- a/Source/Core/VideoBackends/OGL/OGLPipeline.cpp
+++ b/Source/Core/VideoBackends/OGL/OGLPipeline.cpp
@@ -5,7 +5,6 @@
#include "Common/Assert.h"
-#include "VideoBackends/OGL/OGLRender.h"
#include "VideoBackends/OGL/OGLShader.h"
#include "VideoBackends/OGL/OGLVertexManager.h"
#include "VideoBackends/OGL/ProgramShaderCache.h"
diff --git a/Source/Core/VideoBackends/OGL/OGLStreamBuffer.cpp b/Source/Core/VideoBackends/OGL/OGLStreamBuffer.cpp
index 762eaec1b0..b4f26db453 100644
--- a/Source/Core/VideoBackends/OGL/OGLStreamBuffer.cpp
+++ b/Source/Core/VideoBackends/OGL/OGLStreamBuffer.cpp
@@ -8,7 +8,7 @@
#include "Common/MathUtil.h"
#include "Common/MemoryUtil.h"
-#include "VideoBackends/OGL/OGLRender.h"
+#include "VideoBackends/OGL/OGLConfig.h"
#include "VideoCommon/DriverDetails.h"
#include "VideoCommon/OnScreenDisplay.h"
diff --git a/Source/Core/VideoBackends/OGL/OGLTexture.cpp b/Source/Core/VideoBackends/OGL/OGLTexture.cpp
index 8c1b14cd08..3f4c47cbeb 100644
--- a/Source/Core/VideoBackends/OGL/OGLTexture.cpp
+++ b/Source/Core/VideoBackends/OGL/OGLTexture.cpp
@@ -7,6 +7,8 @@
#include "Common/CommonTypes.h"
#include "Common/MsgHandler.h"
+#include "VideoBackends/OGL/OGLConfig.h"
+#include "VideoBackends/OGL/OGLGfx.h"
#include "VideoBackends/OGL/SamplerCache.h"
#include "VideoCommon/VideoConfig.h"
@@ -160,7 +162,7 @@ OGLTexture::OGLTexture(const TextureConfig& tex_config, std::string_view name)
OGLTexture::~OGLTexture()
{
- Renderer::GetInstance()->UnbindTexture(this);
+ GetOGLGfx()->UnbindTexture(this);
glDeleteTextures(1, &m_texId);
}
@@ -190,10 +192,10 @@ void OGLTexture::BlitFramebuffer(OGLTexture* srcentry, const MathUtil::Rectangle
const MathUtil::Rectangle& dst_rect, u32 dst_layer,
u32 dst_level)
{
- Renderer::GetInstance()->BindSharedReadFramebuffer();
+ GetOGLGfx()->BindSharedReadFramebuffer();
glFramebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, srcentry->m_texId, src_level,
src_layer);
- Renderer::GetInstance()->BindSharedDrawFramebuffer();
+ GetOGLGfx()->BindSharedDrawFramebuffer();
glFramebufferTextureLayer(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, m_texId, dst_level,
dst_layer);
@@ -206,7 +208,7 @@ void OGLTexture::BlitFramebuffer(OGLTexture* srcentry, const MathUtil::Rectangle
// 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);
- Renderer::GetInstance()->RestoreFramebufferBinding();
+ GetOGLGfx()->RestoreFramebufferBinding();
}
void OGLTexture::ResolveFromTexture(const AbstractTexture* src,
@@ -388,7 +390,7 @@ void OGLStagingTexture::CopyFromTexture(const AbstractTexture* src,
else
{
// Mutate the shared framebuffer.
- Renderer::GetInstance()->BindSharedReadFramebuffer();
+ GetOGLGfx()->BindSharedReadFramebuffer();
if (AbstractTexture::IsDepthFormat(gltex->GetFormat()))
{
glFramebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, 0, 0, 0);
@@ -404,7 +406,7 @@ void OGLStagingTexture::CopyFromTexture(const AbstractTexture* src,
glReadPixels(src_rect.left, src_rect.top, src_rect.GetWidth(), src_rect.GetHeight(),
GetGLFormatForTextureFormat(src->GetFormat()),
GetGLTypeForTextureFormat(src->GetFormat()), reinterpret_cast(dst_offset));
- Renderer::GetInstance()->RestoreFramebufferBinding();
+ GetOGLGfx()->RestoreFramebufferBinding();
}
glPixelStorei(GL_PACK_ROW_LENGTH, 0);
@@ -597,7 +599,7 @@ std::unique_ptr OGLFramebuffer::Create(OGLTexture* color_attachm
}
DEBUG_ASSERT(glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE);
- Renderer::GetInstance()->RestoreFramebufferBinding();
+ GetOGLGfx()->RestoreFramebufferBinding();
return std::make_unique(color_attachment, depth_attachment, color_format,
depth_format, width, height, layers, samples, fbo);
diff --git a/Source/Core/VideoBackends/OGL/OGLVertexManager.cpp b/Source/Core/VideoBackends/OGL/OGLVertexManager.cpp
index e47e425a3b..03b2f71ac8 100644
--- a/Source/Core/VideoBackends/OGL/OGLVertexManager.cpp
+++ b/Source/Core/VideoBackends/OGL/OGLVertexManager.cpp
@@ -12,8 +12,8 @@
#include "Common/CommonTypes.h"
#include "Common/GL/GLExtensions/GLExtensions.h"
+#include "VideoBackends/OGL/OGLGfx.h"
#include "VideoBackends/OGL/OGLPipeline.h"
-#include "VideoBackends/OGL/OGLRender.h"
#include "VideoBackends/OGL/OGLStreamBuffer.h"
#include "VideoBackends/OGL/ProgramShaderCache.h"
@@ -116,7 +116,7 @@ bool VertexManager::UploadTexelBuffer(const void* data, u32 data_size, TexelBuff
// Bind the correct view to the texel buffer slot.
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_BUFFER, m_texel_buffer_views[static_cast(format)]);
- Renderer::GetInstance()->InvalidateTextureBinding(0);
+ GetOGLGfx()->InvalidateTextureBinding(0);
return true;
}
@@ -141,11 +141,11 @@ bool VertexManager::UploadTexelBuffer(const void* data, u32 data_size, TexelBuff
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_BUFFER, m_texel_buffer_views[static_cast(format)]);
- Renderer::GetInstance()->InvalidateTextureBinding(0);
+ GetOGLGfx()->InvalidateTextureBinding(0);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_BUFFER, m_texel_buffer_views[static_cast(palette_format)]);
- Renderer::GetInstance()->InvalidateTextureBinding(1);
+ GetOGLGfx()->InvalidateTextureBinding(1);
return true;
}
diff --git a/Source/Core/VideoBackends/OGL/ProgramShaderCache.cpp b/Source/Core/VideoBackends/OGL/ProgramShaderCache.cpp
index b4635c36ec..289e99cae0 100644
--- a/Source/Core/VideoBackends/OGL/ProgramShaderCache.cpp
+++ b/Source/Core/VideoBackends/OGL/ProgramShaderCache.cpp
@@ -22,7 +22,8 @@
#include "Core/ConfigManager.h"
#include "Core/System.h"
-#include "VideoBackends/OGL/OGLRender.h"
+#include "VideoBackends/OGL/OGLConfig.h"
+#include "VideoBackends/OGL/OGLGfx.h"
#include "VideoBackends/OGL/OGLShader.h"
#include "VideoBackends/OGL/OGLStreamBuffer.h"
#include "VideoBackends/OGL/OGLVertexManager.h"
@@ -863,8 +864,7 @@ u64 ProgramShaderCache::GenerateShaderID()
bool SharedContextAsyncShaderCompiler::WorkerThreadInitMainThread(void** param)
{
- std::unique_ptr context =
- static_cast(g_renderer.get())->GetMainGLContext()->CreateSharedContext();
+ std::unique_ptr context = GetOGLGfx()->GetMainGLContext()->CreateSharedContext();
if (!context)
{
PanicAlertFmt("Failed to create shared context for shader compiling.");
diff --git a/Source/Core/VideoBackends/OGL/SamplerCache.cpp b/Source/Core/VideoBackends/OGL/SamplerCache.cpp
index c111caa546..2673fd2ddd 100644
--- a/Source/Core/VideoBackends/OGL/SamplerCache.cpp
+++ b/Source/Core/VideoBackends/OGL/SamplerCache.cpp
@@ -6,7 +6,7 @@
#include
#include "Common/CommonTypes.h"
-#include "VideoBackends/OGL/OGLRender.h"
+#include "VideoBackends/OGL/OGLConfig.h"
#include "VideoCommon/VideoConfig.h"
namespace OGL
diff --git a/Source/Core/VideoBackends/OGL/SamplerCache.h b/Source/Core/VideoBackends/OGL/SamplerCache.h
index ad0a9bf3db..be8860c9f8 100644
--- a/Source/Core/VideoBackends/OGL/SamplerCache.h
+++ b/Source/Core/VideoBackends/OGL/SamplerCache.h
@@ -9,7 +9,7 @@
#include "Common/CommonTypes.h"
#include "Common/GL/GLUtil.h"
-#include "VideoBackends/OGL/OGLRender.h"
+#include "VideoCommon/RenderState.h"
namespace OGL
{
diff --git a/Source/Core/VideoCommon/AbstractGfx.cpp b/Source/Core/VideoCommon/AbstractGfx.cpp
index 4406cd46b6..17c95b863a 100644
--- a/Source/Core/VideoCommon/AbstractGfx.cpp
+++ b/Source/Core/VideoCommon/AbstractGfx.cpp
@@ -13,6 +13,8 @@
#include "VideoCommon/VertexManagerBase.h"
#include "VideoCommon/VideoConfig.h"
+std::unique_ptr g_gfx;
+
bool AbstractGfx::IsHeadless() const
{
return true;
diff --git a/Source/Core/VideoCommon/BoundingBox.cpp b/Source/Core/VideoCommon/BoundingBox.cpp
index af0961aab6..0429559846 100644
--- a/Source/Core/VideoCommon/BoundingBox.cpp
+++ b/Source/Core/VideoCommon/BoundingBox.cpp
@@ -13,6 +13,8 @@
#include
+std::unique_ptr g_bounding_box;
+
void BoundingBox::Enable(PixelShaderManager& pixel_shader_manager)
{
m_is_active = true;
diff --git a/Source/Core/VideoCommon/VideoBackendBase.cpp b/Source/Core/VideoCommon/VideoBackendBase.cpp
index 40fcd8b0f4..1ced44e3ae 100644
--- a/Source/Core/VideoCommon/VideoBackendBase.cpp
+++ b/Source/Core/VideoCommon/VideoBackendBase.cpp
@@ -39,8 +39,10 @@
#include "VideoBackends/Metal/VideoBackend.h"
#endif
+#include "VideoCommon/AbstractGfx.h"
#include "VideoCommon/AsyncRequests.h"
#include "VideoCommon/BPStructs.h"
+#include "VideoCommon/BoundingBox.h"
#include "VideoCommon/CPMemory.h"
#include "VideoCommon/CommandProcessor.h"
#include "VideoCommon/Fifo.h"
@@ -324,9 +326,16 @@ void VideoBackendBase::InitializeShared()
// do not initialize again for the config window
m_initialized = true;
- g_renderer = std::make_unique();
+ if (!g_renderer)
+ {
+ // Null and Software Backends supply their own Renderer
+ g_renderer = std::make_unique();
+ }
g_presenter = std::make_unique();
g_frame_dumper = std::make_unique();
+ g_texture_cache = std::make_unique();
+ g_framebuffer_manager = std::make_unique();
+ g_shader_cache = std::make_unique();
auto& system = Core::System::GetInstance();
auto& command_processor = system.GetCommandProcessor();
@@ -340,7 +349,9 @@ void VideoBackendBase::InitializeShared()
system.GetPixelShaderManager().Init();
TMEM::Init();
- if (!g_renderer->Initialize() || !g_presenter->Initialize())
+ if (!g_vertex_manager->Initialize() || !g_renderer->Initialize() || !g_presenter->Initialize() ||
+ !g_shader_cache->Initialize() || !g_framebuffer_manager->Initialize() ||
+ !g_texture_cache->Initialize() || !g_bounding_box->Initialize())
{
PanicAlertFmtT("Failed to initialize renderer classes");
Shutdown();
@@ -349,6 +360,8 @@ void VideoBackendBase::InitializeShared()
g_Config.VerifyValidity();
UpdateActiveConfig();
+
+ g_shader_cache->InitializeShaderCache();
}
void VideoBackendBase::ShutdownShared()
@@ -363,12 +376,15 @@ void VideoBackendBase::ShutdownShared()
if (g_texture_cache)
g_texture_cache->Shutdown();
+ g_bounding_box.reset();
g_perf_query.reset();
g_texture_cache.reset();
g_framebuffer_manager.reset();
g_shader_cache.reset();
g_vertex_manager.reset();
g_renderer.reset();
+ g_presenter.reset();
+ g_gfx.reset();
m_initialized = false;