summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorH. Peter Anvin <hpa@zytor.com>2012-03-10 02:40:34 (GMT)
committerH. Peter Anvin <hpa@zytor.com>2012-03-10 02:40:34 (GMT)
commit2ff9ba56832017ddc4227cece65fa0f83ccc7064 (patch)
treee505ef5f006e4171588de05592cb4bbbf47feb59
parentb444e1737742e091339f1a7b083adc9fa4e06c08 (diff)
downloadgrv-2ff9ba56832017ddc4227cece65fa0f83ccc7064.zip
grv-2ff9ba56832017ddc4227cece65fa0f83ccc7064.tar.gz
grv-2ff9ba56832017ddc4227cece65fa0f83ccc7064.tar.bz2
grv-2ff9ba56832017ddc4227cece65fa0f83ccc7064.tar.xz
Aggregate screen updates
Aggregate screen updates to one per cycle, using SDL_UpdateRects(). Hopefully this should avoid the sluggishness on MacOS X, but that remain to be seen...
-rw-r--r--graphics.c131
-rw-r--r--graphics.h1
-rw-r--r--keyboard.c3
-rw-r--r--play.c2
-rw-r--r--utils.c3
5 files changed, 95 insertions, 45 deletions
diff --git a/graphics.c b/graphics.c
index 161007e..b42632a 100644
--- a/graphics.c
+++ b/graphics.c
@@ -58,6 +58,7 @@ struct screen_char {
};
static struct screen_char screendata[TS_HEIGHT][TS_WIDTH];
+static uint8_t screendirty[TS_HEIGHT][TS_WIDTH];
static struct current_screen {
int x;
@@ -106,15 +107,79 @@ int screen1(int r, int c)
/*
* Prepare screen for modification
*/
+static int screen_lock_ctr = 0;
+
static void lock_screen(void)
{
- SDL_LockSurface(rscreen);
+ if (!screen_lock_ctr++)
+ SDL_LockSurface(rscreen);
+}
+
+static void unlock_screen(void)
+{
+ if (!--screen_lock_ctr)
+ SDL_UnlockSurface(rscreen);
+}
+
+/*
+ * Update all locations on the screen that has been modified.
+ * This must be called with the screen unlocked.
+ */
+void update_screen(void)
+{
+ /*
+ * Maximum number of rectangles possible; if we have more than this
+ * number, then rectangles will be mergable horizontally at a minimum.
+ */
+ struct SDL_Rect rects[TS_WIDTH*TS_HEIGHT/2];
+ SDL_Rect *r = rects;
+ int x, x0, y, y0;
+ int n = 0;
+
+ for (y = 0; y < TS_HEIGHT; y++) {
+ for (x = 0; x < TS_WIDTH; x++) {
+ if (screendirty[y][x]) {
+ x0 = x; y0 = y;
+
+ /* Extend the rectangle horizontally */
+ while (x < TS_WIDTH && screendirty[y][x]) {
+ screendirty[y][x] = 0;
+ x++;
+ }
+
+ /* See if we can expand this rectangle vertically */
+ while (++y < TS_HEIGHT) {
+ int x1;
+ for (x1 = x0; x1 < x; x1++)
+ if (!screendirty[y][x1])
+ goto done;
+
+ /* It worked... */
+ for (x1 = x0; x1 < x; x1++)
+ screendirty[y][x1] = 0;
+ }
+ done:
+ r->x = x0 * FONT_XSIZE;
+ r->y = y0 * FONT_YSIZE;
+ r->w = (x - x0) * FONT_XSIZE;
+ r->h = (y - y0) * FONT_YSIZE;
+ r++;
+ n++;
+
+ y = y0;
+ x--;
+ }
+ }
+ }
+
+ if ( n )
+ SDL_UpdateRects(rscreen, n, rects);
}
/*
* Update the on-screen structure to match the screendata[]
* for character (tx,ty), but don't refresh the rectangle just
- * yet...
+ * yet. This should be called with the screen locked.
*
* tx,ty is zero-based and must be adjusted for doublewidth mode
*/
@@ -152,6 +217,9 @@ static void put_screen(int tx, int ty)
}
pixelr = (uint32_t *)((char *)pixelr + rscreen->pitch);
}
+
+ screendirty[ty][tx] = 1;
+ screendirty[ty][tx+pxwid-1] = 1;
}
/*
@@ -161,52 +229,20 @@ static void put_screen(int tx, int ty)
void update_blink(void)
{
int x, y, xs;
- int gx, gy, gw, gh;
- SDL_Rect rects[TS_WIDTH*TS_HEIGHT]; /* Absolute maximum needed */
- SDL_Rect *rect = rects-1;
- int nrects = 0;
-
- blink_mask ^= 0x80;
xs = current.dwidth+1;
- SDL_LockSurface(rscreen);
+ blink_mask ^= 0x80;
- gw = FONT_XSIZE << current.dwidth;
- gh = FONT_YSIZE;
+ lock_screen();
- for ( y = 0, gy = 0 ; y < TS_HEIGHT ; y++, gy += gh ) {
- for ( x = 0, gx = 0 ; x < TS_WIDTH ; x += xs, gx += gw ) {
- if ( screendata[y][x].attr & 0x80 ) {
+ for ( y = 0 ; y < TS_HEIGHT ; y++ )
+ for ( x = 0 ; x < TS_WIDTH ; x += xs )
+ if ( screendata[y][x].attr & 0x80 )
put_screen(x,y);
- if ( !nrects || rect->y != gy || rect->x+rect->w != gx ) {
- nrects++;
- rect++;
- rect->x = gx; rect->y = gy;
- rect->w = gw; rect->h = gh;
- } else {
- rect->w += gw;
- }
- }
- }
- }
-
- SDL_UnlockSurface(rscreen);
- if ( nrects )
- SDL_UpdateRects(rscreen, nrects, rects);
-}
-
-/*
- * Refresh rectangle and unlock screen
- * Coordinates are inclusive and must be adjusted for double-pixel mode
- */
-static void update_screen(int x0, int y0, int x1, int y1)
-{
- SDL_UnlockSurface(rscreen);
-
- SDL_UpdateRect(rscreen, x0*FONT_XSIZE, y0*FONT_YSIZE,
- (x1-x0+1)*FONT_XSIZE, (y1-y0+1)*FONT_YSIZE);
+ unlock_screen();
+ update_screen();
}
/*
@@ -244,7 +280,8 @@ void print(const char *str)
}
}
}
- update_screen(x0,y0,x1,y1);
+
+ unlock_screen();
current.x = x; current.y = y;
}
@@ -309,7 +346,7 @@ void width(int wid)
/*
* Clear the screen, set all characters to ' ' and set all pixels to the
- * current background
+ * current background, then refresh the screen content.
*/
void cls(void)
{
@@ -335,7 +372,10 @@ void cls(void)
SDL_FillRect(rscreen, &rect, pixelval);
- update_screen(0, 0, TS_WIDTH-1, TS_HEIGHT-1);
+ unlock_screen();
+
+ SDL_UpdateRects(rscreen, 1, &rect);
+ memset(screendirty, 0, sizeof screendirty);
current.x = current.y = 0;
}
@@ -380,7 +420,8 @@ void restore_screen(struct saved_screen *save)
}
}
- update_screen(0, 0, TS_WIDTH-1, TS_HEIGHT-1);
+ unlock_screen();
+ update_screen();
}
/*
diff --git a/graphics.h b/graphics.h
index f993186..16c7f5a 100644
--- a/graphics.h
+++ b/graphics.h
@@ -24,6 +24,7 @@ void lprintf(int r, int c, const char *fmt, ...);
void width(int wid);
void cls(void);
void update_blink(void);
+void update_screen(void);
struct saved_screen;
struct saved_screen *save_screen(void);
diff --git a/keyboard.c b/keyboard.c
index bcb905b..5d586c8 100644
--- a/keyboard.c
+++ b/keyboard.c
@@ -70,11 +70,14 @@ SDL_KeyboardEvent *get_key(void)
if ( (ke = poll_key()) )
return ke;
+ update_screen();
+
while ( SDL_WaitEvent(&event) ) {
if ( event.type == SDL_KEYDOWN )
return &event.key;
else if ( event.type == SDL_USEREVENT && event.user.code == event_blink )
update_blink();
}
+
return NULL;
}
diff --git a/play.c b/play.c
index 93fc725..59091b6 100644
--- a/play.c
+++ b/play.c
@@ -808,6 +808,8 @@ void play(void)
gp.Tid = 0.0;
while ( gp.Status == Status_Live ) {
+ update_screen();
+
/* Wait for an event */
while ( SDL_WaitEvent(&event) ) {
if ( event.type == SDL_USEREVENT ) {
diff --git a/utils.c b/utils.c
index b4fe150..4b3b94b 100644
--- a/utils.c
+++ b/utils.c
@@ -4,6 +4,7 @@
* Utility functions
*/
+#include "graphics.h"
#include "grv.h"
/* Foreground color of a specific character */
@@ -72,6 +73,8 @@ void mymssleep(int ms)
SDL_TimerID mytimer = SDL_AddTimer(ms, post_oneshot, (void *)event_sleep);
SDL_Event event;
+ update_screen();
+
while ( SDL_WaitEvent(&event) ) {
if ( event.type == SDL_USEREVENT ) {
if ( event.user.code == event_sleep ) {