If redrawing the background is a pain, consider using a
double-buffered approach, where the back buffer only contains the
background pixels. For this, you wouldn’t use SDL_DOUBLEBUF, but
rather create the two buffers yourself. At each frame, you can draw
the background (if needed), copy the necessary parts to the front
buffer, and draw foreground objects into the front buffer. The back
buffer could be SDL_SWSURFACE or SDL_HWSURFACE, but if the latter,
the front should be SDL_HWSURFACE as well, to avoid copying pixels
from video RAM to system RAM.
What are the reasons for drawing the background in a separate surface
and the front elements directly in the front buffer? Would it not be
simpler to draw everything in a backbuffer and then just do a flip
after the scene is composed? What am I missing?
Well, keep in mind that you’ll need a dedicated buffer for the background.
This way, you’ll always be able to redraw the parts of the background that
were covered in the previous frame. Whether your background is made of
separate tiles or one surface, you can devise a method to only draw a
certain part of it to erase the sprite.
If you use a double-buffered surface, flipping will not solve the problem.
Because a flip logically switches the front buffer with the back buffer,
the backbuffer’s pixels after a flip will contain the previous frame’s
pixels.
Page-flipping is only truely advantageous for elminating tearing artifacts
to get super-smooth animation, since on some hardware it can sync to the
monitor’s refresh. On the other hardware, it will be much slower, as the
buffers must be copied from system RAM to video RAM each time you do a
flip. Worse yet, the window manager/server on the OS might already
double-buffer windows, which will then require an additional copy. Don’t
forget that before any of this happens, you are drawing stuff into the
back buffer!
Assuming a static background, the choices are as follows:
Slow on most hardware method (using SDL_DOUBLEBUF):
- Draw entire background to backbuffer
- Draw sprite in new location in backbuffer
- Flip
Lets look the best/worst case for this method:
best - all hardware surfaces (like perhaps DirectX)
worst - all software surfaces (like on Mac OS X, where windows are double
buffered and you can only draw into system RAM)
In the best case, this is very fast, since all copies are VRAM->VRAM.
But in the worst case…
- (RAM->RAM speed) * width * height
- (RAM->RAM speed) * sprite width * sprite height
- (RAM->RAM speed) * width * height + (RAM->VRAM speed) * width * height
Since RAM->RAM and RAM->VRAM speeds are many orders of magnitude slower
than a hardware flip, I think you can see how this could be slow.
Now the previously mentioned method which is fast on most hardware.
- Draw background(if changed) in dedicated buffer
- Draw parts of background to screen (to erase sprite)
- Draw Sprite at new location.
- UpdateRects
Lets look at the worst-case performance here:
- 0 ( assuming background is static and previously drawn)
- (RAM->RAM speed) * sprite width * sprite height
- (RAM->RAM speed) * sprite width * sprite height
- (RAM->VRAM speed) * sprite width * sprite height
This has been mentioned many times before on this list; if you want good
performance on a variety of systems, use UpdateRects and only redraw those
parts of the screen that change from frame to frame.
If the background is not static, the performance of this method drops off
to nearly the same as the first approach as you change more pixels in the
background from frame to frame. In this case, it will be dog slow without
hardware support on anything greater than 8bit color 640x480, so you may
as well use SDL_DOUBLEBUF.
This is my understand of drawing in SDL, please correct me if I am wrong.
-DarrellOn Tue, 9 Oct 2001, Ney Andr? de Mello Zunino wrote:
On Tuesday, 09 October, 2001, Darrell Walisser wrote: