[uae] Re: SDL speedup

  • From: blynel@xxxxxxxxxx
  • To: uae@xxxxxxxxxxxxx
  • Date: Fri, 12 Nov 2004 23:10:05 +0100

Hi Rich

Quoting Richard Drummond <evilrich@xxxxxxxxxxxxxx>:
> Can you compare frame-rates on your system with and without this change?
>

Okay, I've done the tests playing one half of Kick Off 2:

With patch:
Average frame time: 19,579630 ms [frames: 19509 time: 381979]

Without patch:
Average frame time: 35,634270 ms [frames: 19066 time: 679403]

As you can see there is a significant slowdown which basically makes
the game unplayable. Kick Off 2 uses 8-way scrolling with a frame rate
of 20ms, which is why I figured flushing the whole screen could never
decrease performance (at not least in this special case). Seems like
there must be some redundant calls to flush_block()!

Here is what I get when turning debug on in 'flush_block' and
'flush_screen':

Function: flush_screen
Function: flush_block 32 32
Function: flush_block 34 34
Function: flush_block 36 36
Function: flush_block 38 38
...[snip]...
Function: flush_block 476 476
Function: flush_block 478 478
Function: flush_block 501 511
Function: flush_screen

Apparently every other line gets flushed and SDL_UpdateRect must have
an overhead, not present in the x11 implementation, which slows thing
down.

I should probadly note that I was using double resolution and
scanlines. When swiching to lowres (without scanlines) I get this
debug info:

Function: flush_screen
Function: flush_block 16 116
Function: flush_block 117 217
Function: flush_block 218 239
Function: flush_block 245 255
Function: flush_screen

Which look more like what should happen. And now the game runs fine of
course :)

Anyway, I've done a fix which merges adjacent blocks (and those
seperated by a scanline) in sucessive call to flush_block:

--- sdlgfx.c    2004-10-26 07:42:20.000000000 +0200
+++ sdlgfx.c.new        2004-11-12 20:35:56.504922840 +0100
@@ -131,22 +131,40 @@
     /* Not implemented for SDL output */
 }

+static int pending_flush = 0;
+static int ystart_p, ystop_p;
+
 void flush_block (int ystart, int ystop)
 {
     DEBUG_LOG ("Function: flush_block %d %d\n", ystart, ystop);

-    SDL_UnlockSurface (prSDLScreen);
-    SDL_UpdateRect (prSDLScreen, 0, ystart, current_width, ystop - ystart + 1);
-    SDL_LockSurface (prSDLScreen);
+    if (pending_flush) {
+        if (ystart <= ystop_p + 2) {
+           /* merge with pending flush */
+           ystop_p = ystop;
+        } else {
+           /* do previous pending flush and make this flush pending */
+           SDL_UpdateRect (prSDLScreen, 0, ystart_p, current_width, ystop_p -
ystart_p + 1);
+           ystart_p = ystart;
+           ystop_p = ystop;
+        }
+    } else {
+        /* make this flush pending */
+        ystart_p = ystart;
+        ystop_p = ystop;
+        pending_flush = 1;
+    }
 }

 void flush_screen (int ystart, int ystop)
 {
     DEBUG_LOG ("Function: flush_screen\n");

-#if 0
-    SDL_UpdateRect(prSDLScreen, 0, 0, current_width, current_height);
-#endif
+    if (prSDLScreen) {
+        SDL_Rect rect = { 0, 0, prSDLScreen->w, prSDLScreen->h };
+        SDL_FillRect (prSDLScreen, &rect, SDL_MapRGB (prSDLScreen->format,
0,0,0));
+        SDL_UpdateRect (prSDLScreen, 0, 0, rect.w, rect.h);
+    }
 }

 void flush_clear_screen (void)

Whih this change everything runs fine for me, and it shouldn't slow
down anything else.

This code should really go in 'drawing.c' but that one seems a bit
more difficult to mess with. Anyway I agree that the 100 line blocks
look a bit arbitrary. If something changes does it really flush a
whole 100 line block? Merging the blocks and only flushing what has
changed seem like a better scheme to me.

Corecting the scanline issue in stead of sidestepping it would be nice
as well :)

Cheers,

Jesper


Other related posts: