[SDL] optimized drawing methodsI

Corona688 tsm at accesscomm.ca
Wed Jan 15 22:03:00 PST 2003

Chris Thielen wrote:

> I was wondering if anybody could explain this to me, I'm running under
> X11 and I don't know if Win32 would show much difference, but here goes:
> I've been trying to get my application to draw as fast as possible, as
> I'm a hobbyist programmer/learn-as-I-go and I've had to rewrite some
> pretty crappy code from the past, and I'm sure I'll rewrite it again.
> But I've been going through various methods of blitting and I was
> wondering if somebody could explain the results to me:
>         My original method consisted of a simple double buffer. I had a
> software surface the size of the window, I'd blit and scratch pixels
> there. It was divided into tiles, and if any pixel within a tile (they
> were about 30x25 or something like that) was drawn to, that pixel became
> dirty, and when all the drawing as done, my flip function would go
> through and flip all the tiles that were dirtied. gprof showed that
> function to be slow, so I tried speeding it up and to reduce blits I
> wrote some code to detect blocks of tiles and such. Okay, that's my
> original method, a simple double buffer. It took about 50% cpu during
> normal gameplay and 85% during heavy action.

Not suprising, if you were using SDL_Flip...  unless you've got actual hardware
double-buffering, it had to blit the ENTIRE surface to the screen ever time...
an 800*600*32bpp window, for example, would need 90MB/s throughput to update at
even 50FPS.  :)

>         My second method was taken from the programmer of LGames. I asked the
> maker of lbreakout2 how he got this application to draw, and so I took
> his advice and avoided SDL_Flip(). I simply drew directly to the window
> surface, writing code to wait for a lock for scratching and got all that
> done. I then had a large array of SDL_Rects which I kept track of all
> blits, and when it came time to flip, I used SDL_UpdateRects() and
> updated them all. This was a major performance increase. 20-30% cpu
> during gameplay and 45% during normal gameplay. All these benchmarks are
> under X11.

OK, that's a pretty good and normal method.  Might be able to do some merging of
rectangles and up the efficiency even more, too.  :)

>         I thought I'd try and be smart and combine both methods, so I could
> blit and scratch around in memory, arguably faster, right? The only
> different between this and my original method, is I'd use a large array
> of SDL_Rects() from my second method. So I blit/scartch to the
> backbuffer, remember the exact rects I did this in, then
> SDL_UpdateRects() on all those. This method proved to be slightly faster
> than my original, method, but no where near as fast as the second
> method. This method was about 20% slower in everything from my second
> method.
> Can anybody explain why the third method wasn't faster? I'm not entirely
> sure. I think maybe there's a huge slowdown in calling SDL_BlitSurface()
> a bazillion times, but shouldn't the original backbuffer method be the
> fastest anyway? Don't most games use a simple dobule buffer? Why is the
> second method, literally just blitting as I need to draw/erase and then
> calling SDL_UpdateRects() on a large array the fastest way to do it?
> Does anybody know why maybe the double buffer method wasn't the fastest?
> Thanks for your thought, I'm not sure why it wouldn't be the fastest.
> Thanks.

The theory of double-buffering, afaik, is you've got two backbuffers that get
swapped in their totality every screen update.  When done in hardware, this is
extremely fast - the video card simply changes which video surface it's
displaying - no blitting at all.  In software, however, it's excruciatingly
slow... it has to copy one of the backbuffers in it's entirety to the actual
buffer on every SDL_Flip() call.

Not exactly sure what SDL_UpdateRects() is doing on double-buffered surfaces,
you're supposed to use SDL_Flip() for that...  plain UpdateRects doesn't work at
all with hardware double-buffering;  you just keep writing stuff to your
backbuffer without the changes ever being displayed 'cause the surfaces don't get
swapped.  And if you do flip every frame, the buffer you're blitting to is two
frames out-of-date, not just one.
In short, double-buffering and traditional dirtyrects don't mix.

So:  The sequence of events with method #1:
   -Blit dirtied items to current backbuffer
   -Blit entire backbuffer to screen

Sequence of events with #2:
   -Blit dirtied items to backbuffer
   -Blit only changed rectangles to screen

Sequence of events with #3:
   -Blit dirtied items to current backbuffer
   -Copy stuff to screen somehow(suspect a total-screen blit, possibly several

More information about the SDL mailing list