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) NAZARA_OPENGLRENDERER_FOREACH_GLES_FUNC(NAZARA_OPENGLRENDERER_FUNC)
#undef NAZARA_OPENGLRENDERER_FUNC #undef NAZARA_OPENGLRENDERER_FUNC
static const Context* GetCurrentContext();
static bool SetCurrentContext(const Context* context);
protected: protected:
virtual bool Activate() const = 0;
virtual void Desactivate() const = 0;
virtual const Loader& GetLoader() = 0; virtual const Loader& GetLoader() = 0;
virtual bool ImplementFallback(const std::string_view& function); virtual bool ImplementFallback(const std::string_view& function);
std::unordered_set<std::string> m_supportedExtensions; static void NotifyContextDestruction(Context* context);
ContextParams m_params; ContextParams m_params;
private: private:
void GL_APIENTRY HandleDebugMessage(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar* message) const; 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(WGLContext&&) = delete;
~WGLContext(); ~WGLContext();
bool Activate() override;
bool Create(const WGLContext* baseContext, const ContextParams& params, const WGLContext* shareContext = nullptr); 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); bool Create(const WGLContext* baseContext, const ContextParams& params, WindowHandle window, const WGLContext* shareContext = nullptr);
void Destroy(); void Destroy();
@ -50,7 +48,8 @@ namespace Nz::GL
bool CreateInternal(const WGLContext* baseContext, const ContextParams& params, const WGLContext* shareContext = nullptr); bool CreateInternal(const WGLContext* baseContext, const ContextParams& params, const WGLContext* shareContext = nullptr);
bool ImplementFallback(const std::string_view& function) override; bool ImplementFallback(const std::string_view& function) override;
void Desactivate(); bool Activate() const override;
void Desactivate() const override;
const Loader& GetLoader() override; const Loader& GetLoader() override;
bool LoadWGLExt(); bool LoadWGLExt();
bool SetPixelFormat(); bool SetPixelFormat();

View File

@ -23,10 +23,10 @@ namespace Nz::GL
const Loader& loader = GetLoader(); 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)); 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)); throw std::runtime_error("failed to load core function " + std::string(funcName));
}; };
@ -114,6 +114,34 @@ namespace Nz::GL
return true; 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) bool Context::ImplementFallback(const std::string_view& function)
{ {
const Loader& loader = GetLoader(); const Loader& loader = GetLoader();
@ -135,6 +163,13 @@ namespace Nz::GL
return false; 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 void Context::HandleDebugMessage(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar* message) const
{ {
std::stringstream ss; std::stringstream ss;

View File

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