Book Image

OpenGL 4 Shading Language Cookbook - Second Edition

By : David Wolff, David A Wolff
Book Image

OpenGL 4 Shading Language Cookbook - Second Edition

By: David Wolff, David A Wolff

Overview of this book

OpenGL Shading Language (GLSL) is a programming language used for customizing parts of the OpenGL graphics pipeline that were formerly fixed-function, and are executed directly on the GPU. It provides programmers with unprecedented flexibility for implementing effects and optimizations utilizing the power of modern GPUs. With Version 4, the language has been further refined to provide programmers with greater power and flexibility, with new stages such as tessellation and compute. OpenGL 4 Shading Language Cookbook provides easy-to-follow examples that first walk you through the theory and background behind each technique, and then go on to provide and explain the GLSL and OpenGL code needed to implement it. Beginner level through to advanced techniques are presented including topics such as texturing, screen-space techniques, lighting, shading, tessellation shaders, geometry shaders, compute shaders, and shadows. OpenGL Shading Language 4 Cookbook is a practical guide that takes you from the fundamentals of programming with modern GLSL and OpenGL, through to advanced techniques. The recipes build upon each other and take you quickly from novice to advanced level code. You'll see essential lighting and shading techniques; examples that demonstrate how to make use of textures for a wide variety of effects and as part of other techniques; examples of screen-space techniques including HDR rendering, bloom, and blur; shadowing techniques; tessellation, geometry, and compute shaders; how to use noise effectively; and animation with particle systems. OpenGL Shading Language 4 Cookbook provides examples of modern shading techniques that can be used as a starting point for programmers to expand upon to produce modern, interactive, 3D computer graphics applications.
Table of Contents (17 chapters)
OpenGL 4 Shading Language Cookbook Second Edition
Credits
About the Author
About the Reviewers
www.PacktPub.com
Preface
Index

Getting debug messages


Prior to recent versions of OpenGL, the traditional way to get debug information was to call glGetError. Unfortunately, that is an exceedingly tedious method for debugging a program. The glGetError function returns an error code if an error has occurred at some point previous to the time the function was called. This means that if we're chasing down a bug, we essentially need to call glGetError after every function call to an OpenGL function, or do a binary search-like process where we call it before and after a block of code, and then move the two calls closer to each other until we determine the source of the error. What a pain!

Thankfully, as of OpenGL 4.3, we now have support for a more modern method for debugging. Now we can register a debug callback function that will be executed whenever an error occurs, or other informational message is generated. Not only that, but we can send our own custom messages to be handled by the same callback, and we can filter the messages using a variety of criteria.

Getting ready

Create an OpenGL program with a debug context. While it is not strictly necessary to acquire a debug context, we might not get messages that are as informative as when we are using a debug context. To create an OpenGL context using GLFW with debugging enabled, use the following function call prior to creating the window.

glfwWindowHint(GLFW_OPENGL_DEBUG_CONTEXT, GL_TRUE);

An OpenGL debug context will have debug messages enabled by default. If, however, you need to enable debug messages explicitly, use the following call.

glEnable(GL_DEBUG_OUTPUT);

How to do it...

Use the following steps:

  1. Create a callback function to receive the debug messages. The function must conform to a specific prototype described in the OpenGL documentation. For this example, we'll use the following one:

    void debugCallback(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar * message, void * param) {
    
        // Convert GLenum parameters to strings
    
    
      printf("%s:%s[%s](%d): %s\n", sourceStr, typeStr, severityStr, id, message);
    }
  2. Register our callback with OpenGL using glDebugMessageCallback:

    glDebugMessageCallback( debugCallback, NULL );
  3. Enable all messages, all sources, all levels, and all IDs:

    glDebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, NULL, GL_TRUE);

How it works...

The callback function debugCallback has several parameters, the most important of which is the debug message itself (the sixth parameter, message). For this example, we simply print the message to standard output, but we could send it to a log file or some other destination.

The first four parameters to debugCallback describe the source, type, id number, and severity of the message. The id number is an unsigned integer specific to the message. The possible values for the source, type and severity parameters are described in the following tables.

The source parameter can have any of the following values:

Source

Generated By

GL_DEBUG_SOURCE_API

Calls to the OpenGL API

GL_DEBUG_SOURCE_WINDOW_SYSTEM

Calls to a window system API

GL_DEBUG_SOURCE_THIRD_PARTY

An application associated with OpenGL

GL_DEBUG_SOURCE_APPLICATION

This application itself.

GL_DEBUG_SOURCE_OTHER

Some other source

The type parameter can have any of the following values:

Type

Description

GL_DEBUG_TYPE_ERROR

An error from the OpenGL API.

GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR

Behavior that has been deprecated

GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR

Undefined behaviour

GL_DEBUG_TYPE_PORTABILITIY

Some functionality is not portable.

GL_DEBUG_TYPE_PERFORMANCE

Possible performance issues

GL_DEBUG_TYPE_MARKER

An annotation

GL_DEBUG_TYPE_PUSH_GROUP

Messages related to debug group push.

GL_DEBUG_TYPE_POP_GROUP

Messages related to debug group pop.

GL_DEBUG_TYPE_OTHER

Other messages

The severity parameter can have the following values:

Severity

Meaning

GL_DEBUG_SEVERITY_HIGH

Errors or dangerous behaviour

GL_DEBUG_SEVERITY_MEDIUM

Major performance warnings, other warnings or use of deprecated functionality.

GL_DEBUG_SEVERITY_LOW

Redundant state changes, unimportant undefined behaviour.

GL_DEBUG_SEVERITY_NOTIFICATION

A notification, not an error or performance issue.

The length parameter is the length of the message string, excluding the null terminator. The last parameter param is a user-defined pointer. We can use this to point to some custom object that might be helpful to the callback function. For example, if we were logging the messages to a file, this could point to an object containing file I/O capabilities. This parameter can be set using the second parameter to glDebugMessageCallback (more on that in the following content).

Within debugCallback we convert each GLenum parameter into a string. Due to space constraints, I don't show all of that code here, but it can be found in the example code for this book. We then print all of the information to standard output.

The call to glDebugMessageCallback registers our callback function with the OpenGL debug system. The first parameter is a pointer to our callback function, and the second parameter (NULL in this example) can be a pointer to any object that we would like to pass into the callback. This pointer is passed as the last parameter with every call to debugCallback.

Finally, the call to glDebugMessageControl determines our message filters. This function can be used to selectively turn on or off any combination of message source, type, id, or severity. In this example, we turn everything on.

There's more...

OpenGL also provides support for stacks of named debug groups. Essentially what this means is that we can remember all of our debug message filter settings on a stack and return to them later after some changes have been made. This might be useful, for example, if there are sections of code where we have needs for filtering some kinds of messages and other sections where we want a different set of messages.

The functions involved are glPushDebugGroup and glPopDebugGroup. A call to glPushDebugGroup generates a debug message with type GL_DEBUG_TYPE_PUSH_GROUP, and retains the current state of our debug filters on a stack. We can then change our filters using glDebugMessageControl, and later return to the original state using glPopDebugGroup. Similarly, the function glPopDebugGroup generates a debug message with type GL_DEBUG_TYPE_POP_GROUP.