You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

1232 lines
52 KiB

#ifndef Magnum_GL_Context_h
#define Magnum_GL_Context_h
/*
This file is part of Magnum.
Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019,
2020, 2021, 2022 Vladimír Vondruš <mosra@centrum.cz>
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.
*/
/** @file
* @brief Class @ref Magnum::GL::Context, @ref Magnum::GL::Extension, macro @ref MAGNUM_ASSERT_GL_VERSION_SUPPORTED(), @ref MAGNUM_ASSERT_GL_EXTENSION_SUPPORTED()
*/
#include <cstdlib>
#include <Corrade/Containers/Array.h>
#include <Corrade/Containers/ArrayTuple.h>
#include <Corrade/Containers/EnumSet.h>
#include <Corrade/Containers/Optional.h>
#include <Corrade/Containers/StaticArray.h>
#include "Magnum/Magnum.h"
#include "Magnum/Math/BoolVector.h"
#include "Magnum/Tags.h"
#include "Magnum/GL/GL.h"
#include "Magnum/GL/OpenGL.h"
#include "Magnum/GL/visibility.h"
#ifdef MAGNUM_BUILD_DEPRECATED
/* For return types of Context::versionString() etc., which used to be a
std::string. Not ideal for the return types, but at least something. */
#include <Corrade/Containers/StringStl.h>
#endif
namespace Magnum {
namespace GL {
namespace Implementation {
struct ContextState;
struct State;
template<class...> class IsExtension;
template<> class IsExtension<> { public: enum: bool { value = true }; };
CORRADE_HAS_TYPE(IsExtension<U>, decltype(T::Index));
template<class T, class U, class ...Args> class IsExtension<T, U, Args...> {
/** @todo C++17: use &&... instead of all this */
public: enum: bool { value = IsExtension<T>::value && IsExtension<U, Args...>::value };
};
/* Context::Configuration::Flag, but because we need to use it inside
Context before the Configuration class is defined, it has to be here */
enum class ContextConfigurationFlag: UnsignedLong {
/* Keeping the 32-bit range reserved for actual GL context flags */
Windowless = 1ull << 59,
QuietLog = 1ull << 60,
VerboseLog = 1ull << 61,
GpuValidation = 1ull << 62,
GpuValidationNoError = 1ull << 63
};
typedef Containers::EnumSet<ContextConfigurationFlag> ContextConfigurationFlags;
CORRADE_ENUMSET_OPERATORS(ContextConfigurationFlags)
}
/**
@brief Run-time information about OpenGL extension
Encapsulates runtime information about OpenGL extension, such as name string,
minimal required OpenGL version and version in which the extension was adopted
to core.
See also @ref Extensions namespace, which contain compile-time information
about OpenGL extensions.
*/
class MAGNUM_GL_EXPORT Extension {
public:
/** @brief All extensions for given OpenGL version */
static Containers::ArrayView<const Extension> extensions(Version version);
/** @brief Internal unique extension index */
constexpr std::size_t index() const { return _index; }
/** @brief Minimal version required by this extension */
constexpr Version requiredVersion() const { return _requiredVersion; }
/** @brief Version in which this extension was adopted to core */
constexpr Version coreVersion() const { return _coreVersion; }
/** @brief Extension string */
constexpr const char* string() const { return _string; }
/** @brief Construct from a compile-time extension */
template<class E, class = typename std::enable_if<Implementation::IsExtension<E>::value>::type> constexpr /*implicit*/ Extension(const E&): _index{E::Index}, _requiredVersion{E::requiredVersion()}, _coreVersion{E::coreVersion()}, _string{E::string()} {}
private:
std::size_t _index;
Version _requiredVersion;
Version _coreVersion;
const char* _string;
};
/**
@brief Magnum OpenGL context
Provides access to OpenGL version and extension information and manages
Magnum's internal OpenGL state tracker.
@m_class{m-note m-success}
@par
There's also the @ref magnum-gl-info "magnum-gl-info" tool that provides
access to OpenGL version, extension and platform-specific limit information
through a command line interface.
@section GL-Context-usage Creating a context
In order to use any Magnum OpenGL functionality, an instance of this class has
to exist and be made current. If you use any `Platform::*Application` classes,
an instance available through @ref Context::current() is automatically created
during construction (or after @ref Platform::Sdl2Application::create() "Platform::*Application::create()"
/ @relativeref{Platform::Sdl2Application,tryCreate()} and you can safely assume
the instance is available during the whole `*Application` lifetime. It's also
possible to create the context without using any `*Application` class using the
@ref Platform::GLContext subclass, see @ref platform for more information.
Various options can be passed using the @ref Configuration class, which is then
extended by various
@ref Platform::Sdl2Application::GLConfiguration "Platform::*Application::GLConfiguration"
and @ref Platform::WindowlessEglContext::Configuration "Platform::Windowless*Application::Configuration"
subclasses.
@subsection GL-Context-usage-command-line Command-line options
In addition to the @ref Configuration, the context is configurable through
command-line options, that are passed either from the `Platform::*Application`
classes or from the @ref Platform::GLContext class. In case an option is set in
both the @ref Configuration and on command-line / environment, the two are
combined together --- flags ORed together, lists joined. Usage:
@code{.sh}
<application> [--magnum-help] [--magnum-disable-workarounds LIST]
[--magnum-disable-extensions LIST]
[--magnum-gpu-validation off|on]
[--magnum-log default|quiet|verbose] ...
@endcode
Arguments:
- `...` --- main application arguments (see `-h` or `--help` for details)
- `--magnum-help` --- display this help message and exit
- `--magnum-disable-workarounds LIST` --- driver workarounds to disable (see
@ref opengl-workarounds for detailed info) (environment:
`MAGNUM_DISABLE_WORKAROUNDS`). Corresponds to
@ref Configuration::addDisabledWorkarounds().
- `--magnum-disable-extensions LIST` --- API extensions to disable
(environment: `MAGNUM_DISABLE_EXTENSIONS`). Corresponds to
@ref Configuration::addDisabledExtensions().
- `--magnum-gpu-validation off|on|no-error` --- GPU validation using
@gl_extension{KHR,debug}, if present (environment:
`MAGNUM_GPU_VALIDATION`) (default: `off`). This sets up @ref DebugOutput
callbacks and also causes
@ref Platform::Sdl2Application::GLConfiguration::Flag::Debug "GLConfiguration::Flag::Debug"
to be enabled for context creation for both windowed and windowless
applications on supported platforms. Corresponds to
@ref Configuration::Flag::GpuValidation /
@ref Configuration::Flag::GpuValidationNoError.
- `--magnum-log default|quiet|verbose` --- console logging
(environment: `MAGNUM_LOG`) (default: `default`). Corresponds to
@ref Configuration::Flag::QuietLog and
@relativeref{Configuration::Flag,VerboseLog}.
Note that all options are prefixed with `--magnum-` to avoid conflicts with
options passed to the application itself. Options that don't have this prefix
are completely ignored, see documentation of the
@ref Utility-Arguments-delegating "Utility::Arguments" class for details.
Particular application implementations add more options for DPI scaling or
GPU selection, see @ref Platform::Sdl2Application, @ref Platform::GlfwApplication
and @ref Platform::WindowlessEglApplication for details.
@subsection GL-Context-usage-multiple Using multiple OpenGL contexts
By default, Magnum assumes you have one OpenGL context active at all times, and
all state tracking is done by the @ref Context instance that's associated with
it. When you are using multiple OpenGL contexts, each of them needs to have a
corresponding @ref Context instance active at the same time, and you need to
ensure you only access OpenGL objects that were created by the same context as
is currently active.
To prevent accidents in common cases, the @ref Context class expects that no
other instance is active during its creation. In order to create additional
instances for other OpenGL contexts, *first* you need to "unset" the current one
with @ref makeCurrent() and *then* create another instance, which will then
become implicitly active:
@snippet MagnumGL-application.cpp Context-makeCurrent-nullptr
Once all needed instances are created, switch between them right after making
the underlying GL context current:
@snippet MagnumGL-application.cpp Context-makeCurrent
@section GL-Context-multithreading Thread safety
If Corrade is compiled with @ref CORRADE_BUILD_MULTITHREADED (the default), the
@ref hasCurrent() and @ref current() accessors are thread-local, matching the
OpenGL context thread locality. This might cause some performance penalties ---
if you are sure that you never need to have multiple independent thread-local
Magnum context, build Corrade with the option disabled.
*/
class MAGNUM_GL_EXPORT Context {
public:
class Configuration;
#ifndef MAGNUM_TARGET_WEBGL
/**
* @brief Context flag
*
* @see @ref Flags, @ref flags(),
* @ref Platform::Sdl2Application::GLConfiguration::setFlags() "Platform::*Application::GLConfiguration::setFlags()"
* @m_enum_values_as_keywords
* @requires_gles Context flags are not available in WebGL.
*/
enum class Flag: GLint {
/**
* Debug context. Enabled automatically by @ref Platform windowed
* and windowless application implementations if the
* @ref Configuration::Flag::GpuValidation flag is set or if the
* `--magnum-gpu-validation`
* @ref GL-Context-usage-command-line "command-line option" is
* set to `on`.
* @requires_gl43 Extension @gl_extension{KHR,debug}
* @requires_gles32 Extension @gl_extension{ANDROID,extension_pack_es31a} /
* @gl_extension{KHR,debug}
*/
#ifndef MAGNUM_TARGET_GLES2
Debug = GL_CONTEXT_FLAG_DEBUG_BIT,
#else
Debug = GL_CONTEXT_FLAG_DEBUG_BIT_KHR,
#endif
#ifndef MAGNUM_TARGET_GLES
/**
* Forward compatible context
* @see @ref isCoreProfile()
* @requires_gl Core/compatibility profile distinction and forward
* compatibility applies only to desktop GL.
*/
ForwardCompatible = GL_CONTEXT_FLAG_FORWARD_COMPATIBLE_BIT,
#endif
/**
* Context without error reporting. Enabled automatically by
* @ref Platform windowed and windowless application
* implementations if the @ref Configuration::Flag::GpuValidationNoError
* flag is set or if the `--magnum-gpu-validation`
* @ref GL-Context-usage-command-line "command-line option" is
* set to `no-error`.
* @requires_gl46 Extension @gl_extension{KHR,no_error}
* @requires_es_extension Extension @gl_extension{KHR,no_error}
*/
#ifndef MAGNUM_TARGET_GLES
NoError = GL_CONTEXT_FLAG_NO_ERROR_BIT,
#else
NoError = GL_CONTEXT_FLAG_NO_ERROR_BIT_KHR,
#endif
#ifndef MAGNUM_TARGET_GLES2
/**
* Context with robust access
* @requires_gl45 Extension @gl_extension{KHR,robustness} or
* @gl_extension{ARB,robustness}
* @requires_gles32 Extension @gl_extension{KHR,robustness} or
* @gl_extension{EXT,robustness}
* @todo In ES2 available under glGetIntegerv(CONTEXT_ROBUST_ACCESS_EXT),
* how to make it compatible?
*/
RobustAccess = GL_CONTEXT_FLAG_ROBUST_ACCESS_BIT
#endif
};
/**
* @brief Context flags
*
* @see @ref flags()
* @requires_gles Context flags are not available in WebGL.
*/
typedef Containers::EnumSet<Flag> Flags;
#endif
/**
* @brief State to reset
*
* @see @ref States, @ref resetState(), @ref opengl-state-tracking
*/
enum class State: UnsignedInt {
/** Reset tracked buffer-related bindings and state */
Buffers = 1 << 0,
#ifndef MAGNUM_TARGET_GLES2
/**
* Unbind currently bound PBO.
*
* Not all third-party code is aware of PBOs, and if a PBO is bound
* when Magnum transfers control to an unaware code, it can cause
* various issues with textures. This is a similar, but rarer,
* case to @ref State::MeshVao / @ref State::BindScratchVao.
*/
UnbindPixelBuffer = 1 << 1,
#endif
/** Reset tracked framebuffer-related bindings and state */
Framebuffers = 1 << 2,
/** Reset tracked mesh-related bindings */
Meshes = 1 << 3,
/**
* Unbind currently bound VAO.
*
* Magnum by default uses VAOs --- each time a @ref Mesh is drawn
* or configured, its VAO is bound, but it is *not* unbound
* afterwards to avoid needless state changes. This may introduce
* problems when using third-party OpenGL code --- it may break
* internal state of a mesh that was used the most recently.
* Similar issue can happen the other way. Calling @ref resetState()
* with @ref State::MeshVao included unbounds any currently bound
* VAO to fix such case.
*/
MeshVao = 1 << 4,
/**
* Bind a "scratch" VAO on core profile.
*
* Use if external code is not VAO-aware and would otherwise try to
* enable vertex attributes on the default (zero) VAO, causing GL
* errors. Meant to be used together with @ref State::MeshVao (or
* @ref State::EnterExternal).
*
* Does nothing on compatibility profile and ES / WebGL platforms,
* as using the default VAO is allowed there.
*/
BindScratchVao = 1 << 5,
/** Reset tracked pixel storage-related state */
PixelStorage = 1 << 6,
/** Reset tracked renderer-related state */
Renderer = 1 << 7,
/** Reset tracked shader-related bindings */
Shaders = 1 << 8,
/** Reset tracked texture-related bindings and state */
Textures = 1 << 9,
#ifndef MAGNUM_TARGET_GLES2
/** Reset tracked transform feedback-related bindings */
TransformFeedback = 1 << 10,
#endif
/**
* Reset state on entering section with external OpenGL code.
*
* Resets all state that could cause external code to accidentally
* modify Magnum objects. This includes @ref State::MeshVao and
* @ref State::UnbindPixelBuffer. In some pathological cases you
* may want to enable @ref State::BindScratchVao as well.
*/
EnterExternal = MeshVao
#ifndef MAGNUM_TARGET_GLES2
|UnbindPixelBuffer
#endif
,
/**
* Reset state on exiting section with external OpenGL code.
*
* Resets Magnum state tracker to avoid being confused by external
* state changes. This resets all states, however
* @ref State::UnbindPixelBuffer is excluded as Magnum's state
* tracker will ensure no PBO is bound when calling related OpenGL
* APIs.
*/
ExitExternal = Buffers|Framebuffers|Meshes|MeshVao|PixelStorage|Renderer|Shaders|Textures
#ifndef MAGNUM_TARGET_GLES2
|TransformFeedback
#endif
};
/**
* @brief States to reset
*
* @see @ref resetState()
*/
typedef Containers::EnumSet<State> States;
/**
* @brief Detected driver
*
* On WebGL, if @webgl_extension{WEBGL,debug_renderer_info} is not
* available and the browser doesn't report the real values through
* @ref vendorString() and @ref rendererString(), driver detection can
* be performed only for limited cases --- see documentation of
* particular values for more information.
* @see @ref DetectedDrivers, @ref detectedDriver()
*/
enum class DetectedDriver: UnsignedShort {
/**
* Proprietary AMD desktop drivers on Windows and Linux. In
* contrast, AMDGPU Mesa drivers report as
* @ref DetectedDriver::Mesa instead.
*/
Amd = 1 << 0,
#if defined(MAGNUM_TARGET_GLES) || defined(DOXYGEN_GENERATING_OUTPUT)
/**
* OpenGL ES implementation by ANGLE (translated to D3D), used by
* browsers on Windows for WebGL. See also
* @ref DetectedDriver::SwiftShader. On WebGL, if
* @webgl_extension{WEBGL,debug_renderer_info} is not available,
* the detection is attempted by checking for a presence of
* @webgl_extension{ANGLE,instanced_arrays} on WebGL 1 (which may
* also be implemented by other drivers than ANGLE) or
* @webgl_extension{WEBGL,multi_draw} on WebGL 2 (which may not be
* available yet on older ANGLE versions), and as a fallback by
* checking if the line size range is just 1, which is always the
* case on D3D but not always on GL.
* @requires_gles ANGLE doesn't support desktop OpenGL contexts.
*/
Angle = 1 << 1,
#endif
/** Intel desktop drivers on Windows */
IntelWindows = 1 << 2,
/**
* Mesa drivers on Windows and Linux. In particular, Intel, AMD
* and NVidia Mesa drivers match as this. See also
* @ref DetectedDriver::Svga3D.
*/
Mesa = 1 << 3,
/** Proprietary NVidia drivers on Windows and Linux */
NVidia = 1 << 4,
/**
* VMware guest GL driver SVGA3D, implemented using Mesa, both
* Windows and Linux guests. See https://www.mesa3d.org/vmware-guest.html
* for more information. Detected in combination with
* @ref DetectedDriver::Mesa.
*/
Svga3D = 1 << 5,
#if defined(MAGNUM_TARGET_GLES) || defined(DOXYGEN_GENERATING_OUTPUT)
/**
* [SwiftShader](https://github.com/google/swiftshader) software
* renderer for OpenGL ES. Usually used by browsers in cases where
* a GPU isn't available. See also @ref DetectedDriver::Angle.
* @requires_gles SwiftShader doesn't support desktop OpenGL
* contexts.
* @m_since{2019,10}
*/
SwiftShader = 1 << 6,
#endif
#if defined(CORRADE_TARGET_ANDROID) || defined(DOXYGEN_GENERATING_OUTPUT)
/**
* ARM Mali drivers on OpenGL ES.
* @partialsupport Available only on
* @ref CORRADE_TARGET_ANDROID "Android".
* @m_since{2019,10}
*/
ArmMali = 1 << 7
#endif
};
/**
* @brief Detected drivers
*
* @see @ref detectedDriver()
*/
typedef Containers::EnumSet<DetectedDriver> DetectedDrivers;
/**
* @brief Whether there is any current context
*
* If Corrade is built with @ref CORRADE_BUILD_MULTITHREADED, current
* context is thread-local instead of global (the default).
* @see @ref current()
*/
static bool hasCurrent();
/**
* @brief Current context
*
* Expect that there is current context. If Corrade is built with
* @ref CORRADE_BUILD_MULTITHREADED, current context is thread-local
* instead of global (the default).
* @see @ref hasCurrent()
*/
static Context& current();
/**
* @brief Make a context current
* @m_since{2019,10}
*
* To be used when you need to manage multiple OpenGL contexts. See
* @ref GL-Context-usage-multiple for more information.
*/
static void makeCurrent(Context* context);
/** @brief Copying is not allowed */
Context(const Context&) = delete;
/** @brief Move constructor */
Context(Context&& other) noexcept;
~Context();
/** @brief Copying is not allowed */
Context& operator=(const Context&) = delete;
/** @brief Move assignment is not allowed */
Context& operator=(Context&&) = delete;
/**
* @brief OpenGL version
*
* @see @ref versionString(), @ref shadingLanguageVersionString()
*/
Version version() const { return _version; }
/**
* @brief Vendor string
*
* The result is *not* cached, repeated queries will result in repeated
* OpenGL calls. The returned view is always
* @relativeref{Corrade,Containers::StringViewFlag::NullTerminated} and
* @relativeref{Corrade::Containers::StringViewFlag,Global}. In WebGL
* the vendor string is implicitly masked away, use
* @ref vendorStringUnmasked() to access the real vendor string, if
* available.
* @see @ref rendererString(), @fn_gl{GetString} with
* @def_gl_keyword{VENDOR}
*/
Containers::StringView vendorString() const;
#if defined(MAGNUM_TARGET_WEBGL) || defined(DOXYGEN_GENERATING_OUTPUT)
/**
* @brief Unmasked vendor string
* @m_since_latest
*
* A WebGL counterpart to @ref vendorString() that returns the real
* vendor string. If @webgl_extension{WEBGL,debug_renderer_info} is not
* available, returns the same as @ref vendorString().
*
* The result is *not* cached, repeated queries will result in repeated
* OpenGL calls. The returned view is always
* @relativeref{Corrade,Containers::StringViewFlag::NullTerminated} and
* @relativeref{Corrade::Containers::StringViewFlag,Global}.
* @see @ref rendererStringUnmasked(), @fn_gl{GetString} with
* @def_gl_keyword{UNMASKED_VENDOR_WEBGL}
* @requires_webgl_only Not available on desktop or ES builds.
*/
Containers::StringView vendorStringUnmasked() const;
#endif
/**
* @brief Renderer string
*
* The result is *not* cached, repeated queries will result in repeated
* OpenGL calls. The returned view is always
* @relativeref{Corrade,Containers::StringViewFlag::NullTerminated} and
* @relativeref{Corrade::Containers::StringViewFlag,Global}. In WebGL
* the renderer string is implicitly masked away, use
* @ref rendererStringUnmasked() to access the real renderer string, if
* available.
* @see @ref vendorString(), @fn_gl{GetString} with
* @def_gl_keyword{RENDERER}
*/
Containers::StringView rendererString() const;
#if defined(MAGNUM_TARGET_WEBGL) || defined(DOXYGEN_GENERATING_OUTPUT)
/**
* @brief Unmasked renderer string
* @m_since_latest
*
* A WebGL counterpart to @ref rendererString() that returns the real
* renderer string. If @webgl_extension{WEBGL,debug_renderer_info} is
* not available, returns the same as @ref rendererString().
*
* The result is *not* cached, repeated queries will result in repeated
* OpenGL calls. The returned view is always
* @relativeref{Corrade,Containers::StringViewFlag::NullTerminated} and
* @relativeref{Corrade::Containers::StringViewFlag,Global}.
* @see @ref vendorStringUnmasked(), @fn_gl{GetString} with
* @def_gl_keyword{UNMASKED_RENDERER_WEBGL}
* @requires_webgl_only Not available on desktop or ES builds.
*/
Containers::StringView rendererStringUnmasked() const;
#endif
/**
* @brief Version string
*
* The result is *not* cached, repeated queries will result in repeated
* OpenGL calls. The returned view is always
* @relativeref{Corrade,Containers::StringViewFlag::NullTerminated} and
* @relativeref{Corrade::Containers::StringViewFlag,Global}.
* @see @ref shadingLanguageVersionString(), @ref version(),
* @fn_gl{GetString} with @def_gl_keyword{VERSION}
*/
Containers::StringView versionString() const;
/**
* @brief Shading language version string
*
* The result is *not* cached, repeated queries will result in repeated
* OpenGL calls. The returned view is always
* @relativeref{Corrade,Containers::StringViewFlag::NullTerminated} and
* @relativeref{Corrade::Containers::StringViewFlag,Global}.
* @see @ref versionString(), @ref version(), @fn_gl{GetString} with
* @def_gl_keyword{SHADING_LANGUAGE_VERSION}
*/
Containers::StringView shadingLanguageVersionString() const;
/**
* @brief Shading language version strings
*
* The result is *not* cached, repeated queries will result in repeated
* OpenGL calls. The returned view is always
* @relativeref{Corrade,Containers::StringViewFlag::NullTerminated} and
* @relativeref{Corrade::Containers::StringViewFlag,Global}.
* @see @ref versionString(), @ref version(), @fn_gl{Get} with
* @def_gl_keyword{NUM_SHADING_LANGUAGE_VERSIONS}, @fn_gl{GetString}
* with @def_gl_keyword{SHADING_LANGUAGE_VERSION}
*/
Containers::Array<Containers::StringView> shadingLanguageVersionStrings() const;
/**
* @brief Extension strings
*
* The result is *not* cached, repeated queries will result in repeated
* OpenGL calls. Note that this function returns list of all extensions
* reported by the driver (even those not supported by Magnum), see
* @ref supportedExtensions(), @ref Extension::extensions() or
* @ref isExtensionSupported() for alternatives. The returned views are
* always @relativeref{Corrade,Containers::StringViewFlag::NullTerminated}
* and @relativeref{Corrade::Containers::StringViewFlag,Global}.
* @see @fn_gl{Get} with @def_gl_keyword{NUM_EXTENSIONS},
* @fn_gl{GetString} with @def_gl_keyword{EXTENSIONS}
*/
Containers::Array<Containers::StringView> extensionStrings() const;
#ifndef MAGNUM_TARGET_WEBGL
/**
* @brief Context flags
*
* @requires_gles Context flags are not available in WebGL.
*/
Flags flags() const { return _flags; }
#endif
#ifdef MAGNUM_BUILD_DEPRECATED
/**
* @brief Supported extensions
*
* The list contains only extensions from OpenGL versions newer than
* the current.
* @m_deprecated_since_latest Deprecated as it doesn't provide anything
* that @ref extensionStrings(), @ref Extension::extensions() and
* @ref isExtensionSupported() wouldn't provide already and only
* causes extra overhead during context creation.
*/
CORRADE_DEPRECATED("use extensionStrings(), Extension::extensions() and isExtensionSupported() instead") Containers::ArrayView<const Extension> supportedExtensions() const {
return _supportedExtensions;
}
#endif
#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_keyword{CORE_PROFILE_MASK},
* @ref Flag::ForwardCompatible
* @requires_gl Core/compatibility profile distinction and forward
* compatibility applies only to desktop GL.
*/
bool isCoreProfile();
#endif
/**
* @brief Whether given OpenGL version is supported
*
* @see @ref supportedVersion(), @ref MAGNUM_ASSERT_GL_VERSION_SUPPORTED()
*/
bool isVersionSupported(Version version) const;
/**
* @brief Get supported OpenGL version
*
* Returns first supported OpenGL version from passed list. Convenient
* equivalent to subsequent @ref isVersionSupported() calls --- the two
* following examples produce the same result:
*
* @snippet MagnumGL.cpp Context-supportedVersion
*
* If no version from the list is supported, returns lowest available
* OpenGL version (@ref Version::GL210 for desktop OpenGL,
* @ref Version::GLES200 for OpenGL ES).
* @see @ref isExtensionSupported(Version) const
*/
Version supportedVersion(std::initializer_list<Version> versions) const;
/**
* @brief Whether given extension is supported
*
* Extensions usable with this function are listed in the
* @ref Extensions namespace in the @ref Magnum/GL/Extensions.h header
* and in the @ref opengl-support "OpenGL support tables". Example
* usage:
*
* @snippet MagnumGL.cpp Context-isExtensionSupported
*
* @see @ref isExtensionSupported(const Extension&) const,
* @ref MAGNUM_ASSERT_GL_EXTENSION_SUPPORTED(),
* @ref isExtensionDisabled()
*/
template<class E> bool isExtensionSupported() const {
return isExtensionSupported<E>(version());
}
/**
* @brief Whether given extension is supported in given version
*
* Similar to @ref isExtensionSupported(), but checks also that the
* minimal required version of the extension is larger or equal to
* @p version. Useful mainly in shader compilation when the decisions
* depend on selected GLSL version, for example:
*
* @snippet MagnumGL.cpp Context-isExtensionSupported-version
*/
template<class E> bool isExtensionSupported(Version version) const {
static_assert(Implementation::IsExtension<E>::value, "expected an OpenGL extension");
return _extensionRequiredVersion[E::Index] <= version && _extensionStatus[E::Index];
}
/**
* @brief Whether given extension is supported
*
* Can be used e.g. for listing extensions available on current
* hardware, but for general usage prefer @ref isExtensionSupported() const,
* as it does most operations in compile time.
* @see @ref supportedExtensions(), @ref Extension::extensions(),
* @ref MAGNUM_ASSERT_GL_EXTENSION_SUPPORTED()
*/
bool isExtensionSupported(const Extension& extension) const {
return isVersionSupported(_extensionRequiredVersion[extension.index()]) && _extensionStatus[extension.index()];
}
/**
* @brief Whether given extension is disabled
*
* Can be used for detecting driver bug workarounds. Disabled
* extensions return @cpp false @ce in @ref isExtensionSupported() even
* if they are advertised as being supported by the driver.
* @see @ref Configuration::addDisabledExtensions(),
* @ref GL-Context-usage-command-line
*/
template<class E> bool isExtensionDisabled() const {
return isExtensionDisabled<E>(version());
}
/**
* @brief Whether given extension is disabled for given version
*
* Similar to above, but can also check for extensions which are
* disabled only for particular versions.
* @see @ref Configuration::addDisabledExtensions(),
* @ref GL-Context-usage-command-line
*/
template<class E> bool isExtensionDisabled(Version version) const {
static_assert(Implementation::IsExtension<E>::value, "expected an OpenGL extension");
/* The extension is advertised, but the minimal version has been
increased */
return E::requiredVersion() <= version && _extensionRequiredVersion[E::Index] > version;
}
/**
* @brief Whether given extension is disabled
*
* Can be used e.g. for listing extensions available on current
* hardware, but for general usage prefer
* @ref isExtensionDisabled() const, as it does most operations at
* compile time.
* @see @ref Configuration::addDisabledExtensions(),
* @ref GL-Context-usage-command-line
*/
bool isExtensionDisabled(const Extension& extension) const {
return isVersionSupported(extension.requiredVersion()) && !isVersionSupported(_extensionRequiredVersion[extension.index()]);
}
/**
* @brief Reset internal state tracker
*
* The engine internally tracks object bindings and other state to
* avoid redundant OpenGL calls. In some cases (e.g. when non-Magnum
* code makes GL calls) the internal tracker no longer reflects actual
* state. Equivalently the third party code can cause accidental
* modifications of Magnum objects. It's thus advised to call this
* function as a barrier between Magnum code and third-party GL code.
*
* The default, when calling this function with no parameters, will
* reset all state. That's the safest option, but may have considerable
* performance impact when third-party and Magnum code is combined very
* often. For greater control it's possible to reset only particular
* states from the @ref State enum.
*
* See also @ref opengl-state-tracking for more information.
*/
void resetState(States states = ~States{});
/**
* @brief Detect driver
*
* Tries to detect driver using various OpenGL state queries. Once the
* detection is done, the result is cached, repeated queries don't
* result in repeated GL calls. Used primarily for enabling
* driver-specific workarounds.
*/
DetectedDrivers detectedDriver();
#ifdef DOXYGEN_GENERATING_OUTPUT
private:
#endif
bool isDriverWorkaroundDisabled(Containers::StringView workaround);
Implementation::State& state() { return *_state; }
/* This function is called from MeshState constructor, which means the
state() pointer is not ready yet so we have to pass it directly */
MAGNUM_GL_LOCAL bool isCoreProfileInternal(Implementation::ContextState& state);
Implementation::ContextConfigurationFlags configurationFlags() const { return _configurationFlags; }
#ifdef DOXYGEN_GENERATING_OUTPUT
private:
#else
protected:
#endif
/* Made protected so it's possible to test the NoCreate constructor and
also not needed to friend Platform::GLContext. */
explicit Context(NoCreateT, Int argc, const char** argv, void functionLoader(Context&));
explicit Context(NoCreateT, Utility::Arguments&& args, Int argc, const char** argv, void functionLoader(Context&)): Context{NoCreate, args, argc, argv, functionLoader} {}
explicit Context(NoCreateT, Utility::Arguments& args, Int argc, const char** argv, void functionLoader(Context&));
bool tryCreate(const Configuration& configuration);
void create(const Configuration& configuration);
private:
#ifndef DOXYGEN_GENERATING_OUTPUT /* https://bugzilla.gnome.org/show_bug.cgi?id=776986 */
friend Implementation::ContextState;
#endif
MAGNUM_GL_LOCAL void disableDriverWorkaround(Containers::StringView workaround);
/* Defined in Implementation/driverSpecific.cpp */
MAGNUM_GL_LOCAL void setupDriverWorkarounds();
#ifndef MAGNUM_TARGET_GLES
MAGNUM_GL_LOCAL static bool isCoreProfileImplementationDefault(Context& self);
MAGNUM_GL_LOCAL static bool isCoreProfileImplementationNV(Context& self);
#endif
void(*_functionLoader)(Context&){};
Version _version;
#ifndef MAGNUM_TARGET_WEBGL
Flags _flags;
#endif
Math::BoolVector<Implementation::ExtensionCount> _extensionStatus;
/* For all extensions that are marked as supported in _extensionStatus,
this field contains the minimal required GL version the extension
needs. Extensions that are disabled have None here. */
Containers::StaticArray<Implementation::ExtensionCount, Version> _extensionRequiredVersion;
#ifdef MAGNUM_BUILD_DEPRECATED
Containers::Array<Extension> _supportedExtensions;
#endif
Containers::ArrayTuple _stateData;
Implementation::State* _state;
Containers::Optional<DetectedDrivers> _detectedDrivers;
/** @todo these are all needed only until the state gets created and
then can be discarded -- what to do? we could avoid including
Array altogether */
/* True means known and disabled, false means known */
Containers::Array<std::pair<Containers::StringView, bool>> _driverWorkarounds;
Containers::Array<Extension> _disabledExtensions;
Implementation::ContextConfigurationFlags _configurationFlags;
};
#ifndef MAGNUM_TARGET_WEBGL
CORRADE_ENUMSET_OPERATORS(Context::Flags)
#endif
CORRADE_ENUMSET_OPERATORS(Context::DetectedDrivers)
CORRADE_ENUMSET_OPERATORS(Context::States)
#ifndef MAGNUM_TARGET_WEBGL
/** @debugoperatorclassenum{Context,Context::Flag} */
MAGNUM_GL_EXPORT Debug& operator<<(Debug& debug, Context::Flag value);
/** @debugoperatorclassenum{Context,Context::Flags} */
MAGNUM_GL_EXPORT Debug& operator<<(Debug& debug, Context::Flags value);
#endif
/** @debugoperatorclassenum{Context,Context::DetectedDriver} */
MAGNUM_GL_EXPORT Debug& operator<<(Debug& debug, Context::DetectedDriver value);
/** @debugoperatorclassenum{Context,Context::DetectedDrivers} */
MAGNUM_GL_EXPORT Debug& operator<<(Debug& debug, Context::DetectedDrivers value);
/**
@brief Configuration
@m_since_latest
Affects how Magnum's context creation behaves. See @ref GL-Context-usage for
more information.
@see @ref Platform::GLContext::GLContext(),
@ref Platform::GLContext::create(),
@ref Platform::GLContext::tryCreate()
*/
class MAGNUM_GL_EXPORT Context::Configuration {
public:
/**
* @brief Context setup flag
*
* Flags affecting the actual GL context are merged with this enum in
* @ref Platform::Sdl2Application::GLConfiguration::Flag "Platform::*Application::GLConfiguration::Flag"
* and @ref Platform::WindowlessEglContext::Configuration::Flag "Platform::Windowless*Application::Configuration::Flag"
* and after context creation available through @ref Context::Flag /
* @ref Context::flags().
* @see @ref Flags, @ref setFlags()
*/
#ifdef DOXYGEN_GENERATING_OUTPUT
enum class Flag: UnsignedLong {
/* Docs only, keep in sync with
Implementation::ContextConfigurationFlag please */
/**
* Treat the context as windowless, assume there's no default
* framebuffer and thus don't initialize or touch
* @ref defaultFramebuffer in any way.
*
* This flag is implicitly enabled in all
* @ref Platform::WindowlessEglContext::Configuration "Platform::Windowless*Application::Configuration",
* and, conversely, not possible to enable in any
* @ref Platform::Sdl2Application::GLConfiguration::Flag "Platform::*Application::GLConfiguration".
*/
Windowless = 1ull << 59,
/**
* Print only warnings and errors instead of the usual startup log
* listing used extensions and workarounds. Ignored if
* @ref Flag::VerboseLog is set.
*
* Corresponds to the `--magnum-log quiet`
* @ref GL-Context-usage-command-line "command-line option".
*/
QuietLog = 1ull << 60,
/**
* Print additional information on startup in addition to the usual
* startup log that lists used extensions and workarounds. Has a
* precedence over @ref Flag::QuietLog.
*
* Corresponds to the `--magnum-log verbose`
* @ref GL-Context-usage-command-line "command-line option".
*/
VerboseLog = 1ull << 61,
/**
* Enable GPU validation, if available. Has a precedence over
* @ref Flag::GpuValidationNoError.
*
* Corresponds to the `--magnum-gpu-validation on`
* @ref GL-Context-usage-command-line "command-line option".
*/
GpuValidation = 1ull << 62,
/**
* Enable a context without error reporting, if available. Ignored
* if @ref Flag::GpuValidation is set.
*
* Corresponds to the `--magnum-gpu-validation no-error`
* @ref GL-Context-usage-command-line "command-line option".
*/
GpuValidationNoError = 1ull << 63
};
#else
typedef Implementation::ContextConfigurationFlag Flag;
#endif
/**
* @brief Context setup flags
*
* @see @ref setFlags(), @ref GL::Context::Flags
*/
#ifdef DOXYGEN_GENERATING_OUTPUT
typedef Containers::EnumSet<Flag> Flags;
#else
typedef Implementation::ContextConfigurationFlags Flags;
#endif
/*implicit*/ Configuration();
/** @brief Copy constructor */
/* The class has to be copyable in order to make command-line and
configuration options easy to merge in application implementations
-- these make a mutable copy and add what arrived via command line */
Configuration(const Configuration& other);
/** @brief Move constructor */
Configuration(Configuration&&) noexcept;
~Configuration();
/** @brief Copy constructor */
Configuration& operator=(const Configuration& other);
/** @brief Move assignment */
Configuration& operator=(Configuration&&) noexcept;
/** @brief Context setup flags */
Flags flags() const { return _flags; }
/**
* @brief Set context setup flags
* @return Reference to self (for method chaining)
*
* By default no flags are set. Note that subclasses might have
* different flag defaults, see their documentation for more
* information. To avoid clearing default flags by accident, prefer to
* use @ref addFlags() and @ref clearFlags() instead.
*
* Particular @ref Flag values correspond to the `--magnum-log` and
* `--magnum-gpu-validation`
* @ref GL-Context-usage-command-line "command-line options".
*/
Configuration& setFlags(Flags flags) {
_flags = flags;
return *this;
}
/**
* @brief Add context setup flags
* @return Reference to self (for method chaining)
*
* Unlike @ref setFlags(), ORs the flags with existing instead of
* replacing them. Useful for preserving the defaults.
* @see @ref clearFlags()
*/
Configuration& addFlags(Flags flags) {
_flags |= flags;
return *this;
}
/**
* @brief Clear context setup flags
* @return Reference to self (for method chaining)
*
* Unlike @ref setFlags(), ANDs the inverse of @p flags with existing
* instead of replacing them. Useful for removing default flags.
* @see @ref addFlags()
*/
Configuration& clearFlags(Flags flags) {
_flags &= ~flags;
return *this;
}
/** @brief Disabled driver workarounds */
Containers::ArrayView<const Containers::StringView> disabledWorkarounds() const;
/**
* @brief Add disabled driver workarounds
* @return Reference to self (for method chaining)
*
* Accepts strings from the list at @ref opengl-workarounds. Unknown
* workarounds are ignored with a warning. By default no workarounds
* are disabled.
*
* Corresponds to the `--magnum-disable-workarounds`
* @ref GL-Context-usage-command-line "command-line option".
*/
Configuration& addDisabledWorkarounds(Containers::ArrayView<const Containers::StringView> workarounds);
/** @overload */
Configuration& addDisabledWorkarounds(std::initializer_list<Containers::StringView> workarounds);
/** @brief Disabled extensions */
Containers::ArrayView<const Extension> disabledExtensions() const;
/**
* @brief Add disabled extensions
* @return Reference to self (for method chaining)
*
* By default no extensions are disabled, except for those disabled by
* driver workarounds.
*
* Corresponds to the `--magnum-disable-extensions`
* @ref GL-Context-usage-command-line "command-line option".
*/
Configuration& addDisabledExtensions(Containers::ArrayView<const Extension> extensions);
/** @overload */
Configuration& addDisabledExtensions(std::initializer_list<Extension> extensions);
/** @overload */
template<class ...E> Configuration& addDisabledExtensions() {
static_assert(Implementation::IsExtension<E...>::value, "expected only OpenGL extensions");
return addDisabledExtensions({E{}...});
}
private:
Flags _flags;
Containers::Array<Containers::StringView> _disabledWorkarounds;
Containers::Array<Extension> _disabledExtensions;
};
#ifndef DOXYGEN_GENERATING_OUTPUT
#define MAGNUM_GL_CONTEXT_CONFIGURATION_SUBCLASS_IMPLEMENTATION(Type) \
Type& addDisabledWorkarounds(Containers::ArrayView<const Containers::StringView> workarounds) { \
GL::Context::Configuration::addDisabledWorkarounds(workarounds); \
return *this; \
} \
Type& addDisabledWorkarounds(std::initializer_list<Containers::StringView> workarounds) { \
GL::Context::Configuration::addDisabledWorkarounds(workarounds); \
return *this; \
} \
\
Type& addDisabledExtensions(Containers::ArrayView<const GL::Extension> extensions) { \
GL::Context::Configuration::addDisabledExtensions(extensions); \
return *this; \
} \
Type& addDisabledExtensions(std::initializer_list<GL::Extension> extensions) { \
GL::Context::Configuration::addDisabledExtensions(extensions); \
return *this; \
} \
template<class ...E> Type& addDisabledExtensions() { \
GL::Context::Configuration::addDisabledExtensions<E...>(); \
return *this; \
}
#endif
/** @hideinitializer
@brief Assert that given OpenGL version is supported
@param version Version
Useful for initial checks on availability of required features.
By default, if assertion fails, an message is printed to error output and the
application aborts. If `CORRADE_NO_ASSERT` is defined, this macro does nothing.
Example usage:
@snippet MagnumGL.cpp Context-MAGNUM_ASSERT_GL_VERSION_SUPPORTED
@see @ref Magnum::GL::Context::isVersionSupported() "GL::Context::isVersionSupported()",
@ref MAGNUM_ASSERT_GL_EXTENSION_SUPPORTED(), @ref CORRADE_ASSERT(),
@ref CORRADE_INTERNAL_ASSERT()
*/
#ifdef CORRADE_NO_ASSERT
#define MAGNUM_ASSERT_GL_VERSION_SUPPORTED(version) do {} while(0)
#else
#define MAGNUM_ASSERT_GL_VERSION_SUPPORTED(version) \
do { \
if(!Magnum::GL::Context::current().isVersionSupported(version)) { \
Corrade::Utility::Error() << "Magnum: required version" << version << "is not supported"; \
std::abort(); \
} \
} while(0)
#endif
/** @hideinitializer
@brief Assert that given OpenGL extension is supported
@param extension Extension name (from the @ref Magnum::GL::Extensions "Extensions"
namespace)
Useful for initial checks on availability of required features.
By default, if assertion fails, an message is printed to error output and the
application aborts. If `CORRADE_NO_ASSERT` is defined, this macro does nothing.
Example usage:
@snippet MagnumGL.cpp Context-MAGNUM_ASSERT_GL_EXTENSION_SUPPORTED
@see @ref Magnum::GL::Context::isExtensionSupported() "Context::isExtensionSupported()",
@ref MAGNUM_ASSERT_GL_VERSION_SUPPORTED(), @ref CORRADE_ASSERT(),
@ref CORRADE_INTERNAL_ASSERT()
*/
#ifdef CORRADE_NO_ASSERT
#define MAGNUM_ASSERT_GL_EXTENSION_SUPPORTED(extension) do {} while(0)
#else
#define MAGNUM_ASSERT_GL_EXTENSION_SUPPORTED(extension) \
do { \
if(!Magnum::GL::Context::current().isExtensionSupported<extension>()) { \
Corrade::Utility::Error() << "Magnum: required extension" << extension::string() << "is not supported"; \
std::abort(); \
} \
} while(0)
#endif
}}
#endif