|
|
|
|
/*
|
|
|
|
|
This file is part of Magnum.
|
|
|
|
|
|
|
|
|
|
Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019,
|
|
|
|
|
2020, 2021, 2022, 2023, 2024, 2025, 2026
|
|
|
|
|
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.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
namespace Magnum {
|
|
|
|
|
/** @page opengl-wrapping OpenGL wrapping layer
|
|
|
|
|
@brief Overview of the base OpenGL wrapper API
|
|
|
|
|
|
|
|
|
|
@tableofcontents
|
|
|
|
|
@m_footernavigation
|
|
|
|
|
|
|
|
|
|
The purpose of the @ref GL library is to simplify interaction with the OpenGL
|
|
|
|
|
API using type-safe C++11 features and RAII, abstracting away extension and
|
|
|
|
|
platform differences, tracking the state for optimum performance and selecting
|
|
|
|
|
the best available code path for given driver.
|
|
|
|
|
|
|
|
|
|
Magnum provides wrappers for most native OpenGL objects like buffers, textures,
|
|
|
|
|
meshes, queries, transform feedback objects, shaders etc., but makes it
|
|
|
|
|
possible to use raw GL calls or combine Magnum with third-party OpenGL
|
|
|
|
|
libraries if the user wants to.
|
|
|
|
|
|
|
|
|
|
@section opengl-wrapping-instances OpenGL object wrapper instances
|
|
|
|
|
|
|
|
|
|
By default, all wrapper classes follow RAII -- underlying OpenGL objects are
|
|
|
|
|
created in the class constructor and deleted in the wrapper class destructor.
|
|
|
|
|
All OpenGL objects are movable (but not copyable) and moves are *destructive*
|
|
|
|
|
--- the moved-from instance does *not* have any associated OpenGL object and
|
|
|
|
|
is thus in an *invalid state*. Calling anything on instances in a moved-from
|
|
|
|
|
state may thus result in OpenGL errors being generated, in some cases even
|
|
|
|
|
application crashes.
|
|
|
|
|
|
|
|
|
|
If you need to preserve the underlying OpenGL object after destruction, you can
|
|
|
|
|
call @cpp release() @ce. It returns ID of the underlying object, the instance
|
|
|
|
|
is then equivalent to the moved-from state and you are responsible for proper
|
|
|
|
|
deletion of the returned OpenGL object (note that it is possible to just query
|
|
|
|
|
ID of the underlying without releasing it using @cpp id() @ce). It is also
|
|
|
|
|
possible to do the opposite --- wrapping an existing OpenGL object ID into a
|
|
|
|
|
Magnum object instance using @cpp wrap() @ce:
|
|
|
|
|
|
|
|
|
|
@snippet GL.cpp opengl-wrapping-transfer
|
|
|
|
|
|
|
|
|
|
The @cpp wrap() @ce and @cpp release() @ce functions are available for all
|
|
|
|
|
OpenGL classes except for @ref GL::AbstractShaderProgram, where the desired
|
|
|
|
|
usage via subclassing isn't really suited for wrapping external objects.
|
|
|
|
|
|
|
|
|
|
@attention
|
|
|
|
|
Note that interaction with third-party OpenGL code as shown above usually
|
|
|
|
|
needs special attention due to the global nature of the OpenGL state
|
|
|
|
|
tracker. See @ref opengl-state-tracking below for more information.
|
|
|
|
|
|
|
|
|
|
@subsection opengl-wrapping-instances-nocreate Delayed context creation and NoCreate constructors
|
|
|
|
|
|
|
|
|
|
Constructing a Magnum GL object requires an active @ref GL::Context instance.
|
|
|
|
|
By default, this instance is automatically created by
|
|
|
|
|
@ref Platform::Sdl2Application "Platform::*Application" constructors, however
|
|
|
|
|
if you use @ref platform-configuration-delayed "delayed context creation" or
|
|
|
|
|
are directly interfacing with @ref platform-custom "custom platform toolkits",
|
|
|
|
|
this is not the case. If OpenGL functionality gets called before the
|
|
|
|
|
@ref GL::Context instance is created (or after it has been destroyed), you may
|
|
|
|
|
end up with the following assertion:
|
|
|
|
|
|
|
|
|
|
@code{.shell-session}
|
|
|
|
|
GL::Context::current(): no current context
|
|
|
|
|
@endcode
|
|
|
|
|
|
|
|
|
|
In the common case of delayed context creation, this problem can be
|
|
|
|
|
circumvented by constructing the OpenGL objects using the @ref NoCreate tag
|
|
|
|
|
first and populating them with live instances once the context is ready. For
|
|
|
|
|
example:
|
|
|
|
|
|
|
|
|
|
@snippet GL-application.cpp opengl-wrapping-nocreate
|
|
|
|
|
|
|
|
|
|
Please note that objects constructed using the @ref NoCreate tag are equivalent
|
|
|
|
|
to the moved-from state, and thus again calling anything on these may result in
|
|
|
|
|
OpenGL errors being generated or even application crashes --- you're
|
|
|
|
|
responsible for correctly initializing the objects before use. If you are fine
|
|
|
|
|
with trading some overhead for extra safety checks, wrap the objects in an
|
|
|
|
|
@relativeref{Corrade,Containers::Optional} instead of using the @ref NoCreate
|
|
|
|
|
constructor.
|
|
|
|
|
|
|
|
|
|
The @ref NoCreate constructor is available for all OpenGL classes, including
|
|
|
|
|
builtin shaders.
|
|
|
|
|
|
|
|
|
|
@section opengl-state-tracking State tracking and interaction with third-party code
|
|
|
|
|
|
|
|
|
|
It is possible (and encouraged) to combine Magnum with third-party libraries or
|
|
|
|
|
even raw OpenGL calls --- trying out features that are not yet implemented in
|
|
|
|
|
Magnum, using some specialized GUI library etc. But bear in mind that in order
|
|
|
|
|
to improve performance and avoid redundant state changes, Magnum internally
|
|
|
|
|
tracks OpenGL state such as currently bound objects, activated renderer
|
|
|
|
|
features etc. When combining Magnum with third-party code, the internal state
|
|
|
|
|
tracker may get confused and you need to reset it using @ref GL::Context::resetState():
|
|
|
|
|
|
|
|
|
|
@snippet GL.cpp opengl-wrapping-state
|
|
|
|
|
|
|
|
|
|
Note that by design it's not possible to reset all state touched by Magnum to
|
|
|
|
|
previous values --- it would involve impractically large amount of queries and
|
|
|
|
|
state switches with serious performance impact. It's thus expected that
|
|
|
|
|
third-party code either does no state tracking or provides similar means to
|
|
|
|
|
reset their state tracker (for example Qt has
|
|
|
|
|
[QQuickWindow::resetOpenGLState()](https://doc.qt.io/archives/qt-5.15/qquickwindow.html#resetOpenGLState)
|
|
|
|
|
that's advised to call before giving the control back to Qt).
|
|
|
|
|
|
|
|
|
|
@section opengl-wrapping-dsa Extension-dependent functionality
|
|
|
|
|
|
|
|
|
|
While the majority of Magnum API stays the same on all platforms and driver
|
|
|
|
|
capabilities, large portion of the functionality needs to be realized under the
|
|
|
|
|
hood using various different OpenGL API calls based on available extensions. If
|
|
|
|
|
required extension is not available, there are two possible outcomes --- either
|
|
|
|
|
given API is simply not available or it is emulated using older functionality.
|
|
|
|
|
|
|
|
|
|
In the first case, to avoid performance overhead, Magnum does not check that
|
|
|
|
|
you use only the APIs that are implemented in the driver --- you are expected to
|
|
|
|
|
do the checks. Documentation of each type, function and enum value explicitly
|
|
|
|
|
states whether the functionality is available everywhere or whether particular
|
|
|
|
|
GL version/extension is required. The information is also aggregated on
|
|
|
|
|
@ref opengl-required-extensions documentation page. Use
|
|
|
|
|
@ref GL::Context::isVersionSupported() or @ref GL::Context::isExtensionSupported():
|
|
|
|
|
|
|
|
|
|
@snippet GL.cpp opengl-wrapping-extensions
|
|
|
|
|
|
|
|
|
|
@attention Using API that requires OpenGL version or extension that is not
|
|
|
|
|
provided by the driver results in undefined behavior --- the best you can
|
|
|
|
|
get is GL error, it may lead to strange behavior and even crashes when
|
|
|
|
|
calling GL functions that are not available.
|
|
|
|
|
|
|
|
|
|
Some functionality can be emulated by Magnum --- it detects available extensions
|
|
|
|
|
and selects best possible code path for optimal performance. On startup, the
|
|
|
|
|
application prints list of extensions that were used to improve the default
|
|
|
|
|
functionality. The most prominent feature is @gl_extension{ARB,direct_state_access}
|
|
|
|
|
(part of OpenGL 4.3). This extension makes it possible to modify OpenGL objects
|
|
|
|
|
without explicitly binding them, reducing the amount of needed API calls.
|
|
|
|
|
Magnum API is designed around direct state access as it is far easier to use
|
|
|
|
|
and less error-prone, but if this extension is not available, the functionality
|
|
|
|
|
is emulated through classic bind-to-edit approach. Other examples of
|
|
|
|
|
extension-dependent functionality is @ref GL::DebugMessage "debug output" which
|
|
|
|
|
is simply no-op when required extensions are not available,
|
|
|
|
|
@ref GL::Texture::setStorage() emulation on platforms that don't support it
|
|
|
|
|
etc. The goal is to abstract away the (mostly unimportant) differences for
|
|
|
|
|
easier porting.
|
|
|
|
|
|
|
|
|
|
@snippet GL.cpp opengl-wrapping-dsa
|
|
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
}
|