From ac98be760b8b1401fd7a3b141883cbf04feba7b7 Mon Sep 17 00:00:00 2001 From: binary1248 Date: Mon, 21 May 2018 17:30:47 +0200 Subject: [PATCH] Allow re-creation of the shared context as a core context if the user indicates they want a core profile context. Sharing of compatibility and core profile contexts is not possible on macOS which is why we need to have a way to re-create the shared context as a core context if required in this case. --- src/SFML/Window/GlContext.cpp | 132 ++++++++++++++++++--------- src/SFML/Window/Win32/WglContext.cpp | 39 ++++---- 2 files changed, 106 insertions(+), 65 deletions(-) diff --git a/src/SFML/Window/GlContext.cpp b/src/SFML/Window/GlContext.cpp index 3cbb70162..2e1a48249 100644 --- a/src/SFML/Window/GlContext.cpp +++ b/src/SFML/Window/GlContext.cpp @@ -212,6 +212,55 @@ namespace // Supported OpenGL extensions std::vector extensions; + // Load our extensions vector with the supported extensions + void loadExtensions() + { + extensions.clear(); + + // Check whether a >= 3.0 context is available + int majorVersion = 0; + glGetIntegerv(GL_MAJOR_VERSION, &majorVersion); + + if (glGetError() == GL_INVALID_ENUM) + { + // Try to load the < 3.0 way + const char* extensionString = reinterpret_cast(glGetString(GL_EXTENSIONS)); + + do + { + const char* extension = extensionString; + + while (*extensionString && (*extensionString != ' ')) + extensionString++; + + extensions.push_back(std::string(extension, extensionString)); + } + while (*extensionString++); + } + else + { + // Try to load the >= 3.0 way + glGetStringiFuncType glGetStringiFunc = NULL; + glGetStringiFunc = reinterpret_cast(sf::priv::GlContext::getFunction("glGetStringi")); + + if (glGetStringiFunc) + { + int numExtensions = 0; + glGetIntegerv(GL_NUM_EXTENSIONS, &numExtensions); + + if (numExtensions) + { + for (unsigned int i = 0; i < static_cast(numExtensions); ++i) + { + const char* extensionString = reinterpret_cast(glGetStringiFunc(GL_EXTENSIONS, i)); + + extensions.push_back(extensionString); + } + } + } + } + } + // Helper to parse OpenGL version strings bool parseVersionString(const char* version, const char* prefix, unsigned int &major, unsigned int &minor) { @@ -260,50 +309,7 @@ void GlContext::initResource() sharedContext->initialize(ContextSettings()); // Load our extensions vector - extensions.clear(); - - // Check whether a >= 3.0 context is available - int majorVersion = 0; - glGetIntegerv(GL_MAJOR_VERSION, &majorVersion); - - if (glGetError() == GL_INVALID_ENUM) - { - // Try to load the < 3.0 way - const char* extensionString = reinterpret_cast(glGetString(GL_EXTENSIONS)); - - do - { - const char* extension = extensionString; - - while(*extensionString && (*extensionString != ' ')) - extensionString++; - - extensions.push_back(std::string(extension, extensionString)); - } - while (*extensionString++); - } - else - { - // Try to load the >= 3.0 way - glGetStringiFuncType glGetStringiFunc = NULL; - glGetStringiFunc = reinterpret_cast(getFunction("glGetStringi")); - - if (glGetStringiFunc) - { - int numExtensions = 0; - glGetIntegerv(GL_NUM_EXTENSIONS, &numExtensions); - - if (numExtensions) - { - for (unsigned int i = 0; i < static_cast(numExtensions); ++i) - { - const char* extensionString = reinterpret_cast(glGetStringiFunc(GL_EXTENSIONS, i)); - - extensions.push_back(extensionString); - } - } - } - } + loadExtensions(); // Deactivate the shared context so that others can activate it when necessary sharedContext->setActive(false); @@ -417,6 +423,25 @@ GlContext* GlContext::create(const ContextSettings& settings, const WindowImpl* Lock lock(mutex); + // If resourceCount is 1 we know that we are inside sf::Context or sf::Window + // Only in this situation we allow the user to indirectly re-create the shared context as a core context + + // Check if we need to convert our shared context into a core context + if ((resourceCount == 1) && + (settings.attributeFlags & ContextSettings::Core) && + !(sharedContext->m_settings.attributeFlags & ContextSettings::Core)) + { + // Re-create our shared context as a core context + ContextSettings sharedSettings(0, 0, 0, settings.majorVersion, settings.minorVersion, settings.attributeFlags); + + delete sharedContext; + sharedContext = new ContextType(NULL, sharedSettings, 1, 1); + sharedContext->initialize(sharedSettings); + + // Reload our extensions vector + loadExtensions(); + } + GlContext* context = NULL; // We don't use acquireTransientContext here since we have @@ -446,6 +471,25 @@ GlContext* GlContext::create(const ContextSettings& settings, unsigned int width Lock lock(mutex); + // If resourceCount is 1 we know that we are inside sf::Context or sf::Window + // Only in this situation we allow the user to indirectly re-create the shared context as a core context + + // Check if we need to convert our shared context into a core context + if ((resourceCount == 1) && + (settings.attributeFlags & ContextSettings::Core) && + !(sharedContext->m_settings.attributeFlags & ContextSettings::Core)) + { + // Re-create our shared context as a core context + ContextSettings sharedSettings(0, 0, 0, settings.majorVersion, settings.minorVersion, settings.attributeFlags); + + delete sharedContext; + sharedContext = new ContextType(NULL, sharedSettings, 1, 1); + sharedContext->initialize(sharedSettings); + + // Reload our extensions vector + loadExtensions(); + } + GlContext* context = NULL; // We don't use acquireTransientContext here since we have diff --git a/src/SFML/Window/Win32/WglContext.cpp b/src/SFML/Window/Win32/WglContext.cpp index fd9f89e48..1bd8e9bef 100644 --- a/src/SFML/Window/Win32/WglContext.cpp +++ b/src/SFML/Window/Win32/WglContext.cpp @@ -84,20 +84,16 @@ m_deviceContext(NULL), m_context (NULL), m_ownsWindow (false) { + // TODO: Delegate to the other constructor in C++11 + // Save the creation settings m_settings = ContextSettings(); - // Make sure that extensions are initialized if this is not the shared context - // The shared context is the context used to initialize the extensions - if (shared && shared->m_deviceContext) - ensureExtensionsInit(shared->m_deviceContext); - // Create the rendering surface (window or pbuffer if supported) createSurface(shared, 1, 1, VideoMode::getDesktopMode().bitsPerPixel); // Create the context - if (m_deviceContext) - createContext(shared); + createContext(shared); } @@ -112,17 +108,11 @@ m_ownsWindow (false) // Save the creation settings m_settings = settings; - // Make sure that extensions are initialized if this is not the shared context - // The shared context is the context used to initialize the extensions - if (shared && shared->m_deviceContext) - ensureExtensionsInit(shared->m_deviceContext); - // Create the rendering surface from the owner window createSurface(owner->getSystemHandle(), bitsPerPixel); // Create the context - if (m_deviceContext) - createContext(shared); + createContext(shared); } @@ -137,17 +127,11 @@ m_ownsWindow (false) // Save the creation settings m_settings = settings; - // Make sure that extensions are initialized if this is not the shared context - // The shared context is the context used to initialize the extensions - if (shared && shared->m_deviceContext) - ensureExtensionsInit(shared->m_deviceContext); - // Create the rendering surface (window or pbuffer if supported) createSurface(shared, width, height, VideoMode::getDesktopMode().bitsPerPixel); // Create the context - if (m_deviceContext) - createContext(shared); + createContext(shared); } @@ -594,6 +578,10 @@ void WglContext::createSurface(HWND window, unsigned int bitsPerPixel) //////////////////////////////////////////////////////////// void WglContext::createContext(WglContext* shared) { + // We can't create an OpenGL context if we don't have a DC + if (!m_deviceContext) + return; + // Get a working copy of the context settings ContextSettings settings = m_settings; @@ -730,6 +718,15 @@ void WglContext::createContext(WglContext* shared) err() << "Failed to share the OpenGL context: " << getErrorString(GetLastError()).toAnsiString() << std::endl; } } + + // If we are the shared context, initialize extensions now + // This enables us to re-create the shared context using extensions if we need to + if (!shared && m_context) + { + makeCurrent(true); + ensureExtensionsInit(m_deviceContext); + makeCurrent(false); + } } } // namespace priv