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;