Sunday, June 19, 2011

OpenGL profiles and deprecation

The rapid advancement of OpenGL and the profile system it uses may be confusing. In this article, I will try to explain the logic behind the OpenGL profiles and the deprecation model it uses. I will also post some code snippets to demonstrate how a context that has the desired version of an OpenGL profile can be created.

First, let's start with remembering that OpenGL has been backward compatible from its inception until version 3.0. While this was convenient for application developers, it put a significant burden on driver developers as they had to support a huge amount of features that had been accumulating over the course of many years.

OpenGL 3.0 for the first time introduced a model for deprecation. It marked certain features of the language that were deemed outdated as deprecated. This meant that these features would be removed in a future release of the API.

While 3.0 did not remove any features (it only marked them as deprecated), it opened up the possibility to create forward compatible contexts. A forward compatible context was one where features marked as deprecated were actually removed. This was aimed to assist application developers to allow them test their code to ensure that it will work on future versions of OpenGL. However, if forward compatibility was not explicitly requested, the default context that came with OpenGL 3.0 was fully backward compatible with all of the earlier versions of the API.

Allowing users to request a forward compatible context meant that a new interface function would have to be defined to allow users make this request. For this reason, new WGL and GLX extension were created (first WGL_ARB_create_context then WGL_ARB_create_context_profile as well as their GLX counterparts). The usage of these extensions will be illustrated at the end of this text.

With OpenGL version 3.1 all the features that were deprecated in 3.0 were actually removed. This was the first time OpenGL broke backwards compatibility. However, the door was left open to support these removed features through an extension called GL_ARB_compatibility. If an implementation made this extension available it restored all of the removed features. And most (if not all) implementations provided this extension. OpenGL 3.1 did not deprecate any features by itself.

Things started to become more formalized with OpenGL 3.2. This version for the first time introduced multiple profiles one of which can be selected during the context creation time. There were only two profiles namely the core and compatibility profiles. Choosing the core profile meant that all of the features deprecated in earlier versions of the API were removed from the context (similar to using a 3.1 version that does not provide the GL_ARB_compatibility extension). However, one could still create a fully backwards compatible context using the compatibility profile. The profile system of 3.2 essentially superseded the GL_ARB_compatibility extension. OpenGL 3.2 core profile did actually deprecate a single feature (querying for MAX_VARYING_COMPONENTS and MAX_VARYING_FLOATS).

Newer versions of OpenGL (3.3, 4.0, and 4.1) did not make any changes on this profile selection mechanism, neither did they deprecate any other features. As of this writing OpenGL is at version 4.1. All the features that were deprecated as of version 3.1 remain deprecated but not removed.

Let as now demonstrate how a developer can create an OpenGL context that has the desired API version and the profile. First, we have to use the standard context creation function wglCreateContext to create a default OpenGL context. We need this context to query the address of the special context creation function that we mentioned above (only Windows example is shown - Linux is similar except that it uses glx functions instead of wgl):

#include <windows.h>
#include <GL/gl.h>
#include "wglext.h"

PFNWGLCREATECONTEXTATTRIBSARBPROC wglCreateContextAttribsARB;

void InitWGLFuncPtrs(HDC hDC)
{
    HGLRC hTempRC = wglCreateContext(hDC);

    wglMakeCurrent(hDC, hTempRC);

    wglCreateContextAttribsARB = (PFNWGLCREATECONTEXTATTRIBSARBPROC) wglGetProcAddress("wglCreateContextAttribsARB");

    wglMakeCurrent(hDC, NULL);
    wglDeleteContext(hTempRC);
}

This gives us the address of wglCreateContextAttribsARB which we will use to create our desired context. Let's say we want create an OpenGL 3.3 core context that is forward compatible (remember that this means all the features that were removed up to and including 3.3 will be stripped from the context - this is what core means. Furthermore all the deprecated features are stripped down as well - this is what the forward compatible flag achieves). This is accomplished by:

void CreateOpenGLContext(HDC hDC)
{
    int attribList[] =
    {
        WGL_CONTEXT_MAJOR_VERSION_ARB, 3,
        WGL_CONTEXT_MINOR_VERSION_ARB, 3,
        WGL_CONTEXT_FLAGS_ARB, WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB,
        WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_CORE_PROFILE_BIT_ARB,
        0, 0
    };

    HGLRC hRC = wglCreateContextAttribsARB(hDC, 0, attribList);
    wglMakeCurrent(hDC, hRC);
}

As you can see wglCreateContextAttribsARB function takes an array of attributes which are terminated by double zeros. We can specify any number of these attributes - the ones that are left out will be set to their default values as explained in the extension document for WGL_ARB_create_context_profile. As a note it is worth remembering that if the requested context is not supported by the OpenGL driver that we are running on wglCreateContextAttribsARB will return NULL. So it is a good practice to check against this case. Finally, one can verify that the desired context is created by looking at the version string that can be obtained by glGetString(GL_VERSION).

That is it for this article. To learn more about the OpenGL profiles, the deprecation model, and all the details of the new context creation function check out the OpenGL specs from www.opengl.org as well as the extension document for WGL_ARB_create_context_profile.

No comments:

Post a Comment