Context guide

Table of Contents

The primary purpose of GLFW is to provide a simple interface to window management and OpenGL and OpenGL ES context creation. GLFW supports multiple windows, with each window having its own context.

This guide introduces the functions related to managing OpenGL and OpenGL ES contexts. There are also guides for the other areas of the GLFW API.

Context objects

A window object encapsulates both a top-level window and an OpenGL or OpenGL ES context. It is created with glfwCreateWindow and destroyed with glfwDestroyWindow or glfwTerminate. See Window creation for more information.

As the window and context are inseparably linked, the window object also serves as the context handle.

Context creation hints

There are a number of hints, specified using glfwWindowHint, related to what kind of context is created. See context related hints in the window guide.

Context object sharing

When creating a window and its OpenGL or OpenGL ES context with glfwCreateWindow, you can specify another window whose context the new one should share its objects (textures, vertex and element buffers, etc.) with.

GLFWwindow* second_window = glfwCreateWindow(640, 480, "Second Window", NULL, first_window);

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 or OpenGL ES 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.

Offscreen contexts

GLFW doesn't support creating contexts without an associated window. However, contexts with hidden windows can be created with the GLFW_VISIBLE window hint.

GLFWwindow* offscreen_context = glfwCreateWindow(640, 480, "", NULL, NULL);

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.

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.

A context is made current with glfwMakeContextCurrent.

The current context is returned by glfwGetCurrentContext.

The following GLFW functions require a context to be current:

Calling any these functions without a current context will generate a GLFW_NO_CURRENT_CONTEXT error.

Buffer swapping

Buffer swapping is part of the window and framebuffer, not the context. See Buffer swapping in the window guide.

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:

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 and OpenGL ES Registry.

Using an extension loader library

This is the easiest and best way to load extensions and newer versions of the OpenGL or OpenGL ES API. One such library is glad and there are several others. They will take care of all the details of declaring and loading everything you need.

The following example will use glad, but other extension loader libraries work similary.

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.

1 python main.py --no-loader --out-path output

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.

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.

#include <glad/glad.h>
#include <GLFW/glfw3.h>

Finally you need to initialize glad once you have a matching current context.

window = glfwCreateWindow(640, 480, "My Window", NULL, NULL);
if (!window)
{
...
}
gladLoadGLLoader((GLADloadproc) glfwGetProcAddress);

Once glad has been loaded, you have access to all OpenGL core and extension functions supported by the context you created and you are ready to start rendering.

You can specify a minimum required OpenGL or OpenGL ES version with context hints. If your needs are more complex, you can check the actual OpenGL or OpenGL ES version with context attributes, or you can check whether a specific version is supported by the current context with the GLAD_GL_VERSION_x_x booleans.

if (GLAD_GL_VERSION_3_2)
{
// Call OpenGL 3.2+ specific code
}

To check whether a specific extension is supported, use the GLAD_GL_xxx booleans.

if (GLAD_GL_ARB_debug_output)
{
// Use GL_ARB_debug_output
}

Loading extensions manually

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 glfwExtensionSupported and glfwGetProcAddress for manual loading of extensions and new API functions.

Note
It is recommended that you use an existing extension loader library, as described above, instead of loading manually.

The glext.h header

The glext.h 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. It it strongly recommended that you use your own copy, as the one shipped with 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 PFNGLGETDEBUGMESSAGELOGARB (for glGetDebugMessageLogARB), i.e. the name is made uppercase and PFN (pointer to function) and PROC (procedure) are added to the ends.

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 whether the context supports the extension. This is done with glfwExtensionSupported.

if (glfwExtensionSupported("GL_ARB_debug_output"))
{
// The extension is supported by the current context
}

The argument is a null terminated ASCII string with the extension name. If the extension is supported, glfwExtensionSupported returns non-zero, otherwise it returns zero.

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 retreive pointers to these functions with glfwGetProcAddress.

PFNGLGETDEBUGMESSAGELOGARB pfnGetDebugMessageLog = glfwGetProcAddress("glGetDebugMessageLogARB");

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.

#include "glext.h"
#define glGetDebugMessageLogARB pfnGetDebugMessageLog
PFNGLGETDEBUGMESSAGELOGARB pfnGetDebugMessageLog;
// Flag indicating whether the extension is supported
int has_debug_output = 0;
void load_extensions(void)
{
if (glfwExtensionSupported("GL_ARB_debug_output"))
{
pfnGetDebugMessageLog = (PFNGLGETDEBUGMESSAGELOGARB) glfwGetProcAddress("glGetDebugMessageLogARB");
if (pfnGetDebugMessageLog)
{
// Both the extension name and the function pointer are present
has_debug_output = 1;
}
}
}
void some_function(void)
{
// Now the extension function can be called as usual
glGetDebugMessageLogARB(...);
}