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.

This commit is contained in:
binary1248 2018-05-21 17:30:47 +02:00 committed by Lukas Dürrenberger
parent 3f4bc3683b
commit ac98be760b
2 changed files with 106 additions and 65 deletions

View File

@ -212,6 +212,55 @@ namespace
// Supported OpenGL extensions
std::vector<std::string> 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<const char*>(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<glGetStringiFuncType>(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<unsigned int>(numExtensions); ++i)
{
const char* extensionString = reinterpret_cast<const char*>(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<const char*>(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<glGetStringiFuncType>(getFunction("glGetStringi"));
if (glGetStringiFunc)
{
int numExtensions = 0;
glGetIntegerv(GL_NUM_EXTENSIONS, &numExtensions);
if (numExtensions)
{
for (unsigned int i = 0; i < static_cast<unsigned int>(numExtensions); ++i)
{
const char* extensionString = reinterpret_cast<const char*>(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

View File

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