Triple Buffering

From GCW Zero Wiki
Jump to: navigation, search

Triple buffering refers to a video output mode in which up to 3 full frames are queued for display.

Contents

Triple buffering versus double buffering

Both double and triple buffering eliminate screen tearing, but they do this in different ways.

Double buffering starves the main thread of a program of CPU time after each frame. The kernel must deschedule a double-buffered application until the front buffer (the previous frame) is fully scanned by the LCD screen in order to avoid tearing. Triple buffering has no such limitation, because there are two back buffers the application can draw into.

If the main thread of your program is also responsible for the creation of audio (e.g. emulation), using double buffering is inadvisable, because it can cause audio underruns as the CPU is starved between frames. Otherwise, either can be used.

Double buffering locks an application to 30 FPS if it can't meet deadlines for 60 FPS, 20 if it can't meet deadlines for 30, 15 if it can't meet deadlines for 20, etc. Triple buffering instead tries to draw as many frames as possible, which may introduce stutter if the FPS is not exactly 60 or 30.

Double buffering is preferable for native games, which need their video output to be fluid. Triple buffering may be preferable for emulators, where every frame counts for perceived performance and smoothness in scrolling games.

Classic implementations of triple buffering are designed to allow applications to draw faster than the refresh rate of the screen. On the GCW Zero, triple buffering prevents applications from running faster than the LCD screen's refresh rate (60 Hz) just as classic double buffering does.

Prerequisites

To develop applications using triple buffering in SDL 1.2, make sure you have the GCW Zero firmware, 2014-05-05 or later. You (but not the end-users) will also need the GCW Zero toolchain, 2014-05-05 or later. End-users will be able to run applications using triple buffering in earlier firmwares, but they will be double-buffered instead. (See the Portability section, below.)

Triple buffering in code

SDL 1.2 applications may request triple buffering like so:

#include "SDL.h"
...
SDL_Surface* screen = SDL_SetVideoMode(320, 240, 16, SDL_HWSURFACE |
#ifdef SDL_TRIPLEBUF
  SDL_TRIPLEBUF
#else
  SDL_DOUBLEBUF
#endif
  );

The example assumes 320x240 output. Other resolutions are usable here; see Hardware Scaling. Other SDL_SetVideoMode flags, such as SDL_FULLSCREEN, can also be used.

Portability

The reason for the conditional compilation above is that OpenDingux supports triple buffering via an extension to SDL 1.2.

/opt/gcw0-toolchain/usr/mipsel-gcw0-linux-uclibc/sysroot/usr/include/SDL/SDL_video.h:
#define SDL_TRIPLEBUF  0x40000100      /**< Set up triple-buffered video mode */

This bitfield constant sets the bit normally used for SDL_DOUBLEBUF, plus one extension bit. This allows applications that are compiled to use SDL_TRIPLEBUF to continue working if run under an OpenDingux firmware or other environment that doesn't have this triple buffering extension. Those environments will run triple-buffered applications with double buffering.

Other considerations

A double-buffered application that draws a border around a game that is smaller than 320x240 for only 2 frames, when made to use triple buffering, will have a third buffer that is not cleared; remnants of its border may flicker into and out of view.

This can be dangerous to those who suffer from photosensitive epilepsy, and must be dealt with by clearing a third frame before proceeding with drawing only the middle of the screen in further frames.

Other assumptions made by software-rendered games about the number of buffers that will exist need to be adjusted, especially if they use partial clearing of even the game area.