Implement AbstractGfx for OpenGL

Mostly involves moving contents of OGLRender
to OGLGfx and OGLConfig
This commit is contained in:
Scott Mansell 2023-01-27 13:21:09 +13:00
parent 8a23629345
commit f0336a3129
20 changed files with 905 additions and 872 deletions

View File

@ -569,9 +569,10 @@
<ClInclude Include="VideoBackends\Null\VideoBackend.h" /> <ClInclude Include="VideoBackends\Null\VideoBackend.h" />
<ClInclude Include="VideoBackends\OGL\GPUTimer.h" /> <ClInclude Include="VideoBackends\OGL\GPUTimer.h" />
<ClInclude Include="VideoBackends\OGL\OGLBoundingBox.h" /> <ClInclude Include="VideoBackends\OGL\OGLBoundingBox.h" />
<ClInclude Include="VideoBackends\OGL\OGLConfig.h" />
<ClInclude Include="VideoBackends\OGL\OGLGfx.h" />
<ClInclude Include="VideoBackends\OGL\OGLPerfQuery.h" /> <ClInclude Include="VideoBackends\OGL\OGLPerfQuery.h" />
<ClInclude Include="VideoBackends\OGL\OGLPipeline.h" /> <ClInclude Include="VideoBackends\OGL\OGLPipeline.h" />
<ClInclude Include="VideoBackends\OGL\OGLRender.h" />
<ClInclude Include="VideoBackends\OGL\OGLShader.h" /> <ClInclude Include="VideoBackends\OGL\OGLShader.h" />
<ClInclude Include="VideoBackends\OGL\OGLStreamBuffer.h" /> <ClInclude Include="VideoBackends\OGL\OGLStreamBuffer.h" />
<ClInclude Include="VideoBackends\OGL\OGLTexture.h" /> <ClInclude Include="VideoBackends\OGL\OGLTexture.h" />
@ -1175,11 +1176,12 @@
<ClCompile Include="VideoBackends\Null\NullTexture.cpp" /> <ClCompile Include="VideoBackends\Null\NullTexture.cpp" />
<ClCompile Include="VideoBackends\Null\NullVertexManager.cpp" /> <ClCompile Include="VideoBackends\Null\NullVertexManager.cpp" />
<ClCompile Include="VideoBackends\OGL\OGLBoundingBox.cpp" /> <ClCompile Include="VideoBackends\OGL\OGLBoundingBox.cpp" />
<ClCompile Include="VideoBackends\OGL\OGLConfig.cpp" />
<ClCompile Include="VideoBackends\OGL\OGLGfx.cpp" />
<ClCompile Include="VideoBackends\OGL\OGLMain.cpp" /> <ClCompile Include="VideoBackends\OGL\OGLMain.cpp" />
<ClCompile Include="VideoBackends\OGL\OGLNativeVertexFormat.cpp" /> <ClCompile Include="VideoBackends\OGL\OGLNativeVertexFormat.cpp" />
<ClCompile Include="VideoBackends\OGL\OGLPerfQuery.cpp" /> <ClCompile Include="VideoBackends\OGL\OGLPerfQuery.cpp" />
<ClCompile Include="VideoBackends\OGL\OGLPipeline.cpp" /> <ClCompile Include="VideoBackends\OGL\OGLPipeline.cpp" />
<ClCompile Include="VideoBackends\OGL\OGLRender.cpp" />
<ClCompile Include="VideoBackends\OGL\OGLShader.cpp" /> <ClCompile Include="VideoBackends\OGL\OGLShader.cpp" />
<ClCompile Include="VideoBackends\OGL\OGLStreamBuffer.cpp" /> <ClCompile Include="VideoBackends\OGL\OGLStreamBuffer.cpp" />
<ClCompile Include="VideoBackends\OGL\OGLTexture.cpp" /> <ClCompile Include="VideoBackends\OGL\OGLTexture.cpp" />

View File

