OpenGL: Better handling for activation/desactivation

This commit is contained in:
Lynix 2020-04-19 15:28:59 +02:00
parent d62e99091f
commit f63d045676
4 changed files with 76 additions and 54 deletions

View File

@ -56,17 +56,24 @@ namespace Nz::GL
NAZARA_OPENGLRENDERER_FOREACH_GLES_FUNC(NAZARA_OPENGLRENDERER_FUNC)
#undef NAZARA_OPENGLRENDERER_FUNC
static const Context* GetCurrentContext();
static bool SetCurrentContext(const Context* context);
protected:
virtual bool Activate() const = 0;
virtual void Desactivate() const = 0;
virtual const Loader& GetLoader() = 0;
virtual bool ImplementFallback(const std::string_view& function);
std::unordered_set<std::string> m_supportedExtensions;
static void NotifyContextDestruction(Context* context);
ContextParams m_params;
private:
void GL_APIENTRY HandleDebugMessage(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar* message) const;
std::unordered_set<std::string> m_supportedExtensions;
};
}

View File

@ -31,8 +31,6 @@ namespace Nz::GL
WGLContext(WGLContext&&) = delete;
~WGLContext();
bool Activate() override;
bool Create(const WGLContext* baseContext, const ContextParams& params, const WGLContext* shareContext = nullptr);
bool Create(const WGLContext* baseContext, const ContextParams& params, WindowHandle window, const WGLContext* shareContext = nullptr);
void Destroy();
@ -50,7 +48,8 @@ namespace Nz::GL
bool CreateInternal(const WGLContext* baseContext, const ContextParams& params, const WGLContext* shareContext = nullptr);
bool ImplementFallback(const std::string_view& function) override;
void Desactivate();
bool Activate() const override;
void Desactivate() const override;
const Loader& GetLoader() override;
bool LoadWGLExt();
bool SetPixelFormat();

View File

