diff options
-rw-r--r-- | console.c | 171 | ||||
-rw-r--r-- | console.h | 135 | ||||
-rw-r--r-- | curses.c | 38 | ||||
-rw-r--r-- | hw/cirrus_vga.c | 19 | ||||
-rw-r--r-- | hw/nseries.c | 3 | ||||
-rw-r--r-- | hw/palm.c | 3 | ||||
-rw-r--r-- | hw/vga.c | 101 | ||||
-rw-r--r-- | hw/vga_int.h | 2 | ||||
-rw-r--r-- | qemu-common.h | 3 | ||||
-rw-r--r-- | sdl.c | 88 | ||||
-rw-r--r-- | vl.c | 87 | ||||
-rw-r--r-- | vnc.c | 107 |
12 files changed, 498 insertions, 259 deletions
@@ -1044,12 +1044,15 @@ void console_select(unsigned int index) 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 && s->g_width && s->g_height - && (s->g_width != ds_get_width(s->ds) || s->g_height != ds_get_height(s->ds))) - dpy_resize(s->ds, s->g_width, s->g_height); + 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(); } } @@ -1157,16 +1160,6 @@ void kbd_put_keysym(int keysym) static void text_console_invalidate(void *opaque) { 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); } @@ -1346,13 +1339,12 @@ CharDriverState *text_console_init(DisplayState *ds, const char *p) 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); } } @@ -1360,12 +1352,137 @@ 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); - } + dpy_copy(console->ds, src_x, src_y, dst_x, dst_y, w, h); } } + +static 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 8: + pf.rmask = 0x000000E0; + pf.gmask = 0x0000001C; + pf.bmask = 0x00000003; + pf.rmax = 7; + pf.gmax = 7; + pf.bmax = 3; + pf.rshift = 5; + pf.gshift = 2; + pf.bshift = 0; + break; + 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: + case 32: + 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; + 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); +} @@ -73,75 +73,168 @@ void kbd_put_keysym(int keysym); /* consoles */ -struct DisplayState { - uint8_t *data; - int linesize; - int depth; - int bgr; /* BGR color order instead of RGB. Only valid for depth == 32 */ +#define QEMU_BIG_ENDIAN_FLAG 0x01 +#define QEMU_ALLOCATED_FLAG 0x02 + +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; - 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 */ 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)(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); + +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_cursor(DisplayState *s, int x, int y) +static inline void dpy_setdata(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_setdata) dcl->dpy_setdata(s); + dcl = dcl->next; + } +} + +static inline void dpy_refresh(DisplayState *s) +{ + 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; @@ -97,13 +97,13 @@ static void curses_calc_pad(void) } } -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 @@ static void curses_refresh(DisplayState *ds) 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 @@ static void curses_refresh(DisplayState *ds) 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 @@ static void curses_keyboard_setup(void) 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 @@ void curses_display_init(DisplayState *ds, int full_screen) #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 index f9ad479573..55c2cc18a1 100644 --- a/hw/cirrus_vga.c +++ b/hw/cirrus_vga.c @@ -793,22 +793,9 @@ static int cirrus_bitblt_videotovideo_copy(CirrusVGAState * s) if (BLTUNSAFE(s)) return 0; - 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 { - (*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 index d52a5e9efd..9559fd0245 100644 --- a/hw/nseries.c +++ b/hw/nseries.c @@ -1360,7 +1360,8 @@ static void n8x0_init(ram_addr_t ram_size, const char *boot_device, /* 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 = { @@ -277,7 +277,8 @@ static void palmte_init(ram_addr_t ram_size, int vga_ram_size, /* 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 = { @@ -1243,6 +1243,10 @@ static void vga_get_text_resolution(VGAState *s, int *pwidth, int *pheight, *pcheight = cheight; } +typedef unsigned int rgb_to_pixel_dup_func(unsigned int r, unsigned int g, unsigned b); + +static rgb_to_pixel_dup_func *rgb_to_pixel_dup_table[NB_DEPTHS]; + /* * Text mode update * Missing: @@ -1266,9 +1270,6 @@ static void vga_draw_text(VGAState *s, int full_update) vga_dirty_log_stop(s); - full_update |= update_palette16(s); - palette = s->last_palette; - /* compute font data address (in plane 2) */ v = s->sr[3]; offset = (((v >> 4) & 1) | ((v << 1) & 6)) * 8192 * 4 + 2; @@ -1303,16 +1304,23 @@ static void vga_draw_text(VGAState *s, int full_update) } if (width != s->last_width || height != s->last_height || - cw != s->last_cw || cheight != s->last_ch) { + cw != s->last_cw || cheight != s->last_ch || s->last_depth) { 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); + s->last_depth = 0; s->last_width = width; s->last_height = height; s->last_ch = cheight; s->last_cw = cw; full_update = 1; } + s->rgb_to_pixel = + rgb_to_pixel_dup_table[get_depth_index(s->ds)]; + full_update |= update_palette16(s); + palette = s->last_palette; + x_incr = cw * ((ds_get_bits_per_pixel(s->ds) + 7) >> 3); + cursor_offset = ((s->cr[0x0e] << 8) | s->cr[0x0f]) - s->start_addr; if (cursor_offset != s->cursor_offset || s->cr[0xa] != s->cursor_start || @@ -1504,8 +1512,6 @@ static vga_draw_line_func *vga_draw_line_table[NB_DEPTHS * VGA_DRAW_LINE_NB] = { vga_draw_line32_16bgr, }; -typedef unsigned int rgb_to_pixel_dup_func(unsigned int r, unsigned int g, unsigned b); - static rgb_to_pixel_dup_func *rgb_to_pixel_dup_table[NB_DEPTHS] = { rgb_to_pixel8_dup, rgb_to_pixel15_dup, @@ -1580,7 +1586,7 @@ static void vga_sync_dirty_bitmap(VGAState *s) */ static void vga_draw_graphic(VGAState *s, int full_update) { - int y1, y, update, page_min, page_max, linesize, y_start, double_scan, mask; + int y1, y, update, page_min, page_max, linesize, y_start, double_scan, mask, depth; int width, height, shift_control, line_offset, page0, page1, bwidth, bits; int disp_width, multi_scan, multi_run; uint8_t *d; @@ -1663,16 +1669,41 @@ static void vga_draw_graphic(VGAState *s, int full_update) } vga_draw_line = vga_draw_line_table[v * NB_DEPTHS + get_depth_index(s->ds)]; - if (disp_width != s->last_width || - height != s->last_height) { - qemu_console_resize(s->console, disp_width, height); + depth = s->get_bpp(s); + if (s->line_offset != s->last_line_offset || + disp_width != s->last_width || + height != s->last_height || + s->last_depth != depth) { + if (depth == 16 || depth == 32) { + 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)); + 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); } - if (s->cursor_invalidate) + + s->rgb_to_pixel = + rgb_to_pixel_dup_table[get_depth_index(s->ds)]; + + if (!is_buffer_shared(s->ds->surface) && s->cursor_invalidate) s->cursor_invalidate(s); line_offset = s->line_offset; @@ -1718,9 +1749,11 @@ static void vga_draw_graphic(VGAState *s, int full_update) page_min = page0; if (page1 > page_max) page_max = page1; - vga_draw_line(s, d, s->vram_ptr + addr, width); - if (s->cursor_draw_line) - s->cursor_draw_line(s, d, y); + 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); + } } else { if (y_start >= 0) { /* flush to display */ @@ -1767,6 +1800,8 @@ static void vga_draw_blank(VGAState *s, int full_update) return; vga_dirty_log_stop(s); + s->rgb_to_pixel = + rgb_to_pixel_dup_table[get_depth_index(s->ds)]; if (ds_get_bits_per_pixel(s->ds) == 8) val = s->rgb_to_pixel(0, 0, 0); else @@ -1793,9 +1828,6 @@ static void vga_update_display(void *opaque) if (ds_get_bits_per_pixel(s->ds) == 0) { /* nothing to do */ } else { - s->rgb_to_pixel = - rgb_to_pixel_dup_table[get_depth_index(s->ds)]; - full_update = 0; if (!(s->ar_index & 0x20)) { graphic_mode = GMODE_BLANK; @@ -1966,7 +1998,9 @@ static void vga_update_text(void *opaque, console_ch_t *chardata) 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; @@ -2047,7 +2081,9 @@ static void vga_update_text(void *opaque, console_ch_t *chardata) 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 ++, ' '); @@ -2505,12 +2541,8 @@ static void vga_save_dpy_update(DisplayState *s, { } -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) @@ -2570,24 +2602,29 @@ static void vga_screen_dump_common(VGAState *s, const char *filename, int w, int h) { 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)); - ds->linesize = w * sizeof(uint32_t); - ds->data = qemu_mallocz(h * ds->linesize); s->ds = ds; s->graphic_mode = -1; vga_update_display(s); - ppm_save(filename, ds->data, w, h, ds->linesize); - qemu_free(ds->data); + + 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/vga_int.h b/hw/vga_int.h index 39b7367dff..319678a9a9 100644 --- a/hw/vga_int.h +++ b/hw/vga_int.h @@ -154,9 +154,11 @@ typedef void (* vga_update_retrace_info_fn)(struct VGAState *s); uint32_t line_compare; \ uint32_t start_addr; \ uint32_t plane_updated; \ + uint32_t last_line_offset; \ uint8_t last_cw, last_ch; \ uint32_t last_width, last_height; /* in chars or pixels */ \ uint32_t last_scr_width, last_scr_height; /* in pixels */ \ + uint32_t last_depth; /* in bits */ \ uint8_t cursor_start, cursor_end; \ uint32_t cursor_offset; \ unsigned int (*rgb_to_pixel)(unsigned int r, \ diff --git a/qemu-common.h b/qemu-common.h index db6c1a612c..d83e61be35 100644 --- a/qemu-common.h +++ b/qemu-common.h @@ -166,6 +166,9 @@ typedef struct HCIInfo HCIInfo; 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; @@ -31,7 +31,9 @@ #include <signal.h> #endif -static SDL_Surface *screen; +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,11 +54,34 @@ static SDL_Cursor *guest_sprite = 0; static void sdl_update(DisplayState *ds, int x, int y, int w, int h) { + 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); - SDL_UpdateRect(screen, x, y, w, h); + + SDL_BlitSurface(guest_screen, &rec, real_screen, &rec); + SDL_Flip(real_screen); +} + +static void sdl_setdata(DisplayState *ds) +{ + 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(DisplayState *ds, int w, int h) +static void sdl_resize(DisplayState *ds) { int flags; @@ -68,40 +93,23 @@ static void sdl_resize(DisplayState *ds, int w, int h) if (gui_noframe) flags |= SDL_NOFRAME; - width = w; - height = h; - again: - screen = SDL_SetVideoMode(w, h, 0, flags); - if (!screen) { + real_screen = SDL_SetVideoMode(ds_get_width(ds), ds_get_height(ds), 0, flags); + if (!real_screen) { fprintf(stderr, "Could not open SDL display\n"); exit(1); } - if (!screen->pixels && (flags & SDL_HWSURFACE) && (flags & SDL_FULLSCREEN)) { + if (!real_screen->pixels && (flags & SDL_HWSURFACE) && (flags & SDL_FULLSCREEN)) { flags &= ~SDL_HWSURFACE; goto again; } - if (!screen->pixels) { + if (!real_screen->pixels) { fprintf(stderr, "Could not open SDL display\n"); exit(1); } - ds->data = screen->pixels; - ds->linesize = screen->pitch; - ds->depth = screen->format->BitsPerPixel; - /* SDL BitsPerPixel never indicates any values other than - multiples of 8, so we need to check for strange depths. */ - if (ds->depth == 16) { - uint32_t mask; - - mask = screen->format->Rmask; - mask |= screen->format->Gmask; - mask |= screen->format->Bmask; - if ((mask & 0x8000) == 0) - ds->depth = 15; - } - ds->width = w; - ds->height = h; + + sdl_setdata(ds); } /* generic keyboard conversion */ @@ -337,7 +345,7 @@ static void sdl_send_mouse_event(int dx, int dy, int dz, int x, int y, int state static void toggle_full_screen(DisplayState *ds) { gui_fullscreen = !gui_fullscreen; - sdl_resize(ds, screen->w, screen->h); + sdl_resize(ds); if (gui_fullscreen) { gui_saved_grab = gui_grab; sdl_grab_start(); @@ -366,7 +374,7 @@ static void sdl_refresh(DisplayState *ds) while (SDL_PollEvent(ev)) { switch (ev->type) { case SDL_VIDEOEXPOSE: - sdl_update(ds, 0, 0, screen->w, screen->h); + sdl_update(ds, 0, 0, real_screen->w, real_screen->h); break; case SDL_KEYDOWN: case SDL_KEYUP: @@ -521,12 +529,12 @@ static void sdl_refresh(DisplayState *ds) 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; @@ -539,7 +547,7 @@ static void sdl_refresh(DisplayState *ds) static void sdl_fill(DisplayState *ds, int x, int y, int w, int h, uint32_t c) { SDL_Rect dst = { x, y, w, h }; - SDL_FillRect(screen, &dst, c); + SDL_FillRect(real_screen, &dst, c); } static void sdl_mouse_warp(int x, int y, int on) @@ -635,14 +643,18 @@ void sdl_display_init(DisplayState *ds, int full_screen, int no_frame) exit(1); } - ds->dpy_update = sdl_update; - ds->dpy_resize = sdl_resize; - ds->dpy_refresh = sdl_refresh; - ds->dpy_fill = sdl_fill; + 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; + dcl->dpy_fill = sdl_fill; ds->mouse_set = sdl_mouse_warp; ds->cursor_define = sdl_mouse_define; + register_displaychangelistener(ds, dcl); - sdl_resize(ds, 640, 400); sdl_update_caption(); SDL_EnableKeyRepeat(250, 50); gui_grab = 0; @@ -193,6 +193,7 @@ enum vga_retrace_method vga_retrace_method = VGA_RETRACE_DUMB; 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; @@ -2764,20 +2765,21 @@ static void dumb_update(DisplayState *ds, int x, int y, int w, int h) { } -static void dumb_resize(DisplayState *ds, int w, int h) +static void dumb_resize(DisplayState *ds) { } 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 = NULL; - ds->gui_timer_interval = 0; - 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); } /***********************************************************/ @@ -3360,13 +3362,19 @@ static QEMUMachine *find_machine(const char *name) 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 { @@ -3848,6 +3856,7 @@ static void help(int exitcode) "-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 TARGET_I386 "-no-fd-bootchk disable boot signature checking for floppy disks\n" @@ -4064,6 +4073,7 @@ enum { QEMU_OPTION_no_frame, QEMU_OPTION_alt_grab, QEMU_OPTION_no_quit, + QEMU_OPTION_sdl, QEMU_OPTION_pidfile, QEMU_OPTION_no_kqemu, QEMU_OPTION_kernel_kqemu, @@ -4176,6 +4186,7 @@ static const QEMUOption qemu_options[] = { { "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 { "pidfile", HAS_ARG, QEMU_OPTION_pidfile }, { "win2k-hack", 0, QEMU_OPTION_win2k_hack }, @@ -4495,6 +4506,7 @@ int main(int argc, char **argv, char **envp) 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; @@ -5007,6 +5019,9 @@ int main(int argc, char **argv, char **envp) case QEMU_OPTION_no_quit: no_quit = 1; break; + case QEMU_OPTION_sdl: + sdl = 1; + break; #endif case QEMU_OPTION_pidfile: pid_file = optarg; @@ -5404,6 +5419,7 @@ int main(int argc, char **argv, char **envp) /* terminal init */ memset(&display_state, 0, sizeof(display_state)); + ds->surface = qemu_create_displaysurface(640, 480, 32, 640 * 4); if (nographic) { if (curses) { fprintf(stderr, "fatal: -nographic can't be used with -curses\n"); @@ -5411,26 +5427,30 @@ int main(int argc, char **argv, char **envp) } /* nearly nothing to do */ dumb_display_init(ds); - } else if (vnc_display != NULL) { - vnc_display_init(ds); - if (vnc_display_open(ds, vnc_display) < 0) - exit(1); - } else + } else { #if defined(CONFIG_CURSES) - if (curses) { - curses_display_init(ds, full_screen); - } else + if (curses) { + /* At the moment curses cannot be used with other displays */ + curses_display_init(ds, full_screen); + } else #endif - { + { + if (vnc_display != NULL) { + vnc_display_init(ds); + if (vnc_display_open(ds, vnc_display) < 0) + exit(1); + } + if (sdl || !vnc_display) #if defined(CONFIG_SDL) - sdl_display_init(ds, full_screen, no_frame); + sdl_display_init(ds, full_screen, no_frame); #elif defined(CONFIG_COCOA) - cocoa_display_init(ds, full_screen); + cocoa_display_init(ds, full_screen); #else - dumb_display_init(ds); + dumb_display_init(ds); #endif + } } - + dpy_resize(ds); #ifndef _WIN32 /* must be after terminal init, SDL library changes signal handlers */ termsig_setup(); @@ -5541,11 +5561,14 @@ int main(int argc, char **argv, char **envp) } } - 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 if (use_gdbstub) { /* XXX: use standard host:port notation and modify options @@ -180,6 +180,7 @@ struct VncState }; static VncState *vnc_state; /* needed for info vnc */ +static DisplayChangeListener *dcl; void do_info_vnc(void) { @@ -213,7 +214,7 @@ static void vnc_flush(VncState *vs); static void vnc_update_client(void *opaque); static void vnc_client_read(void *opaque); -static void vnc_colordepth(DisplayState *ds, int depth); +static void vnc_colordepth(DisplayState *ds); static inline void vnc_set_bit(uint32_t *d, int k) { @@ -291,35 +292,30 @@ static void vnc_framebuffer_update(VncState *vs, int x, int y, int w, int h, vnc_write_s32(vs, encoding); } -static void vnc_dpy_resize(DisplayState *ds, int w, int h) +static void vnc_dpy_resize(DisplayState *ds) { int size_changed; VncState *vs = ds->opaque; - ds->data = qemu_realloc(ds->data, w * h * vs->depth); - vs->old_data = qemu_realloc(vs->old_data, w * h * vs->depth); + vs->old_data = qemu_realloc(vs->old_data, ds_get_linesize(ds) * ds_get_height(ds)); - if (ds->data == NULL || vs->old_data == NULL) { + if (vs->old_data == 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; - ds->linesize = w * vs->depth; + vnc_colordepth(ds); + size_changed = ds_get_width(ds) != vs->width || ds_get_height(ds) != vs->height; if (size_changed) { - vs->width = ds->width; - vs->height = ds->height; + vs->width = ds_get_width(ds); + vs->height = ds_get_height(ds); if (vs->csock != -1 && vs->has_resize) { 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); } } @@ -494,36 +490,10 @@ static void send_framebuffer_update(VncState *vs, int x, int y, int w, int h) 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; - char *old_row; - int y = 0; - int pitch = ds_get_linesize(ds); VncState *vs = ds->opaque; 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_write_u8(vs, 0); /* msg id */ vnc_write_u8(vs, 0); vnc_write_u16(vs, 1); /* number of rects */ @@ -770,7 +740,7 @@ static int vnc_client_io_error(VncState *vs, int ret, int last_errno) 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); vs->need_update = 0; @@ -1226,7 +1196,7 @@ static void set_encodings(VncState *vs, int32_t *encodings, size_t n_encodings) 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]) { @@ -1234,7 +1204,7 @@ static void set_encodings(VncState *vs, int32_t *encodings, size_t n_encodings) 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; @@ -1387,33 +1357,25 @@ static void pixel_format_message (VncState *vs) { vnc_write(vs, pad, 3); /* padding */ } -static void vnc_colordepth(DisplayState *ds, int depth) +static void vnc_dpy_setdata(DisplayState *ds) +{ + /* We don't have to do anything */ +} + +static void vnc_colordepth(DisplayState *ds) { int host_big_endian_flag; struct VncState *vs = ds->opaque; - switch (depth) { - case 24: - if (ds->depth == 32) return; - depth = 32; - break; - case 15: - case 8: - case 0: - return; - default: - break; - } - #ifdef WORDS_BIGENDIAN host_big_endian_flag = 1; #else 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->server_red_max = 7; vs->server_green_max = 7; vs->server_blue_max = 3; @@ -1422,7 +1384,7 @@ static void vnc_colordepth(DisplayState *ds, int depth) vs->server_blue_shift = 0; break; case 16: - vs->depth = depth / 8; + vs->depth = 2; vs->server_red_max = 31; vs->server_green_max = 63; vs->server_blue_max = 31; @@ -1448,7 +1410,7 @@ static void vnc_colordepth(DisplayState *ds, int depth) 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); } else { @@ -2237,7 +2199,7 @@ static int protocol_version(VncState *vs, uint8_t *version, size_t len) static void vnc_connect(VncState *vs) { 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, vs); vnc_write(vs, "RFB 003.008\n", 12); @@ -2247,7 +2209,7 @@ static void vnc_connect(VncState *vs) memset(vs->dirty_row, 0xFF, sizeof(vs->dirty_row)); vs->has_resize = 0; vs->has_hextile = 0; - vs->ds->dpy_copy = NULL; + dcl->dpy_copy = NULL; vnc_update_client(vs); reset_keys(vs); } @@ -2272,11 +2234,12 @@ void vnc_display_init(DisplayState *ds) 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; @@ -2298,13 +2261,11 @@ void vnc_display_init(DisplayState *ds) vs->timer = qemu_new_timer(rt_clock, vnc_update_client, vs); - vs->ds->data = NULL; - vs->ds->dpy_update = vnc_dpy_update; - vs->ds->dpy_resize = vnc_dpy_resize; - vs->ds->dpy_refresh = NULL; - - vnc_colordepth(vs->ds, 32); - vnc_dpy_resize(vs->ds, 640, 400); + 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); vs->as.freq = 44100; vs->as.nchannels = 2; |