Stefano Stabellini
2009-Mar-02 17:19 UTC
[Xen-devel] [PATCH 4 of 13] DisplayState interface change
Import "DisplayState interface change" from qemu mainstream: the patch has been adapted to qemu-xen and merged with several following fixes. The original qemu svn commit is the following: git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@6336 c046a42c-6fe2-441c-8c8c-71466251a162 Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com> --- diff --git a/console.c b/console.c --- a/console.c +++ b/console.c @@ -1000,20 +1000,16 @@ if (index >= MAX_CONSOLES) return; + active_console->g_width = ds_get_width(active_console->ds); + active_console->g_height = ds_get_height(active_console->ds); s = consoles[index]; if (s) { + DisplayState *ds = s->ds; active_console = s; - if (s->console_type == TEXT_CONSOLE) { - if (s->g_width != s->ds->width || - s->g_height != s->ds->height) { - s->g_width = s->ds->width; - s->g_height = s->ds->height; - text_console_resize(s); - } - console_refresh(s); - } else { - vga_hw_invalidate(); - } + ds->surface = qemu_resize_displaysurface(ds->surface, s->g_width, + s->g_height, 32, 4 * s->g_width); + dpy_resize(s->ds); + vga_hw_invalidate(); } } @@ -1121,15 +1117,6 @@ { TextConsole *s = (TextConsole *) opaque; - if (s->g_width != ds_get_width(s->ds) || s->g_height != ds_get_height(s->ds)) { - if (s->console_type == TEXT_CONSOLE_FIXED_SIZE) - dpy_resize(s->ds, s->g_width, s->g_height); - else { - s->g_width = ds_get_width(s->ds); - s->g_height = ds_get_height(s->ds); - text_console_resize(s); - } - } console_refresh(s); } @@ -1263,8 +1250,8 @@ s->total_height = DEFAULT_BACKSCROLL; s->x = 0; s->y = 0; - s->g_width = s->ds->width; - s->g_height = s->ds->height; + s->g_width = ds_get_width(s->ds); + s->g_height = ds_get_height(s->ds); /* Set text attribute defaults */ s->t_attrib_default.bold = 0; @@ -1286,26 +1273,191 @@ void qemu_console_resize(QEMUConsole *console, int width, int height) { - if (console->g_width != width || console->g_height != height - || !ds_get_data(console->ds)) { - console->g_width = width; - console->g_height = height; - if (active_console == console) { - dpy_resize(console->ds, width, height); - } + console->g_width = width; + console->g_height = height; + if (active_console == console) { + DisplayState *ds = console->ds; + ds->surface = qemu_resize_displaysurface(ds->surface, width, height, 32, 4 * width); + dpy_resize(console->ds); } } void qemu_console_copy(QEMUConsole *console, int src_x, int src_y, int dst_x, int dst_y, int w, int h) { - if (active_console == console) { - if (console->ds->dpy_copy) - console->ds->dpy_copy(console->ds, - src_x, src_y, dst_x, dst_y, w, h); - else { - /* TODO */ - console->ds->dpy_update(console->ds, dst_x, dst_y, w, h); - } + if (active_console == console) + dpy_copy(console->ds, src_x, src_y, dst_x, dst_y, w, h); +} + +PixelFormat qemu_different_endianness_pixelformat(int bpp) +{ + PixelFormat pf; + + memset(&pf, 0x00, sizeof(PixelFormat)); + + pf.bits_per_pixel = bpp; + pf.bytes_per_pixel = bpp / 8; + pf.depth = bpp == 32 ? 24 : bpp; + + switch (bpp) { + case 24: + pf.rmask = 0x000000FF; + pf.gmask = 0x0000FF00; + pf.bmask = 0x00FF0000; + pf.rmax = 255; + pf.gmax = 255; + pf.bmax = 255; + pf.rshift = 0; + pf.gshift = 8; + pf.bshift = 16; + break; + case 32: + pf.rmask = 0x0000FF00; + pf.gmask = 0x00FF0000; + pf.bmask = 0xFF000000; + pf.amask = 0x00000000; + pf.amax = 255; + pf.rmax = 255; + pf.gmax = 255; + pf.bmax = 255; + pf.ashift = 0; + pf.rshift = 8; + pf.gshift = 16; + pf.bshift = 24; + break; + default: + break; } + return pf; } + +PixelFormat qemu_default_pixelformat(int bpp) +{ + PixelFormat pf; + + memset(&pf, 0x00, sizeof(PixelFormat)); + + pf.bits_per_pixel = bpp; + pf.bytes_per_pixel = bpp / 8; + pf.depth = bpp == 32 ? 24 : bpp; + + switch (bpp) { + case 16: + pf.rmask = 0x0000F800; + pf.gmask = 0x000007E0; + pf.bmask = 0x0000001F; + pf.rmax = 31; + pf.gmax = 63; + pf.bmax = 31; + pf.rshift = 11; + pf.gshift = 5; + pf.bshift = 0; + break; + case 24: + pf.rmask = 0x00FF0000; + pf.gmask = 0x0000FF00; + pf.bmask = 0x000000FF; + pf.rmax = 255; + pf.gmax = 255; + pf.bmax = 255; + pf.rshift = 16; + pf.gshift = 8; + pf.bshift = 0; + case 32: + pf.rmask = 0x00FF0000; + pf.gmask = 0x0000FF00; + pf.bmask = 0x000000FF; + pf.amax = 255; + pf.rmax = 255; + pf.gmax = 255; + pf.bmax = 255; + pf.ashift = 24; + pf.rshift = 16; + pf.gshift = 8; + pf.bshift = 0; + break; + default: + break; + } + return pf; +} + +DisplaySurface* qemu_create_displaysurface(int width, int height, int bpp, int linesize) +{ + DisplaySurface *surface = (DisplaySurface*) qemu_mallocz(sizeof(DisplaySurface)); + if (surface == NULL) { + fprintf(stderr, "qemu_create_displaysurface: malloc failed\n"); + exit(1); + } + + surface->width = width; + surface->height = height; + surface->linesize = linesize; + surface->pf = qemu_default_pixelformat(bpp); +#ifdef WORDS_BIGENDIAN + surface->flags = QEMU_ALLOCATED_FLAG | QEMU_BIG_ENDIAN_FLAG; +#else + surface->flags = QEMU_ALLOCATED_FLAG; +#endif + surface->data = (uint8_t*) qemu_mallocz(surface->linesize * surface->height); + if (surface->data == NULL) { + fprintf(stderr, "qemu_create_displaysurface: malloc failed\n"); + exit(1); + } + + return surface; +} + +DisplaySurface* qemu_resize_displaysurface(DisplaySurface *surface, + int width, int height, int bpp, int linesize) +{ + surface->width = width; + surface->height = height; + surface->linesize = linesize; + surface->pf = qemu_default_pixelformat(bpp); + if (surface->flags & QEMU_ALLOCATED_FLAG) + surface->data = (uint8_t*) qemu_realloc(surface->data, surface->linesize * surface->height); + else + surface->data = (uint8_t*) qemu_malloc(surface->linesize * surface->height); + if (surface->data == NULL) { + fprintf(stderr, "qemu_resize_displaysurface: malloc failed\n"); + exit(1); + } +#ifdef WORDS_BIGENDIAN + surface->flags = QEMU_ALLOCATED_FLAG | QEMU_BIG_ENDIAN_FLAG; +#else + surface->flags = QEMU_ALLOCATED_FLAG; +#endif + + return surface; +} + +DisplaySurface* qemu_create_displaysurface_from(int width, int height, int bpp, + int linesize, uint8_t *data) +{ + DisplaySurface *surface = (DisplaySurface*) qemu_mallocz(sizeof(DisplaySurface)); + if (surface == NULL) { + fprintf(stderr, "qemu_create_displaysurface_from: malloc failed\n"); + exit(1); + } + + surface->width = width; + surface->height = height; + surface->linesize = linesize; + surface->pf = qemu_default_pixelformat(bpp); +#ifdef WORDS_BIGENDIAN + surface->flags = QEMU_BIG_ENDIAN_FLAG; +#endif + surface->data = data; + + return surface; +} + +void qemu_free_displaysurface(DisplaySurface *surface) +{ + if (surface == NULL) + return; + if (surface->flags & QEMU_ALLOCATED_FLAG) + qemu_free(surface->data); + qemu_free(surface); +} diff --git a/console.h b/console.h --- a/console.h +++ b/console.h @@ -67,80 +67,170 @@ /* in ms */ #define GUI_REFRESH_INTERVAL 30 +#define QEMU_BIG_ENDIAN_FLAG 0x01 +#define QEMU_ALLOCATED_FLAG 0x02 -struct DisplayState { - uint8_t *data; - int linesize; - int depth; - int bgr; /* BGR color order instead of RGB. Only valid for depth == 32 */ +struct PixelFormat { + uint8_t bits_per_pixel; + uint8_t bytes_per_pixel; + uint8_t depth; /* color depth in bits */ + uint32_t rmask, gmask, bmask, amask; + uint8_t rshift, gshift, bshift, ashift; + uint8_t rmax, gmax, bmax, amax; +}; + +struct DisplaySurface { + uint8_t flags; int width; int height; - void *opaque; - uint32_t *palette; - struct QEMUTimer *gui_timer; + int linesize; /* bytes per line */ + uint8_t *data; + + struct PixelFormat pf; +}; + +struct DisplayChangeListener { + int idle; uint64_t gui_timer_interval; - int idle; /* there is nothing to update (window invisible), set by vnc/sdl */ - int shared_buf; void (*dpy_update)(struct DisplayState *s, int x, int y, int w, int h); - void (*dpy_resize)(struct DisplayState *s, int w, int h); - void (*dpy_resize_shared)(struct DisplayState *s, int w, int h, int depth, int linesize, void *pixels); - void (*dpy_setdata)(DisplayState *s, void *pixels); + void (*dpy_resize)(struct DisplayState *s); + void (*dpy_setdata)(struct DisplayState *s); void (*dpy_refresh)(struct DisplayState *s); void (*dpy_copy)(struct DisplayState *s, int src_x, int src_y, int dst_x, int dst_y, int w, int h); void (*dpy_fill)(struct DisplayState *s, int x, int y, int w, int h, uint32_t c); void (*dpy_text_cursor)(struct DisplayState *s, int x, int y); + + struct DisplayChangeListener *next; }; + +struct DisplayState { + struct DisplaySurface *surface; + void *opaque; + struct QEMUTimer *gui_timer; + + struct DisplayChangeListener* listeners; + + void (*mouse_set)(int x, int y, int on); + void (*cursor_define)(int width, int height, int bpp, int hot_x, int hot_y, + uint8_t *image, uint8_t *mask); +}; + +DisplaySurface* qemu_create_displaysurface(int width, int height, int bpp, int linesize); +DisplaySurface* qemu_resize_displaysurface(DisplaySurface *surface, + int width, int height, int bpp, int linesize); +DisplaySurface* qemu_create_displaysurface_from(int width, int height, int bpp, + int linesize, uint8_t *data); +void qemu_free_displaysurface(DisplaySurface *surface); +PixelFormat qemu_different_endianness_pixelformat(int bpp); +PixelFormat qemu_default_pixelformat(int bpp); + +static inline int is_buffer_shared(DisplaySurface *surface) +{ + return (!(surface->flags & QEMU_ALLOCATED_FLAG)); +} + +static inline void register_displaychangelistener(DisplayState *ds, DisplayChangeListener *dcl) +{ + dcl->next = ds->listeners; + ds->listeners = dcl; +} static inline void dpy_update(DisplayState *s, int x, int y, int w, int h) { - s->dpy_update(s, x, y, w, h); + struct DisplayChangeListener *dcl = s->listeners; + while (dcl != NULL) { + dcl->dpy_update(s, x, y, w, h); + dcl = dcl->next; + } } -static inline void dpy_resize(DisplayState *s, int w, int h) +static inline void dpy_resize(DisplayState *s) { - s->dpy_resize(s, w, h); + struct DisplayChangeListener *dcl = s->listeners; + while (dcl != NULL) { + dcl->dpy_resize(s); + dcl = dcl->next; + } } -static inline void dpy_resize_shared(DisplayState *s, int w, int h, int depth, int linesize, void *pixels) + +static inline void dpy_setdata(DisplayState *s) { - s->dpy_resize_shared(s, w, h, depth, linesize, pixels); + struct DisplayChangeListener *dcl = s->listeners; + while (dcl != NULL) { + if (dcl->dpy_setdata) dcl->dpy_setdata(s); + dcl = dcl->next; + } } -static inline void dpy_cursor(DisplayState *s, int x, int y) + +static inline void dpy_refresh(DisplayState *s) { - if (s->dpy_text_cursor) - s->dpy_text_cursor(s, x, y); + struct DisplayChangeListener *dcl = s->listeners; + while (dcl != NULL) { + if (dcl->dpy_refresh) dcl->dpy_refresh(s); + dcl = dcl->next; + } +} + +static inline void dpy_copy(struct DisplayState *s, int src_x, int src_y, + int dst_x, int dst_y, int w, int h) { + struct DisplayChangeListener *dcl = s->listeners; + while (dcl != NULL) { + if (dcl->dpy_copy) + dcl->dpy_copy(s, src_x, src_y, dst_x, dst_y, w, h); + else /* TODO */ + dcl->dpy_update(s, dst_x, dst_y, w, h); + dcl = dcl->next; + } +} + +static inline void dpy_fill(struct DisplayState *s, int x, int y, + int w, int h, uint32_t c) { + struct DisplayChangeListener *dcl = s->listeners; + while (dcl != NULL) { + if (dcl->dpy_fill) dcl->dpy_fill(s, x, y, w, h, c); + dcl = dcl->next; + } +} + +static inline void dpy_cursor(struct DisplayState *s, int x, int y) { + struct DisplayChangeListener *dcl = s->listeners; + while (dcl != NULL) { + if (dcl->dpy_text_cursor) dcl->dpy_text_cursor(s, x, y); + dcl = dcl->next; + } } static inline int ds_get_linesize(DisplayState *ds) { - return ds->linesize; + return ds->surface->linesize; } static inline uint8_t* ds_get_data(DisplayState *ds) { - return ds->data; + return ds->surface->data; } static inline int ds_get_width(DisplayState *ds) { - return ds->width; + return ds->surface->width; } static inline int ds_get_height(DisplayState *ds) { - return ds->height; + return ds->surface->height; } static inline int ds_get_bits_per_pixel(DisplayState *ds) { - return ds->depth; + return ds->surface->pf.bits_per_pixel; } static inline int ds_get_bytes_per_pixel(DisplayState *ds) { - return (ds->depth / 8); + return ds->surface->pf.bytes_per_pixel; } typedef unsigned long console_ch_t; diff --git a/curses.c b/curses.c --- a/curses.c +++ b/curses.c @@ -97,13 +97,13 @@ } } -static void curses_resize(DisplayState *ds, int w, int h) +static void curses_resize(DisplayState *ds) { - if (w == gwidth && h == gheight) + if (ds_get_width(ds) == gwidth && ds_get_height(ds) == gheight) return; - gwidth = w; - gheight = h; + gwidth = ds_get_width(ds); + gheight = ds_get_height(ds); curses_calc_pad(); } @@ -169,8 +169,8 @@ clear(); refresh(); curses_calc_pad(); - ds->width = FONT_WIDTH * width; - ds->height = FONT_HEIGHT * height; + ds->surface->width = FONT_WIDTH * width; + ds->surface->height = FONT_HEIGHT * height; vga_hw_invalidate(); invalidate = 0; } @@ -197,8 +197,8 @@ refresh(); curses_calc_pad(); curses_update(ds, 0, 0, width, height); - ds->width = FONT_WIDTH * width; - ds->height = FONT_HEIGHT * height; + ds->surface->width = FONT_WIDTH * width; + ds->surface->height = FONT_HEIGHT * height; continue; } #endif @@ -338,6 +338,7 @@ void curses_display_init(DisplayState *ds, int full_screen) { + DisplayChangeListener *dcl; #ifndef _WIN32 if (!isatty(1)) { fprintf(stderr, "We need a terminal output\n"); @@ -357,18 +358,19 @@ #endif #endif - ds->data = (void *) screen; - ds->linesize = 0; - ds->depth = 0; - ds->width = 640; - ds->height = 400; - ds->dpy_update = curses_update; - ds->dpy_resize = curses_resize; - ds->dpy_refresh = curses_refresh; - ds->dpy_text_cursor = curses_cursor_position; + dcl = (DisplayChangeListener *) qemu_mallocz(sizeof(DisplayChangeListener)); + if (!dcl) + exit(1); + dcl->dpy_update = curses_update; + dcl->dpy_resize = curses_resize; + dcl->dpy_refresh = curses_refresh; + dcl->dpy_text_cursor = curses_cursor_position; + register_displaychangelistener(ds, dcl); + qemu_free_displaysurface(ds->surface); + ds->surface = qemu_create_displaysurface_from(80, 25, 0, 0, (uint8_t*) screen); invalidate = 1; /* Standard VGA initial text mode dimensions */ - curses_resize(ds, 80, 25); + curses_resize(ds); } diff --git a/hw/cirrus_vga.c b/hw/cirrus_vga.c --- a/hw/cirrus_vga.c +++ b/hw/cirrus_vga.c @@ -794,26 +794,9 @@ static int cirrus_bitblt_videotovideo_copy(CirrusVGAState * s) { - if (s->ds->dpy_copy) { - cirrus_do_copy(s, s->cirrus_blt_dstaddr - s->start_addr, - s->cirrus_blt_srcaddr - s->start_addr, - s->cirrus_blt_width, s->cirrus_blt_height); - } else { - - if (BLTUNSAFE(s)) - return 0; - - (*s->cirrus_rop) (s, s->vram_ptr + - (s->cirrus_blt_dstaddr & s->cirrus_addr_mask), - s->vram_ptr + - (s->cirrus_blt_srcaddr & s->cirrus_addr_mask), - s->cirrus_blt_dstpitch, s->cirrus_blt_srcpitch, - s->cirrus_blt_width, s->cirrus_blt_height); - - cirrus_invalidate_region(s, s->cirrus_blt_dstaddr, - s->cirrus_blt_dstpitch, s->cirrus_blt_width, - s->cirrus_blt_height); - } + cirrus_do_copy(s, s->cirrus_blt_dstaddr - s->start_addr, + s->cirrus_blt_srcaddr - s->start_addr, + s->cirrus_blt_width, s->cirrus_blt_height); return 1; } diff --git a/hw/nseries.c b/hw/nseries.c --- a/hw/nseries.c +++ b/hw/nseries.c @@ -1361,7 +1361,8 @@ /* FIXME: We shouldn''t really be doing this here. The LCD controller will set the size once configured, so this just sets an initial size until the guest activates the display. */ - dpy_resize(ds, 800, 480); + ds->surface = qemu_resize_displaysurface(ds->surface, 800, 480, 32, 4 * 800); + dpy_resize(ds); } static struct arm_boot_info n800_binfo = { diff --git a/hw/palm.c b/hw/palm.c --- a/hw/palm.c +++ b/hw/palm.c @@ -278,7 +278,8 @@ /* FIXME: We shouldn''t really be doing this here. The LCD controller will set the size once configured, so this just sets an initial size until the guest activates the display. */ - dpy_resize(ds, 320, 320); + ds->surface = qemu_resize_displaysurface(ds->surface, 320, 320, 32, 4 * 320); + dpy_resize(ds); } QEMUMachine palmte_machine = { diff --git a/hw/vga.c b/hw/vga.c --- a/hw/vga.c +++ b/hw/vga.c @@ -1270,18 +1270,19 @@ return; } - s->last_scr_width = width * cw; - s->last_scr_height = height * cheight; if (width != s->last_width || height != s->last_height || cw != s->last_cw || cheight != s->last_ch || s->last_depth) { - dpy_resize(s->ds, s->last_scr_width, s->last_scr_height); + s->last_scr_width = width * cw; + s->last_scr_height = height * cheight; + qemu_console_resize(s->console, s->last_scr_width, s->last_scr_height); + dpy_resize(s->ds); s->last_depth = 0; + s->last_width = width; + s->last_height = height; + s->last_ch = cheight; + s->last_cw = cw; full_update = 1; } - s->last_width = width; - s->last_height = height; - s->last_ch = cheight; - s->last_cw = cw; s->rgb_to_pixel = rgb_to_pixel_dup_table[get_depth_index(s->ds)]; @@ -1289,7 +1290,7 @@ full_update |= update_palette16(s); palette = s->last_palette; - x_incr = cw * ((s->ds->depth + 7) >> 3); + x_incr = cw * ds_get_bytes_per_pixel(s->ds); /* compute font data address (in plane 2) */ v = s->sr[3]; offset = (((v >> 4) & 1) | ((v << 1) & 6)) * 8192 * 4 + 2; @@ -1323,7 +1324,7 @@ cw = 9; if (s->sr[1] & 0x08) cw = 16; /* NOTE: no 18 pixel wide */ - x_incr = cw * ((ds_get_bits_per_pixel(s->ds) + 7) >> 3); + x_incr = cw * ds_get_bytes_per_pixel(s->ds); width = (s->cr[0x01] + 1); if (s->cr[0x06] == 100) { /* ugly hack for CGA 160x100x16 - explain me the logic */ @@ -1616,31 +1617,43 @@ disp_width <<= 1; } - ds_depth = s->ds->depth; + ds_depth = ds_get_bits_per_pixel(s->ds); depth = s->get_bpp(s); - if (s->ds->dpy_resize_shared) { - if (s->line_offset != s->last_line_offset || - disp_width != s->last_width || - height != s->last_height || - s->last_depth != depth) { - dpy_resize_shared(s->ds, disp_width, height, depth, s->line_offset, s->vram_ptr + (s->start_addr * 4)); - s->last_scr_width = disp_width; - s->last_scr_height = height; - s->last_width = disp_width; - s->last_height = height; - s->last_line_offset = s->line_offset; - s->last_depth = depth; - full_update = 1; - } else if (s->ds->shared_buf && (full_update || s->ds->data != s->vram_ptr + (s->start_addr * 4))) - s->ds->dpy_setdata(s->ds, s->vram_ptr + (s->start_addr * 4)); - } else if (disp_width != s->last_width || - height != s->last_height) { - dpy_resize(s->ds, disp_width, height); + if (s->line_offset != s->last_line_offset || + disp_width != s->last_width || + height != s->last_height || + s->last_depth != depth) { +#if defined(WORDS_BIGENDIAN) == defined(TARGET_WORDS_BIGENDIAN) + if (depth == 16 || depth == 32) { +#else + if (depth == 32) { +#endif + if (is_graphic_console()) { + qemu_free_displaysurface(s->ds->surface); + s->ds->surface = qemu_create_displaysurface_from(disp_width, height, depth, + s->line_offset, + s->vram_ptr + (s->start_addr * 4)); +#if defined(WORDS_BIGENDIAN) != defined(TARGET_WORDS_BIGENDIAN) + s->ds->surface->pf = qemu_different_endianness_pixelformat(depth); +#endif + dpy_resize(s->ds); + } else { + qemu_console_resize(s->console, disp_width, height); + } + } else { + qemu_console_resize(s->console, disp_width, height); + } s->last_scr_width = disp_width; s->last_scr_height = height; s->last_width = disp_width; s->last_height = height; + s->last_line_offset = s->line_offset; + s->last_depth = depth; full_update = 1; + } else if (is_graphic_console() && is_buffer_shared(s->ds->surface) && + (full_update || s->ds->surface->data != s->vram_ptr + (s->start_addr * 4))) { + s->ds->surface->data = s->vram_ptr + (s->start_addr * 4); + dpy_setdata(s->ds); } s->rgb_to_pixel = @@ -1695,7 +1708,7 @@ } vga_draw_line = vga_draw_line_table[v * NB_DEPTHS + get_depth_index(s->ds)]; - if (!s->ds->shared_buf && s->cursor_invalidate) + if (!is_buffer_shared(s->ds->surface) && s->cursor_invalidate) s->cursor_invalidate(s); line_offset = s->line_offset; @@ -1756,8 +1769,8 @@ y_start = -1; page_min = 0; page_max = 0; - d = s->ds->data; - linesize = s->ds->linesize; + d = ds_get_data(s->ds); + linesize = ds_get_linesize(s->ds); y1 = 0; for(y = 0; y < height; y++) { addr = addr1; @@ -1789,7 +1802,7 @@ page_min = page0; if (page_max == 0 || page1 > page_max) page_max = page1; - if (!s->ds->shared_buf) { + if (!is_buffer_shared(s->ds->surface)) { vga_draw_line(s, d, s->vram_ptr + addr, width); if (s->cursor_draw_line) s->cursor_draw_line(s, d, y); @@ -1844,15 +1857,15 @@ s->rgb_to_pixel rgb_to_pixel_dup_table[get_depth_index(s->ds)]; - if (s->ds->depth == 8) + if (ds_get_bits_per_pixel(s->ds) == 8) val = s->rgb_to_pixel(0, 0, 0); else val = 0; - w = s->last_scr_width * ((s->ds->depth + 7) >> 3); - d = s->ds->data; + w = s->last_scr_width * ds_get_bytes_per_pixel(s->ds); + d = ds_get_data(s->ds); for(i = 0; i < s->last_scr_height; i++) { memset(d, val, w); - d += s->ds->linesize; + d += ds_get_linesize(s->ds); } dpy_update(s->ds, 0, 0, s->last_scr_width, s->last_scr_height); @@ -1977,7 +1990,9 @@ cw != s->last_cw || cheight != s->last_ch) { s->last_scr_width = width * cw; s->last_scr_height = height * cheight; - qemu_console_resize(s->console, width, height); + s->ds->surface->width = width; + s->ds->surface->height = height; + dpy_resize(s->ds); s->last_width = width; s->last_height = height; s->last_ch = cheight; @@ -2058,7 +2073,9 @@ s->last_width = 60; s->last_height = height = 3; dpy_cursor(s->ds, -1, -1); - qemu_console_resize(s->console, s->last_width, height); + s->ds->surface->width = s->last_width; + s->ds->surface->height = height; + dpy_resize(s->ds); for (dst = chardata, i = 0; i < s->last_width * height; i ++) console_write_ch(dst ++, '' ''); @@ -2520,7 +2537,6 @@ s->vram_offset = vga_ram_offset; s->vram_size = vga_ram_size; s->ds = ds; - ds->palette = s->last_palette; s->get_bpp = vga_get_bpp; s->get_offsets = vga_get_offsets; s->get_resolution = vga_get_resolution; @@ -2690,12 +2706,8 @@ { } -static void vga_save_dpy_resize(DisplayState *s, int w, int h) +static void vga_save_dpy_resize(DisplayState *s) { - s->linesize = w * 4; - s->data = qemu_mallocz(h * s->linesize); - vga_save_w = w; - vga_save_h = h; } static void vga_save_dpy_refresh(DisplayState *s) @@ -2737,25 +2749,28 @@ { VGAState *s = (VGAState *)opaque; DisplayState *saved_ds, ds1, *ds = &ds1; + DisplayChangeListener dcl; /* XXX: this is a little hackish */ vga_invalidate_display(s); saved_ds = s->ds; memset(ds, 0, sizeof(DisplayState)); - ds->dpy_update = vga_save_dpy_update; - ds->dpy_resize = vga_save_dpy_resize; - ds->dpy_refresh = vga_save_dpy_refresh; - ds->depth = 32; - + memset(&dcl, 0, sizeof(DisplayChangeListener)); + dcl.dpy_update = vga_save_dpy_update; + dcl.dpy_resize = vga_save_dpy_resize; + dcl.dpy_refresh = vga_save_dpy_refresh; + register_displaychangelistener(ds, &dcl); + ds->surface = qemu_create_displaysurface(ds_get_width(saved_ds), + ds_get_height(saved_ds), 32, 4 * ds_get_width(saved_ds)); + s->ds = ds; s->graphic_mode = -1; vga_update_display(s); - if (ds_get_data(ds)) { - ppm_save(filename, ds_get_data(ds), vga_save_w, vga_save_h, - ds_get_linesize(s->ds)); - qemu_free(ds_get_data(ds)); - } + ppm_save(filename, ds_get_data(ds), vga_save_w, vga_save_h, + ds_get_linesize(ds)); + + qemu_free_displaysurface(ds->surface); s->ds = saved_ds; } diff --git a/hw/xenfb.c b/hw/xenfb.c --- a/hw/xenfb.c +++ b/hw/xenfb.c @@ -700,21 +700,30 @@ { struct XenFB *xenfb = opaque; int i; + struct DisplayChangeListener *l; if (xenfb->feature_update) { #ifdef XENFB_TYPE_REFRESH_PERIOD - int period; + int period = 99999999; + int idle = 1; if (xenfb_queue_full(xenfb)) return; - if (xenfb->c.ds->idle) - period = XENFB_NO_REFRESH; - else { - period = xenfb->c.ds->gui_timer_interval; - if (!period) - period = GUI_REFRESH_INTERVAL; - } + for (l = xenfb->c.ds->listeners; l != NULL; l = l->next) { + if (l->idle) + continue; + idle = 0; + if (!l->gui_timer_interval) { + if (period > GUI_REFRESH_INTERVAL) + period = GUI_REFRESH_INTERVAL; + } else { + if (period > l->gui_timer_interval) + period = l->gui_timer_interval; + } + } + if (idle) + period = XENFB_NO_REFRESH; if (xenfb->refresh_period != period) { xenfb_send_refresh_period(xenfb, period); @@ -733,7 +742,9 @@ if (xenfb->width != ds_get_width(xenfb->c.ds) || xenfb->height != ds_get_height(xenfb->c.ds)) { xen_be_printf(&xenfb->c.xendev, 1, "update: resizing: %dx%d\n", xenfb->width, xenfb->height); - dpy_resize(xenfb->c.ds, xenfb->width, xenfb->height); + xenfb->c.ds->surface->width = xenfb->width; + xenfb->c.ds->surface->height = xenfb->height; + dpy_resize(xenfb->c.ds); xenfb->up_fullscreen = 1; } diff --git a/qemu-common.h b/qemu-common.h --- a/qemu-common.h +++ b/qemu-common.h @@ -131,6 +131,9 @@ typedef struct AudioState AudioState; typedef struct BlockDriverState BlockDriverState; typedef struct DisplayState DisplayState; +typedef struct DisplayChangeListener DisplayChangeListener; +typedef struct DisplaySurface DisplaySurface; +typedef struct PixelFormat PixelFormat; typedef struct TextConsole TextConsole; typedef TextConsole QEMUConsole; typedef struct CharDriverState CharDriverState; diff --git a/sdl.c b/sdl.c --- a/sdl.c +++ b/sdl.c @@ -35,8 +35,9 @@ #include <SDL_opengl.h> #endif -static SDL_Surface *screen; -static SDL_Surface *shared = NULL; +static DisplayChangeListener *dcl; +static SDL_Surface *real_screen; +static SDL_Surface *guest_screen = NULL; static int gui_grab; /* if true, all keyboard/mouse events are grabbed */ static int last_vm_running; static int gui_saved_grab; @@ -52,17 +53,15 @@ static SDL_Cursor *sdl_cursor_hidden; static int absolute_enabled = 0; static int opengl_enabled; -static uint8_t bgr; - -static void sdl_colourdepth(DisplayState *ds, int depth); #ifdef CONFIG_OPENGL static GLint tex_format; static GLint tex_type; static GLuint texture_ref = 0; static GLint gl_format; +static uint8_t bgr; -static void opengl_setdata(DisplayState *ds, void *pixels) +static void opengl_setdata(DisplayState *ds) { glEnable(GL_TEXTURE_RECTANGLE_ARB); glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); @@ -72,14 +71,13 @@ glDisable(GL_DEPTH_TEST); glDepthMask(GL_FALSE); glDisable(GL_CULL_FACE); - glViewport( 0, 0, screen->w, screen->h); + glViewport( 0, 0, real_screen->w, real_screen->h); glMatrixMode(GL_PROJECTION); glLoadIdentity(); - glOrtho(0, screen->w, screen->h, 0, -1,1); + glOrtho(0, real_screen->w, real_screen->h, 0, -1,1); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glClear(GL_COLOR_BUFFER_BIT); - ds->data = pixels; if (texture_ref) { glDeleteTextures(1, &texture_ref); @@ -90,27 +88,6 @@ glBindTexture(GL_TEXTURE_RECTANGLE_ARB, texture_ref); glPixelStorei(GL_UNPACK_LSB_FIRST, 1); switch (ds_get_bits_per_pixel(ds)) { - case 8: - if (ds->palette == NULL) { - tex_format = GL_RGB; - tex_type = GL_UNSIGNED_BYTE_3_3_2; - } else { - int i; - GLushort paletter[256], paletteg[256], paletteb[256]; - for (i = 0; i < 256; i++) { - uint8_t rgb = ds->palette[i] >> 16; - paletter[i] = ((rgb & 0xe0) >> 5) * 65535 / 7; - paletteg[i] = ((rgb & 0x1c) >> 2) * 65535 / 7; - paletteb[i] = (rgb & 0x3) * 65535 / 3; - } - glPixelMapusv(GL_PIXEL_MAP_I_TO_R, 256, paletter); - glPixelMapusv(GL_PIXEL_MAP_I_TO_G, 256, paletteg); - glPixelMapusv(GL_PIXEL_MAP_I_TO_B, 256, paletteb); - - tex_format = GL_COLOR_INDEX; - tex_type = GL_UNSIGNED_BYTE; - } - break; case 16: tex_format = GL_RGB; tex_type = GL_UNSIGNED_SHORT_5_6_5; @@ -120,7 +97,7 @@ tex_type = GL_UNSIGNED_BYTE; break; case 32: - if (!bgr) { + if (bgr == (ds->surface->pf.rshift < ds->surface->pf.bshift)) { tex_format = GL_BGRA; tex_type = GL_UNSIGNED_BYTE; } else { @@ -130,7 +107,7 @@ break; } glPixelStorei(GL_UNPACK_ROW_LENGTH, (ds_get_linesize(ds) / ds_get_bytes_per_pixel(ds))); - glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, gl_format, ds_get_width(ds), ds_get_height(ds), 0, tex_format, tex_type, pixels); + glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, gl_format, ds_get_width(ds), ds_get_height(ds), 0, tex_format, tex_type, ds_get_data(ds)); glTexParameterf(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_PRIORITY, 1.0); glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_LINEAR); @@ -149,12 +126,12 @@ glBegin(GL_QUADS); glTexCoord2d(0, 0); glVertex2d(0, 0); - glTexCoord2d(ds->width, 0); - glVertex2d(screen->w, 0); - glTexCoord2d(ds->width, ds->height); - glVertex2d(screen->w, screen->h); - glTexCoord2d(0, ds->height); - glVertex2d(0, screen->h); + glTexCoord2d(ds_get_width(ds), 0); + glVertex2d(real_screen->w, 0); + glTexCoord2d(ds_get_width(ds), ds_get_height(ds)); + glVertex2d(real_screen->w, real_screen->h); + glTexCoord2d(0, ds_get_height(ds)); + glVertex2d(0, real_screen->h); glEnd(); glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0); SDL_GL_SwapBuffers(); @@ -163,130 +140,73 @@ 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); - if (shared) { - SDL_Rect rec; - rec.x = x; - rec.y = y; - rec.w = w; - rec.h = h; - SDL_BlitSurface(shared, &rec, screen, &rec); - } - SDL_Flip(screen); + SDL_Rect rec; + rec.x = x; + rec.y = y; + rec.w = w; + rec.h = h; + // printf("updating x=%d y=%d w=%d h=%d\n", x, y, w, h);i + + SDL_BlitSurface(guest_screen, &rec, real_screen, &rec); + SDL_UpdateRect(real_screen, x, y, w, h); } -static void sdl_setdata(DisplayState *ds, void *pixels) +static void sdl_setdata(DisplayState *ds) { - uint32_t rmask, gmask, bmask, amask = 0; - switch (ds_get_bits_per_pixel(ds)) { - case 8: - rmask = 0x000000E0; - gmask = 0x0000001C; - bmask = 0x00000003; - break; - case 16: - rmask = 0x0000F800; - gmask = 0x000007E0; - bmask = 0x0000001F; - break; - case 24: - rmask = 0x00FF0000; - gmask = 0x0000FF00; - bmask = 0x000000FF; - break; - case 32: - rmask = 0x00FF0000; - gmask = 0x0000FF00; - bmask = 0x000000FF; - break; - default: - return; - } - shared = SDL_CreateRGBSurfaceFrom(pixels, width, height, ds_get_bits_per_pixel(ds), ds_get_linesize(ds), rmask , gmask, bmask, amask); - if (ds_get_bits_per_pixel(ds) == 8 && ds->palette != NULL) { - SDL_Color palette[256]; - int i; - for (i = 0; i < 256; i++) { - uint8_t rgb = ds->palette[i] >> 16; - palette[i].r = ((rgb & 0xe0) >> 5) * 255 / 7; - palette[i].g = ((rgb & 0x1c) >> 2) * 255 / 7; - palette[i].b = (rgb & 0x3) * 255 / 3; - } - SDL_SetColors(shared, palette, 0, 256); - } - ds->data = pixels; + SDL_Rect rec; + rec.x = 0; + rec.y = 0; + rec.w = real_screen->w; + rec.h = real_screen->h; + + if (guest_screen != NULL) SDL_FreeSurface(guest_screen); + + guest_screen = SDL_CreateRGBSurfaceFrom(ds_get_data(ds), ds_get_width(ds), ds_get_height(ds), + ds_get_bits_per_pixel(ds), ds_get_linesize(ds), + ds->surface->pf.rmask, ds->surface->pf.gmask, + ds->surface->pf.bmask, ds->surface->pf.amask); } -static void sdl_resize_shared(DisplayState *ds, int w, int h, int depth, int linesize, void *pixels) +static void sdl_resize(DisplayState *ds) { int flags; // printf("resizing to %d %d\n", w, h); - - sdl_colourdepth(ds, depth); - #ifdef CONFIG_OPENGL - if (ds->shared_buf && opengl_enabled) + if (opengl_enabled) flags = SDL_OPENGL|SDL_RESIZABLE; else #endif - flags = SDL_HWSURFACE|SDL_ASYNCBLIT|SDL_HWACCEL|SDL_DOUBLEBUF|SDL_HWPALETTE; + flags = SDL_HWSURFACE|SDL_ASYNCBLIT|SDL_HWACCEL; - if (gui_fullscreen) { + if (gui_fullscreen) flags |= SDL_FULLSCREEN; - flags &= ~SDL_RESIZABLE; - } if (gui_noframe) flags |= SDL_NOFRAME; - width = w; - height = h; - - again: - screen = SDL_SetVideoMode(w, h, 0, flags); - - if (!screen) { - fprintf(stderr, "Could not open SDL display: %s\n", SDL_GetError()); + width = ds_get_width(ds); + height = ds_get_height(ds); + real_screen = SDL_SetVideoMode(width, height, 0, flags); + if (!real_screen) { if (opengl_enabled) { /* Fallback to SDL */ opengl_enabled = 0; - ds->dpy_update = sdl_update; - ds->dpy_setdata = sdl_setdata; - ds->dpy_resize_shared = sdl_resize_shared; - sdl_resize_shared(ds, w, h, depth, linesize, pixels); + dcl->dpy_update = sdl_update; + dcl->dpy_setdata = sdl_setdata; + sdl_resize(ds); return; } + fprintf(stderr, "Could not open SDL display\n"); exit(1); } - if (!opengl_enabled) { - if (!screen->pixels && (flags & SDL_HWSURFACE) && (flags & SDL_FULLSCREEN)) { - flags &= ~SDL_HWSURFACE; - goto again; - } - - if (!screen->pixels) { - fprintf(stderr, "Could not open SDL display: %s\n", SDL_GetError()); - exit(1); - } +#ifdef CONFIG_OPENGL + if (real_screen->format->Bshift > real_screen->format->Rshift) { + bgr = 1; + } else { + bgr = 0; } - - ds->width = w; - ds->height = h; - if (!ds->shared_buf) { - ds->depth = screen->format->BitsPerPixel; - if (screen->format->Bshift > screen->format->Rshift) { - bgr = 1; - } else { - bgr = 0; - } - shared = NULL; - ds->data = screen->pixels; - ds->linesize = screen->pitch; - } else { - ds->linesize = linesize; -#ifdef CONFIG_OPENGL - switch(screen->format->BitsPerPixel) { + switch(real_screen->format->BitsPerPixel) { case 8: gl_format = GL_RGB; break; @@ -297,36 +217,15 @@ gl_format = GL_RGB; break; case 32: - if (!screen->format->Rshift) + if (!real_screen->format->Rshift) gl_format = GL_BGRA; else gl_format = GL_RGBA; break; - }; + }; #endif - } - if (ds->shared_buf) ds->dpy_setdata(ds, pixels); -} -static void sdl_resize(DisplayState *ds, int w, int h) -{ - sdl_resize_shared(ds, w, h, 0, w * ds_get_bytes_per_pixel(ds), NULL); -} - -static void sdl_colourdepth(DisplayState *ds, int depth) -{ - if (!depth || !ds->depth) { - ds->shared_buf = 0; - ds->dpy_update = sdl_update; - return; - } - ds->shared_buf = 1; - ds->depth = depth; -#ifdef CONFIG_OPENGL - if (opengl_enabled) { - ds->dpy_update = opengl_update; - } -#endif + dcl->dpy_setdata(ds); } /* generic keyboard conversion */ @@ -525,8 +424,8 @@ } SDL_GetMouseState(&dx, &dy); - dx = dx * 0x7FFF / (screen->w - 1); - dy = dy * 0x7FFF / (screen->h - 1); + dx = dx * 0x7FFF / (real_screen->w - 1); + dy = dy * 0x7FFF / (real_screen->h - 1); } else if (absolute_enabled) { sdl_show_cursor(); absolute_enabled = 0; @@ -538,7 +437,7 @@ static void toggle_full_screen(DisplayState *ds) { gui_fullscreen = !gui_fullscreen; - sdl_resize_shared(ds, ds_get_width(ds), ds_get_height(ds), ds_get_bits_per_pixel(ds), ds_get_linesize(ds), ds_get_data(ds)); + sdl_resize(ds); if (gui_fullscreen) { gui_saved_grab = gui_grab; sdl_grab_start(); @@ -566,7 +465,7 @@ while (SDL_PollEvent(ev)) { switch (ev->type) { case SDL_VIDEOEXPOSE: - ds->dpy_update(ds, 0, 0, ds->width, ds->height); + dcl->dpy_update(ds, 0, 0, ds_get_width(ds), ds_get_height(ds)); break; case SDL_KEYDOWN: case SDL_KEYUP: @@ -726,23 +625,23 @@ if (ev->active.state & SDL_APPACTIVE) { if (ev->active.gain) { /* Back to default interval */ - ds->gui_timer_interval = 0; - ds->idle = 0; + dcl->gui_timer_interval = 0; + dcl->idle = 0; } else { /* Sleeping interval */ - ds->gui_timer_interval = 500; - ds->idle = 1; + dcl->gui_timer_interval = 500; + dcl->idle = 1; } } break; #ifdef CONFIG_OPENGL case SDL_VIDEORESIZE: { - if (ds->shared_buf && opengl_enabled) { + if (opengl_enabled) { SDL_ResizeEvent *rev = &ev->resize; - screen = SDL_SetVideoMode(rev->w, rev->h, 0, SDL_OPENGL|SDL_RESIZABLE); - opengl_setdata(ds, ds->data); - opengl_update(ds, 0, 0, ds->width, ds->height); + real_screen = SDL_SetVideoMode(rev->w, rev->h, 0, SDL_OPENGL|SDL_RESIZABLE); + opengl_setdata(ds); + opengl_update(ds, 0, 0, ds_get_width(ds), ds_get_height(ds)); } break; } @@ -792,17 +691,21 @@ signal(SIGQUIT, SIG_DFL); #endif - ds->dpy_update = sdl_update; - ds->dpy_resize = sdl_resize; - ds->dpy_resize_shared = sdl_resize_shared; - ds->dpy_refresh = sdl_refresh; - ds->dpy_setdata = sdl_setdata; + dcl = qemu_mallocz(sizeof(DisplayChangeListener)); + if (!dcl) + exit(1); + dcl->dpy_update = sdl_update; + dcl->dpy_resize = sdl_resize; + dcl->dpy_refresh = sdl_refresh; + dcl->dpy_setdata = sdl_setdata; #ifdef CONFIG_OPENGL - if (opengl_enabled) - ds->dpy_setdata = opengl_setdata; + if (opengl_enabled) { + dcl->dpy_update = opengl_update; + dcl->dpy_setdata = opengl_setdata; + } #endif + register_displaychangelistener(ds, dcl); - sdl_resize(ds, 640, 400); sdl_update_caption(); SDL_EnableKeyRepeat(250, 50); gui_grab = 0; diff --git a/vl.c b/vl.c --- a/vl.c +++ b/vl.c @@ -195,6 +195,7 @@ static DisplayState display_state; int nographic; static int curses; +static int sdl; const char* keyboard_layout = NULL; int64_t ticks_per_sec; ram_addr_t ram_size; @@ -6245,7 +6246,7 @@ { } -static void dumb_resize(DisplayState *ds, int w, int h) +static void dumb_resize(DisplayState *ds) { } @@ -6258,14 +6259,15 @@ static void dumb_display_init(DisplayState *ds) { - ds->data = NULL; - ds->linesize = 0; - ds->depth = 0; - ds->dpy_update = dumb_update; - ds->dpy_resize = dumb_resize; - ds->dpy_refresh = dumb_refresh; - ds->gui_timer_interval = 500; - ds->idle = 1; + DisplayChangeListener *dcl = qemu_mallocz(sizeof(DisplayChangeListener)); + if (!dcl) + exit(1); + dcl->dpy_update = dumb_update; + dcl->dpy_resize = dumb_resize; + dcl->dpy_refresh = NULL; + dcl->idle = 1; + dcl->gui_timer_interval = 500; + register_displaychangelistener(ds, dcl); } /***********************************************************/ @@ -7901,13 +7903,19 @@ static void gui_update(void *opaque) { + uint64_t interval = GUI_REFRESH_INTERVAL; DisplayState *ds = opaque; - ds->dpy_refresh(ds); - qemu_mod_timer(ds->gui_timer, - (ds->gui_timer_interval ? - ds->gui_timer_interval : - GUI_REFRESH_INTERVAL) - + qemu_get_clock(rt_clock)); + DisplayChangeListener *dcl = ds->listeners; + + dpy_refresh(ds); + + while (dcl != NULL) { + if (dcl->gui_timer_interval && + dcl->gui_timer_interval < interval) + interval = dcl->gui_timer_interval; + dcl = dcl->next; + } + qemu_mod_timer(ds->gui_timer, interval + qemu_get_clock(rt_clock)); } struct vm_change_state_entry { @@ -8394,6 +8402,7 @@ "-no-frame open SDL window without a frame and window decorations\n" "-alt-grab use Ctrl-Alt-Shift to grab mouse (instead of Ctrl-Alt)\n" "-no-quit disable SDL window close capability\n" + "-sdl enable SDL\n" #endif #ifdef CONFIG_OPENGL "-disable-opengl disable OpenGL rendering, using SDL" @@ -8607,6 +8616,7 @@ QEMU_OPTION_no_frame, QEMU_OPTION_alt_grab, QEMU_OPTION_no_quit, + QEMU_OPTION_sdl, QEMU_OPTION_domid, QEMU_OPTION_disable_opengl, QEMU_OPTION_direct_pci, @@ -8727,6 +8737,7 @@ { "no-frame", 0, QEMU_OPTION_no_frame }, { "alt-grab", 0, QEMU_OPTION_alt_grab }, { "no-quit", 0, QEMU_OPTION_no_quit }, + { "sdl", 0, QEMU_OPTION_sdl }, #endif #ifdef CONFIG_OPENGL { "disable-opengl", 0, QEMU_OPTION_disable_opengl }, @@ -9048,6 +9059,7 @@ const char *kernel_filename, *kernel_cmdline; const char *boot_devices = ""; DisplayState *ds = &display_state; + DisplayChangeListener *dcl; int cyls, heads, secs, translation; const char *net_clients[MAX_NET_CLIENTS]; int nb_net_clients; @@ -9593,6 +9605,9 @@ break; case QEMU_OPTION_no_quit: no_quit = 1; + break; + case QEMU_OPTION_sdl: + sdl = 1; break; #endif case QEMU_OPTION_disable_opengl: @@ -10033,6 +10048,7 @@ /* terminal init */ memset(&display_state, 0, sizeof(display_state)); + ds->surface = qemu_create_displaysurface(640, 480, 32, 640 * 4); #ifdef CONFIG_STUBDOM if (xenfb_pv_display_init(ds) == 0) { } else @@ -10042,33 +10058,35 @@ fprintf(stderr, "fatal: -nographic can''t be used with -curses\n"); exit(1); } - /* nearly nothing to do */ - dumb_display_init(ds); - } else if (vnc_display != NULL || vncunused != 0) { - int vnc_display_port; - char password[20]; - vnc_display_init(ds); - xenstore_read_vncpasswd(domid, password, sizeof(password)); - vnc_display_password(ds, password); - vnc_display_port = vnc_display_open(ds, vnc_display, vncunused); - if (vnc_display_port < 0) - exit(1); - xenstore_write_vncport(vnc_display_port); - } else + } else { #if defined(CONFIG_CURSES) - if (curses) { - curses_display_init(ds, full_screen); - } else -#endif - { + if (curses) { + /* At the moment curses cannot be used with other displays */ + curses_display_init(ds, full_screen); + } else +#endif + { + if (vnc_display != NULL || vncunused != 0) { + int vnc_display_port; + char password[20]; + vnc_display_init(ds); + xenstore_read_vncpasswd(domid, password, sizeof(password)); + vnc_display_password(ds, password); + vnc_display_port = vnc_display_open(ds, vnc_display, vncunused); + if (vnc_display_port < 0) + exit(1); + xenstore_write_vncport(vnc_display_port); + } #if defined(CONFIG_SDL) - sdl_display_init(ds, full_screen, no_frame, opengl_enabled); + if (sdl || !vnc_display) + sdl_display_init(ds, full_screen, no_frame, opengl_enabled); #elif defined(CONFIG_COCOA) - cocoa_display_init(ds, full_screen); -#else - dumb_display_init(ds); -#endif - } + if (sdl || !vnc_display) + cocoa_display_init(ds, full_screen); +#endif + } + } + dpy_resize(ds); #ifndef _WIN32 /* must be after terminal init, SDL library changes signal handlers */ @@ -10155,9 +10173,13 @@ } } - if (display_state.dpy_refresh) { - display_state.gui_timer = qemu_new_timer(rt_clock, gui_update, &display_state); - qemu_mod_timer(display_state.gui_timer, qemu_get_clock(rt_clock)); + dcl = ds->listeners; + while (dcl != NULL) { + if (dcl->dpy_refresh != NULL) { + display_state.gui_timer = qemu_new_timer(rt_clock, gui_update, &display_state); + qemu_mod_timer(display_state.gui_timer, qemu_get_clock(rt_clock)); + } + dcl = dcl->next; } #ifdef CONFIG_GDBSTUB diff --git a/vnc.c b/vnc.c --- a/vnc.c +++ b/vnc.c @@ -232,6 +232,7 @@ }; static VncState *vnc_state; /* needed for info vnc */ +static DisplayChangeListener *dcl; #define DIRTY_PIXEL_BITS 64 #define X2DP_DOWN(vs, x) ((x) >> (vs)->dirty_pixel_shift) @@ -277,7 +278,7 @@ static void dequeue_framebuffer_update(VncState *vs); static int is_empty_queue(VncState *vs); static void free_queue(VncState *vs); -static void vnc_colourdepth(DisplayState *ds, int depth); +static void vnc_colordepth(DisplayState *ds); #if 0 static inline void vnc_set_bit(uint32_t *d, int k) @@ -340,8 +341,8 @@ mask = ~(0ULL); h += y; - if (h > vs->ds->height) - h = vs->ds->height; + if (h > ds_get_height(vs->ds)) + h = ds_get_height(vs->ds); for (; y < h; y++) row[y] |= mask; } @@ -369,69 +370,43 @@ vnc_write_s32(vs, encoding); } -static void vnc_dpy_resize_shared(DisplayState *ds, int w, int h, int depth, int linesize, void *pixels) +static void vnc_dpy_resize(DisplayState *ds) { - static int allocated; int size_changed; VncState *vs = ds->opaque; int o; - vnc_colourdepth(ds, depth); - if (!ds->shared_buf) { - ds->linesize = w * vs->depth; - if (allocated) - ds->data = qemu_realloc(ds->data, h * ds->linesize); - else - ds->data = malloc(h * ds->linesize); - allocated = 1; - } else { - ds->linesize = linesize; - if (allocated) { - free(ds->data); - allocated = 0; - } - } - vs->old_data = qemu_realloc(vs->old_data, h * ds->linesize); - vs->dirty_row = qemu_realloc(vs->dirty_row, h * sizeof(vs->dirty_row[0])); - vs->update_row = qemu_realloc(vs->update_row, h * sizeof(vs->dirty_row[0])); + vs->old_data = qemu_realloc(vs->old_data, ds_get_height(ds) * ds_get_linesize(ds)); + vs->dirty_row = qemu_realloc(vs->dirty_row, ds_get_height(ds) * sizeof(vs->dirty_row[0])); + vs->update_row = qemu_realloc(vs->update_row, ds_get_height(ds) * sizeof(vs->dirty_row[0])); - if (ds->data == NULL || vs->old_data == NULL || - vs->dirty_row == NULL || vs->update_row == NULL) { + if (vs->old_data == NULL || vs->dirty_row == NULL || vs->update_row == NULL) { fprintf(stderr, "vnc: memory allocation failed\n"); exit(1); } - if (ds->depth != vs->depth * 8) { - ds->depth = vs->depth * 8; + if (ds_get_bytes_per_pixel(ds) != vs->depth) console_color_init(ds); - } - size_changed = ds->width != w || ds->height != h; - ds->width = w; - ds->height = h; + vnc_colordepth(ds); + size_changed = ds_get_width(ds) != vs->width || ds_get_height(ds) != vs->height; if (vs->csock != -1 && vs->has_resize && size_changed) { - vs->width = ds->width; - vs->height = ds->height; + vs->width = ds_get_width(ds); + vs->height = ds_get_height(ds); if (vs->update_requested) { vnc_write_u8(vs, 0); /* msg id */ vnc_write_u8(vs, 0); vnc_write_u16(vs, 1); /* number of rects */ - vnc_framebuffer_update(vs, 0, 0, ds->width, ds->height, -223); + vnc_framebuffer_update(vs, 0, 0, ds_get_width(ds), ds_get_height(ds), -223); vnc_flush(vs); vs->update_requested--; } else { - enqueue_framebuffer_update(vs, 0, 0, ds->width, ds->height, -223); + enqueue_framebuffer_update(vs, 0, 0, ds_get_width(ds), ds_get_height(ds), -223); } } vs->dirty_pixel_shift = 0; - for (o = DIRTY_PIXEL_BITS; o < ds->width; o *= 2) + for (o = DIRTY_PIXEL_BITS; o < ds_get_width(ds); o *= 2) vs->dirty_pixel_shift++; - framebuffer_set_updated(vs, 0, 0, ds->width, ds->height); - if (ds->shared_buf) ds->data = pixels; -} - -static void vnc_dpy_resize(DisplayState *ds, int w, int h) -{ - vnc_dpy_resize_shared(ds, w, h, 0, w * (ds->depth / 8), NULL); + framebuffer_set_updated(vs, 0, 0, ds_get_width(ds), ds_get_height(ds)); } /* fastest code */ @@ -589,19 +564,8 @@ static void vnc_copy(DisplayState *ds, int src_x, int src_y, int dst_x, int dst_y, int w, int h) { - int src, dst; - uint8_t *src_row; - uint8_t *dst_row; - uint8_t *old_row; - int y = 0; - int pitch = ds_get_linesize(ds); VncState *vs = ds->opaque; int updating_client = 1; - - if (ds->shared_buf) { - framebuffer_set_updated(vs, dst_x, dst_y, w, h); - return; - } if (!vs->update_requested || src_x < vs->visible_x || src_y < vs->visible_y || @@ -613,27 +577,7 @@ updating_client = 0; if (updating_client) - _vnc_update_client(vs); - - if (dst_y > src_y) { - y = h - 1; - pitch = -pitch; - } - - src = (ds_get_linesize(ds) * (src_y + y) + vs->depth * src_x); - dst = (ds_get_linesize(ds) * (dst_y + y) + vs->depth * dst_x); - - src_row = ds_get_data(ds) + src; - dst_row = ds_get_data(ds) + dst; - old_row = vs->old_data + dst; - - for (y = 0; y < h; y++) { - memmove(old_row, src_row, w * vs->depth); - memmove(dst_row, src_row, w * vs->depth); - src_row += pitch; - dst_row += pitch; - old_row += pitch; - } + _vnc_update_client(vs); if (updating_client && vs->csock != -1 && !vs->has_update) { vnc_write_u8(vs, 0); /* msg id */ @@ -695,16 +639,16 @@ now = qemu_get_clock(rt_clock); if (vs->width != DP2X(vs, DIRTY_PIXEL_BITS)) - width_mask = (1ULL << X2DP_UP(vs, vs->ds->width)) - 1; + width_mask = (1ULL << X2DP_UP(vs, ds_get_width(vs->ds))) - 1; else width_mask = ~(0ULL); /* Walk through the dirty map and eliminate tiles that really aren''t dirty */ - row = vs->ds->data; + row = ds_get_data(vs->ds); old_row = vs->old_data; - for (y = 0; y < vs->ds->height; y++) { + for (y = 0; y < ds_get_height(vs->ds); y++) { if (vs->dirty_row[y] & width_mask) { int x; uint8_t *ptr, *old_ptr; @@ -712,7 +656,7 @@ ptr = row; old_ptr = old_row; - for (x = 0; x < X2DP_UP(vs, vs->ds->width); x++) { + for (x = 0; x < X2DP_UP(vs, ds_get_width(vs->ds)); x++) { if (vs->dirty_row[y] & (1ULL << x)) { if (memcmp(old_ptr, ptr, tile_bytes)) { vs->has_update = 1; @@ -727,12 +671,12 @@ } } - row += vs->ds->linesize; - old_row += vs->ds->linesize; + row += ds_get_linesize(vs->ds); + old_row += ds_get_linesize(vs->ds); } - if (!vs->has_update || vs->visible_y >= vs->ds->height || - vs->visible_x >= vs->ds->width) + if (!vs->has_update || vs->visible_y >= ds_get_height(vs->ds) || + vs->visible_x >= ds_get_width(vs->ds)) goto backoff; /* Count rectangles */ @@ -743,11 +687,11 @@ vnc_write_u16(vs, 0); maxy = vs->visible_y + vs->visible_h; - if (maxy > vs->ds->height) - maxy = vs->ds->height; + if (maxy > ds_get_height(vs->ds)) + maxy = ds_get_height(vs->ds); maxx = vs->visible_x + vs->visible_w; - if (maxx > vs->ds->width) - maxx = vs->ds->width; + if (maxx > ds_get_width(vs->ds)) + maxx = ds_get_width(vs->ds); for (y = vs->visible_y; y < maxy; y++) { int x; @@ -791,7 +735,7 @@ vs->has_update = 0; vnc_flush(vs); vs->last_update_time = now; - vs->ds->idle = 0; + dcl->idle = 0; vs->timer_interval /= 2; if (vs->timer_interval < VNC_REFRESH_INTERVAL_BASE) @@ -806,7 +750,7 @@ vs->timer_interval = VNC_REFRESH_INTERVAL_MAX; if (now - vs->last_update_time >= VNC_MAX_UPDATE_INTERVAL) { if (!vs->update_requested) { - vs->ds->idle = 1; + dcl->idle = 1; } else { /* Send a null update. If the client is no longer interested (e.g. minimised) it''ll ignore this, and we @@ -992,7 +936,7 @@ qemu_set_fd_handler2(vs->csock, NULL, NULL, NULL, NULL); closesocket(vs->csock); vs->csock = -1; - vs->ds->idle = 1; + dcl->idle = 1; buffer_reset(&vs->input); buffer_reset(&vs->output); free_queue(vs); @@ -1213,12 +1157,12 @@ vnc_write_u8(vs, 0); vnc_write_u16(vs, 1); vnc_framebuffer_update(vs, absolute, 0, - vs->ds->width, vs->ds->height, -257); + ds_get_width(vs->ds), ds_get_height(vs->ds), -257); vnc_flush(vs); vs->update_requested--; } else { enqueue_framebuffer_update(vs, absolute, 0, - vs->ds->width, vs->ds->height, -257); + ds_get_width(vs->ds), ds_get_height(vs->ds), -257); } } vs->absolute = absolute; @@ -1241,8 +1185,8 @@ dz = 1; if (vs->absolute) { - kbd_mouse_event(x * 0x7FFF / (vs->ds->width - 1), - y * 0x7FFF / (vs->ds->height - 1), + kbd_mouse_event(x * 0x7FFF / (ds_get_width(vs->ds) - 1), + y * 0x7FFF / (ds_get_height(vs->ds) - 1), dz, buttons); } else if (vs->has_pointer_type_change) { x -= 0x7FFF; @@ -1568,7 +1512,7 @@ vs->has_pointer_type_change = 0; vs->has_WMVi = 0; vs->absolute = -1; - vs->ds->dpy_copy = NULL; + dcl->dpy_copy = NULL; for (i = n_encodings - 1; i >= 0; i--) { switch (encodings[i]) { @@ -1576,7 +1520,7 @@ vs->has_hextile = 0; break; case 1: /* CopyRect */ - vs->ds->dpy_copy = vnc_copy; + dcl->dpy_copy = vnc_copy; break; case 5: /* Hextile */ vs->has_hextile = 1; @@ -1717,30 +1661,15 @@ vnc_write(vs, pad, 3); /* padding */ } -static void vnc_dpy_setdata(DisplayState *ds, void *pixels) +static void vnc_dpy_setdata(DisplayState *ds) { - ds->data = pixels; + /* We don''t have to do anything */ } -static void vnc_colourdepth(DisplayState *ds, int depth) +static void vnc_colordepth(DisplayState *ds) { int host_big_endian_flag; struct VncState *vs = ds->opaque; - - switch (depth) { - case 24: - ds->shared_buf = 0; - if (ds->depth == 32) return; - depth = 32; - break; - case 8: - case 0: - ds->shared_buf = 0; - return; - default: - ds->shared_buf = 1; - break; - } #ifdef WORDS_BIGENDIAN host_big_endian_flag = 1; @@ -1748,9 +1677,9 @@ host_big_endian_flag = 0; #endif - switch (depth) { + switch (ds_get_bits_per_pixel(ds)) { case 8: - vs->depth = depth / 8; + vs->depth = 1; vs->red_max1 = 7; vs->green_max1 = 7; vs->blue_max1 = 3; @@ -1759,7 +1688,7 @@ vs->blue_shift1 = 0; break; case 16: - vs->depth = depth / 8; + vs->depth = 2; vs->red_max1 = 31; vs->green_max1 = 63; vs->blue_max1 = 31; @@ -1787,12 +1716,12 @@ vnc_write_u8(vs, 0); /* msg id */ vnc_write_u8(vs, 0); vnc_write_u16(vs, 1); /* number of rects */ - vnc_framebuffer_update(vs, 0, 0, ds->width, ds->height, 0x574D5669); + vnc_framebuffer_update(vs, 0, 0, ds_get_width(ds), ds_get_height(ds), 0x574D5669); pixel_format_message(vs); vnc_flush(vs); vs->update_requested--; } else { - enqueue_framebuffer_update(vs, 0, 0, ds->width, ds->height, 0x574D5669); + enqueue_framebuffer_update(vs, 0, 0, ds_get_width(ds), ds_get_height(ds), 0x574D5669); } } else { if (vs->pix_bpp == 4 && vs->depth == 4 && @@ -2536,17 +2465,17 @@ vs->csock = accept(vs->lsock, (struct sockaddr *)&addr, &addrlen); if (vs->csock != -1) { VNC_DEBUG("New client on socket %d\n", vs->csock); - vs->ds->idle = 0; + dcl->idle = 0; socket_set_nonblock(vs->csock); qemu_set_fd_handler2(vs->csock, NULL, vnc_client_read, NULL, opaque); vnc_write(vs, "RFB 003.008\n", 12); vnc_flush(vs); vnc_read_when(vs, protocol_version, 12); - framebuffer_set_updated(vs, 0, 0, vs->ds->width, vs->ds->height); + framebuffer_set_updated(vs, 0, 0, ds_get_width(vs->ds), ds_get_height(vs->ds)); vs->has_resize = 0; vs->has_hextile = 0; vs->update_requested = 0; - vs->ds->dpy_copy = NULL; + dcl->dpy_copy = NULL; vnc_timer_init(vs); } } @@ -2558,11 +2487,12 @@ VncState *vs; vs = qemu_mallocz(sizeof(VncState)); - if (!vs) + dcl = qemu_mallocz(sizeof(DisplayChangeListener)); + if (!vs || !dcl) exit(1); ds->opaque = vs; - ds->idle = 1; + dcl->idle = 1; vnc_state = vs; vs->display = NULL; vs->password = NULL; @@ -2582,17 +2512,11 @@ exit(1); vs->modifiers_state[0x45] = 1; /* NumLock on - on boot */ - vs->ds->data = NULL; - vs->ds->dpy_update = vnc_dpy_update; - vs->ds->dpy_resize = vnc_dpy_resize; - vs->ds->dpy_setdata = vnc_dpy_setdata; - vs->ds->dpy_resize_shared = vnc_dpy_resize_shared; - vs->ds->dpy_refresh = NULL; - - vs->ds->width = 640; - vs->ds->height = 400; - vs->ds->linesize = 640 * 4; - vnc_dpy_resize_shared(ds, ds->width, ds->height, 24, ds->linesize, NULL); + dcl->dpy_update = vnc_dpy_update; + dcl->dpy_resize = vnc_dpy_resize; + dcl->dpy_setdata = vnc_dpy_setdata; + dcl->dpy_refresh = NULL; + register_displaychangelistener(ds, dcl); } #ifdef CONFIG_VNC_TLS diff --git a/xenfbfront.c b/xenfbfront.c --- a/xenfbfront.c +++ b/xenfbfront.c @@ -23,6 +23,7 @@ static char *kbd_path, *fb_path; static unsigned char linux2scancode[KEY_MAX + 1]; +static DisplayChangeListener *dcl; extern uint32_t vga_ram_size; @@ -47,50 +48,27 @@ fbfront_update(fb_dev, x, y, w, h); } -static void xenfb_pv_resize_shared(DisplayState *ds, int w, int h, int depth, int linesize, void *pixels) +static void xenfb_pv_resize(DisplayState *ds) { XenFBState *xs = ds->opaque; struct fbfront_dev *fb_dev = xs->fb_dev; int offset; - fprintf(stderr,"resize to %dx%d@%d, %d required\n", w, h, depth, linesize); - ds->width = w; - ds->height = h; - if (!depth) { - ds->shared_buf = 0; - ds->depth = 32; - } else { - ds->shared_buf = 1; - ds->depth = depth; - } - if (!linesize) - ds->shared_buf = 0; - if (!ds->shared_buf) - linesize = w * 4; - ds->linesize = linesize; + fprintf(stderr,"resize to %dx%d@%d, %d required\n", ds_get_width(ds), ds_get_height(ds), ds_get_bits_per_pixel(ds), ds_get_linesize(ds)); if (!fb_dev) return; - if (ds->shared_buf) { - offset = pixels - xs->vga_vram; - ds->data = pixels; - fbfront_resize(fb_dev, ds_get_width(ds), ds_get_height(ds), ds_get_linesize(ds), ds_get_bits_per_pixel(ds), offset); - } else { - ds->data = xs->nonshared_vram; - fbfront_resize(fb_dev, w, h, linesize, ds_get_bits_per_pixel(ds), vga_ram_size); - } + if (!(ds->surface->flags & QEMU_ALLOCATED_FLAG)) + offset = ((void *) ds_get_data(ds)) - xs->vga_vram; + else + offset = vga_ram_size; + fbfront_resize(fb_dev, ds_get_width(ds), ds_get_height(ds), ds_get_linesize(ds), ds_get_bits_per_pixel(ds), offset); } -static void xenfb_pv_resize(DisplayState *ds, int w, int h) -{ - xenfb_pv_resize_shared(ds, w, h, 0, 0, NULL); -} - -static void xenfb_pv_setdata(DisplayState *ds, void *pixels) +static void xenfb_pv_setdata(DisplayState *ds) { XenFBState *xs = ds->opaque; struct fbfront_dev *fb_dev = xs->fb_dev; - int offset = pixels - xs->vga_vram; - ds->data = pixels; + int offset = ((void *) ds_get_data(ds)) - xs->vga_vram; if (!fb_dev) return; fbfront_resize(fb_dev, ds_get_width(ds), ds_get_height(ds), ds_get_linesize(ds), ds_get_bits_per_pixel(ds), offset); @@ -115,12 +93,12 @@ case XENFB_TYPE_REFRESH_PERIOD: if (buf[i].refresh_period.period == XENFB_NO_REFRESH) { /* Sleeping interval */ - ds->idle = 1; - ds->gui_timer_interval = 500; + dcl->idle = 1; + dcl->gui_timer_interval = 500; } else { /* Set interval */ - ds->idle = 0; - ds->gui_timer_interval = buf[i].refresh_period.period; + dcl->idle = 0; + dcl->gui_timer_interval = buf[i].refresh_period.period; } default: /* ignore unknown events */ @@ -247,22 +225,19 @@ init_SEMAPHORE(&xs->kbd_sem, 0); xs->ds = ds; + xs->nonshared_vram = ds_get_data(ds); create_thread("kbdfront", kbdfront_thread, (void*) xs); - ds->data = xs->nonshared_vram = qemu_memalign(PAGE_SIZE, vga_ram_size); - memset(ds->data, 0, vga_ram_size); + dcl = qemu_mallocz(sizeof(DisplayChangeListener)); + if (!dcl) + exit(1); ds->opaque = xs; - ds->depth = 32; - ds->bgr = 0; - ds->width = 640; - ds->height = 400; - ds->linesize = 640 * 4; - ds->dpy_update = xenfb_pv_update; - ds->dpy_resize = xenfb_pv_resize; - ds->dpy_resize_shared = xenfb_pv_resize_shared; - ds->dpy_setdata = xenfb_pv_setdata; - ds->dpy_refresh = xenfb_pv_refresh; + dcl->dpy_update = xenfb_pv_update; + dcl->dpy_resize = xenfb_pv_resize; + dcl->dpy_setdata = xenfb_pv_setdata; + dcl->dpy_refresh = xenfb_pv_refresh; + register_displaychangelistener(ds, dcl); return 0; } @@ -295,11 +270,10 @@ } free(fb_path); - if (ds->shared_buf) { - offset = (void*) ds->data - xs->vga_vram; + if (!(ds->surface->flags & QEMU_ALLOCATED_FLAG)) { + offset = (void*) ds_get_data(ds) - xs->vga_vram; } else { offset = vga_ram_size; - ds->data = xs->nonshared_vram; } if (offset) fbfront_resize(fb_dev, ds_get_width(ds), ds_get_height(ds), ds_get_linesize(ds), ds_get_bits_per_pixel(ds), offset); _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel