mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-02-11 06:59:07 +01:00
Implement AbstractGfx for OpenGL
Mostly involves moving contents of OGLRender to OGLGfx and OGLConfig
This commit is contained in:
parent
8a23629345
commit
f0336a3129
@ -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" />
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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
|
78
Source/Core/VideoBackends/OGL/OGLConfig.h
Normal file
78
Source/Core/VideoBackends/OGL/OGLConfig.h
Normal 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
|
730
Source/Core/VideoBackends/OGL/OGLGfx.cpp
Normal file
730
Source/Core/VideoBackends/OGL/OGLGfx.cpp
Normal 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
|
@ -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
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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)
|
||||||
|
@ -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"
|
||||||
|
@ -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"
|
||||||
|
@ -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);
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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.");
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
{
|
{
|
||||||
|
@ -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;
|
||||||
|
@ -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;
|
||||||
|
@ -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;
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user