@ -2,14 +2,16 @@ add_library(videoogl
GPUTimer.h GPUTimer.h
OGLBoundingBox.cpp OGLBoundingBox.cpp
OGLBoundingBox.h OGLBoundingBox.h
OGLConfig.cpp
OGLConfig.h
OGLGfx.cpp
OGLGfx.h
OGLMain.cpp OGLMain.cpp
OGLNativeVertexFormat.cpp OGLNativeVertexFormat.cpp
OGLPerfQuery.cpp OGLPerfQuery.cpp
OGLPerfQuery.h OGLPerfQuery.h
OGLPipeline.cpp OGLPipeline.cpp
OGLPipeline.h OGLPipeline.h
OGLRender.cpp
OGLRender.h
OGLShader.cpp OGLShader.cpp
OGLShader.h OGLShader.h
OGLStreamBuffer.cpp OGLStreamBuffer.cpp

View File

@ -3,7 +3,7 @@
#include "VideoBackends/OGL/OGLBoundingBox.h" #include "VideoBackends/OGL/OGLBoundingBox.h"
#include "VideoBackends/OGL/OGLRender.h" #include "VideoBackends/OGL/OGLGfx.h"
#include "VideoCommon/DriverDetails.h" #include "VideoCommon/DriverDetails.h"
namespace OGL namespace OGL
@ -35,7 +35,7 @@ std::vector<BBoxType> OGLBoundingBox::Read(u32 index, u32 length)
// on nVidia drivers. This is more noticeable at higher internal resolutions. // on nVidia drivers. This is more noticeable at higher internal resolutions.
// Using glGetBufferSubData instead does not seem to exhibit this slowdown. // Using glGetBufferSubData instead does not seem to exhibit this slowdown.
if (!DriverDetails::HasBug(DriverDetails::BUG_SLOW_GETBUFFERSUBDATA) && if (!DriverDetails::HasBug(DriverDetails::BUG_SLOW_GETBUFFERSUBDATA) &&
!static_cast<Renderer*>(g_renderer.get())->IsGLES()) !static_cast<OGLGfx*>(g_gfx.get())->IsGLES())
{ {
// We also need to ensure the the CPU does not receive stale values which have been updated by // 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 // the GPU. Apparently the buffer here is not coherent on NVIDIA drivers. Not sure if this is a

View File

@ -1,136 +1,26 @@
// Copyright 2008 Dolphin Emulator Project // Copyright 2023 Dolphin Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#include "VideoBackends/OGL/OGLRender.h" #include "VideoBackends/OGL/OGLConfig.h"
#include <algorithm>
#include <cmath>
#include <cstdio>
#include <memory>
#include <string>
#include "Common/CommonTypes.h"
#include "Common/GL/GLContext.h" #include "Common/GL/GLContext.h"
#include "Common/GL/GLUtil.h" #include "Common/GL/GLExtensions/GLExtensions.h"
#include "Common/Logging/LogManager.h" #include "Common/Logging/LogManager.h"
#include "Common/MathUtil.h"
#include "Common/MsgHandler.h" #include "Common/MsgHandler.h"
#include "Common/StringUtil.h"
#include "Core/Config/GraphicsSettings.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/DriverDetails.h"
#include "VideoCommon/FramebufferManager.h"
#include "VideoCommon/OnScreenDisplay.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 "VideoCommon/VideoConfig.h"
#include <cstdio>
#include <string>
#include <string_view>
namespace OGL namespace OGL
{ {
VideoConfig g_ogl_config; void InitDriverInfo()
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()
{ {
const std::string_view svendor(g_ogl_config.gl_vendor); const std::string_view svendor(g_ogl_config.gl_vendor);
const std::string_view srenderer(g_ogl_config.gl_renderer); 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); DriverDetails::Init(DriverDetails::API_OPENGL, vendor, driver, version, family);
} }
// Init functions bool PopulateConfig(GLContext* m_main_gl_context)
Renderer::Renderer(std::unique_ptr<GLContext> main_gl_context, float backbuffer_scale)
: ::Renderer(static_cast<int>(std::max(main_gl_context->GetBackBufferWidth(), 1u)),
static_cast<int>(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())
{ {
// Create the window framebuffer.
if (!m_main_gl_context->IsHeadless())
{
m_system_framebuffer = std::make_unique<OGLFramebuffer>(
nullptr, nullptr, AbstractTextureFormat::RGBA8, AbstractTextureFormat::Undefined,
std::max(m_main_gl_context->GetBackBufferWidth(), 1u),
std::max(m_main_gl_context->GetBackBufferHeight(), 1u), 1, 1, 0);
m_current_framebuffer = m_system_framebuffer.get();
}
bool bSuccess = true; bool bSuccess = true;
bool supports_glsl_cache = false; bool supports_glsl_cache = false;
@ -347,8 +219,6 @@ Renderer::Renderer(std::unique_ptr<GLContext> main_gl_context, float backbuffer_
g_ogl_config.gl_renderer = (const char*)glGetString(GL_RENDERER); g_ogl_config.gl_renderer = (const char*)glGetString(GL_RENDERER);
g_ogl_config.gl_version = (const char*)glGetString(GL_VERSION); g_ogl_config.gl_version = (const char*)glGetString(GL_VERSION);
InitDriverInfo();
if (!m_main_gl_context->IsGLES()) if (!m_main_gl_context->IsGLES())
{ {
if (!GLExtensions::Supports("GL_ARB_framebuffer_object")) if (!GLExtensions::Supports("GL_ARB_framebuffer_object"))
@ -402,15 +272,6 @@ Renderer::Renderer(std::unique_ptr<GLContext> main_gl_context, float backbuffer_
"GPU: Does your video card support OpenGL 3.3?"); "GPU: Does your video card support OpenGL 3.3?");
bSuccess = false; 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. // Copy the GPU name to g_Config, so Analytics can see it.
@ -694,29 +555,6 @@ Renderer::Renderer(std::unique_ptr<GLContext> main_gl_context, float backbuffer_
} }
g_Config.backend_info.bSupportsPipelineCacheData = supports_glsl_cache; 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; int samples;
glGetIntegerv(GL_SAMPLES, &samples); glGetIntegerv(GL_SAMPLES, &samples);
if (samples > 1) if (samples > 1)
@ -733,11 +571,7 @@ Renderer::Renderer(std::unique_ptr<GLContext> main_gl_context, float backbuffer_
} }
if (!bSuccess) if (!bSuccess)
{ return false;
// Not all needed extensions are supported, so we have to stop here.
// Else some of the next calls might crash.
return;
}
g_Config.VerifyValidity(); g_Config.VerifyValidity();
UpdateActiveConfig(); UpdateActiveConfig();
@ -772,565 +606,7 @@ Renderer::Renderer(std::unique_ptr<GLContext> main_gl_context, float backbuffer_
g_ogl_config.bSupportsCopySubImage ? "" : "CopyImageSubData ", g_ogl_config.bSupportsCopySubImage ? "" : "CopyImageSubData ",
g_ActiveConfig.backend_info.bSupportsDepthClamp ? "" : "DepthClamp "); 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; return true;
} }
void Renderer::Shutdown()
{
::Renderer::Shutdown();
glDeleteFramebuffers(1, &m_shared_draw_framebuffer);
glDeleteFramebuffers(1, &m_shared_read_framebuffer);
}
std::unique_ptr<AbstractTexture> Renderer::CreateTexture(const TextureConfig& config,
std::string_view name)
{
return std::make_unique<OGLTexture>(config, name);
}
std::unique_ptr<AbstractStagingTexture> Renderer::CreateStagingTexture(StagingTextureType type,
const TextureConfig& config)
{
return OGLStagingTexture::Create(type, config);
}
std::unique_ptr<AbstractFramebuffer> Renderer::CreateFramebuffer(AbstractTexture* color_attachment,
AbstractTexture* depth_attachment)
{
return OGLFramebuffer::Create(static_cast<OGLTexture*>(color_attachment),
static_cast<OGLTexture*>(depth_attachment));
}
std::unique_ptr<AbstractShader>
Renderer::CreateShaderFromSource(ShaderStage stage, std::string_view source, std::string_view name)
{
return OGLShader::CreateFromSource(stage, source, name);
}
std::unique_ptr<AbstractShader>
Renderer::CreateShaderFromBinary(ShaderStage stage, const void* data, size_t length,
[[maybe_unused]] std::string_view name)
{
return nullptr;
}
std::unique_ptr<AbstractPipeline> 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<int>& rc)
{
glScissor(rc.left, rc.top, rc.GetWidth(), rc.GetHeight());
}
std::unique_ptr<::BoundingBox> Renderer::CreateBoundingBox() const
{
return std::make_unique<OGLBoundingBox>();
}
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<GLint>(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<const OGLPipeline*>(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<const OGLPipeline*>(m_current_pipeline)->GetGLPrimitive(),
num_indices, GL_UNSIGNED_SHORT,
static_cast<u16*>(nullptr) + base_index, base_vertex);
}
else
{
glDrawElements(static_cast<const OGLPipeline*>(m_current_pipeline)->GetGLPrimitive(),
num_indices, GL_UNSIGNED_SHORT, static_cast<u16*>(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<const OGLShader*>(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<const OGLPipeline*>(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<int>& 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<OGLFramebuffer*>(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<const OGLPipeline*>(pipeline)->GetRasterizationState());
ApplyDepthState(static_cast<const OGLPipeline*>(pipeline)->GetDepthState());
ApplyBlendingState(static_cast<const OGLPipeline*>(pipeline)->GetBlendingState());
ProgramShaderCache::BindVertexFormat(
static_cast<const OGLPipeline*>(pipeline)->GetVertexFormat());
static_cast<const OGLPipeline*>(pipeline)->GetProgram()->shader.Bind();
}
else
{
ProgramShaderCache::InvalidateLastProgram();
glUseProgram(0);
}
m_current_pipeline = pipeline;
}
void Renderer::SetTexture(u32 index, const AbstractTexture* texture)
{
const OGLTexture* gl_texture = static_cast<const OGLTexture*>(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<OGLTexture*>(texture)->GetGLTextureId(), 0, GL_TRUE, 0,
access, static_cast<OGLTexture*>(texture)->GetGLFormatForImageTexture());
}
else
{
glBindImageTexture(0, 0, 0, GL_FALSE, 0, GL_READ_ONLY, GL_RGBA8);
}
m_bound_image_texture = texture;
}
void Renderer::UnbindTexture(const AbstractTexture* texture)
{
for (size_t i = 0; i < m_bound_textures.size(); i++)
{
if (m_bound_textures[i] != texture)
continue;
glActiveTexture(static_cast<GLenum>(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<VideoCommon::AsyncShaderCompiler> Renderer::CreateAsyncShaderCompiler()
{
return std::make_unique<SharedContextAsyncShaderCompiler>();
}
void Renderer::BindSharedReadFramebuffer()
{
glBindFramebuffer(GL_READ_FRAMEBUFFER, m_shared_read_framebuffer);
}
void Renderer::BindSharedDrawFramebuffer()
{
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_shared_draw_framebuffer);
}
void Renderer::RestoreFramebufferBinding()
{
glBindFramebuffer(
GL_FRAMEBUFFER,
m_current_framebuffer ? static_cast<OGLFramebuffer*>(m_current_framebuffer)->GetFBO() : 0);
}
} // namespace OGL } // namespace OGL

View File

@ -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

View File

@ -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 <string_view>
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<GLContext> 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<OGLFramebuffer>(
nullptr, nullptr, AbstractTextureFormat::RGBA8, AbstractTextureFormat::Undefined,
std::max(m_main_gl_context->GetBackBufferWidth(), 1u),
std::max(m_main_gl_context->GetBackBufferHeight(), 1u), 1, 1, 0);
m_current_framebuffer = m_system_framebuffer.get();
}
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<AbstractTexture> OGLGfx::CreateTexture(const TextureConfig& config,
std::string_view name)
{
return std::make_unique<OGLTexture>(config, name);
}
std::unique_ptr<AbstractStagingTexture> OGLGfx::CreateStagingTexture(StagingTextureType type,
const TextureConfig& config)
{
return OGLStagingTexture::Create(type, config);
}
std::unique_ptr<AbstractFramebuffer> OGLGfx::CreateFramebuffer(AbstractTexture* color_attachment,
AbstractTexture* depth_attachment)
{
return OGLFramebuffer::Create(static_cast<OGLTexture*>(color_attachment),
static_cast<OGLTexture*>(depth_attachment));
}
std::unique_ptr<AbstractShader>
OGLGfx::CreateShaderFromSource(ShaderStage stage, std::string_view source, std::string_view name)
{
return OGLShader::CreateFromSource(stage, source, name);
}
std::unique_ptr<AbstractShader>
OGLGfx::CreateShaderFromBinary(ShaderStage stage, const void* data, size_t length,
[[maybe_unused]] std::string_view name)
{
return nullptr;
}
std::unique_ptr<AbstractPipeline> 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<int>& 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<GLint>(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<const OGLPipeline*>(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<const OGLPipeline*>(m_current_pipeline)->GetGLPrimitive(),
num_indices, GL_UNSIGNED_SHORT,
static_cast<u16*>(nullptr) + base_index, base_vertex);
}
else
{
glDrawElements(static_cast<const OGLPipeline*>(m_current_pipeline)->GetGLPrimitive(),
num_indices, GL_UNSIGNED_SHORT, static_cast<u16*>(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<const OGLShader*>(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<const OGLPipeline*>(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<OGLFramebuffer*>(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<int>& rc,
const MathUtil::Rectangle<int>& 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<const OGLPipeline*>(pipeline)->GetRasterizationState());
ApplyDepthState(static_cast<const OGLPipeline*>(pipeline)->GetDepthState());
ApplyBlendingState(static_cast<const OGLPipeline*>(pipeline)->GetBlendingState());
ProgramShaderCache::BindVertexFormat(
static_cast<const OGLPipeline*>(pipeline)->GetVertexFormat());
static_cast<const OGLPipeline*>(pipeline)->GetProgram()->shader.Bind();
}
else
{
ProgramShaderCache::InvalidateLastProgram();
glUseProgram(0);
}
m_current_pipeline = pipeline;
}
void OGLGfx::SetTexture(u32 index, const AbstractTexture* texture)
{
const OGLTexture* gl_texture = static_cast<const OGLTexture*>(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<OGLTexture*>(texture)->GetGLTextureId(), 0, GL_TRUE, 0,
access, static_cast<OGLTexture*>(texture)->GetGLFormatForImageTexture());
}
else
{
glBindImageTexture(0, 0, 0, GL_FALSE, 0, GL_READ_ONLY, GL_RGBA8);
}
m_bound_image_texture = texture;
}
void 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<GLenum>(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<VideoCommon::AsyncShaderCompiler> OGLGfx::CreateAsyncShaderCompiler()
{
return std::make_unique<SharedContextAsyncShaderCompiler>();
}
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<OGLFramebuffer*>(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

View File

@ -1,99 +1,25 @@
// Copyright 2008 Dolphin Emulator Project // Copyright 2023 Dolphin Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#pragma once #pragma once
#include <array> #include "VideoCommon/AbstractGfx.h"
#include <string>
#include <string_view>
#include "Common/GL/GLContext.h" class GLContext;
#include "Common/GL/GLExtensions/GLExtensions.h"
#include "VideoCommon/RenderBase.h"
class BoundingBox;
namespace OGL namespace OGL
{ {
class OGLFramebuffer; class OGLFramebuffer;
class OGLPipeline;
class OGLTexture; class OGLTexture;
enum GlslVersion class OGLGfx final : public AbstractGfx
{
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
{ {
public: public:
Renderer(std::unique_ptr<GLContext> main_gl_context, float backbuffer_scale); OGLGfx(std::unique_ptr<GLContext> main_gl_context, float backbuffer_scale);
~Renderer() override; ~OGLGfx();
static Renderer* GetInstance() { return static_cast<Renderer*>(g_renderer.get()); }
bool IsHeadless() const override; bool IsHeadless() const override;
bool Initialize() override;
void Shutdown() override;
std::unique_ptr<AbstractTexture> CreateTexture(const TextureConfig& config, std::unique_ptr<AbstractTexture> CreateTexture(const TextureConfig& config,
std::string_view name) override; std::string_view name) override;
std::unique_ptr<AbstractStagingTexture> std::unique_ptr<AbstractStagingTexture>
@ -116,6 +42,8 @@ public:
void SetAndDiscardFramebuffer(AbstractFramebuffer* framebuffer) override; void SetAndDiscardFramebuffer(AbstractFramebuffer* framebuffer) override;
void SetAndClearFramebuffer(AbstractFramebuffer* framebuffer, const ClearColor& color_value = {}, void SetAndClearFramebuffer(AbstractFramebuffer* framebuffer, const ClearColor& color_value = {},
float depth_value = 0.0f) override; float depth_value = 0.0f) override;
void ClearRegion(const MathUtil::Rectangle<int>& rc, const MathUtil::Rectangle<int>& target_rc,
bool colorEnable, bool alphaEnable, bool zEnable, u32 color, u32 z) override;
void SetScissorRect(const MathUtil::Rectangle<int>& rc) override; void SetScissorRect(const MathUtil::Rectangle<int>& rc) override;
void SetTexture(u32 index, const AbstractTexture* texture) override; void SetTexture(u32 index, const AbstractTexture* texture) override;
void SetSamplerState(u32 index, const SamplerState& state) override; void SetSamplerState(u32 index, const SamplerState& state) override;
@ -137,34 +65,30 @@ public:
void WaitForGPUIdle() override; void WaitForGPUIdle() override;
void OnConfigChanged(u32 bits) override; void OnConfigChanged(u32 bits) override;
void ClearScreen(const MathUtil::Rectangle<int>& rc, bool colorEnable, bool alphaEnable, virtual void SelectLeftBuffer() override;
bool zEnable, u32 color, u32 z) override; virtual void SelectRightBuffer() override;
virtual void SelectMainBuffer() override;
std::unique_ptr<VideoCommon::AsyncShaderCompiler> CreateAsyncShaderCompiler() override; std::unique_ptr<VideoCommon::AsyncShaderCompiler> CreateAsyncShaderCompiler() override;
// Only call methods from this on the GPU thread. // Only call methods from this on the GPU thread.
GLContext* GetMainGLContext() const { return m_main_gl_context.get(); } 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. // Invalidates a cached texture binding. Required for texel buffers when they borrow the units.
void InvalidateTextureBinding(u32 index) { m_bound_textures[index] = nullptr; } void InvalidateTextureBinding(u32 index) { m_bound_textures[index] = nullptr; }
// The shared framebuffer exists for copying textures when extensions are not available. It is // The shared framebuffer exists for copying textures when extensions are not available. It is
// slower, but the only way to do these things otherwise. // slower, but the only way to do these things otherwise.
GLuint GetSharedReadFramebuffer() const { return m_shared_read_framebuffer; } u32 GetSharedReadFramebuffer() const { return m_shared_read_framebuffer; }
GLuint GetSharedDrawFramebuffer() const { return m_shared_draw_framebuffer; } u32 GetSharedDrawFramebuffer() const { return m_shared_draw_framebuffer; }
void BindSharedReadFramebuffer(); void BindSharedReadFramebuffer();
void BindSharedDrawFramebuffer(); void BindSharedDrawFramebuffer();
// Restores FBO binding after it's been changed. // Restores FBO binding after it's been changed.
void RestoreFramebufferBinding(); void RestoreFramebufferBinding();
protected: SurfaceInfo GetSurfaceInfo() const override;
std::unique_ptr<BoundingBox> CreateBoundingBox() const override;
virtual void SelectLeftBuffer() override;
virtual void SelectRightBuffer() override;
virtual void SelectMainBuffer() override;
private: private:
void CheckForSurfaceChange(); void CheckForSurfaceChange();
@ -181,7 +105,14 @@ private:
RasterizationState m_current_rasterization_state; RasterizationState m_current_rasterization_state;
DepthState m_current_depth_state; DepthState m_current_depth_state;
BlendingState m_current_blend_state; BlendingState m_current_blend_state;
GLuint m_shared_read_framebuffer = 0; u32 m_shared_read_framebuffer = 0;
GLuint m_shared_draw_framebuffer = 0; u32 m_shared_draw_framebuffer = 0;
float m_backbuffer_scale;
}; };
inline OGLGfx* GetOGLGfx()
{
return static_cast<OGLGfx*>(g_gfx.get());
}
} // namespace OGL } // namespace OGL

View File

@ -46,8 +46,10 @@ Make AA apply instantly during gameplay if possible
#include "Core/Config/GraphicsSettings.h" #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/OGLPerfQuery.h"
#include "VideoBackends/OGL/OGLRender.h"
#include "VideoBackends/OGL/OGLVertexManager.h" #include "VideoBackends/OGL/OGLVertexManager.h"
#include "VideoBackends/OGL/ProgramShaderCache.h" #include "VideoBackends/OGL/ProgramShaderCache.h"
#include "VideoBackends/OGL/SamplerCache.h" #include "VideoBackends/OGL/SamplerCache.h"
@ -185,26 +187,16 @@ bool VideoBackend::Initialize(const WindowSystemInfo& wsi)
if (!InitializeGLExtensions(main_gl_context.get()) || !FillBackendInfo()) if (!InitializeGLExtensions(main_gl_context.get()) || !FillBackendInfo())
return false; return false;
InitializeShared(); g_gfx = std::make_unique<OGLGfx>(std::move(main_gl_context), wsi.render_surface_scale);
g_renderer = std::make_unique<Renderer>(std::move(main_gl_context), wsi.render_surface_scale);
ProgramShaderCache::Init(); ProgramShaderCache::Init();
g_vertex_manager = std::make_unique<VertexManager>(); g_vertex_manager = std::make_unique<VertexManager>();
g_shader_cache = std::make_unique<VideoCommon::ShaderCache>();
g_framebuffer_manager = std::make_unique<FramebufferManager>();
g_perf_query = GetPerfQuery(); g_perf_query = GetPerfQuery();
g_texture_cache = std::make_unique<TextureCacheBase>();
g_sampler_cache = std::make_unique<SamplerCache>(); g_sampler_cache = std::make_unique<SamplerCache>();
g_bounding_box = std::make_unique<OGLBoundingBox>();
if (!g_vertex_manager->Initialize() || !g_shader_cache->Initialize() || InitializeShared();
!g_renderer->Initialize() || !g_framebuffer_manager->Initialize() ||
!g_texture_cache->Initialize())
{
PanicAlertFmtT("Failed to initialize renderer classes");
Shutdown();
return false;
}
g_shader_cache->InitializeShaderCache();
return true; return true;
} }

View File

@ -6,7 +6,7 @@
#include "Common/GL/GLUtil.h" #include "Common/GL/GLUtil.h"
#include "Common/MsgHandler.h" #include "Common/MsgHandler.h"
#include "VideoBackends/OGL/OGLRender.h" #include "VideoBackends/OGL/OGLGfx.h"
#include "VideoBackends/OGL/OGLVertexManager.h" #include "VideoBackends/OGL/OGLVertexManager.h"
#include "VideoBackends/OGL/ProgramShaderCache.h" #include "VideoBackends/OGL/ProgramShaderCache.h"
@ -19,7 +19,7 @@
namespace OGL namespace OGL
{ {
std::unique_ptr<NativeVertexFormat> std::unique_ptr<NativeVertexFormat>
Renderer::CreateNativeVertexFormat(const PortableVertexDeclaration& vtx_decl) OGLGfx::CreateNativeVertexFormat(const PortableVertexDeclaration& vtx_decl)
{ {
return std::make_unique<GLVertexFormat>(vtx_decl); return std::make_unique<GLVertexFormat>(vtx_decl);
} }

View File

@ -8,7 +8,8 @@
#include "Common/CommonTypes.h" #include "Common/CommonTypes.h"
#include "Common/GL/GLExtensions/GLExtensions.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/VideoCommon.h"
#include "VideoCommon/VideoConfig.h" #include "VideoCommon/VideoConfig.h"
@ -16,7 +17,7 @@ namespace OGL
{ {
std::unique_ptr<PerfQueryBase> GetPerfQuery() std::unique_ptr<PerfQueryBase> GetPerfQuery()
{ {
const bool is_gles = static_cast<Renderer*>(g_renderer.get())->IsGLES(); const bool is_gles = static_cast<OGLGfx*>(g_gfx.get())->IsGLES();
if (is_gles && GLExtensions::Supports("GL_NV_occlusion_query_samples")) if (is_gles && GLExtensions::Supports("GL_NV_occlusion_query_samples"))
return std::make_unique<PerfQueryGLESNV>(); return std::make_unique<PerfQueryGLESNV>();
else if (is_gles) else if (is_gles)

View File

@ -5,7 +5,6 @@
#include "Common/Assert.h" #include "Common/Assert.h"
#include "VideoBackends/OGL/OGLRender.h"
#include "VideoBackends/OGL/OGLShader.h" #include "VideoBackends/OGL/OGLShader.h"
#include "VideoBackends/OGL/OGLVertexManager.h" #include "VideoBackends/OGL/OGLVertexManager.h"
#include "VideoBackends/OGL/ProgramShaderCache.h" #include "VideoBackends/OGL/ProgramShaderCache.h"

View File

@ -8,7 +8,7 @@
#include "Common/MathUtil.h" #include "Common/MathUtil.h"
#include "Common/MemoryUtil.h" #include "Common/MemoryUtil.h"
#include "VideoBackends/OGL/OGLRender.h" #include "VideoBackends/OGL/OGLConfig.h"
#include "VideoCommon/DriverDetails.h" #include "VideoCommon/DriverDetails.h"
#include "VideoCommon/OnScreenDisplay.h" #include "VideoCommon/OnScreenDisplay.h"

View File

@ -7,6 +7,8 @@
#include "Common/CommonTypes.h" #include "Common/CommonTypes.h"
#include "Common/MsgHandler.h" #include "Common/MsgHandler.h"
#include "VideoBackends/OGL/OGLConfig.h"
#include "VideoBackends/OGL/OGLGfx.h"
#include "VideoBackends/OGL/SamplerCache.h" #include "VideoBackends/OGL/SamplerCache.h"
#include "VideoCommon/VideoConfig.h" #include "VideoCommon/VideoConfig.h"
@ -160,7 +162,7 @@ OGLTexture::OGLTexture(const TextureConfig& tex_config, std::string_view name)
OGLTexture::~OGLTexture() OGLTexture::~OGLTexture()
{ {
Renderer::GetInstance()->UnbindTexture(this); GetOGLGfx()->UnbindTexture(this);
glDeleteTextures(1, &m_texId); glDeleteTextures(1, &m_texId);
} }
@ -190,10 +192,10 @@ void OGLTexture::BlitFramebuffer(OGLTexture* srcentry, const MathUtil::Rectangle
const MathUtil::Rectangle<int>& dst_rect, u32 dst_layer, const MathUtil::Rectangle<int>& dst_rect, u32 dst_layer,
u32 dst_level) u32 dst_level)
{ {
Renderer::GetInstance()->BindSharedReadFramebuffer(); GetOGLGfx()->BindSharedReadFramebuffer();
glFramebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, srcentry->m_texId, src_level, glFramebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, srcentry->m_texId, src_level,
src_layer); src_layer);
Renderer::GetInstance()->BindSharedDrawFramebuffer(); GetOGLGfx()->BindSharedDrawFramebuffer();
glFramebufferTextureLayer(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, m_texId, dst_level, glFramebufferTextureLayer(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, m_texId, dst_level,
dst_layer); 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 // 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. // restore, as the framebuffer and scissor test are the only things we changed.
glEnable(GL_SCISSOR_TEST); glEnable(GL_SCISSOR_TEST);
Renderer::GetInstance()->RestoreFramebufferBinding(); GetOGLGfx()->RestoreFramebufferBinding();
} }
void OGLTexture::ResolveFromTexture(const AbstractTexture* src, void OGLTexture::ResolveFromTexture(const AbstractTexture* src,
@ -388,7 +390,7 @@ void OGLStagingTexture::CopyFromTexture(const AbstractTexture* src,
else else
{ {
// Mutate the shared framebuffer. // Mutate the shared framebuffer.
Renderer::GetInstance()->BindSharedReadFramebuffer(); GetOGLGfx()->BindSharedReadFramebuffer();
if (AbstractTexture::IsDepthFormat(gltex->GetFormat())) if (AbstractTexture::IsDepthFormat(gltex->GetFormat()))
{ {
glFramebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, 0, 0, 0); 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(), glReadPixels(src_rect.left, src_rect.top, src_rect.GetWidth(), src_rect.GetHeight(),
GetGLFormatForTextureFormat(src->GetFormat()), GetGLFormatForTextureFormat(src->GetFormat()),
GetGLTypeForTextureFormat(src->GetFormat()), reinterpret_cast<void*>(dst_offset)); GetGLTypeForTextureFormat(src->GetFormat()), reinterpret_cast<void*>(dst_offset));
Renderer::GetInstance()->RestoreFramebufferBinding(); GetOGLGfx()->RestoreFramebufferBinding();
} }
glPixelStorei(GL_PACK_ROW_LENGTH, 0); glPixelStorei(GL_PACK_ROW_LENGTH, 0);
@ -597,7 +599,7 @@ std::unique_ptr<OGLFramebuffer> OGLFramebuffer::Create(OGLTexture* color_attachm
} }
DEBUG_ASSERT(glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE); DEBUG_ASSERT(glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE);
Renderer::GetInstance()->RestoreFramebufferBinding(); GetOGLGfx()->RestoreFramebufferBinding();
return std::make_unique<OGLFramebuffer>(color_attachment, depth_attachment, color_format, return std::make_unique<OGLFramebuffer>(color_attachment, depth_attachment, color_format,
depth_format, width, height, layers, samples, fbo); depth_format, width, height, layers, samples, fbo);

View File

@ -12,8 +12,8 @@
#include "Common/CommonTypes.h" #include "Common/CommonTypes.h"
#include "Common/GL/GLExtensions/GLExtensions.h" #include "Common/GL/GLExtensions/GLExtensions.h"
#include "VideoBackends/OGL/OGLGfx.h"
#include "VideoBackends/OGL/OGLPipeline.h" #include "VideoBackends/OGL/OGLPipeline.h"
#include "VideoBackends/OGL/OGLRender.h"
#include "VideoBackends/OGL/OGLStreamBuffer.h" #include "VideoBackends/OGL/OGLStreamBuffer.h"
#include "VideoBackends/OGL/ProgramShaderCache.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. // Bind the correct view to the texel buffer slot.
glActiveTexture(GL_TEXTURE0); glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_BUFFER, m_texel_buffer_views[static_cast<u32>(format)]); glBindTexture(GL_TEXTURE_BUFFER, m_texel_buffer_views[static_cast<u32>(format)]);
Renderer::GetInstance()->InvalidateTextureBinding(0); GetOGLGfx()->InvalidateTextureBinding(0);
return true; return true;
} }
@ -141,11 +141,11 @@ bool VertexManager::UploadTexelBuffer(const void* data, u32 data_size, TexelBuff
glActiveTexture(GL_TEXTURE0); glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_BUFFER, m_texel_buffer_views[static_cast<u32>(format)]); glBindTexture(GL_TEXTURE_BUFFER, m_texel_buffer_views[static_cast<u32>(format)]);
Renderer::GetInstance()->InvalidateTextureBinding(0); GetOGLGfx()->InvalidateTextureBinding(0);
glActiveTexture(GL_TEXTURE1); glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_BUFFER, m_texel_buffer_views[static_cast<u32>(palette_format)]); glBindTexture(GL_TEXTURE_BUFFER, m_texel_buffer_views[static_cast<u32>(palette_format)]);
Renderer::GetInstance()->InvalidateTextureBinding(1); GetOGLGfx()->InvalidateTextureBinding(1);
return true; return true;
} }

View File

@ -22,7 +22,8 @@
#include "Core/ConfigManager.h" #include "Core/ConfigManager.h"
#include "Core/System.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/OGLShader.h"
#include "VideoBackends/OGL/OGLStreamBuffer.h" #include "VideoBackends/OGL/OGLStreamBuffer.h"
#include "VideoBackends/OGL/OGLVertexManager.h" #include "VideoBackends/OGL/OGLVertexManager.h"
@ -863,8 +864,7 @@ u64 ProgramShaderCache::GenerateShaderID()
bool SharedContextAsyncShaderCompiler::WorkerThreadInitMainThread(void** param) bool SharedContextAsyncShaderCompiler::WorkerThreadInitMainThread(void** param)
{ {
std::unique_ptr<GLContext> context = std::unique_ptr<GLContext> context = GetOGLGfx()->GetMainGLContext()->CreateSharedContext();
static_cast<Renderer*>(g_renderer.get())->GetMainGLContext()->CreateSharedContext();
if (!context) if (!context)
{ {
PanicAlertFmt("Failed to create shared context for shader compiling."); PanicAlertFmt("Failed to create shared context for shader compiling.");

View File

@ -6,7 +6,7 @@
#include <memory> #include <memory>
#include "Common/CommonTypes.h" #include "Common/CommonTypes.h"
#include "VideoBackends/OGL/OGLRender.h" #include "VideoBackends/OGL/OGLConfig.h"
#include "VideoCommon/VideoConfig.h" #include "VideoCommon/VideoConfig.h"
namespace OGL namespace OGL

View File

@ -9,7 +9,7 @@
#include "Common/CommonTypes.h" #include "Common/CommonTypes.h"
#include "Common/GL/GLUtil.h" #include "Common/GL/GLUtil.h"
#include "VideoBackends/OGL/OGLRender.h" #include "VideoCommon/RenderState.h"
namespace OGL namespace OGL
{ {

View File

@ -13,6 +13,8 @@
#include "VideoCommon/VertexManagerBase.h" #include "VideoCommon/VertexManagerBase.h"
#include "VideoCommon/VideoConfig.h" #include "VideoCommon/VideoConfig.h"
std::unique_ptr<AbstractGfx> g_gfx;
bool AbstractGfx::IsHeadless() const bool AbstractGfx::IsHeadless() const
{ {
return true; return true;

View File

@ -13,6 +13,8 @@
#include <algorithm> #include <algorithm>
std::unique_ptr<BoundingBox> g_bounding_box;
void BoundingBox::Enable(PixelShaderManager& pixel_shader_manager) void BoundingBox::Enable(PixelShaderManager& pixel_shader_manager)
{ {
m_is_active = true; m_is_active = true;

View File

@ -39,8 +39,10 @@
#include "VideoBackends/Metal/VideoBackend.h" #include "VideoBackends/Metal/VideoBackend.h"
#endif #endif
#include "VideoCommon/AbstractGfx.h"
#include "VideoCommon/AsyncRequests.h" #include "VideoCommon/AsyncRequests.h"
#include "VideoCommon/BPStructs.h" #include "VideoCommon/BPStructs.h"
#include "VideoCommon/BoundingBox.h"
#include "VideoCommon/CPMemory.h" #include "VideoCommon/CPMemory.h"
#include "VideoCommon/CommandProcessor.h" #include "VideoCommon/CommandProcessor.h"
#include "VideoCommon/Fifo.h" #include "VideoCommon/Fifo.h"
@ -324,9 +326,16 @@ void VideoBackendBase::InitializeShared()
// do not initialize again for the config window // do not initialize again for the config window
m_initialized = true; m_initialized = true;
if (!g_renderer)
{
// Null and Software Backends supply their own Renderer
g_renderer = std::make_unique<Renderer>(); g_renderer = std::make_unique<Renderer>();
}
g_presenter = std::make_unique<VideoCommon::Presenter>(); g_presenter = std::make_unique<VideoCommon::Presenter>();
g_frame_dumper = std::make_unique<FrameDumper>(); g_frame_dumper = std::make_unique<FrameDumper>();
g_texture_cache = std::make_unique<TextureCacheBase>();
g_framebuffer_manager = std::make_unique<FramebufferManager>();
g_shader_cache = std::make_unique<VideoCommon::ShaderCache>();
auto& system = Core::System::GetInstance(); auto& system = Core::System::GetInstance();
auto& command_processor = system.GetCommandProcessor(); auto& command_processor = system.GetCommandProcessor();
@ -340,7 +349,9 @@ void VideoBackendBase::InitializeShared()
system.GetPixelShaderManager().Init(); system.GetPixelShaderManager().Init();
TMEM::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"); PanicAlertFmtT("Failed to initialize renderer classes");
Shutdown(); Shutdown();
@ -349,6 +360,8 @@ void VideoBackendBase::InitializeShared()
g_Config.VerifyValidity(); g_Config.VerifyValidity();
UpdateActiveConfig(); UpdateActiveConfig();
g_shader_cache->InitializeShaderCache();
} }
void VideoBackendBase::ShutdownShared() void VideoBackendBase::ShutdownShared()
@ -363,12 +376,15 @@ void VideoBackendBase::ShutdownShared()
if (g_texture_cache) if (g_texture_cache)
g_texture_cache->Shutdown(); g_texture_cache->Shutdown();
g_bounding_box.reset();
g_perf_query.reset(); g_perf_query.reset();
g_texture_cache.reset(); g_texture_cache.reset();
g_framebuffer_manager.reset(); g_framebuffer_manager.reset();
g_shader_cache.reset(); g_shader_cache.reset();
g_vertex_manager.reset(); g_vertex_manager.reset();
g_renderer.reset(); g_renderer.reset();
g_presenter.reset();
g_gfx.reset();
m_initialized = false; m_initialized = false;