What are GLAD, GLFW and OpenGL?

Matt Pinch
6 min readJan 16, 2024

What is OpenGL?

Suppose we have 3 restaurants and we want each restaurant to make the same exact pizza. Each restaurant is in a different country, uses different measurement units, different types of ovens and speaks different languages. Even though they are all capable of creating the same pizza, we would need three different recipes to produce the same pizza.

Annoying, right?

It would be a lot easier if there was an abstraction layer so that the restaurant employees can use the same language, oven settings and measurement units which would then be translated to the location specific language, settings and units. The pizza would be standardized, less likely to have mistakes in it and the restaurant’s employees could seamlessly move between restaurants.

OpenGL acts as that abstraction layer for communicating with an operating system’s hardware used to render graphics. OpenGL translates the standardized set of instructions (draw a triangle on the screen) to the GPU or CPU specific instructions for drawing a triangle on the screen (use the AMD or NVIDIA or Intel specific software to draw a triangle on the screen).

This works because OpenGL is just specifying an interface (imagine we had a DrawTriangle function) while the hardware providers like NVIDIA provide the software that has the actual implementation of the DrawTriangle function itself. The software containing the implementation of these functions that execute on the CPU or GPU arecalled graphics drivers.

By using the OpenGL standardized interface, this allows everyone to work off the same codebase even if the hardware is different.

What is GLFW?

OpenGL creates an abstraction layer for rendering graphics, but there are some important parts of the rendering pipeline it doesn’t handle.

First, it doesn’t handle creating the window, or the context, in which all the rendering is happening. Think of the graphics pipeline as being separated into two parts — the window where all the graphics are being rendered, and the rendering itself. In our pizza analogy, the window would be the restaurant itself while the rendering would be everything happening inside to make the pizza. More specifically, GLFW takes care of creating the window while OpenGL takes care of rendering stuff within the window.

Secondly, OpenGL does not handle external input like mouse clicks or keyboard presses. GLFW also takes care of processing these inputs.

OpenGL is only responsible for providing an interface for rendering graphics. GLFW is a library that provides functionality for creating a context window and processing input for an OpenGL application by interfacing with the operating system’s relevant libraries. It’s able to accomplish this by linking an operating specific library that contains functionality to manage windows, inputs, etc to the program using OpenGL.

What do you mean “linking an operating specific library”?

GLFW provides something called a dynamic library. This means that the program using OpenGL is linked to another piece of code that has all the functionality needed in order to create windows and handle inputs. The advantage to doing things this way is that creating windows and processing external inputs is a very common use case for lots of programs. Therefore it makes sense to have one library loaded into memory that has all the functionality required to handle window creation and input processing so that many other programs can use the same code. This makes it more modular and less error-prone. When a program needs to create a window, for example, it finds where in memory that function is located and executes it.

Since these functions are located and executed at runtime, this means that if there are any problems with the library they are only discovered at runtime.

What is GLAD?

Back to the pizza analogy, if we want to make a simple cheese pizza, it will be different depending on where we are located. If we are in one country, we will have to go to one grocery store for the ingredients, use the local language, pay with the local currency and bake at some degrees in whichever temperature unit is locally used. If we are in a different country we will repeat the same steps but use a different grocery store, language, currency and temperature units. It would be great if we can just have the same set of instructions per restaurant that are mapped to the local translations.

This translation from the same set of instructions into the locality specific instructions is what GLAD helps OpenGL do. In this case, OpenGL is the “same set of instructions” and the different hardware are the “different countries.”

In order for OpenGL to successfully render stuff into the window, it needs to interface with the graphics drivers on the machine. For this to happen, the OpenGL functions need to be mapped to their corresponding operating system specific rendering functionality. This means a lot of checking “if this is a windows operating system, map the OpenGL rendering function to this Windows specific graphics function and do XYZ functionality, else map the OpenGL rendering function to a different operating system rendering function and do ABC functionality.”

This introduces a lot of boilerplate code into the application and increases the chance of creating a bug. GLAD is what’s called an extension loader but in simple English it’s something you can import into your code that provides a function you can call which handles all of this mapping under the hood for you and reduces the amount of code you need to write.

Source code in GLAD looks something like this:

#if GLAD_PLATFORM_APPLE
// if compilation is happening on Apple operating system, do this
#elif GLAD_PLATFORM_WIN32
// if compilation is happening on Windows operating system, do this
#else
// do this for all other operating systems
#endif

You can see that GLAD executes different code depending on what operating system the code is compiling on.

I still don’t really understand GLAD

Let’s look at an example where we don’t use GLAD taken from learnopengl.com

typedef void (*GL_GENBUFFERS) (GLsizei, GLuint*); 
/*
Here we have defined a function type called GL_GENBUFFERS
that returns void and accepts data types GLsizei, GLuint* as
input parameters. Notice the function type is *GL_GENBUFFERS as
opposed to GL_GENBUFFERS (notice the asterisk) which means
this is actually a pointer to a function.
*/
GL_GENBUFFERS glGenBuffers = (GL_GENBUFFERS)wglGetProcAddress("glGenBuffers");
/*
Here we will pass in the name of the function, glGenBuffers, to a
function called wglGetProcAddress. This is a windows-specific function
that tries to find the glGenBuffers function on the graphics driver.
Specifically, this function belongs to the windows graphics layer and
its job is to find where the glGenBuffers function exists within the
graphics driver. Once it has been found, it returns it to the
OpenGL program so that it can be used.
This means that whoever is providing the GPU or CPU, whether it be
Intel, AMD or NVIDIA, has implemented the
glGenBuffers function and that is what is being stored in glGenBuffers
*/
unsigned int buffer;
glGenBuffers(1, &buffer);
// Now we're just calling the function.

One potential point of confusion: why are we looking for an OpenGL function somewhere else if we are already using the OpenGL library?

All major graphics drivers ship today with out of the box OpenGL support. This means that they have implemented functions, like glGenBuffers, which support OpenGL and are meant for programs using OpenGL to map to them. Because graphics drivers can be different from each other, even on the same hardware which use different software versions, the implementation of the function itself could be different (newer NVIDIA graphics drivers could have better performance by changing implementation of a function or utilizing improved hardware, for example) even if they deliver the same rendered result.

--

--

Matt Pinch
Matt Pinch

Written by Matt Pinch

Are we inside a simulator.

No responses yet