diff --git a/doc/opengl-mapping.dox b/doc/opengl-mapping.dox index 688af3637..7152907b4 100644 --- a/doc/opengl-mapping.dox +++ b/doc/opengl-mapping.dox @@ -394,6 +394,7 @@ OpenGL function | Matching API @def_gl{COLOR_CLEAR_VALUE}, \n @def_gl{DEPTH_CLEAR_VALUE}, \n @def_gl{STENCIL_CLEAR_VALUE} | not queryable, @ref Renderer::setClearColor(), \n @ref Renderer::setClearDepth() and \n @ref Renderer::setClearStencil() setters only @def_gl{COLOR_WRITEMASK}, \n @def_gl{DEPTH_WRITEMASK}, \n @def_gl{STENCIL_BACK_WRITEMASK}, \n @def_gl{STENCIL_WRITEMASK} | not queryable, @ref Renderer::setColorMask(), \n @ref Renderer::setDepthMask() and \n @ref Renderer::setStencilMask() setters only @def_gl{CONTEXT_FLAGS} | @ref Context::flags() +@def_gl{CONTEXT_PROFILE_MASK} | @ref Context::isCoreProfile() @def_gl{CURRENT_PROGRAM} | not queryable but tracked internally @def_gl{DEBUG_GROUP_STACK_DEPTH} | | @def_gl{DEPTH_FUNC} | not queryable, @ref Renderer::setDepthFunction() setter only diff --git a/src/Magnum/CMakeLists.txt b/src/Magnum/CMakeLists.txt index 8d9105546..8898909dd 100644 --- a/src/Magnum/CMakeLists.txt +++ b/src/Magnum/CMakeLists.txt @@ -54,6 +54,7 @@ set(Magnum_SRCS Version.cpp Implementation/BufferState.cpp + Implementation/ContextState.cpp Implementation/FramebufferState.cpp Implementation/MeshState.cpp Implementation/RendererState.cpp @@ -121,6 +122,7 @@ set(Magnum_HEADERS # Header files to display in project view of IDEs only set(Magnum_PRIVATE_HEADERS Implementation/BufferState.h + Implementation/ContextState.h Implementation/FramebufferState.h Implementation/maxTextureSize.h Implementation/MeshState.h diff --git a/src/Magnum/Context.cpp b/src/Magnum/Context.cpp index 1fc54918a..66a889286 100644 --- a/src/Magnum/Context.cpp +++ b/src/Magnum/Context.cpp @@ -25,6 +25,9 @@ #include "Context.h" +#ifndef MAGNUM_TARGET_GLES +#include /* std::find in isCoreProfileImplementationNV() */ +#endif #include /* for initialization log redirection */ #include #include @@ -47,6 +50,7 @@ #include "Magnum/Renderer.h" #include "Implementation/State.h" +#include "Implementation/ContextState.h" #include "Implementation/BufferState.h" #include "Implementation/FramebufferState.h" #include "Implementation/MeshState.h" @@ -775,6 +779,31 @@ std::vector Context::extensionStrings() const { return extensions; } +#ifndef MAGNUM_TARGET_GLES +bool Context::isCoreProfile() { + Implementation::ContextState& state = *_state->context; + Implementation::ContextState::CoreProfile& value = state.coreProfile; + + if(value == Implementation::ContextState::CoreProfile::Initial) + value = (this->*state.isCoreProfileImplementation)() ? + Implementation::ContextState::CoreProfile::Core : + Implementation::ContextState::CoreProfile::Compatibility; + + return value == Implementation::ContextState::CoreProfile::Core; +} + +bool Context::isCoreProfileImplementationDefault() { + GLint value = 0; + glGetIntegerv(GL_CONTEXT_PROFILE_MASK, &value); + return value & GL_CONTEXT_CORE_PROFILE_BIT; +} + +bool Context::isCoreProfileImplementationNV() { + auto extensions = extensionStrings(); + return std::find(extensions.begin(), extensions.end(), "GL_ARB_compatibility") == extensions.end(); +} +#endif + bool Context::isVersionSupported(Version version) const { #ifndef MAGNUM_TARGET_GLES if(version == Version::GLES200) diff --git a/src/Magnum/Context.h b/src/Magnum/Context.h index b2f4eaff4..cbf10f651 100644 --- a/src/Magnum/Context.h +++ b/src/Magnum/Context.h @@ -43,7 +43,10 @@ namespace Magnum { -namespace Implementation { struct State; } +namespace Implementation { + struct ContextState; + struct State; +} namespace Platform { class Context; } /** @@ -112,6 +115,7 @@ Arguments: */ class MAGNUM_EXPORT Context { + friend Implementation::ContextState; friend Platform::Context; public: @@ -371,6 +375,18 @@ class MAGNUM_EXPORT Context { return _supportedExtensions; } + #ifndef MAGNUM_TARGET_GLES + /** + * @brief Detect if current OpenGL context is a core profile + * + * The result is cached, repeated queries don't result in repeated + * OpenGL calls. + * @see @fn_gl{Get} with @def_gl{CORE_PROFILE_MASK} + * @requires_gl Not available on OpenGL ES or WebGL. + */ + bool isCoreProfile(); + #endif + /** * @brief Whether given OpenGL version is supported * @@ -517,6 +533,11 @@ class MAGNUM_EXPORT Context { /* Defined in Implementation/driverSpecific.cpp */ MAGNUM_LOCAL void setupDriverWorkarounds(); + #ifndef MAGNUM_TARGET_GLES + MAGNUM_LOCAL bool isCoreProfileImplementationDefault(); + MAGNUM_LOCAL bool isCoreProfileImplementationNV(); + #endif + void(*_functionLoader)(); Version _version; #ifndef MAGNUM_TARGET_WEBGL diff --git a/src/Magnum/Implementation/ContextState.cpp b/src/Magnum/Implementation/ContextState.cpp new file mode 100644 index 000000000..1647b2c8b --- /dev/null +++ b/src/Magnum/Implementation/ContextState.cpp @@ -0,0 +1,44 @@ +/* + This file is part of Magnum. + + Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017 + Vladimír Vondruš + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. +*/ + +#include "ContextState.h" + +#include "Magnum/Context.h" + +namespace Magnum { namespace Implementation { + +ContextState::ContextState(Context& context, std::vector&) { + #ifndef MAGNUM_TARGET_GLES + if((context.detectedDriver() & Context::DetectedDriver::NVidia) && + !context.isDriverWorkaroundDisabled("nv-zero-context-profile-mask")) + { + isCoreProfileImplementation = &Context::isCoreProfileImplementationNV; + } else isCoreProfileImplementation = &Context::isCoreProfileImplementationDefault; + #else + static_cast(context); + #endif +} + +}} diff --git a/src/Magnum/Implementation/ContextState.h b/src/Magnum/Implementation/ContextState.h new file mode 100644 index 000000000..9684aeb3b --- /dev/null +++ b/src/Magnum/Implementation/ContextState.h @@ -0,0 +1,58 @@ +#ifndef Magnum_Implementation_ContextState_h +#define Magnum_Implementation_ContextState_h +/* + This file is part of Magnum. + + Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017 + Vladimír Vondruš + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. +*/ + +#include +#include + +#include "Magnum/Magnum.h" + +#ifdef _MSC_VER +/* Otherwise the member function pointers will have different size based on + whether the header was included or not. CAUSES SERIOUS MEMORY CORRUPTION AND + IS NOT CAUGHT BY ANY WARNING WHATSOEVER! AARGH! */ +#include "Magnum/Context.h" +#endif + +namespace Magnum { namespace Implementation { + +struct ContextState { + explicit ContextState(Context& context, std::vector& extensions); + + #ifndef MAGNUM_TARGET_GLES + enum class CoreProfile { + Initial, + Core, + Compatibility + } coreProfile = CoreProfile::Initial; + + bool (Context::*isCoreProfileImplementation)(); + #endif +}; + +}} + +#endif diff --git a/src/Magnum/Implementation/State.cpp b/src/Magnum/Implementation/State.cpp index 4c0ed5c1a..71fd6c01f 100644 --- a/src/Magnum/Implementation/State.cpp +++ b/src/Magnum/Implementation/State.cpp @@ -31,6 +31,7 @@ #include "Magnum/Extensions.h" #include "BufferState.h" +#include "ContextState.h" #ifndef MAGNUM_TARGET_WEBGL #include "DebugState.h" #endif @@ -60,6 +61,7 @@ State::State(Context& context, std::ostream* const out) { #endif buffer.reset(new BufferState{context, extensions}); + this->context.reset(new ContextState{context, extensions}); #ifndef MAGNUM_TARGET_WEBGL debug.reset(new DebugState{context, extensions}); #endif diff --git a/src/Magnum/Implementation/State.h b/src/Magnum/Implementation/State.h index 60064b742..a5838f218 100644 --- a/src/Magnum/Implementation/State.h +++ b/src/Magnum/Implementation/State.h @@ -33,6 +33,7 @@ namespace Magnum { namespace Implementation { struct BufferState; +struct ContextState; #ifndef MAGNUM_TARGET_WEBGL struct DebugState; #endif @@ -58,6 +59,7 @@ struct State { enum: GLuint { DisengagedBinding = ~0u }; std::unique_ptr buffer; + std::unique_ptr context; #ifndef MAGNUM_TARGET_WEBGL std::unique_ptr debug; #endif diff --git a/src/Magnum/Implementation/driverSpecific.cpp b/src/Magnum/Implementation/driverSpecific.cpp index 860039e02..3db658b43 100644 --- a/src/Magnum/Implementation/driverSpecific.cpp +++ b/src/Magnum/Implementation/driverSpecific.cpp @@ -78,6 +78,10 @@ namespace { /* NVidia drivers (358.16) return only the first slice of compressed cube map image when querying all six slice using ARB_DSA API */ "nv-cubemap-broken-full-compressed-image-query", + + /* NVidia drivers return 0 when asked for GL_CONTEXT_PROFILE_MASK, + so it needs to be worked around by asking for GL_ARB_compatibility */ + "nv-zero-context-profile-mask", #endif #ifdef CORRADE_TARGET_NACL