Book Image

OpenGL 4 Shading Language Cookbook - Third Edition

By : David Wolff
Book Image

OpenGL 4 Shading Language Cookbook - Third Edition

By: David Wolff

Overview of this book

OpenGL 4 Shading Language Cookbook, Third Edition provides easy-to-follow recipes that first walk you through the theory and background behind each technique, and then proceed to showcase and explain the GLSL and OpenGL code needed to implement them. The book begins by familiarizing you with beginner-level topics such as compiling and linking shader programs, saving and loading shader binaries (including SPIR-V), and using an OpenGL function loader library. We then proceed to cover basic lighting and shading effects. After that, you'll learn to use textures, produce shadows, and use geometry and tessellation shaders. Topics such as particle systems, screen-space ambient occlusion, deferred rendering, depth-based tessellation, and physically based rendering will help you tackle advanced topics. OpenGL 4 Shading Language Cookbook, Third Edition also covers advanced topics such as shadow techniques (including the two of the most common techniques: shadow maps and shadow volumes). You will learn how to use noise in shaders and how to use compute shaders. The book 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)
Title Page
Packt Upsell
Contributors
Preface
Index

Loading a SPIR-V shader program


Standard, Portable Intermediate Representation - V (SPIR-V) is an intermediate language designed and standardized by the Khronos Group for shaders. It is intended to be a compiler target for a number of different languages. In the Vulkan API, shaders are required to be compiled to SPIR-V before they can be loaded. SPIR-V is intended to provide developers with the freedom to develop their shaders in any language they want (as long as it can be compiled to SPIR-V), and avoid the need for an OpenGL (or Vulkan) implementation to provide compilers for multiple languages. 

Support for SPIR-V shader binaries was added to OpenGL core with version 4.6, but is also available via the ARB_gl_spirv extension for earlier OpenGL versions.

Currently, the Khronos Group provides a reference compiler for compiling GLSL to SPIR-V. It is available on GitHub at https://github.com/KhronosGroup/glslang.

In this recipe, we'll go through the steps involved in precompiling a GLSL shader pair to SPIR-V, and then load it into an OpenGL program.

Getting ready

Download and compile the OpenGL shader validator from https://github.com/KhronosGroup/glslang. Make sure that the glslangValidator binary is available in your PATH command line. In this example, we'll use the shader pair located in the basic.vert.glslandbasic.frag.glsl files.

Note that you'll need to use explicit locations for all of your input/output variables in the shaders. For details, see the Linking a shader program recipe.

 

Note

All variables used for input/output interfaces (in/out variables) must have a location assigned.

How to do it...

Start by compiling the shader pair into SPIR-V using the glslangValidator tool:

glslangValidator -G -o basic.vert.spv basic.vert.glsl
glslangValidator -G -o basic.frag.spv basic.frag.glsl

If successful, this produces the basic.vert.spv and basic.frag.spv SPIR-V output files.

To load your SPIR-V shaders into an OpenGL program, use glShaderBinary and glSpecializeShader. With glShaderBinary, use GL_SHADER_BINARY_FORMAT_SPIR_V as the binary format:

GLuint vertShader = glCreateShader(GL_VERTEX_SHADER);

// Load the shader into a std::vector
std::ifstream inStream("basic.vert.spv", std::ios::binary);
std::istreambuf_iterator<char> startIt(inStream), endIt;
std::vector<char> buffer(startIt, endIt);
inStream.close();

// Load using glShaderBinary
glShaderBinary(1, &vertShader, GL_SHADER_BINARY_FORMAT_SPIR_V, buffer.data(), buffer.size());

// Specialize the shader (specify the entry point)
glSpecializeShader( vertShader, "main", 0, 0, 0);

// Check for success/failure
GLint status;
glGetShaderiv(vertShader, GL_COMPILE_STATUS, &status);
if( GL_FALSE == status ) {
  // Loading failed...
}

The process is nearly exactly the same for the fragment shader; just use GL_FRAGMENT_SHADER instead of GL_VERTEX_SHADER on the first line.

 

 

Finally, we create the program object, attach the shaders, and link. This process is identical to that shown in the Linking a shader program recipe, so we won't reproduce it here.

How it works...

The glShaderBinary function provides us with the ability to load shaders that have been compiled to the SPIR-V format. This part is fairly straightforward.

The function that might be a bit more confusing is glSpecializeShader. We are required to call this function before the shader stage can be linked. This call is needed because a single SPIR-V file can have multiple entry points, and SPIR-V files can have specialization constants, which are parameters that the user can provide before it is compiled into native code. 

At a minimum, we need to define the entry point for our shader. Since the source language is GLSL, the entry point is main. We specify the entry point(s) via the second argument. For GLSL, we simply use the main constant string. The last three parameters can be used to define the specialization constants. The first of the three is the number of constants, the next is a pointer to an array of constant indices, and the last is a pointer to an array of constant values.

The process of specializing an SPIR-V shader is similar to compiling a GLSL shader. Before calling glSpecializeShader, or if specialization fails, the compile status will be GL_FALSE. If specialization succeeds, the compile status will be GL_TRUE. As with GLSL shaders, we can query the shader info log to get detailed error messages (see the Compiling a shader recipe).

There's more...

SPIR-V appears to be the future of shader programming in the Vulkan/OpenGL space. However, GLSL is not going away anytime soon. GLSL compilers still ship with OpenGL and there's currently no sign that they will be removed or deprecated. The OpenGL specification still considers GLSL to be the primary shading language. 

However, if you're interested in getting on board with SPIR-V early, or you have an interest in moving toward Vulkan, it might be valuable to you to start working with SPIR-V now in OpenGL. Fortunately, that's possible, at least in recent versions of OpenGL.

 

 

The future of SPIR-V is very bright. There is already a (mostly complete) compiler for HLSL that targets SPIR-V, and it is likely that other languages will be developed soon. It's an exciting time for shader programming!

See also

  • The chapter01/scenebasic.cpp file in the example code
  • The Compiling a shader recipe
  • The Linking a shader program recipe