[SDL] Problems in Full Screen
David Olofson
david at olofson.net
Fri May 23 03:54:02 PDT 2003
On Friday 23 May 2003 06.10, eDU! wrote:
[...]
> Can you tell me what could be the possible problem? Im sure that
> its not an sdl problem, and its just the way im "showing" the
> images. Maybe the background image. I can't guess it.
When you use double buffering, there are basically two possible ways
it can be arranged:
1) True page flipping, with two hardware surfaces that
are swapped when you SDL_Flip(). You render into one
while the other one is being displayed.
2) "Fake" page flipping, with one hardware surface for
the display, and one software surface for rendering.
When you SDL_Flip(), the software back surface (or
"shadow surface") is copied into the front hardware
surface.
When you're deailing with full screen scrollers and the like, where
the whole screen is repainted every frame, the difference is
irrelevant. Both arrangements will work fine.
However, as soon as you start doing partial updates, it makes a big
difference!
If you're on a "case 2" display, there's no problem; each flip will
just make sure the current version of your screen becomes visible.
You get to keep the back surface as a base for further rendering.
Now, if you do this on a "case 1" display, this no longer works. When
you flip, the page you just rendered into is *swapped* with the one
that was displayed. Of course, you still get your new frame
displayed, but your new back buffer is the *previous* frame you
flipped into display. You now have to perform updates for two frames
to catch up; one to get back to the state of the frame you just
flipped into display, and one to turn that into the next frame.
In short, if you set up a double buffered screen and get a hardware
surface, you need to do all updates twice per frame, or deal with the
"old back buffer" in some other way.
More specifically, you need to blit the background image twice, with
an SDL_Flip() in between, and then you need to do something about the
sprite removal.
The safe way (works with both styles of double buffering) is to
remember all sprite "dirty rects" for the last two frames. Before you
blit the sprites for a new frame, restore all dirty rects from *both*
buffers. Then blit your sprites, overwriting the oldest set of dirty
rects.
A more efficient way is to restore using only the older set of dirty
rects. (The newer one *shouldn't* be relevant until the next frame,
since it describes the page that's currently being displayed.)
However, do keep in mind that this breaks down unless you *really*
have a true hardware pageflipping ("case 1") display.
Don't start whining about modern video subsystems being a PITA just
yet, though. There's a third, hybrid method that covers both cases
without much extra cost: Instead of just restoring every single dirty
rect in the two sets, make a first pass where you merge overlapping
rects, to avoid updating some areas multiple times.
In many cases when dealing with sprites, and you don't have tons of
them (ie not too many overlapping sprites), you can just consider the
last two positions of each sprite, and create a dirty rect that
covers both positions. As long as sprites move a reasonable speeds,
this means the dirty rect is only a few pixels bigger than the
sprite. Just in case, you could calculate the area of the resulting
dirty rect, and if it's more than twice the area of the sprite's
bounding rect, keep the separate dirty rects instead.
In Project Spitfire/DOS (double buffered h/w scrolling with an extra
buffer for scheduled background rendering), I used a variant of the
"use only the older diry rects set" method. I didn't use dirty rects
at all, but rather kept a local tiled map for each buffer. This map
would first be filed with the index of an illegal (non-drawing)
background tile. When rendering sprites into the buffer, I would copy
tile indices from the level map into the buffer for each tile that
the sprite would overdraw. To remove the sprites, I just scanned the
"dirty map" and repainted any valid tiles found in it. Very simple
and low cost way of avoiding overdraw when removing sprites.
Of course, there's always the fool proof, totally portable, but not
too fast brute force approach: Always repaint the whole screen
whether you really need to or not.
If you're scrolling the whole screen, you normally need to do this
anyway. For something like a Break-Out clone or something more like a
normal application (buttons, sliders and stuff), it would be a huge
waste of resources, and it would multiply your minimum system
requirements by an insane factor for no real reason.
So, you need to be aware of both methods, and pick the one that makes
most sense for each application.
Hmm... I didn't realize there was this much to say about basic sprite
rendering. It's all obvious enough to me that I keep forgetting, I
guess. Maybe I should hack some basic "sprites on still background"
examples, and HTMLize the above to go with it? This is an FAQ entry,
by all means.
//David Olofson - Programmer, Composer, Open Source Advocate
.- The Return of Audiality! --------------------------------.
| Free/Open Source Audio Engine for use in Games or Studio. |
| RT and off-line synth. Scripting. Sample accurate timing. |
`-----------------------------------> http://audiality.org -'
--- http://olofson.net --- http://www.reologica.se ---
More information about the SDL
mailing list