Hot reloading shaders

Daniel Andersson
2019-04-19

A common way to get started writing shaders is to use something like the editor for The Book of Shaders or Shadertoy. You can do similar quick editing/iterating on a desktop application, even if the application is written in a compiled language. Reloading a shader is actually pretty simple to do, the hard part is to get an OpenGL, or another GPU API, application running on desktop. At a later date I might add a minimal example, but for now this blog post will be more high level.

You can use something like inotify(Linux) or ReadDirectoryChangesW(Windows) to monitor the directory where the shaders are stored on disk. When you edit and save your shaders, you will get notified which file was changed. Then you need to figure out which shader that file belongs to, and do something similar to this:

void reload_shader(GLuint *shader, const char *vertex_path, const char *fragment_path)
{
  GLuint result = create_shader(vertex_path, fragment_path);
  if (result) {
    glDeleteShader(*shader);
    *shader = result;
  }
}

Depending on how the uniforms and attributes are handled in the application, you may have to do some other initialization after reloading the shader.

Currently I do not use inotify to detect changes in shaders. I reload the shader manually on keypress instead, that is why there is a delay after saving the shader file.

When I first tried Unreal Engine 4 I thought it was kind of ‘magical’ that you could change the viewport to show different modes, like the ‘light view’, which is black and white. After implementing a project that uses OpenGL, it turns out that doing that is not magic at all. I realize that Unreal Engine 4’s feature is probably more involved but still.

If there are other people than programmers working on the application, some UI sliders would probably be required for changing contribrution of the different sources in the video above. But if there are only a few programmers and a few technically minded artists or similar on a project, you probably do not have to implement all UI features and can just rely on reloading code.