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.
 
 
 
 
 

167 lines
8.5 KiB

/*
This file is part of Magnum.
Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019,
2020, 2021, 2022, 2023, 2024
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()](http://doc.qt.io/qt-5/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
*/
}