diff options
Diffstat (limited to 'src/SFML/Window/GlContext.cpp')
-rw-r--r-- | src/SFML/Window/GlContext.cpp | 260 |
1 files changed, 240 insertions, 20 deletions
diff --git a/src/SFML/Window/GlContext.cpp b/src/SFML/Window/GlContext.cpp index 53e6280..1a66774 100644 --- a/src/SFML/Window/GlContext.cpp +++ b/src/SFML/Window/GlContext.cpp @@ -1,7 +1,7 @@ //////////////////////////////////////////////////////////// // // SFML - Simple and Fast Multimedia Library -// Copyright (C) 2007-2014 Laurent Gomila (laurent.gom@gmail.com) +// Copyright (C) 2007-2015 Laurent Gomila (laurent@sfml-dev.org) // // This software is provided 'as-is', without any express or implied warranty. // In no event will the authors be held liable for any damages arising from the use of this software. @@ -29,14 +29,11 @@ #include <SFML/System/ThreadLocalPtr.hpp> #include <SFML/System/Mutex.hpp> #include <SFML/System/Lock.hpp> +#include <SFML/System/Err.hpp> #include <SFML/OpenGL.hpp> #include <set> #include <cstdlib> -#ifdef SFML_SYSTEM_IOS - #include <OpenGLES/ES1/gl.h> -#else - #include <SFML/Window/glext/glext.h> -#endif +#include <cstring> #if !defined(SFML_OPENGL_ES) @@ -73,9 +70,60 @@ #endif +#if defined(SFML_SYSTEM_WINDOWS) + + typedef const GLubyte* (APIENTRY *glGetStringiFuncType)(GLenum, GLuint); + +#else + + typedef const GLubyte* (*glGetStringiFuncType)(GLenum, GLuint); + +#endif + +#if !defined(GL_MULTISAMPLE) + #define GL_MULTISAMPLE 0x809D +#endif + +#if !defined(GL_MAJOR_VERSION) + #define GL_MAJOR_VERSION 0x821B +#endif + +#if !defined(GL_MINOR_VERSION) + #define GL_MINOR_VERSION 0x821C +#endif + +#if !defined(GL_NUM_EXTENSIONS) + #define GL_NUM_EXTENSIONS 0x821D +#endif + +#if !defined(GL_CONTEXT_FLAGS) + #define GL_CONTEXT_FLAGS 0x821E +#endif + +#if !defined(GL_CONTEXT_FLAG_DEBUG_BIT) + #define GL_CONTEXT_FLAG_DEBUG_BIT 0x00000002 +#endif + +#if !defined(GL_CONTEXT_PROFILE_MASK) + #define GL_CONTEXT_PROFILE_MASK 0x9126 +#endif + +#if !defined(GL_CONTEXT_CORE_PROFILE_BIT) + #define GL_CONTEXT_CORE_PROFILE_BIT 0x00000001 +#endif + +#if !defined(GL_CONTEXT_COMPATIBILITY_PROFILE_BIT) + #define GL_CONTEXT_COMPATIBILITY_PROFILE_BIT 0x00000002 +#endif + namespace { + // AMD drivers have issues with internal synchronization + // We need to make sure that no operating system context + // or pixel format operations are performed simultaneously + sf::Mutex mutex; + // This per-thread variable holds the current context for each thread sf::ThreadLocalPtr<sf::priv::GlContext> currentContext(NULL); @@ -121,6 +169,8 @@ namespace priv //////////////////////////////////////////////////////////// void GlContext::globalInit() { + Lock lock(mutex); + // Create the shared context sharedContext = new ContextType(NULL); sharedContext->initialize(); @@ -135,12 +185,14 @@ void GlContext::globalInit() //////////////////////////////////////////////////////////// void GlContext::globalCleanup() { + Lock lock(mutex); + // Destroy the shared context delete sharedContext; sharedContext = NULL; // Destroy the internal contexts - sf::Lock lock(internalContextsMutex); + Lock internalContextsLock(internalContextsMutex); for (std::set<GlContext*>::iterator it = internalContexts.begin(); it != internalContexts.end(); ++it) delete *it; internalContexts.clear(); @@ -159,6 +211,9 @@ void GlContext::ensureContext() //////////////////////////////////////////////////////////// GlContext* GlContext::create() { + Lock lock(mutex); + + // Create the context GlContext* context = new ContextType(sharedContext); context->initialize(); @@ -172,9 +227,12 @@ GlContext* GlContext::create(const ContextSettings& settings, const WindowImpl* // Make sure that there's an active context (context creation may need extensions, and thus a valid context) ensureContext(); + Lock lock(mutex); + // Create the context GlContext* context = new ContextType(sharedContext, settings, owner, bitsPerPixel); context->initialize(); + context->checkSettings(settings); return context; } @@ -186,15 +244,35 @@ GlContext* GlContext::create(const ContextSettings& settings, unsigned int width // Make sure that there's an active context (context creation may need extensions, and thus a valid context) ensureContext(); + Lock lock(mutex); + // Create the context GlContext* context = new ContextType(sharedContext, settings, width, height); context->initialize(); + context->checkSettings(settings); return context; } //////////////////////////////////////////////////////////// +GlFunctionPointer GlContext::getFunction(const char* name) +{ +#if !defined(SFML_OPENGL_ES) + + Lock lock(mutex); + + return ContextType::getFunction(name); + +#else + + return 0; + +#endif +} + + +//////////////////////////////////////////////////////////// GlContext::~GlContext() { // Deactivate the context before killing it, unless we're inside Cleanup() @@ -217,6 +295,8 @@ bool GlContext::setActive(bool active) { if (this != currentContext) { + Lock lock(mutex); + // Activate the context if (makeCurrent()) { @@ -260,12 +340,27 @@ GlContext::GlContext() //////////////////////////////////////////////////////////// -int GlContext::evaluateFormat(unsigned int bitsPerPixel, const ContextSettings& settings, int colorBits, int depthBits, int stencilBits, int antialiasing) +int GlContext::evaluateFormat(unsigned int bitsPerPixel, const ContextSettings& settings, int colorBits, int depthBits, int stencilBits, int antialiasing, bool accelerated) { - return std::abs(static_cast<int>(bitsPerPixel - colorBits)) + - std::abs(static_cast<int>(settings.depthBits - depthBits)) + - std::abs(static_cast<int>(settings.stencilBits - stencilBits)) + - std::abs(static_cast<int>(settings.antialiasingLevel - antialiasing)); + int colorDiff = static_cast<int>(bitsPerPixel) - colorBits; + int depthDiff = static_cast<int>(settings.depthBits) - depthBits; + int stencilDiff = static_cast<int>(settings.stencilBits) - stencilBits; + int antialiasingDiff = static_cast<int>(settings.antialiasingLevel) - antialiasing; + + // Weight sub-scores so that better settings don't score equally as bad as worse settings + colorDiff *= ((colorDiff > 0) ? 100000 : 1); + depthDiff *= ((depthDiff > 0) ? 100000 : 1); + stencilDiff *= ((stencilDiff > 0) ? 100000 : 1); + antialiasingDiff *= ((antialiasingDiff > 0) ? 100000 : 1); + + // Aggregate the scores + int score = std::abs(colorDiff) + std::abs(depthDiff) + std::abs(stencilDiff) + std::abs(antialiasingDiff); + + // Make sure we prefer hardware acceleration over features + if (!accelerated) + score += 100000000; + + return score; } @@ -276,18 +371,95 @@ void GlContext::initialize() setActive(true); // Retrieve the context version number - const GLubyte* version = glGetString(GL_VERSION); - if (version) + int majorVersion = 0; + int minorVersion = 0; + + // Try the new way first + glGetIntegerv(GL_MAJOR_VERSION, &majorVersion); + glGetIntegerv(GL_MINOR_VERSION, &minorVersion); + + if (glGetError() != GL_INVALID_ENUM) { - // The beginning of the returned string is "major.minor" (this is standard) - m_settings.majorVersion = version[0] - '0'; - m_settings.minorVersion = version[2] - '0'; + m_settings.majorVersion = static_cast<unsigned int>(majorVersion); + m_settings.minorVersion = static_cast<unsigned int>(minorVersion); } else { - // Can't get the version number, assume 2.0 - m_settings.majorVersion = 2; - m_settings.minorVersion = 0; + // Try the old way + const GLubyte* version = glGetString(GL_VERSION); + if (version) + { + // The beginning of the returned string is "major.minor" (this is standard) + m_settings.majorVersion = version[0] - '0'; + m_settings.minorVersion = version[2] - '0'; + } + else + { + // Can't get the version number, assume 1.1 + m_settings.majorVersion = 1; + m_settings.minorVersion = 1; + } + } + + // 3.0 contexts only deprecate features, but do not remove them yet + // 3.1 contexts remove features if ARB_compatibility is not present + // 3.2+ contexts remove features only if a core profile is requested + + // If the context was created with wglCreateContext, it is guaranteed to be compatibility. + // If a 3.0 context was created with wglCreateContextAttribsARB, it is guaranteed to be compatibility. + // If a 3.1 context was created with wglCreateContextAttribsARB, the compatibility flag + // is set only if ARB_compatibility is present + // If a 3.2+ context was created with wglCreateContextAttribsARB, the compatibility flag + // would have been set correctly already depending on whether ARB_create_context_profile is supported. + + // If the user requests a 3.0 context, it will be a compatibility context regardless of the requested profile. + // If the user requests a 3.1 context and its creation was successful, the specification + // states that it will not be a compatibility profile context regardless of the requested + // profile unless ARB_compatibility is present. + + m_settings.attributeFlags = ContextSettings::Default; + + if (m_settings.majorVersion >= 3) + { + // Retrieve the context flags + int flags = 0; + glGetIntegerv(GL_CONTEXT_FLAGS, &flags); + + if (flags & GL_CONTEXT_FLAG_DEBUG_BIT) + m_settings.attributeFlags |= ContextSettings::Debug; + + if ((m_settings.majorVersion == 3) && (m_settings.minorVersion == 1)) + { + m_settings.attributeFlags |= ContextSettings::Core; + + glGetStringiFuncType glGetStringiFunc = reinterpret_cast<glGetStringiFuncType>(getFunction("glGetStringi")); + + if (glGetStringiFunc) + { + int numExtensions = 0; + glGetIntegerv(GL_NUM_EXTENSIONS, &numExtensions); + + for (unsigned int i = 0; i < static_cast<unsigned int>(numExtensions); ++i) + { + const char* extensionString = reinterpret_cast<const char*>(glGetStringiFunc(GL_EXTENSIONS, i)); + + if (std::strstr(extensionString, "GL_ARB_compatibility")) + { + m_settings.attributeFlags &= ~static_cast<Uint32>(ContextSettings::Core); + break; + } + } + } + } + else if ((m_settings.majorVersion > 3) || (m_settings.minorVersion >= 2)) + { + // Retrieve the context profile + int profile = 0; + glGetIntegerv(GL_CONTEXT_PROFILE_MASK, &profile); + + if (profile & GL_CONTEXT_CORE_PROFILE_BIT) + m_settings.attributeFlags |= ContextSettings::Core; + } } // Enable antialiasing if needed @@ -295,6 +467,54 @@ void GlContext::initialize() glEnable(GL_MULTISAMPLE); } + +//////////////////////////////////////////////////////////// +void GlContext::checkSettings(const ContextSettings& requestedSettings) +{ + // Perform checks to inform the user if they are getting a context they might not have expected + + // Detect any known non-accelerated implementations and warn + const char* vendorName = reinterpret_cast<const char*>(glGetString(GL_VENDOR)); + const char* rendererName = reinterpret_cast<const char*>(glGetString(GL_RENDERER)); + + if (vendorName && rendererName) + { + if ((std::strcmp(vendorName, "Microsoft Corporation") == 0) && (std::strcmp(rendererName, "GDI Generic") == 0)) + { + err() << "Warning: Detected \"Microsoft Corporation GDI Generic\" OpenGL implementation" << std::endl + << "The current OpenGL implementation is not hardware-accelerated" << std::endl; + } + } + + int version = m_settings.majorVersion * 10 + m_settings.minorVersion; + int requestedVersion = requestedSettings.majorVersion * 10 + requestedSettings.minorVersion; + + if ((m_settings.attributeFlags != requestedSettings.attributeFlags) || + (version < requestedVersion) || + (m_settings.stencilBits < requestedSettings.stencilBits) || + (m_settings.antialiasingLevel < requestedSettings.antialiasingLevel) || + (m_settings.depthBits < requestedSettings.depthBits)) + { + err() << "Warning: The created OpenGL context does not fully meet the settings that were requested" << std::endl; + err() << "Requested: version = " << requestedSettings.majorVersion << "." << requestedSettings.minorVersion + << " ; depth bits = " << requestedSettings.depthBits + << " ; stencil bits = " << requestedSettings.stencilBits + << " ; AA level = " << requestedSettings.antialiasingLevel + << std::boolalpha + << " ; core = " << ((requestedSettings.attributeFlags & ContextSettings::Core) != 0) + << " ; debug = " << ((requestedSettings.attributeFlags & ContextSettings::Debug) != 0) + << std::noboolalpha << std::endl; + err() << "Created: version = " << m_settings.majorVersion << "." << m_settings.minorVersion + << " ; depth bits = " << m_settings.depthBits + << " ; stencil bits = " << m_settings.stencilBits + << " ; AA level = " << m_settings.antialiasingLevel + << std::boolalpha + << " ; core = " << ((m_settings.attributeFlags & ContextSettings::Core) != 0) + << " ; debug = " << ((m_settings.attributeFlags & ContextSettings::Debug) != 0) + << std::noboolalpha << std::endl; + } +} + } // namespace priv } // namespace sf |