330 lines
12 KiB
Plaintext
330 lines
12 KiB
Plaintext
|
/*!
|
||
|
|
||
|
@page context Context guide
|
||
|
|
||
|
@tableofcontents
|
||
|
|
||
|
This guide introduces the OpenGL and OpenGL ES context related functions of
|
||
|
GLFW. There are also guides for the other areas of the GLFW API.
|
||
|
|
||
|
- @ref intro
|
||
|
- @ref window
|
||
|
- @ref monitor
|
||
|
- @ref input
|
||
|
|
||
|
|
||
|
@section context_object Context objects
|
||
|
|
||
|
A window object encapsulates both a top-level window and an OpenGL or OpenGL ES
|
||
|
context. It is created with @ref glfwCreateWindow and destroyed with @ref
|
||
|
glfwDestroyWindow or @ref glfwTerminate. See @ref window_creation for more
|
||
|
information.
|
||
|
|
||
|
As the window and context are inseparably linked, the window object also serves
|
||
|
as the context handle.
|
||
|
|
||
|
To test the creation of various kinds of contexts and see their properties, run
|
||
|
the `glfwinfo` test program.
|
||
|
|
||
|
|
||
|
@subsection context_hints Context creation hints
|
||
|
|
||
|
There are a number of hints, specified using @ref glfwWindowHint, related to
|
||
|
what kind of context is created. See
|
||
|
[context related hints](@ref window_hints_ctx) in the window guide.
|
||
|
|
||
|
|
||
|
@subsection context_sharing Context object sharing
|
||
|
|
||
|
When creating a window and its OpenGL or OpenGL ES context with @ref
|
||
|
glfwCreateWindow, you can specify another window whose context the new one
|
||
|
should share its objects (textures, vertex and element buffers, etc.) with.
|
||
|
|
||
|
@code
|
||
|
GLFWwindow* second_window = glfwCreateWindow(640, 480, "Second Window", NULL, first_window);
|
||
|
@endcode
|
||
|
|
||
|
Object sharing is implemented by the operating system and graphics driver. On
|
||
|
platforms where it is possible to choose which types of objects are shared, GLFW
|
||
|
requests that all types are shared.
|
||
|
|
||
|
See the relevant chapter of the [OpenGL](https://www.opengl.org/registry/) or
|
||
|
[OpenGL ES](http://www.khronos.org/opengles/) reference documents for more
|
||
|
information. The name and number of this chapter unfortunately varies between
|
||
|
versions and APIs, but has at times been named _Shared Objects and Multiple
|
||
|
Contexts_.
|
||
|
|
||
|
GLFW comes with a simple object sharing test program called `sharing`.
|
||
|
|
||
|
|
||
|
@subsection context_offscreen Offscreen contexts
|
||
|
|
||
|
GLFW doesn't support creating contexts without an associated window. However,
|
||
|
contexts with hidden windows can be created with the
|
||
|
[GLFW_VISIBLE](@ref window_hints_wnd) window hint.
|
||
|
|
||
|
@code
|
||
|
glfwWindowHint(GLFW_VISIBLE, GL_FALSE);
|
||
|
|
||
|
GLFWwindow* offscreen_context = glfwCreateWindow(640, 480, "", NULL, NULL);
|
||
|
@endcode
|
||
|
|
||
|
The window never needs to be shown and its context can be used as a plain
|
||
|
offscreen context. Depending on the window manager, the size of a hidden
|
||
|
window's framebuffer may not be usable or modifiable, so framebuffer
|
||
|
objects are recommended for rendering with such contexts.
|
||
|
|
||
|
__OS X:__ The first time a window is created the menu bar is populated with
|
||
|
common commands like Hide, Quit and About. This is not desirable for example
|
||
|
when writing a command-line only application. The menu bar setup can be
|
||
|
disabled with a [compile-time option](@ref compile_options_osx).
|
||
|
|
||
|
|
||
|
@section context_current Current context
|
||
|
|
||
|
Before you can make OpenGL or OpenGL ES calls, you need to have a current
|
||
|
context of the correct type. A context can only be current for a single thread
|
||
|
at a time, and a thread can only have a single context current at a time.
|
||
|
|
||
|
The context of a window is made current with @ref glfwMakeContextCurrent.
|
||
|
|
||
|
@code
|
||
|
glfwMakeContextCurrent(window);
|
||
|
@endcode
|
||
|
|
||
|
The window of the current context is returned by @ref glfwGetCurrentContext.
|
||
|
|
||
|
@code
|
||
|
GLFWwindow* window = glfwGetCurrentContext();
|
||
|
@endcode
|
||
|
|
||
|
The following GLFW functions require a context to be current. Calling any these
|
||
|
functions without a current context will generate a @ref GLFW_NO_CURRENT_CONTEXT
|
||
|
error.
|
||
|
|
||
|
- @ref glfwSwapInterval
|
||
|
- @ref glfwExtensionSupported
|
||
|
- @ref glfwGetProcAddress
|
||
|
|
||
|
|
||
|
@section context_swap Buffer swapping
|
||
|
|
||
|
Buffer swapping is part of the window and framebuffer, not the context. See
|
||
|
@ref buffer_swap.
|
||
|
|
||
|
|
||
|
@section context_glext OpenGL and OpenGL ES extensions
|
||
|
|
||
|
One of the benefits of OpenGL and OpenGL ES are their extensibility.
|
||
|
Hardware vendors may include extensions in their implementations that extend the
|
||
|
API before that functionality is included in a new version of the OpenGL or
|
||
|
OpenGL ES specification, and some extensions are never included and remain
|
||
|
as extensions until they become obsolete.
|
||
|
|
||
|
An extension is defined by:
|
||
|
|
||
|
- An extension name (e.g. `GL_ARB_debug_output`)
|
||
|
- New OpenGL tokens (e.g. `GL_DEBUG_SEVERITY_HIGH_ARB`)
|
||
|
- New OpenGL functions (e.g. `glGetDebugMessageLogARB`)
|
||
|
|
||
|
Note the `ARB` affix, which stands for Architecture Review Board and is used
|
||
|
for official extensions. The extension above was created by the ARB, but there
|
||
|
are many different affixes, like `NV` for Nvidia and `AMD` for, well, AMD. Any
|
||
|
group may also use the generic `EXT` affix. Lists of extensions, together with
|
||
|
their specifications, can be found at the
|
||
|
[OpenGL Registry](http://www.opengl.org/registry/) and
|
||
|
[OpenGL ES Registry](https://www.khronos.org/registry/gles/).
|
||
|
|
||
|
|
||
|
@subsection context_glext_auto Loading extension with a loader library
|
||
|
|
||
|
An extension loader library is the easiest and best way to access both OpenGL and
|
||
|
OpenGL ES extensions and modern versions of the core OpenGL or OpenGL ES APIs.
|
||
|
They will take care of all the details of declaring and loading everything you
|
||
|
need. One such library is [glad](https://github.com/Dav1dde/glad) and there are
|
||
|
several others.
|
||
|
|
||
|
The following example will use glad but all extension loader libraries work
|
||
|
similarly.
|
||
|
|
||
|
First you need to generate the source files using the glad Python script. This
|
||
|
example generates a loader for any version of OpenGL, which is the default for
|
||
|
both GLFW and glad, but loaders for OpenGL ES, as well as loaders for specific
|
||
|
API versions and extension sets can be generated. The generated files are
|
||
|
written to the `output` directory.
|
||
|
|
||
|
@code{.sh}
|
||
|
python main.py --generator c --no-loader --out-path output
|
||
|
@endcode
|
||
|
|
||
|
The `--no-loader` option is added because GLFW already provides a function for
|
||
|
loading OpenGL and OpenGL ES function pointers and glad can call this instead of
|
||
|
having to implement its own. There are several other command-line options as
|
||
|
well. See the glad documentation for details.
|
||
|
|
||
|
Add the generated `output/src/glad.c`, `output/include/glad/glad.h` and
|
||
|
`output/include/KHR/khrplatform.h` files to your build. Then you need to
|
||
|
include the glad header file, which will replace the OpenGL header of your
|
||
|
development environment. By including the glad header before the GLFW header,
|
||
|
it suppresses the development environment's OpenGL or OpenGL ES header.
|
||
|
|
||
|
@code
|
||
|
#include <glad/glad.h>
|
||
|
#include <GLFW/glfw3.h>
|
||
|
@endcode
|
||
|
|
||
|
Finally you need to initialize glad once you have a suitable current context.
|
||
|
|
||
|
@code
|
||
|
window = glfwCreateWindow(640, 480, "My Window", NULL, NULL);
|
||
|
if (!window)
|
||
|
{
|
||
|
...
|
||
|
}
|
||
|
|
||
|
glfwMakeContextCurrent(window);
|
||
|
|
||
|
gladLoadGLLoader((GLADloadproc) glfwGetProcAddress);
|
||
|
@endcode
|
||
|
|
||
|
Once glad has been loaded, you have access to all OpenGL core and extension
|
||
|
functions supported by both the context you created and the glad loader you
|
||
|
generated and you are ready to start rendering.
|
||
|
|
||
|
You can specify a minimum required OpenGL or OpenGL ES version with
|
||
|
[context hints](@ref window_hints_ctx). If your needs are more complex, you can
|
||
|
check the actual OpenGL or OpenGL ES version with
|
||
|
[context attributes](@ref window_attribs_ctx), or you can check whether
|
||
|
a specific version is supported by the current context with the
|
||
|
`GLAD_GL_VERSION_x_x` booleans.
|
||
|
|
||
|
@code
|
||
|
if (GLAD_GL_VERSION_3_2)
|
||
|
{
|
||
|
// Call OpenGL 3.2+ specific code
|
||
|
}
|
||
|
@endcode
|
||
|
|
||
|
To check whether a specific extension is supported, use the `GLAD_GL_xxx`
|
||
|
booleans.
|
||
|
|
||
|
@code
|
||
|
if (GLAD_GL_ARB_debug_output)
|
||
|
{
|
||
|
// Use GL_ARB_debug_output
|
||
|
}
|
||
|
@endcode
|
||
|
|
||
|
|
||
|
@subsection context_glext_manual Loading extensions manually
|
||
|
|
||
|
__Do not use this technique__ unless it is absolutely necessary. An
|
||
|
[extension loader library](@ref context_glext_auto) will save you a ton of
|
||
|
tedious, repetitive, error prone work.
|
||
|
|
||
|
To use a certain extension, you must first check whether the context supports
|
||
|
that extension and then, if it introduces new functions, retrieve the pointers
|
||
|
to those functions. GLFW provides @ref glfwExtensionSupported and @ref
|
||
|
glfwGetProcAddress for manual loading of extensions and new API functions.
|
||
|
|
||
|
This section will demonstrate manual loading of OpenGL extensions. The loading
|
||
|
of OpenGL ES extensions is identical except for the name of the extension header.
|
||
|
|
||
|
|
||
|
@subsubsection context_glext_header The glext.h header
|
||
|
|
||
|
The `glext.h` extension header is a continually updated file that defines the
|
||
|
interfaces for all OpenGL extensions. The latest version of this can always be
|
||
|
found at the [OpenGL Registry](http://www.opengl.org/registry/). There are also
|
||
|
extension headers for the various versions of OpenGL ES at the
|
||
|
[OpenGL ES Registry](https://www.khronos.org/registry/gles/). It it strongly
|
||
|
recommended that you use your own copy of the extension header, as the one
|
||
|
included in your development environment may be several years out of date and
|
||
|
may not include the extensions you wish to use.
|
||
|
|
||
|
The header defines function pointer types for all functions of all extensions it
|
||
|
supports. These have names like `PFNGLGETDEBUGMESSAGELOGARBPROC` (for
|
||
|
`glGetDebugMessageLogARB`), i.e. the name is made uppercase and `PFN` (pointer
|
||
|
to function) and `PROC` (procedure) are added to the ends.
|
||
|
|
||
|
To include the extension header, define [GLFW_INCLUDE_GLEXT](@ref build_macros)
|
||
|
before including the GLFW header.
|
||
|
|
||
|
@code
|
||
|
#define GLFW_INCLUDE_GLEXT
|
||
|
#include <GLFW/glfw3.h>
|
||
|
@endcode
|
||
|
|
||
|
|
||
|
@subsubsection context_glext_string Checking for extensions
|
||
|
|
||
|
A given machine may not actually support the extension (it may have older
|
||
|
drivers or a graphics card that lacks the necessary hardware features), so it
|
||
|
is necessary to check at run-time whether the context supports the extension.
|
||
|
This is done with @ref glfwExtensionSupported.
|
||
|
|
||
|
@code
|
||
|
if (glfwExtensionSupported("GL_ARB_debug_output"))
|
||
|
{
|
||
|
// The extension is supported by the current context
|
||
|
}
|
||
|
@endcode
|
||
|
|
||
|
The argument is a null terminated ASCII string with the extension name. If the
|
||
|
extension is supported, @ref glfwExtensionSupported returns `GL_TRUE`, otherwise
|
||
|
it returns `GL_FALSE`.
|
||
|
|
||
|
|
||
|
@subsubsection context_glext_proc Fetching function pointers
|
||
|
|
||
|
Many extensions, though not all, require the use of new OpenGL functions.
|
||
|
These functions often do not have entry points in the client API libraries of
|
||
|
your operating system, making it necessary to fetch them at run time. You can
|
||
|
retrieve pointers to these functions with @ref glfwGetProcAddress.
|
||
|
|
||
|
@code
|
||
|
PFNGLGETDEBUGMESSAGELOGARBPROC pfnGetDebugMessageLog = glfwGetProcAddress("glGetDebugMessageLogARB");
|
||
|
@endcode
|
||
|
|
||
|
In general, you should avoid giving the function pointer variables the (exact)
|
||
|
same name as the function, as this may confuse your linker. Instead, you can
|
||
|
use a different prefix, like above, or some other naming scheme.
|
||
|
|
||
|
Now that all the pieces have been introduced, here is what they might look like
|
||
|
when used together.
|
||
|
|
||
|
@code
|
||
|
#define GLFW_INCLUDE_GLEXT
|
||
|
#include <GLFW/glfw3.h>
|
||
|
|
||
|
#define glGetDebugMessageLogARB pfnGetDebugMessageLog
|
||
|
PFNGLGETDEBUGMESSAGELOGARBPROC pfnGetDebugMessageLog;
|
||
|
|
||
|
// Flag indicating whether the extension is supported
|
||
|
int has_ARB_debug_output = 0;
|
||
|
|
||
|
void load_extensions(void)
|
||
|
{
|
||
|
if (glfwExtensionSupported("GL_ARB_debug_output"))
|
||
|
{
|
||
|
pfnGetDebugMessageLog = (PFNGLGETDEBUGMESSAGELOGARBPROC) glfwGetProcAddress("glGetDebugMessageLogARB");
|
||
|
if (pfnGetDebugMessageLog)
|
||
|
{
|
||
|
// Both the extension name and the function pointer are present
|
||
|
has_ARB_debug_output = 1;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void some_function(void)
|
||
|
{
|
||
|
if (has_ARB_debug_output)
|
||
|
{
|
||
|
// Now the extension function can be called as usual
|
||
|
glGetDebugMessageLogARB(...);
|
||
|
}
|
||
|
}
|
||
|
@endcode
|
||
|
|
||
|
*/
|