Double Buffering

An introduction to double buffering - the foundational technique behind real time graphics
This lesson is part of the course:

Game Dev with SDL3

Learn C++ and SDL development by creating hands on, practical projects inspired by classic retro games

Free, Unlimited Access
aSDL7.jpg
Ryan McCombe
Ryan McCombe
Posted

In the previous lesson, we described a typical game loop:

  1. Get input
  2. Update all our objects
  3. Render the frame

The transition from step 2 to step 3 warrants some further explanation. There is some theory here that is very important to understanding how SDL, and real time graphics in general, works.

In computer graphics, we simulate movement by quickly showing a sequence of still images, typically called “frames”.

A lot of complexity and elaborate algorithms can go into generating these frames. But, after all the processing, we’re just with a collection of pixel colors we want to show the user.

What are Buffers?

A buffer is an area of memory where data is stored for a short period of time. Frames are buffers - we can think of them as big arrays of pixel objects. Our goal boils down to determining which color each pixel needs to be, and to write those values into the buffer.

The problem is that we can’t do that all at once. It takes many statements, function calls and calculations to generate a frame, and they don’t all complete at the same time.

That presents a problem for our users - we don’t want them to witness the frame being constructed. That would shatter the illusion. So, we invented double buffering.

Double Buffering

With double buffering, we have, predictably, two buffers. There’s the one the user is seeing, and the one we’re building to show to them next.

The buffer the user is seeing is called the “front buffer”, and the one we’re building is the “back buffer”. When we’ve completely finished building the back buffer, we swap them around.

The back buffer becomes the front buffer and is shown to our users. The front buffer becomes the back buffer, and we start creating our next frame in it.

This is typically managed on the GPU but, were we to create the effect in C++, we could imagine it being something like this:

using Buffer = std::vector<Pixel>;
Buffer A;
Buffer B;

Buffer* Front { &A };
Buffer* Back { &B };

while(true) {
  DrawEnvironment(Back);
  DrawCharacters(Back);
  DrawUI(Back);
  std::swap(Front, Back);
}

Double Buffering in SDL2

In SDL2, the double buffering is mostly handled for us. When we use commands like SDL_FillRect, SDL ensures this is being done on the back buffer.

However, we do need to tell SDL when it needs to swap buffers. When we’re working with window surfaces, that command is SDL_UpdateWindowSurface.

If we’re making changes in our application, and those changes do not seem to be appearing, the first thing we should do is make sure we’re calling SDL_UpdateWindowSurface after making our changes.

In our example application loop from the previous lesson, we were calling this function as the final step of the loop. This ensures our buffers are swapped as quickly as possible, maximising our frame rate.

Theory: Screen Tearing and VSync

It's generally beyond the scope of this course, but as an aside for anyone who has heard the phrases, and wants some more context on what they are. These two concepts are inherently linked to the multiple buffer setup we're discussing here.

Once our software implements double buffering, there’s an unpleasant interaction that can happen with our hardware.

This is because computer monitors don’t update their display all at once - that is also a process that takes some time. If we trigger our swap in the middle of that process, part of the monitor can show one frame, whilst another part shows a different frame. This is what causes screen tearing.

It is also why screen tearing is more common at higher frame rates. Higher frame rates means more frequent swaps, which means more swaps happening at the same time the monitor is refreshing.

There are various options for dealing with this, a popular one being synchronizing the application’s refresh rate with the hardware refresh rate. Variations of this idea are commonly called vertical sync (vsync).

Theory: Triple Buffering

When our refresh rate is synchronized with the hardware’s refresh rate, this presents an interesting problem for us. When we complete the next frame, it needs to wait in the back buffer until the hardware is ready for it.

So, we’re left sitting with a completed frame in both our buffers. Until the hardware requests the swap, we can’t start working on our next frame. Predictably, this is the use case for adding yet another buffer to the process. With triple buffering, we have:

  1. The front buffer, which the user is currently seeing
  2. The middle buffer, which has a completed frame ready to be used the next time the monitor updates
  3. The back buffer, where we’re creating the frame to come after that

Was this lesson useful?

Ryan McCombe
Ryan McCombe
Posted
DreamShaper_v7_cyberpunk_woman_playing_video_games_modest_clot_0.jpg
This lesson is part of the course:

Game Dev with SDL3

Learn C++ and SDL development by creating hands on, practical projects inspired by classic retro games

Free, Unlimited Access
Creating an SDL Application
  • 25.Making Minesweeper with C++ and SDL2
  • 26.Project Setup
  • 27.GPUs and Rasterization
  • 28.SDL Renderers
DreamShaper_v7_cyberpunk_woman_playing_video_games_modest_clot_0.jpg
This lesson is part of the course:

Game Dev with SDL3

Learn C++ and SDL development by creating hands on, practical projects inspired by classic retro games

Free, unlimited access

This course includes:

  • 27 Lessons
  • 100+ Code Samples
  • 91% Positive Reviews
  • Regularly Updated
  • Help and FAQ
Next Lesson

Keyboard and Mouse Input in SDL2

Learn how SDL2 handles user input, and how we can react to it to update our application in real time.
aSDL8.jpg
Contact|Privacy Policy|Terms of Use
Copyright © 2024 - All Rights Reserved