@ -23,10 +23,10 @@ namespace Nz::GL
const Loader& loader = GetLoader();
auto LoadSymbol = [&](auto& func, const char* funcName)
auto LoadSymbol = [&](auto& func, const char* funcName, bool mandatory)
{
func = reinterpret_cast<std::decay_t<decltype(func)>>(loader.LoadFunction(funcName));
if (!func && !ImplementFallback(funcName) && !func) //< Not a mistake
if (!func && !ImplementFallback(funcName) && !func && mandatory) //< Not a mistake
throw std::runtime_error("failed to load core function " + std::string(funcName));
};
@ -114,6 +114,34 @@ namespace Nz::GL
return true;
}
const Context* Context::GetCurrentContext()
{
return s_currentContext;
}
bool Context::SetCurrentContext(const Context* context)
{
const Context*& currentContext = s_currentContext; //< Pay TLS cost only once
if (currentContext == context)
return true;
if (currentContext)
{
currentContext->Desactivate();
currentContext = nullptr;
}
if (context)
{
if (!context->Activate())
return false;
currentContext = context;
}
return true;
}
bool Context::ImplementFallback(const std::string_view& function)
{
const Loader& loader = GetLoader();
@ -135,6 +163,13 @@ namespace Nz::GL
return false;
}
void Context::NotifyContextDestruction(Context* context)
{
const Context*& currentContext = s_currentContext; //< Pay TLS cost only once
if (currentContext == context)
currentContext = nullptr;
}
void Context::HandleDebugMessage(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar* message) const
{
std::stringstream ss;

View File

@ -12,8 +12,6 @@
namespace Nz::GL
{
thread_local WGLContext* s_currentContext = nullptr;
GL::WGLContext::WGLContext(const WGLLoader& loader) :
m_loader(loader)
{
@ -24,30 +22,6 @@ namespace Nz::GL
Destroy();
}
bool WGLContext::Activate()
{
WGLContext*& currentContext = s_currentContext; //< Pay TLS cost only once
if (currentContext)
{
if (currentContext == this)
return true;
// Only one context can be activated per thread
currentContext->Desactivate();
}
bool succeeded = m_loader.wglMakeCurrent(m_deviceContext, m_handle);
if (!succeeded)
{
NazaraError("failed to activate context: " + Error::GetLastSystemError());
return false;
}
currentContext = this;
return true;
}
bool WGLContext::Create(const WGLContext* baseContext, const ContextParams& params, const WGLContext* shareContext)
{
// Creating a context requires a device context, create window to get one
@ -79,9 +53,7 @@ namespace Nz::GL
{
if (m_handle)
{
WGLContext*& currentContext = s_currentContext; //< Pay TLS cost only once
if (currentContext == this)
currentContext = nullptr;
NotifyContextDestruction(this);
m_loader.wglDeleteContext(m_handle);
m_handle = nullptr;
@ -139,8 +111,8 @@ namespace Nz::GL
}
std::array<int, 3 * 2 + 1> attributes = {
WGL_CONTEXT_MAJOR_VERSION_ARB, version.major,
WGL_CONTEXT_MINOR_VERSION_ARB, version.minor,
WGL_CONTEXT_MAJOR_VERSION_ARB, int(version.major),
WGL_CONTEXT_MINOR_VERSION_ARB, int(version.minor),
WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_CORE_PROFILE_BIT_ARB | WGL_CONTEXT_ES_PROFILE_BIT_EXT
};
@ -180,8 +152,8 @@ namespace Nz::GL
}
std::array<int, 3 * 2 + 1> attributes = {
WGL_CONTEXT_MAJOR_VERSION_ARB, version.major,
WGL_CONTEXT_MINOR_VERSION_ARB, version.minor,
WGL_CONTEXT_MAJOR_VERSION_ARB, int(version.major),
WGL_CONTEXT_MINOR_VERSION_ARB, int(version.minor),
WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_CORE_PROFILE_BIT_ARB
};
@ -243,22 +215,31 @@ namespace Nz::GL
glClearDepthf = [](GLfloat depth)
{
assert(s_currentContext);
s_currentContext->fallbacks.glClearDepth(depth);
const WGLContext* context = static_cast<const WGLContext*>(GetCurrentContext());
assert(context);
context->fallbacks.glClearDepth(depth);
};
}
return true;
}
void WGLContext::Desactivate()
bool WGLContext::Activate() const
{
WGLContext*& currentContext = s_currentContext; //< Pay TLS cost only once
if (currentContext == this)
bool succeeded = m_loader.wglMakeCurrent(m_deviceContext, m_handle);
if (!succeeded)
{
m_loader.wglMakeCurrent(nullptr, nullptr);
currentContext = nullptr;
NazaraError("failed to activate context: " + Error::GetLastSystemError());
return false;
}
return true;
}
void WGLContext::Desactivate() const
{
assert(GetCurrentContext() == this);
m_loader.wglMakeCurrent(nullptr, nullptr);
}
const Loader& WGLContext::GetLoader()
@ -308,7 +289,7 @@ namespace Nz::GL
int pixelFormat = 0;
if (m_params.sampleCount > 1)
{
WGLContext* currentContext = s_currentContext; //< Pay TLS cost only once
const WGLContext* currentContext = static_cast<const WGLContext*>(GetCurrentContext()); //< Pay TLS cost only once
if (currentContext)
{
// WGL_ARB_pixel_format and WGL_EXT_pixel_format are the same, except for the symbol
@ -320,13 +301,13 @@ namespace Nz::GL
WGL_DRAW_TO_WINDOW_ARB, GL_TRUE,
WGL_SUPPORT_OPENGL_ARB, GL_TRUE,
WGL_ACCELERATION_ARB, WGL_FULL_ACCELERATION_ARB,
WGL_COLOR_BITS_ARB, (m_params.bitsPerPixel == 32) ? 24 : m_params.bitsPerPixel,
WGL_ALPHA_BITS_ARB, (m_params.bitsPerPixel == 32) ? 8 : 0,
WGL_DEPTH_BITS_ARB, m_params.depthBits,
WGL_STENCIL_BITS_ARB, m_params.stencilBits,
WGL_DOUBLE_BUFFER_ARB, (m_params.doubleBuffering) ? GL_TRUE : GL_FALSE,
WGL_COLOR_BITS_ARB, int((m_params.bitsPerPixel == 32) ? 24 : m_params.bitsPerPixel),
WGL_ALPHA_BITS_ARB, int((m_params.bitsPerPixel == 32) ? 8 : 0),
WGL_DEPTH_BITS_ARB, int(m_params.depthBits),
WGL_STENCIL_BITS_ARB, int(m_params.stencilBits),
WGL_DOUBLE_BUFFER_ARB, int((m_params.doubleBuffering) ? GL_TRUE : GL_FALSE),
WGL_SAMPLE_BUFFERS_ARB, GL_TRUE,
WGL_SAMPLES_ARB, m_params.sampleCount
WGL_SAMPLES_ARB, int(m_params.sampleCount)
};
int& sampleCount = attributes[attributes.size() - 3];
@ -344,7 +325,7 @@ namespace Nz::GL
}
while (sampleCount > 1);
if (m_params.sampleCount != sampleCount)
if (int(m_params.sampleCount) != sampleCount)
NazaraWarning("couldn't find a pixel format matching " + std::to_string(m_params.sampleCount) + " sample count, using " + std::to_string(sampleCount) + " sample(s) instead");
m_params.sampleCount = sampleCount;