Double Buffering: Difference between revisions

Jump to navigation Jump to search
[unchecked revision][unchecked revision]
Content deleted Content added
Creature (talk | contribs)
Updated <pre> blocks (with C and C++ language <code> tags).
Creature (talk | contribs)
Did some minor cosmetic changes and added some more information.
Line 1: Line 1:
{{Rating|1}}
{{Rating|1}}
Double-buffering is a term that is well known throughout the graphics industry. Most applications (primarily games) seldom work without it as it has many advantages over single-buffering.
Double-buffering is a term that is well known throughout the graphics industry. Most applications (primarily games) seldom work without it as it has many advantages over single-buffering (but also has a few disadvantages).


== What it is ==
== What Is It? ==
==== The Buffers ====
==== The Buffers ====
Double-buffering possibly sounds harder than it actually is. In theory, you have a buffer A and a buffer B, which are usually respectively called the front-and back-buffer. On single-buffered displays, you draw straight to video memory, so suppose video memory is located at address 0xB800 (like console video memory is), you just start modifying values starting from this address (as you probably know) to show characters on the screen. If you would do this with double-buffering (which isn't a very good idea with console video memory, by the way), 0xB800 would represent buffer A (the front-buffer). Buffer B is created and allocated by your favourite malloc function (or new[] operator).
Double-buffering possibly sounds harder than it actually is. In theory, you have a buffer A and a buffer B, which are usually respectively called the front-and back-buffer. On single-buffered displays, you draw straight to video memory, so suppose video memory is located at address 0xB800 (like console video memory is), you just start modifying values starting from this address (as you probably know) to show characters on the screen. If you would do this with double-buffering (which isn't a very good idea with console video memory, by the way), 0xB800 would represent buffer A (the front-buffer) whilst buffer B is created and allocated by your favourite malloc function (or new[] operator).


==== Where To Write To ====
==== Where To Write To ====
Now, instead of writing directly to console video memory (at 0xB800), you write everything to the address where Buffer B is located. The process of drawing characters is exactly the same as before, except you're now writing to another memory address. When you're done drawing, you 'swap the buffers'. One way of 'swapping the buffers' is copying the contents of Buffer B to Buffer A (you literally 'swap the contents from B to A').
Instead of writing directly to console video memory (at 0xB800), you write everything to the address where Buffer B is located. The process of drawing characters is exactly the same as before, except you're now writing to another memory address.
When you're done drawing, you copy the contents of the back buffer (buffer B) to the front buffer (buffer A). This process is commonly called 'swapping the buffers', though swapping isn't interpreted as switching the contents around, but more of in 'switching the order of the buffers'. By 'swapping the buffers', the back buffer is now seen by the user and carries the same pixel values as the front buffer. The back buffer can then be freely modified again until ready to be then swapped again.


==== What Actually Is Seen ====
==== What Actually Is Seen ====
When using double-buffering, the user is looking at Buffer A while you're drawing to Buffer B. When using single-buffering, the user is looking at Buffer A at the same time you're modifying that buffer. So that means the user doesn't see any pixels being modified at the moments he or she is looking at the screen.
When using double-buffering, the user is looking at Buffer A while you're drawing to Buffer B. When using single-buffering, the user is looking at buffer A at the same time you're modifying that buffer. So that means the user doesn't see any pixels being modified at the moments he or she is looking at the screen. He or she will notice the changes as soon as you swap the buffers.


==== Important Note ====
==== Important Note ====
I used console video memory as an example here, as pratically every OS developer knows how to use this, but it is still not recommended to use double-buffering on a console display, as it is practically useless and wastes memory (unless you're using some kind of game loop for your OS). Double-buffering can be very useful when you're building your own GUI though.
I used console video memory as an example here, as pratically every OS developer knows how to use this, but it is still not recommended to use double-buffering on a console display, as it is practically useless and wastes memory (unless you're using some kind of game loop for your OS). Double-buffering can be very useful when you're building your own GUI though. On console displays, you usually also don't need double-buffering since there are no problems with artifacts.


== Advantages ==
== Advantages ==
Now why would you want to use double-buffering over single buffering in e.g. your GUI, games, or video displays? Well, the main advantages of double-buffering are:
The main advantage of using this is that it usually takes care of things like artifacts and flickering. When you're drawing an entire GUI on a single-buffered display and your blitting isn't too fast (sometimes even if it is fast), there is a possibility the user's screen will flicker or he/she will literally see the pixels appearing (overwriting the old pixels) on the screen. With double-buffering, everything is drawn at once, which is much faster.

* The user does not see every pixel modification (so if the same pixel gets modified 5 times, the user will only see the last one). This helps preventing 'flickering' (or screen flashes).
* Double-buffering usually takes care of artifacts you or the user might be experiencing.
* Writing to video memory is only performed once, on the buffer swap, instead of repeatidly for every pixel of which some might be overlapped later and might be invisible.


== Disadvantages ==
== Disadvantages ==
Even though double-buffering is useful, it also has negative characteristics; for one it takes up extra memory. The simplest way of creating a double buffer would be something like this:
Even though double-buffering is useful, it also has negative characteristics.

* You need to create a second buffer with the same size of the vdeo memory (and for large displays such as 1280x1024x32 this can be an expensive cost).
* You need to copy the back buffer to the front buffer every time the buffer needs to be swapped (in games with a frame-rate of 30, 30 times each second). So better make sure your 'memcpy' and other memory functions are optimized!

Note that the buffer doesn't always have to have the same size as the video memory, there are also other ways to do double-buffering, for one you could also have some sort of compression system where a number indicates how many pixels have the same value. Then again, that would have an extra performance cost if not done efficiently. Below you'll find an example of how to create a basic double-buffering system.


==== Buffer Creating In C ====
==== Buffer Creating In C ====
Line 54: Line 64:
void InitVideo(unsigned short ScreenWidth, unsigned short ScreenHeight, unsigned char BitsPerPixel)
void InitVideo(unsigned short ScreenWidth, unsigned short ScreenHeight, unsigned char BitsPerPixel)
{
{
/* Warning: This is an example, you should fill in the address of your video memory here. */
/* Warning: 0xEEEEEEE servces as an example, you should fill in the address of your video memory here. */
VidMem = ((byte *) 0xEEEEEEE);
VidMem = ((byte *) 0xEEEEEEE);
BackBuffer = ((byte *) (malloc(ScreenWidth * ScreenHeight * BitsPerPixel)));
BackBuffer = ((byte *) (malloc(ScreenWidth * ScreenHeight * BitsPerPixel)));
Line 72: Line 82:
{
{
/* Put a pixel onto the back buffer here. */
/* Put a pixel onto the back buffer here. */
/* Remember to write to the BACK buffer instead of the FRONT buffer (VidMem). */
/* Remember to write to the BACK buffer instead of the FRONT buffer (the front buffer represents your video memory). */
}
}


/*
/*
* Swaps the back and front buffer.
* Swaps the back and front buffer.
* I've chosen the simple way; copy the back buffer to the front buffer.
* Most commonly done by simply copying the back buffer to the front buffer.
*/
*/
void SwapBuffers()
void SwapBuffers()
Line 83: Line 93:
/* Copy the contents of the back buffer to the front buffer. */
/* Copy the contents of the back buffer to the front buffer. */
memcpy(VidMem, BackBuffer, ScrW * ScrH * Bpp);
memcpy(VidMem, BackBuffer, ScrW * ScrH * Bpp);

/* Possibly clear the back buffer here. */
}
}


Line 90: Line 98:
* An example of how to use these functions.
* An example of how to use these functions.
*/
*/
void DoSomething()
void ProgramLoop()
{
{
while(OS_Is_Running)
while(Program_Is_Running)
{
{
/* Handle events, update window coordinates and other things, ... */

/*
/*
* You should probably implement some sort of FillScreen or FillRect function,
* You should probably implement some sort of FillScreen or FillRect function,
* or at least something that clears the back buffer before drawing.
* or something that clears the back buffer before drawing. Setting the entire
* back buffer to 0 (black) will suffice for a basic system.
*/
*/
memset(Backbuffer, 0, ScrW * ScrH * Bpp);
memset(Backbuffer, 0, ScrW * ScrH * Bpp);


/* Draw everything using drawing functions, like the SetPixel function. */
/* Draw everything: a GUI, windows, other things. This example puts 2 white pixels on the screen. */
SetPixel(50, 50, 0xFFFFFF);
SetPixel(50, 50, 0xFFFFFF);
SetPixel(25, 25, 0xFFFFFF);
SetPixel(25, 25, 0xFFFFFF);
Line 142: Line 153:
{
{
/* Put a pixel onto the back buffer here. */
/* Put a pixel onto the back buffer here. */
/* Remember to write to the BACK buffer instead of the FRONT buffer (VidMem). */
/* Remember to write to the BACK buffer instead of the FRONT buffer (the front buffer represents your video memory). */
}
}


/*
/*
* Swaps the back and front buffer.
* Swaps the back and front buffer.
* I've chosen the simple way; copy the back buffer to the front buffer.
* Most commonly done by simply copying the back buffer to the front buffer.
*/
*/
void SwapBuffers()
void SwapBuffers()
Line 153: Line 164:
/* Copy the contents of the back buffer to the front buffer. */
/* Copy the contents of the back buffer to the front buffer. */
memcpy(VidMem, BackBuffer, ScrW * ScrH * Bpp);
memcpy(VidMem, BackBuffer, ScrW * ScrH * Bpp);

/* Possibly clear the back buffer here. */
}
}


Line 160: Line 169:
* An example of how to use these functions.
* An example of how to use these functions.
*/
*/
void DoSomething()
void ProgramLoop()
{
{
while(OS_Is_Running)
while(Program_Is_Running)
{
{
/* Handle events, update window coordinates and other things, ... */

/*
/*
* You should probably implement some sort of FillScreen or FillRect function,
* You should probably implement some sort of FillScreen or FillRect function,
* or at least something that clears the back buffer before drawing.
* or something that clears the back buffer before drawing. Setting the entire
* back buffer to 0 (black) will suffice for a basic system.
*/
*/
memset(Backbuffer, 0, ScrW * ScrH * Bpp);
memset(Backbuffer, 0, ScrW * ScrH * Bpp);


/* Draw everything using drawing functions, like the SetPixel function. */
/* Draw everything: a GUI, windows, other things. This example puts 2 white pixels on the screen. */
SetPixel(50, 50, 0xFFFFFF);
SetPixel(50, 50, 0xFFFFFF);
SetPixel(25, 25, 0xFFFFFF);
SetPixel(25, 25, 0xFFFFFF);
Line 180: Line 192:
</source>
</source>


I believe this example is mostly clear. As there are too many different ways of changing video modes or putting pixels, I'm going to let you fill it in yourself. If you want more information, you can go to the [[GUI|GUI]] or the [[Drawing_In_Protected_Mode|Drawing In Protected Mode]] pages.
I believe this example is mostly clear. As there are too many different ways of changing video modes or putting pixels, I'm going to let you fill that in yourself. If you want more information, you can go to the [[GUI|GUI]] or the [[Drawing_In_Protected_Mode|Drawing In Protected Mode]] pages.

Note also that the above code might be very 'irregular'. As you know, there is no limit on the drawing, so it is possibly that the first draw takes 30 milliseconds, while the second draw takes 40 milliseconds or the first few seconds, you have a frame-rate of 100 frames per second whilst the next couple of seconds, you have a frame-rate of only 20 frames per second. Because of this, drawing times are usually capped. In the most common GUI's (such as the one in Windows), this is not really of any importance, since only parts of the screen are redrawn if they are 'invalidated' (usually referred to as 'Invalidated rectangles'), but in games, the screen is being constantly redrawn, usually up to 60 times per second. Today's API's usually clamp this value to the screen refresh rate, this is why they usually have values such as '60' or '75'. Normally, a frame-rate of 25 to 30 suffices to have a 'smooth' display.


I've used some sort of loop here (it looks like a game loop), but remember that most GUI's on OS' do not work with game loops, they usually work with some sort of invalidation system. Meaning a control is redrawn only if it is invalidated, which happens on occassions such as moving or resizing the control.
I've used some sort of loop here (it looks like a game loop), but remember that most GUI's on OS' do not work with game loops, they usually work with some sort of invalidation system. Meaning a control is redrawn only if it is invalidated, which happens on occassions such as moving or resizing the control.
Line 186: Line 200:
== What Else ==
== What Else ==
==== Triple Buffering ====
==== Triple Buffering ====
As if it wasn't enough, there is also triple buffering. But as this article is not about that subject, it's explained here. Triple buffering works with the same principle as double buffering but has a few other advantages and disadvantages.
As if it wasn't enough, there is also triple buffering. But as this article is not about that subject, it's not explained here. Triple buffering works through the same principle as double buffering but has a few other advantages and disadvantages.


[[Category:Video]]
[[Category:Video]]