39
\$\begingroup\$

I want to check if my understanding of the causes for using double (or triple) buffering is correct:

A monitor with 60Hz refresh's the monitor-display 60 times per second. If the monitor refresh the monitor-display, he updates pixel for pixel and line for line. The monitor requests the color values for the pixels from the video memory.

If I run now a game, then this game is constantly manipulating this video memory.

If this game don't use a buffer strategy (double buffering etc.) then the following problem can happen:

The monitor is now refreshing his monitor-display. At this moment the monitor had refreshed the first half monitor-display already. At the same time, the game had manipulated the video memory with new data. Now the monitor accesses for the second half monitor-display this new manipulated data from the video memory. The problems can be tearing or flickering.

Is my understanding of cases of using buffer strategy correct? Are there other reasons?

\$\endgroup\$

1 Answer 1

74
\$\begingroup\$

Fundamentally, a core goal in rendering is for each frame displayed on the monitor to present a single, coherent image. There are several different strategies which are, or were, used in order to achieve this.

In the following, I mention "vsync". Vsync is the moment at which the monitor begins drawing a new screen image; it's the point at which "vblank" begins on a traditional CRT screen, where the scanline momentarily stops drawing and moves back to the top of the monitor. This moment is very important for many of the approaches to frame coherence.

"Tearing" is what we call it when a screen renders from two different images, within a single frame. If, for example, I've drawn two screen images which are intended to be displayed one after the other, but the monitor has instead displayed the top half of frame one, and the bottom half of frame two, that's "tearing". This happens due to changing the data the monitor is reading from while the monitor is drawing, instead of during vblank. (In modern programs, this typically happens because the user disabled waiting for vsync in their driver settings)

Zero-Buffer

On the oldest hardware, there often wasn't enough memory to hold a full screen image, and so instead of drawing a screen image, you needed to specify colors for each scanline individually, while the monitor was in the process of drawing that line. On the Atari 2600, for example, you had just 76 machine instruction cycles to specify what color went into each pixel of the scanline, before the television started to actually draw that scanline. And then you had 76 instruction cycles to provide the contents for the next scanline, and so on.

Single-Buffer

When drawing in a "single-buffer" context, you're drawing straight into the VRAM which is being read from by the monitor. In this approach, you "race the scanline". The general idea is that when the scanline starts drawing the previous frame's contents at the top of the screen, you draw into VRAM behind it. So while the scanline is drawing the screen image for the last frame, you're drawing the next frame behind the scanline.

In general, you're trying to finish drawing the next-frame image before the scanline "laps" you by coming around again and overtaking the pixels that you're drawing, and also to never get ahead of the scanline, or else your new frame might draw into what should have been the previous frame.

For this reason, single-buffer rendering typically worked itself by drawing scanlines, from top to bottom, and from left to right. If you drew in some other order, it was likely that the scanline would come around again and spot bits of the "next" image which you hadn't gotten around to drawing yet.

Note that in modern operating systems, you typically never have an opportunity to draw single-buffered, though this was fairly common thirty years ago. (gosh do I feel old right now -- this is what I was doing when I first started out in game development)

Double-Buffer

This is much, much simpler than either of the strategies that came before.

In a double-buffering system, we have enough memory to store two different screen images, and so we designate one of them as the "front buffer" and the other, the "back buffer". The "front buffer" is what's currently being displayed, and the "back buffer" is where we're currently drawing.

After we finish drawing a screen image to the back buffer, we wait until vsync, and then swap the two buffers. This way, the back buffer becomes the front buffer, and vice versa, and the whole swap happened while the monitor wasn't drawing anything.

Triple-Buffer

One issue often raised with double-buffer approaches is that after we finish drawing to the back buffer, we have to just sit around waiting for vsync before we can swap the buffers and continue working; we could have been doing calculations during that time! What's more, all the time that we're waiting to swap between the buffers, the image in that back buffer is getting older and older, thus increasing the user's perceived latency.

In triple-buffer systems, we create ourselves three buffers -- one front buffer and two back buffers. The idea is this:

The monitor is displaying the front buffer, and we're drawing into back buffer #1. If we finish drawing into back buffer #1 before the monitor finishes drawing the front buffer, then instead of waiting for vsync, we instead immediately start drawing the next frame into back buffer #2. If we finish and vsync still hasn't come, we start drawing back into back buffer #1, and so on. The idea is that when vsync eventually happens, one or the other of our back buffers will be complete, and that one can be swapped for the front buffer.

The benefit of triple-buffering is that we don't lose the time that we spent waiting for vsync in the double-buffering approach, and the image swapped onto the front buffer may be "fresher" than one which had been waiting for vsync for 8ms. The down-side of triple-buffering is that we need extra memory for storing the extra screen image, and that our CPU/GPU usage will be higher (again, since we don't slow down to wait for vsync).

Typically, modern drivers will often perform triple-buffering transparently, behind the scenes. You write your code to do double-buffering, and the driver will actually return control to you early, and just internally handle swapping between however many back buffers it wants to use, without your code ever being aware of it.

GPU vendors currently recommend that you not implement triple-buffering yourself -- the driver will do it for you automatically.

\$\endgroup\$
8
  • 8
    \$\begingroup\$ This is an incredibly detailed answer, and explains why a lot of things are done the way they are (like the screen coordinate space, etc). Also answered my question "why not quadruple buffers? Quintuple?" I didn't realize that buffer swapping happened in the background, meaning that two back buffers are the maximum needed. Upvoted. \$\endgroup\$
    – user6662
    Commented Aug 23, 2014 at 2:29
  • \$\begingroup\$ Actually there exists quad buffering. This is double buffering for stereoscopic view. swiftless.com/tutorials/opengl/smooth_rotation.html \$\endgroup\$
    – Narek
    Commented Nov 1, 2017 at 12:54
  • 1
    \$\begingroup\$ @Narek No. Quoting from your link: "You can’t really enable actual quad buffering in computer graphics environments as there’s no real point". Suggesting that doing double buffering on two different views simultaneously would be "quad buffering" is just amusing wordplay; not something real. \$\endgroup\$ Commented Nov 14, 2017 at 6:30
  • 1
    \$\begingroup\$ @TrevorPowell Your point it totally clear though. It doesn't make sense to have more than 3 buffers for one render buffer. \$\endgroup\$
    – Narek
    Commented Nov 15, 2017 at 9:22
  • 1
    \$\begingroup\$ @TrevorPowell Quad buffering is not just double buffering for 2 displays. Next to certain optimizations for stereoscopy, it also guarantees both frames to be written at the same time (in sync). This is specifically important for stereo views because you don't want your left eye to see another frame than your right eye. In OpenGL, the multiview rendering extension uses quad buffering under the hood. Quad buffering might not be widely supported, so then half of the resolution may be sacrificed to put both views in a single frame which may also ensure both frames are rendered at the same time. \$\endgroup\$
    – Yeti
    Commented Nov 10, 2018 at 10:35

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .