Commit 7b5d76dae31881d3cdb6f748ad4e84ddd7b66f3e

Authored by aliguori
1 parent 86dbdd40

DisplayAllocator interface (Stefano Stabellini)

Hi all,
this patch adds a DisplayAllocator interface that allows display
frontends (sdl in particular) to provide a preallocated display buffer
for the graphical backend to use.

Whenever a graphical backend cannot use
qemu_create_displaysurface_from because its own internal pixel format
cannot be exported directly (text mode or graphical mode with color
depth 8 or 24), it creates another display buffer in memory using
qemu_create_displaysurface and does the conversion.
This new buffer needs to be blitted into the sdl surface buffer every time
we need to update portions of the screen.
We can avoid this using the DisplayAllocator interace: sdl provides its
own implementation of qemu_create_displaysurface, giving back the sdl
surface buffer directly (as we used to do before the DisplayState
changes).
Since the buffer returned by sdl could be in bgr format we need to put
back in the handlers of that case.

This approach is good if the two following conditions are true:

1) the sdl surface is a software surface that resides in main memory;

2) the host display color depth is either 16 or 32 bpp.

If first condition is false we can have bad performances using sdl
and vnc together.
If the second condition is false performances are certainly not going to
improve but they shouldn't get worse either.

The first condition is always true, at least on linux/X11 systems; but I
believe is true also on other platforms.
The second condition is true in the vast majority of the cases.

This patch should also have the good side effect of solving the sdl
2D slowness malc was reporting on MacOS, because SDL_BlitSurface is not
going to be called anymore when the guest is in text mode or 24bpp.
However the root problem is still present so I suspect we may
still see some slowness on MacOS when the guest is in 32 or 16 bpp.

Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>


git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@6839 c046a42c-6fe2-441c-8c8c-71466251a162
console.c
@@ -1068,8 +1068,7 @@ void console_select(unsigned int index) @@ -1068,8 +1068,7 @@ void console_select(unsigned int index)
1068 DisplayState *ds = s->ds; 1068 DisplayState *ds = s->ds;
1069 active_console = s; 1069 active_console = s;
1070 if (ds_get_bits_per_pixel(s->ds)) { 1070 if (ds_get_bits_per_pixel(s->ds)) {
1071 - ds->surface = qemu_resize_displaysurface(ds->surface, s->g_width,  
1072 - s->g_height, 32, 4 * s->g_width); 1071 + ds->surface = qemu_resize_displaysurface(ds, s->g_width, s->g_height);
1073 } else { 1072 } else {
1074 s->ds->surface->width = s->width; 1073 s->ds->surface->width = s->width;
1075 s->ds->surface->height = s->height; 1074 s->ds->surface->height = s->height;
@@ -1277,11 +1276,12 @@ DisplayState *graphic_console_init(vga_hw_update_ptr update, @@ -1277,11 +1276,12 @@ DisplayState *graphic_console_init(vga_hw_update_ptr update,
1277 DisplayState *ds; 1276 DisplayState *ds;
1278 1277
1279 ds = (DisplayState *) qemu_mallocz(sizeof(DisplayState)); 1278 ds = (DisplayState *) qemu_mallocz(sizeof(DisplayState));
1280 - ds->surface = qemu_create_displaysurface(640, 480, 32, 640 * 4); 1279 + ds->allocator = &default_allocator;
  1280 + ds->surface = qemu_create_displaysurface(ds, 640, 480);
1281 1281
1282 s = new_console(ds, GRAPHIC_CONSOLE); 1282 s = new_console(ds, GRAPHIC_CONSOLE);
1283 if (s == NULL) { 1283 if (s == NULL) {
1284 - qemu_free_displaysurface(ds->surface); 1284 + qemu_free_displaysurface(ds);
1285 qemu_free(ds); 1285 qemu_free(ds);
1286 return NULL; 1286 return NULL;
1287 } 1287 }
@@ -1429,7 +1429,7 @@ void qemu_console_resize(DisplayState *ds, int width, int height) @@ -1429,7 +1429,7 @@ void qemu_console_resize(DisplayState *ds, int width, int height)
1429 s->g_width = width; 1429 s->g_width = width;
1430 s->g_height = height; 1430 s->g_height = height;
1431 if (is_graphic_console()) { 1431 if (is_graphic_console()) {
1432 - ds->surface = qemu_resize_displaysurface(ds->surface, width, height, 32, 4 * width); 1432 + ds->surface = qemu_resize_displaysurface(ds, width, height);
1433 dpy_resize(ds); 1433 dpy_resize(ds);
1434 } 1434 }
1435 } 1435 }
@@ -1552,14 +1552,14 @@ PixelFormat qemu_default_pixelformat(int bpp) @@ -1552,14 +1552,14 @@ PixelFormat qemu_default_pixelformat(int bpp)
1552 return pf; 1552 return pf;
1553 } 1553 }
1554 1554
1555 -DisplaySurface* qemu_create_displaysurface(int width, int height, int bpp, int linesize) 1555 +DisplaySurface* defaultallocator_create_displaysurface(int width, int height)
1556 { 1556 {
1557 DisplaySurface *surface = (DisplaySurface*) qemu_mallocz(sizeof(DisplaySurface)); 1557 DisplaySurface *surface = (DisplaySurface*) qemu_mallocz(sizeof(DisplaySurface));
1558 1558
1559 surface->width = width; 1559 surface->width = width;
1560 surface->height = height; 1560 surface->height = height;
1561 - surface->linesize = linesize;  
1562 - surface->pf = qemu_default_pixelformat(bpp); 1561 + surface->linesize = width * 4;
  1562 + surface->pf = qemu_default_pixelformat(32);
1563 #ifdef WORDS_BIGENDIAN 1563 #ifdef WORDS_BIGENDIAN
1564 surface->flags = QEMU_ALLOCATED_FLAG | QEMU_BIG_ENDIAN_FLAG; 1564 surface->flags = QEMU_ALLOCATED_FLAG | QEMU_BIG_ENDIAN_FLAG;
1565 #else 1565 #else
@@ -1570,13 +1570,13 @@ DisplaySurface* qemu_create_displaysurface(int width, int height, int bpp, int l @@ -1570,13 +1570,13 @@ DisplaySurface* qemu_create_displaysurface(int width, int height, int bpp, int l
1570 return surface; 1570 return surface;
1571 } 1571 }
1572 1572
1573 -DisplaySurface* qemu_resize_displaysurface(DisplaySurface *surface,  
1574 - int width, int height, int bpp, int linesize) 1573 +DisplaySurface* defaultallocator_resize_displaysurface(DisplaySurface *surface,
  1574 + int width, int height)
1575 { 1575 {
1576 surface->width = width; 1576 surface->width = width;
1577 surface->height = height; 1577 surface->height = height;
1578 - surface->linesize = linesize;  
1579 - surface->pf = qemu_default_pixelformat(bpp); 1578 + surface->linesize = width * 4;
  1579 + surface->pf = qemu_default_pixelformat(32);
1580 if (surface->flags & QEMU_ALLOCATED_FLAG) 1580 if (surface->flags & QEMU_ALLOCATED_FLAG)
1581 surface->data = (uint8_t*) qemu_realloc(surface->data, surface->linesize * surface->height); 1581 surface->data = (uint8_t*) qemu_realloc(surface->data, surface->linesize * surface->height);
1582 else 1582 else
@@ -1607,7 +1607,7 @@ DisplaySurface* qemu_create_displaysurface_from(int width, int height, int bpp, @@ -1607,7 +1607,7 @@ DisplaySurface* qemu_create_displaysurface_from(int width, int height, int bpp,
1607 return surface; 1607 return surface;
1608 } 1608 }
1609 1609
1610 -void qemu_free_displaysurface(DisplaySurface *surface) 1610 +void defaultallocator_free_displaysurface(DisplaySurface *surface)
1611 { 1611 {
1612 if (surface == NULL) 1612 if (surface == NULL)
1613 return; 1613 return;
console.h
@@ -113,11 +113,18 @@ struct DisplayChangeListener { @@ -113,11 +113,18 @@ struct DisplayChangeListener {
113 struct DisplayChangeListener *next; 113 struct DisplayChangeListener *next;
114 }; 114 };
115 115
  116 +struct DisplayAllocator {
  117 + DisplaySurface* (*create_displaysurface)(int width, int height);
  118 + DisplaySurface* (*resize_displaysurface)(DisplaySurface *surface, int width, int height);
  119 + void (*free_displaysurface)(DisplaySurface *surface);
  120 +};
  121 +
116 struct DisplayState { 122 struct DisplayState {
117 struct DisplaySurface *surface; 123 struct DisplaySurface *surface;
118 void *opaque; 124 void *opaque;
119 struct QEMUTimer *gui_timer; 125 struct QEMUTimer *gui_timer;
120 126
  127 + struct DisplayAllocator* allocator;
121 struct DisplayChangeListener* listeners; 128 struct DisplayChangeListener* listeners;
122 129
123 void (*mouse_set)(int x, int y, int on); 130 void (*mouse_set)(int x, int y, int on);
@@ -129,15 +136,40 @@ struct DisplayState { @@ -129,15 +136,40 @@ struct DisplayState {
129 136
130 void register_displaystate(DisplayState *ds); 137 void register_displaystate(DisplayState *ds);
131 DisplayState *get_displaystate(void); 138 DisplayState *get_displaystate(void);
132 -DisplaySurface* qemu_create_displaysurface(int width, int height, int bpp, int linesize);  
133 -DisplaySurface* qemu_resize_displaysurface(DisplaySurface *surface,  
134 - int width, int height, int bpp, int linesize);  
135 DisplaySurface* qemu_create_displaysurface_from(int width, int height, int bpp, 139 DisplaySurface* qemu_create_displaysurface_from(int width, int height, int bpp,
136 int linesize, uint8_t *data); 140 int linesize, uint8_t *data);
137 -void qemu_free_displaysurface(DisplaySurface *surface);  
138 PixelFormat qemu_different_endianness_pixelformat(int bpp); 141 PixelFormat qemu_different_endianness_pixelformat(int bpp);
139 PixelFormat qemu_default_pixelformat(int bpp); 142 PixelFormat qemu_default_pixelformat(int bpp);
140 143
  144 +extern struct DisplayAllocator default_allocator;
  145 +DisplayAllocator *register_displayallocator(DisplayState *ds, DisplayAllocator *da);
  146 +DisplaySurface* defaultallocator_create_displaysurface(int width, int height);
  147 +DisplaySurface* defaultallocator_resize_displaysurface(DisplaySurface *surface, int width, int height);
  148 +void defaultallocator_free_displaysurface(DisplaySurface *surface);
  149 +
  150 +static inline DisplaySurface* qemu_create_displaysurface(DisplayState *ds, int width, int height)
  151 +{
  152 + return ds->allocator->create_displaysurface(width, height);
  153 +}
  154 +
  155 +static inline DisplaySurface* qemu_resize_displaysurface(DisplayState *ds, int width, int height)
  156 +{
  157 + return ds->allocator->resize_displaysurface(ds->surface, width, height);
  158 +}
  159 +
  160 +static inline void qemu_free_displaysurface(DisplayState *ds)
  161 +{
  162 + ds->allocator->free_displaysurface(ds->surface);
  163 +}
  164 +
  165 +static inline int is_surface_bgr(DisplaySurface *surface)
  166 +{
  167 + if (surface->pf.bits_per_pixel == 32 && surface->pf.rshift == 0)
  168 + return 1;
  169 + else
  170 + return 0;
  171 +}
  172 +
141 static inline int is_buffer_shared(DisplaySurface *surface) 173 static inline int is_buffer_shared(DisplaySurface *surface)
142 { 174 {
143 return (!(surface->flags & QEMU_ALLOCATED_FLAG)); 175 return (!(surface->flags & QEMU_ALLOCATED_FLAG));
curses.c
@@ -364,7 +364,7 @@ void curses_display_init(DisplayState *ds, int full_screen) @@ -364,7 +364,7 @@ void curses_display_init(DisplayState *ds, int full_screen)
364 dcl->dpy_refresh = curses_refresh; 364 dcl->dpy_refresh = curses_refresh;
365 dcl->dpy_text_cursor = curses_cursor_position; 365 dcl->dpy_text_cursor = curses_cursor_position;
366 register_displaychangelistener(ds, dcl); 366 register_displaychangelistener(ds, dcl);
367 - qemu_free_displaysurface(ds->surface); 367 + qemu_free_displaysurface(ds);
368 ds->surface = qemu_create_displaysurface_from(640, 400, 0, 0, (uint8_t*) screen); 368 ds->surface = qemu_create_displaysurface_from(640, 400, 0, 0, (uint8_t*) screen);
369 369
370 invalidate = 1; 370 invalidate = 1;
hw/musicpal.c
@@ -831,7 +831,7 @@ static void lcd_refresh(void *opaque) @@ -831,7 +831,7 @@ static void lcd_refresh(void *opaque)
831 break; 831 break;
832 LCD_REFRESH(8, rgb_to_pixel8) 832 LCD_REFRESH(8, rgb_to_pixel8)
833 LCD_REFRESH(16, rgb_to_pixel16) 833 LCD_REFRESH(16, rgb_to_pixel16)
834 - LCD_REFRESH(32, rgb_to_pixel32) 834 + LCD_REFRESH(32, (is_surface_bgr(s->ds) ? rgb_to_pixel32bgr : rgb_to_pixel32))
835 default: 835 default:
836 cpu_abort(cpu_single_env, "unsupported colour depth %i\n", 836 cpu_abort(cpu_single_env, "unsupported colour depth %i\n",
837 ds_get_bits_per_pixel(s->ds)); 837 ds_get_bits_per_pixel(s->ds));
hw/nseries.c
@@ -1362,7 +1362,7 @@ static void n8x0_init(ram_addr_t ram_size, const char *boot_device, @@ -1362,7 +1362,7 @@ static void n8x0_init(ram_addr_t ram_size, const char *boot_device,
1362 will set the size once configured, so this just sets an initial 1362 will set the size once configured, so this just sets an initial
1363 size until the guest activates the display. */ 1363 size until the guest activates the display. */
1364 ds = get_displaystate(); 1364 ds = get_displaystate();
1365 - ds->surface = qemu_resize_displaysurface(ds->surface, 800, 480, 32, 4 * 800); 1365 + ds->surface = qemu_resize_displaysurface(ds, 800, 480);
1366 dpy_resize(ds); 1366 dpy_resize(ds);
1367 } 1367 }
1368 1368
hw/palm.c
@@ -278,7 +278,7 @@ static void palmte_init(ram_addr_t ram_size, int vga_ram_size, @@ -278,7 +278,7 @@ static void palmte_init(ram_addr_t ram_size, int vga_ram_size,
278 /* FIXME: We shouldn't really be doing this here. The LCD controller 278 /* FIXME: We shouldn't really be doing this here. The LCD controller
279 will set the size once configured, so this just sets an initial 279 will set the size once configured, so this just sets an initial
280 size until the guest activates the display. */ 280 size until the guest activates the display. */
281 - ds->surface = qemu_resize_displaysurface(ds->surface, 320, 320, 32, 4 * 320); 281 + ds->surface = qemu_resize_displaysurface(ds, 320, 320);
282 dpy_resize(ds); 282 dpy_resize(ds);
283 } 283 }
284 284
hw/sm501.c
@@ -948,7 +948,10 @@ static inline int get_depth_index(DisplayState *s) @@ -948,7 +948,10 @@ static inline int get_depth_index(DisplayState *s)
948 case 16: 948 case 16:
949 return 2; 949 return 2;
950 case 32: 950 case 32:
951 - return 3; 951 + if (is_surface_bgr(s->surface))
  952 + return 4;
  953 + else
  954 + return 3;
952 } 955 }
953 } 956 }
954 957
hw/tcx.c
@@ -66,7 +66,10 @@ static void update_palette_entries(TCXState *s, int start, int end) @@ -66,7 +66,10 @@ static void update_palette_entries(TCXState *s, int start, int end)
66 s->palette[i] = rgb_to_pixel16(s->r[i], s->g[i], s->b[i]); 66 s->palette[i] = rgb_to_pixel16(s->r[i], s->g[i], s->b[i]);
67 break; 67 break;
68 case 32: 68 case 32:
69 - s->palette[i] = rgb_to_pixel32(s->r[i], s->g[i], s->b[i]); 69 + if (is_surface_bgr(s->ds->surface))
  70 + s->palette[i] = rgb_to_pixel32bgr(s->r[i], s->g[i], s->b[i]);
  71 + else
  72 + s->palette[i] = rgb_to_pixel32(s->r[i], s->g[i], s->b[i]);
70 break; 73 break;
71 } 74 }
72 } 75 }
@@ -124,11 +127,12 @@ static inline void tcx24_draw_line32(TCXState *s1, uint8_t *d, @@ -124,11 +127,12 @@ static inline void tcx24_draw_line32(TCXState *s1, uint8_t *d,
124 const uint32_t *cplane, 127 const uint32_t *cplane,
125 const uint32_t *s24) 128 const uint32_t *s24)
126 { 129 {
127 - int x, r, g, b; 130 + int x, bgr, r, g, b;
128 uint8_t val, *p8; 131 uint8_t val, *p8;
129 uint32_t *p = (uint32_t *)d; 132 uint32_t *p = (uint32_t *)d;
130 uint32_t dval; 133 uint32_t dval;
131 134
  135 + bgr = is_surface_bgr(s1->ds->surface);
132 for(x = 0; x < width; x++, s++, s24++) { 136 for(x = 0; x < width; x++, s++, s24++) {
133 if ((be32_to_cpu(*cplane++) & 0xff000000) == 0x03000000) { 137 if ((be32_to_cpu(*cplane++) & 0xff000000) == 0x03000000) {
134 // 24-bit direct, BGR order 138 // 24-bit direct, BGR order
@@ -137,7 +141,10 @@ static inline void tcx24_draw_line32(TCXState *s1, uint8_t *d, @@ -137,7 +141,10 @@ static inline void tcx24_draw_line32(TCXState *s1, uint8_t *d,
137 b = *p8++; 141 b = *p8++;
138 g = *p8++; 142 g = *p8++;
139 r = *p8++; 143 r = *p8++;
140 - dval = rgb_to_pixel32(r, g, b); 144 + if (bgr)
  145 + dval = rgb_to_pixel32bgr(r, g, b);
  146 + else
  147 + dval = rgb_to_pixel32(r, g, b);
141 } else { 148 } else {
142 val = *s; 149 val = *s;
143 dval = s1->palette[val]; 150 dval = s1->palette[val];
hw/vga.c
@@ -1161,7 +1161,10 @@ static inline int get_depth_index(DisplayState *s) @@ -1161,7 +1161,10 @@ static inline int get_depth_index(DisplayState *s)
1161 case 16: 1161 case 16:
1162 return 2; 1162 return 2;
1163 case 32: 1163 case 32:
1164 - return 3; 1164 + if (is_surface_bgr(s->surface))
  1165 + return 4;
  1166 + else
  1167 + return 3;
1165 } 1168 }
1166 } 1169 }
1167 1170
@@ -1627,7 +1630,7 @@ static void vga_draw_graphic(VGAState *s, int full_update) @@ -1627,7 +1630,7 @@ static void vga_draw_graphic(VGAState *s, int full_update)
1627 if (depth == 32) { 1630 if (depth == 32) {
1628 #endif 1631 #endif
1629 if (is_graphic_console()) { 1632 if (is_graphic_console()) {
1630 - qemu_free_displaysurface(s->ds->surface); 1633 + qemu_free_displaysurface(s->ds);
1631 s->ds->surface = qemu_create_displaysurface_from(disp_width, height, depth, 1634 s->ds->surface = qemu_create_displaysurface_from(disp_width, height, depth,
1632 s->line_offset, 1635 s->line_offset,
1633 s->vram_ptr + (s->start_addr * 4)); 1636 s->vram_ptr + (s->start_addr * 4));
@@ -2619,7 +2622,7 @@ static void vga_screen_dump_common(VGAState *s, const char *filename, @@ -2619,7 +2622,7 @@ static void vga_screen_dump_common(VGAState *s, const char *filename,
2619 dcl.dpy_resize = vga_save_dpy_resize; 2622 dcl.dpy_resize = vga_save_dpy_resize;
2620 dcl.dpy_refresh = vga_save_dpy_refresh; 2623 dcl.dpy_refresh = vga_save_dpy_refresh;
2621 register_displaychangelistener(ds, &dcl); 2624 register_displaychangelistener(ds, &dcl);
2622 - ds->surface = qemu_create_displaysurface(w, h, 32, 4 * w); 2625 + ds->surface = qemu_create_displaysurface(ds, w, h);
2623 2626
2624 s->ds = ds; 2627 s->ds = ds;
2625 s->graphic_mode = -1; 2628 s->graphic_mode = -1;
@@ -2627,7 +2630,7 @@ static void vga_screen_dump_common(VGAState *s, const char *filename, @@ -2627,7 +2630,7 @@ static void vga_screen_dump_common(VGAState *s, const char *filename,
2627 2630
2628 ppm_save(filename, ds->surface); 2631 ppm_save(filename, ds->surface);
2629 2632
2630 - qemu_free_displaysurface(ds->surface); 2633 + qemu_free_displaysurface(ds);
2631 s->ds = saved_ds; 2634 s->ds = saved_ds;
2632 } 2635 }
2633 2636
qemu-common.h
@@ -162,6 +162,7 @@ typedef struct BlockDriverState BlockDriverState; @@ -162,6 +162,7 @@ typedef struct BlockDriverState BlockDriverState;
162 typedef struct DisplayState DisplayState; 162 typedef struct DisplayState DisplayState;
163 typedef struct DisplayChangeListener DisplayChangeListener; 163 typedef struct DisplayChangeListener DisplayChangeListener;
164 typedef struct DisplaySurface DisplaySurface; 164 typedef struct DisplaySurface DisplaySurface;
  165 +typedef struct DisplayAllocator DisplayAllocator;
165 typedef struct PixelFormat PixelFormat; 166 typedef struct PixelFormat PixelFormat;
166 typedef struct TextConsole TextConsole; 167 typedef struct TextConsole TextConsole;
167 typedef TextConsole QEMUConsole; 168 typedef TextConsole QEMUConsole;
@@ -53,17 +53,20 @@ static int absolute_enabled = 0; @@ -53,17 +53,20 @@ static int absolute_enabled = 0;
53 static int guest_cursor = 0; 53 static int guest_cursor = 0;
54 static int guest_x, guest_y; 54 static int guest_x, guest_y;
55 static SDL_Cursor *guest_sprite = 0; 55 static SDL_Cursor *guest_sprite = 0;
  56 +static uint8_t allocator;
  57 +static uint8_t hostbpp;
56 58
57 static void sdl_update(DisplayState *ds, int x, int y, int w, int h) 59 static void sdl_update(DisplayState *ds, int x, int y, int w, int h)
58 { 60 {
59 - SDL_Rect rec;  
60 - rec.x = x;  
61 - rec.y = y;  
62 - rec.w = w;  
63 - rec.h = h;  
64 // printf("updating x=%d y=%d w=%d h=%d\n", x, y, w, h); 61 // printf("updating x=%d y=%d w=%d h=%d\n", x, y, w, h);
65 -  
66 - SDL_BlitSurface(guest_screen, &rec, real_screen, &rec); 62 + if (guest_screen) {
  63 + SDL_Rect rec;
  64 + rec.x = x;
  65 + rec.y = y;
  66 + rec.w = w;
  67 + rec.h = h;
  68 + SDL_BlitSurface(guest_screen, &rec, real_screen, &rec);
  69 + }
67 SDL_UpdateRect(real_screen, x, y, w, h); 70 SDL_UpdateRect(real_screen, x, y, w, h);
68 } 71 }
69 72
@@ -83,7 +86,7 @@ static void sdl_setdata(DisplayState *ds) @@ -83,7 +86,7 @@ static void sdl_setdata(DisplayState *ds)
83 ds->surface->pf.bmask, ds->surface->pf.amask); 86 ds->surface->pf.bmask, ds->surface->pf.amask);
84 } 87 }
85 88
86 -static void sdl_resize(DisplayState *ds) 89 +static void do_sdl_resize(int width, int height, int bpp)
87 { 90 {
88 int flags; 91 int flags;
89 92
@@ -95,15 +98,101 @@ static void sdl_resize(DisplayState *ds) @@ -95,15 +98,101 @@ static void sdl_resize(DisplayState *ds)
95 if (gui_noframe) 98 if (gui_noframe)
96 flags |= SDL_NOFRAME; 99 flags |= SDL_NOFRAME;
97 100
98 - width = ds_get_width(ds);  
99 - height = ds_get_height(ds);  
100 - real_screen = SDL_SetVideoMode(width, height, 0, flags); 101 + real_screen = SDL_SetVideoMode(width, height, bpp, flags);
101 if (!real_screen) { 102 if (!real_screen) {
102 fprintf(stderr, "Could not open SDL display\n"); 103 fprintf(stderr, "Could not open SDL display\n");
103 exit(1); 104 exit(1);
104 } 105 }
  106 +}
  107 +
  108 +static void sdl_resize(DisplayState *ds)
  109 +{
  110 + if (!allocator) {
  111 + do_sdl_resize(ds_get_width(ds), ds_get_height(ds), 0);
  112 + sdl_setdata(ds);
  113 + } else {
  114 + if (guest_screen != NULL) {
  115 + SDL_FreeSurface(guest_screen);
  116 + guest_screen = NULL;
  117 + }
  118 + }
  119 +}
  120 +
  121 +static PixelFormat sdl_to_qemu_pixelformat(SDL_PixelFormat *sdl_pf)
  122 +{
  123 + PixelFormat qemu_pf;
  124 +
  125 + memset(&qemu_pf, 0x00, sizeof(PixelFormat));
  126 +
  127 + qemu_pf.bits_per_pixel = sdl_pf->BitsPerPixel;
  128 + qemu_pf.bytes_per_pixel = sdl_pf->BytesPerPixel;
  129 + qemu_pf.depth = (qemu_pf.bits_per_pixel) == 32 ? 24 : (qemu_pf.bits_per_pixel);
  130 +
  131 + qemu_pf.rmask = sdl_pf->Rmask;
  132 + qemu_pf.gmask = sdl_pf->Gmask;
  133 + qemu_pf.bmask = sdl_pf->Bmask;
  134 + qemu_pf.amask = sdl_pf->Amask;
  135 +
  136 + qemu_pf.rshift = sdl_pf->Rshift;
  137 + qemu_pf.gshift = sdl_pf->Gshift;
  138 + qemu_pf.bshift = sdl_pf->Bshift;
  139 + qemu_pf.ashift = sdl_pf->Ashift;
  140 +
  141 + qemu_pf.rbits = 8 - sdl_pf->Rloss;
  142 + qemu_pf.gbits = 8 - sdl_pf->Gloss;
  143 + qemu_pf.bbits = 8 - sdl_pf->Bloss;
  144 + qemu_pf.abits = 8 - sdl_pf->Aloss;
  145 +
  146 + qemu_pf.rmax = ((1 << qemu_pf.rbits) - 1);
  147 + qemu_pf.gmax = ((1 << qemu_pf.gbits) - 1);
  148 + qemu_pf.bmax = ((1 << qemu_pf.bbits) - 1);
  149 + qemu_pf.amax = ((1 << qemu_pf.abits) - 1);
  150 +
  151 + return qemu_pf;
  152 +}
  153 +
  154 +static DisplaySurface* sdl_create_displaysurface(int width, int height)
  155 +{
  156 + DisplaySurface *surface = (DisplaySurface*) qemu_mallocz(sizeof(DisplaySurface));
  157 + if (surface == NULL) {
  158 + fprintf(stderr, "sdl_create_displaysurface: malloc failed\n");
  159 + exit(1);
  160 + }
  161 +
  162 + surface->width = width;
  163 + surface->height = height;
105 164
106 - sdl_setdata(ds); 165 + if (hostbpp == 16)
  166 + do_sdl_resize(width, height, 16);
  167 + else
  168 + do_sdl_resize(width, height, 32);
  169 +
  170 + surface->pf = sdl_to_qemu_pixelformat(real_screen->format);
  171 + surface->linesize = real_screen->pitch;
  172 + surface->data = real_screen->pixels;
  173 +
  174 +#ifdef WORDS_BIGENDIAN
  175 + surface->flags = QEMU_ALLOCATED_FLAG | QEMU_BIG_ENDIAN_FLAG;
  176 +#else
  177 + surface->flags = QEMU_ALLOCATED_FLAG;
  178 +#endif
  179 + allocator = 1;
  180 +
  181 + return surface;
  182 +}
  183 +
  184 +static void sdl_free_displaysurface(DisplaySurface *surface)
  185 +{
  186 + allocator = 0;
  187 + if (surface == NULL)
  188 + return;
  189 + qemu_free(surface);
  190 +}
  191 +
  192 +static DisplaySurface* sdl_resize_displaysurface(DisplaySurface *surface, int width, int height)
  193 +{
  194 + sdl_free_displaysurface(surface);
  195 + return sdl_create_displaysurface(width, height);
107 } 196 }
108 197
109 /* generic keyboard conversion */ 198 /* generic keyboard conversion */
@@ -391,7 +480,7 @@ static void sdl_send_mouse_event(int dx, int dy, int dz, int x, int y, int state @@ -391,7 +480,7 @@ static void sdl_send_mouse_event(int dx, int dy, int dz, int x, int y, int state
391 static void toggle_full_screen(DisplayState *ds) 480 static void toggle_full_screen(DisplayState *ds)
392 { 481 {
393 gui_fullscreen = !gui_fullscreen; 482 gui_fullscreen = !gui_fullscreen;
394 - sdl_resize(ds); 483 + do_sdl_resize(real_screen->w, real_screen->h, real_screen->format->BitsPerPixel);
395 if (gui_fullscreen) { 484 if (gui_fullscreen) {
396 gui_saved_grab = gui_grab; 485 gui_saved_grab = gui_grab;
397 sdl_grab_start(); 486 sdl_grab_start();
@@ -669,6 +758,8 @@ void sdl_display_init(DisplayState *ds, int full_screen, int no_frame) @@ -669,6 +758,8 @@ void sdl_display_init(DisplayState *ds, int full_screen, int no_frame)
669 { 758 {
670 int flags; 759 int flags;
671 uint8_t data = 0; 760 uint8_t data = 0;
  761 + DisplayAllocator *da;
  762 + const SDL_VideoInfo *vi;
672 763
673 #if defined(__APPLE__) 764 #if defined(__APPLE__)
674 /* always use generic keymaps */ 765 /* always use generic keymaps */
@@ -689,6 +780,8 @@ void sdl_display_init(DisplayState *ds, int full_screen, int no_frame) @@ -689,6 +780,8 @@ void sdl_display_init(DisplayState *ds, int full_screen, int no_frame)
689 fprintf(stderr, "Could not initialize SDL - exiting\n"); 780 fprintf(stderr, "Could not initialize SDL - exiting\n");
690 exit(1); 781 exit(1);
691 } 782 }
  783 + vi = SDL_GetVideoInfo();
  784 + hostbpp = vi->vfmt->BitsPerPixel;
692 785
693 dcl = qemu_mallocz(sizeof(DisplayChangeListener)); 786 dcl = qemu_mallocz(sizeof(DisplayChangeListener));
694 dcl->dpy_update = sdl_update; 787 dcl->dpy_update = sdl_update;
@@ -700,6 +793,18 @@ void sdl_display_init(DisplayState *ds, int full_screen, int no_frame) @@ -700,6 +793,18 @@ void sdl_display_init(DisplayState *ds, int full_screen, int no_frame)
700 ds->cursor_define = sdl_mouse_define; 793 ds->cursor_define = sdl_mouse_define;
701 register_displaychangelistener(ds, dcl); 794 register_displaychangelistener(ds, dcl);
702 795
  796 + da = qemu_mallocz(sizeof(DisplayAllocator));
  797 + da->create_displaysurface = sdl_create_displaysurface;
  798 + da->resize_displaysurface = sdl_resize_displaysurface;
  799 + da->free_displaysurface = sdl_free_displaysurface;
  800 + if (register_displayallocator(ds, da) == da) {
  801 + DisplaySurface *surf;
  802 + surf = sdl_create_displaysurface(ds_get_width(ds), ds_get_height(ds));
  803 + defaultallocator_free_displaysurface(ds->surface);
  804 + ds->surface = surf;
  805 + dpy_resize(ds);
  806 + }
  807 +
703 sdl_update_caption(); 808 sdl_update_caption();
704 SDL_EnableKeyRepeat(250, 50); 809 SDL_EnableKeyRepeat(250, 50);
705 gui_grab = 0; 810 gui_grab = 0;
@@ -2874,6 +2874,12 @@ void pcmcia_info(Monitor *mon) @@ -2874,6 +2874,12 @@ void pcmcia_info(Monitor *mon)
2874 /***********************************************************/ 2874 /***********************************************************/
2875 /* register display */ 2875 /* register display */
2876 2876
  2877 +struct DisplayAllocator default_allocator = {
  2878 + defaultallocator_create_displaysurface,
  2879 + defaultallocator_resize_displaysurface,
  2880 + defaultallocator_free_displaysurface
  2881 +};
  2882 +
2877 void register_displaystate(DisplayState *ds) 2883 void register_displaystate(DisplayState *ds)
2878 { 2884 {
2879 DisplayState **s; 2885 DisplayState **s;
@@ -2889,12 +2895,19 @@ DisplayState *get_displaystate(void) @@ -2889,12 +2895,19 @@ DisplayState *get_displaystate(void)
2889 return display_state; 2895 return display_state;
2890 } 2896 }
2891 2897
  2898 +DisplayAllocator *register_displayallocator(DisplayState *ds, DisplayAllocator *da)
  2899 +{
  2900 + if(ds->allocator == &default_allocator) ds->allocator = da;
  2901 + return ds->allocator;
  2902 +}
  2903 +
2892 /* dumb display */ 2904 /* dumb display */
2893 2905
2894 static void dumb_display_init(void) 2906 static void dumb_display_init(void)
2895 { 2907 {
2896 DisplayState *ds = qemu_mallocz(sizeof(DisplayState)); 2908 DisplayState *ds = qemu_mallocz(sizeof(DisplayState));
2897 - ds->surface = qemu_create_displaysurface(640, 480, 32, 640 * 4); 2909 + ds->allocator = &default_allocator;
  2910 + ds->surface = qemu_create_displaysurface(ds, 640, 480);
2898 register_displaystate(ds); 2911 register_displaystate(ds);
2899 } 2912 }
2900 2913