Index: sdl.c =================================================================== RCS file: /cvsroot/qemu/qemu/sdl.c,v retrieving revision 1.15 diff -u -3 -p -r1.15 sdl.c --- sdl.c 5 Jul 2004 22:13:07 -0000 1.15 +++ sdl.c 10 Jul 2004 08:14:05 -0000 @@ -33,6 +33,8 @@ #define CONFIG_SDL_GENERIC_KBD #endif +#include + static SDL_Surface *screen; static int gui_grab; /* if true, all keyboard/mouse events are grabbed */ static int last_vm_running; @@ -41,10 +43,126 @@ static int gui_fullscreen; static int gui_key_modifier_pressed; static int gui_keysym; +/* Mechanism to reduce the total amount of data transmitted to the X + server, often quite dramatically. Keep a shadow copy of video + memory in alt_pixels, and when asked to update a rectangle, used + the shadow copy to establish areas which are the same, and so do + not need updating. +*/ + +static int* alt_pixels = NULL; + +#define THRESH 32 + +/* Return 1 if the area [x .. x+w-1, y .. y+w-1] is different from + the old version and so needs updating. */ +static int cmpArea ( int x, int y, unsigned int w, unsigned int h) +{ + int i, j; + unsigned int sll; + int* p1base = (int*)screen->pixels; + int* p2base = (int*)alt_pixels; + assert(screen->format->BytesPerPixel == 4); + sll = ((unsigned int)screen->pitch) >> 2; + + for (j = y; j < y+h; j++) { + for (i = x; i < x+w; i++) { + if (p1base [j * sll +i] != p2base [j * sll +i]) + return 1; + } + } + return 0; +} + +static void copyArea ( int x, int y, unsigned int w, unsigned int h) +{ + int i, j; + unsigned int sll; + int* p1base = (int*)screen->pixels; + int* p2base = (int*)alt_pixels; + assert(screen->format->BytesPerPixel == 4); + sll = ((unsigned int)screen->pitch) >> 2; + for (j = y; j < y+h; j++) { + for (i = x; i < x+w; i++) { + p2base [j * sll +i] = p1base [j * sll +i]; + } + } +} + + +static void econoUpdate (DisplayState *ds, int x, int y, + unsigned int w, unsigned int h) +{ + static int tested_total = 0; + static int update_total = 0; + + int xi, xj, xlim, yi, yj, ylim, ntest, nupd; + if (w == 0 || h == 0) + return; + xlim = x + w; + ylim = y + h; + + ntest = nupd = 0; + for (xi = x; xi < xlim; xi += THRESH) { + xj = xi + THRESH; + if (xj > xlim) xj = xlim; + for (yi = y; yi < ylim; yi += THRESH) { + yj = yi + THRESH; + if (yj > ylim) yj = ylim; + if (xj-xi == 0 || yj-yi == 0) + continue; + ntest++; + if (cmpArea(xi, yi, xj-xi, yj-yi)) { + nupd++; + copyArea(xi, yi, xj-xi, yj-yi); + SDL_UpdateRect(screen, xi, yi, xj-xi, yj-yi); + } + } + } + tested_total += ntest; + update_total += nupd; + printf("(tested, updated): total (%d, %d), this time (%d, %d)\n", + tested_total, update_total, ntest, nupd); +} + + static void sdl_update(DisplayState *ds, int x, int y, int w, int h) { - // printf("updating x=%d y=%d w=%d h=%d\n", x, y, w, h); - SDL_UpdateRect(screen, x, y, w, h); + int warned = 0; + //printf("updating x=%d y=%d w=%d h=%d\n", x, y, w, h); + // printf("Total Size %d %d\n", screen->w, screen->h); + //printf("BytesPerPixel %d\n", screen->format->BytesPerPixel); + //printf("pitch %d\n", screen->pitch); + + if (screen->format->BytesPerPixel != 4 + || screen->pitch != screen->w * screen->format->BytesPerPixel) { + if (!warned) { + warned = 1; + fprintf(stderr, "qemu: SDL update optimisation disabled\n" + " (wrong bits-per-pixel, or wrong pitch)\n"); + } + SDL_UpdateRect(screen, x, y, w, h); + return; + } + + assert(screen->pitch == screen->w * screen->format->BytesPerPixel); + assert(sizeof(int) == 4); + if (alt_pixels == NULL) { + /* First time through (at this resolution). + Copy entire screen. */ + int i, word32s = screen->w * screen->h; + //printf("copying init screen\n"); + alt_pixels = malloc(word32s * sizeof(int)); + assert(alt_pixels); + for (i = 0; i < word32s; i++) + alt_pixels[i] = ((int*)(screen->pixels))[i]; + SDL_UpdateRect(screen, x, y, w, h); + //printf("done\n"); + } else { + assert(w >= 0); + assert(h >= 0); + econoUpdate(ds, x, y, w, h); + } } static void sdl_resize(DisplayState *ds, int w, int h) @@ -53,6 +171,11 @@ static void sdl_resize(DisplayState *ds, // printf("resizing to %d %d\n", w, h); + if (alt_pixels) { + free(alt_pixels); + alt_pixels = NULL; + } + flags = SDL_HWSURFACE|SDL_ASYNCBLIT|SDL_HWACCEL; flags |= SDL_RESIZABLE; if (gui_fullscreen)