aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--hw/display/vga.c18
-rw-r--r--include/ui/console.h4
-rw-r--r--include/ui/qemu-pixman.h2
-rw-r--r--include/ui/sdl2.h2
-rw-r--r--ui/console.c25
-rw-r--r--ui/gtk.c13
-rw-r--r--ui/qemu-pixman.c29
-rw-r--r--ui/sdl.c26
-rw-r--r--ui/sdl2-2d.c13
-rw-r--r--ui/sdl2.c13
-rw-r--r--ui/spice-display.c13
-rw-r--r--ui/vnc.c15
12 files changed, 137 insertions, 36 deletions
diff --git a/hw/display/vga.c b/hw/display/vga.c
index a620c07864..ffcfce38a4 100644
--- a/hw/display/vga.c
+++ b/hw/display/vga.c
@@ -1437,6 +1437,7 @@ static void vga_draw_graphic(VGACommonState *s, int full_update)
uint32_t v, addr1, addr;
vga_draw_line_func *vga_draw_line = NULL;
bool share_surface;
+ pixman_format_code_t format;
#ifdef HOST_WORDS_BIGENDIAN
bool byteswap = !s->big_endian_fb;
#else
@@ -1481,8 +1482,19 @@ static void vga_draw_graphic(VGACommonState *s, int full_update)
depth = s->get_bpp(s);
- share_surface = (!s->force_shadow) &&
- ( depth == 32 || (depth == 16 && !byteswap) );
+ /*
+ * Check whether we can share the surface with the backend
+ * or whether we need a shadow surface. We share native
+ * endian surfaces for 15bpp and above and byteswapped
+ * surfaces for 24bpp and above.
+ */
+ format = qemu_default_pixman_format(depth, !byteswap);
+ if (format) {
+ share_surface = dpy_gfx_check_format(s->con, format)
+ && !s->force_shadow;
+ } else {
+ share_surface = false;
+ }
if (s->line_offset != s->last_line_offset ||
disp_width != s->last_width ||
height != s->last_height ||
@@ -1490,8 +1502,6 @@ static void vga_draw_graphic(VGACommonState *s, int full_update)
s->last_byteswap != byteswap ||
share_surface != is_buffer_shared(surface)) {
if (share_surface) {
- pixman_format_code_t format =
- qemu_default_pixman_format(depth, !byteswap);
surface = qemu_create_displaysurface_from(disp_width,
height, format, s->line_offset,
s->vram_ptr + (s->start_addr * 4));
diff --git a/include/ui/console.h b/include/ui/console.h
index 22ef8ca6b3..047b6dab8d 100644
--- a/include/ui/console.h
+++ b/include/ui/console.h
@@ -161,6 +161,8 @@ typedef struct DisplayChangeListenerOps {
void (*dpy_gfx_copy)(DisplayChangeListener *dcl,
int src_x, int src_y,
int dst_x, int dst_y, int w, int h);
+ bool (*dpy_gfx_check_format)(DisplayChangeListener *dcl,
+ pixman_format_code_t format);
void (*dpy_text_cursor)(DisplayChangeListener *dcl,
int x, int y);
@@ -235,6 +237,8 @@ void dpy_gfx_update_dirty(QemuConsole *con,
MemoryRegion *address_space,
uint64_t base,
bool invalidate);
+bool dpy_gfx_check_format(QemuConsole *con,
+ pixman_format_code_t format);
static inline int surface_stride(DisplaySurface *s)
{
diff --git a/include/ui/qemu-pixman.h b/include/ui/qemu-pixman.h
index 381969d97b..3dee5761cc 100644
--- a/include/ui/qemu-pixman.h
+++ b/include/ui/qemu-pixman.h
@@ -37,6 +37,8 @@ PixelFormat qemu_pixelformat_from_pixman(pixman_format_code_t format);
pixman_format_code_t qemu_default_pixman_format(int bpp, bool native_endian);
int qemu_pixman_get_type(int rshift, int gshift, int bshift);
pixman_format_code_t qemu_pixman_get_format(PixelFormat *pf);
+bool qemu_pixman_check_format(DisplayChangeListener *dcl,
+ pixman_format_code_t format);
pixman_image_t *qemu_pixman_linebuf_create(pixman_format_code_t format,
int width);
diff --git a/include/ui/sdl2.h b/include/ui/sdl2.h
index f56c596e31..51fff2e9b8 100644
--- a/include/ui/sdl2.h
+++ b/include/ui/sdl2.h
@@ -28,5 +28,7 @@ void sdl2_2d_switch(DisplayChangeListener *dcl,
DisplaySurface *new_surface);
void sdl2_2d_refresh(DisplayChangeListener *dcl);
void sdl2_2d_redraw(struct sdl2_console *scon);
+bool sdl2_2d_check_format(DisplayChangeListener *dcl,
+ pixman_format_code_t format);
#endif /* SDL2_H */
diff --git a/ui/console.c b/ui/console.c
index 258af5dfff..87574a73a8 100644
--- a/ui/console.c
+++ b/ui/console.c
@@ -1439,6 +1439,31 @@ void dpy_gfx_replace_surface(QemuConsole *con,
qemu_free_displaysurface(old_surface);
}
+bool dpy_gfx_check_format(QemuConsole *con,
+ pixman_format_code_t format)
+{
+ DisplayChangeListener *dcl;
+ DisplayState *s = con->ds;
+
+ QLIST_FOREACH(dcl, &s->listeners, next) {
+ if (dcl->con && dcl->con != con) {
+ /* dcl bound to another console -> skip */
+ continue;
+ }
+ if (dcl->ops->dpy_gfx_check_format) {
+ if (!dcl->ops->dpy_gfx_check_format(dcl, format)) {
+ return false;
+ }
+ } else {
+ /* default is to whitelist native 32 bpp only */
+ if (format != qemu_default_pixman_format(32, true)) {
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
static void dpy_refresh(DisplayState *s)
{
DisplayChangeListener *dcl;
diff --git a/ui/gtk.c b/ui/gtk.c
index 0385757bf5..6a81076ffc 100644
--- a/ui/gtk.c
+++ b/ui/gtk.c
@@ -1654,12 +1654,13 @@ static GtkWidget *gd_create_menu_machine(GtkDisplayState *s)
}
static const DisplayChangeListenerOps dcl_ops = {
- .dpy_name = "gtk",
- .dpy_gfx_update = gd_update,
- .dpy_gfx_switch = gd_switch,
- .dpy_refresh = gd_refresh,
- .dpy_mouse_set = gd_mouse_set,
- .dpy_cursor_define = gd_cursor_define,
+ .dpy_name = "gtk",
+ .dpy_gfx_update = gd_update,
+ .dpy_gfx_switch = gd_switch,
+ .dpy_gfx_check_format = qemu_pixman_check_format,
+ .dpy_refresh = gd_refresh,
+ .dpy_mouse_set = gd_mouse_set,
+ .dpy_cursor_define = gd_cursor_define,
};
static GSList *gd_vc_gfx_init(GtkDisplayState *s, VirtualConsole *vc,
diff --git a/ui/qemu-pixman.c b/ui/qemu-pixman.c
index 1f6fea535b..4116e1507b 100644
--- a/ui/qemu-pixman.c
+++ b/ui/qemu-pixman.c
@@ -84,7 +84,7 @@ pixman_format_code_t qemu_default_pixman_format(int bpp, bool native_endian)
break;
}
}
- g_assert_not_reached();
+ return 0;
}
int qemu_pixman_get_type(int rshift, int gshift, int bshift)
@@ -125,6 +125,33 @@ pixman_format_code_t qemu_pixman_get_format(PixelFormat *pf)
return format;
}
+/*
+ * Return true for known-good pixman conversions.
+ *
+ * UIs using pixman for format conversion can hook this into
+ * DisplayChangeListenerOps->dpy_gfx_check_format
+ */
+bool qemu_pixman_check_format(DisplayChangeListener *dcl,
+ pixman_format_code_t format)
+{
+ switch (format) {
+ /* 32 bpp */
+ case PIXMAN_x8r8g8b8:
+ case PIXMAN_a8r8g8b8:
+ case PIXMAN_b8g8r8x8:
+ case PIXMAN_b8g8r8a8:
+ /* 24 bpp */
+ case PIXMAN_r8g8b8:
+ case PIXMAN_b8g8r8:
+ /* 16 bpp */
+ case PIXMAN_x1r5g5b5:
+ case PIXMAN_r5g6b5:
+ return true;
+ default:
+ return false;
+ }
+}
+
pixman_image_t *qemu_pixman_linebuf_create(pixman_format_code_t format,
int width)
{
diff --git a/ui/sdl.c b/ui/sdl.c
index 3e9d81076b..138ca73407 100644
--- a/ui/sdl.c
+++ b/ui/sdl.c
@@ -151,6 +151,19 @@ static void sdl_switch(DisplayChangeListener *dcl,
pf.bmask, pf.amask);
}
+static bool sdl_check_format(DisplayChangeListener *dcl,
+ pixman_format_code_t format)
+{
+ /*
+ * We let SDL convert for us a few more formats than,
+ * the native ones. Thes are the ones I have tested.
+ */
+ return (format == PIXMAN_x8r8g8b8 ||
+ format == PIXMAN_b8g8r8x8 ||
+ format == PIXMAN_x1r5g5b5 ||
+ format == PIXMAN_r5g6b5);
+}
+
/* generic keyboard conversion */
#include "sdl_keysym.h"
@@ -865,12 +878,13 @@ static void sdl_cleanup(void)
}
static const DisplayChangeListenerOps dcl_ops = {
- .dpy_name = "sdl",
- .dpy_gfx_update = sdl_update,
- .dpy_gfx_switch = sdl_switch,
- .dpy_refresh = sdl_refresh,
- .dpy_mouse_set = sdl_mouse_warp,
- .dpy_cursor_define = sdl_mouse_define,
+ .dpy_name = "sdl",
+ .dpy_gfx_update = sdl_update,
+ .dpy_gfx_switch = sdl_switch,
+ .dpy_gfx_check_format = sdl_check_format,
+ .dpy_refresh = sdl_refresh,
+ .dpy_mouse_set = sdl_mouse_warp,
+ .dpy_cursor_define = sdl_mouse_define,
};
void sdl_display_init(DisplayState *ds, int full_screen, int no_frame)
diff --git a/ui/sdl2-2d.c b/ui/sdl2-2d.c
index 9264817e76..f907c21895 100644
--- a/ui/sdl2-2d.c
+++ b/ui/sdl2-2d.c
@@ -120,3 +120,16 @@ void sdl2_2d_redraw(struct sdl2_console *scon)
surface_width(scon->surface),
surface_height(scon->surface));
}
+
+bool sdl2_2d_check_format(DisplayChangeListener *dcl,
+ pixman_format_code_t format)
+{
+ /*
+ * We let SDL convert for us a few more formats than,
+ * the native ones. Thes are the ones I have tested.
+ */
+ return (format == PIXMAN_x8r8g8b8 ||
+ format == PIXMAN_b8g8r8x8 ||
+ format == PIXMAN_x1r5g5b5 ||
+ format == PIXMAN_r5g6b5);
+}
diff --git a/ui/sdl2.c b/ui/sdl2.c
index 1ae2781624..60e3c3b6fa 100644
--- a/ui/sdl2.c
+++ b/ui/sdl2.c
@@ -668,12 +668,13 @@ static void sdl_cleanup(void)
}
static const DisplayChangeListenerOps dcl_2d_ops = {
- .dpy_name = "sdl2-2d",
- .dpy_gfx_update = sdl2_2d_update,
- .dpy_gfx_switch = sdl2_2d_switch,
- .dpy_refresh = sdl2_2d_refresh,
- .dpy_mouse_set = sdl_mouse_warp,
- .dpy_cursor_define = sdl_mouse_define,
+ .dpy_name = "sdl2-2d",
+ .dpy_gfx_update = sdl2_2d_update,
+ .dpy_gfx_switch = sdl2_2d_switch,
+ .dpy_gfx_check_format = sdl2_2d_check_format,
+ .dpy_refresh = sdl2_2d_refresh,
+ .dpy_mouse_set = sdl_mouse_warp,
+ .dpy_cursor_define = sdl_mouse_define,
};
void sdl_display_init(DisplayState *ds, int full_screen, int no_frame)
diff --git a/ui/spice-display.c b/ui/spice-display.c
index d2e379379f..8c872129de 100644
--- a/ui/spice-display.c
+++ b/ui/spice-display.c
@@ -760,12 +760,13 @@ static void display_mouse_define(DisplayChangeListener *dcl,
}
static const DisplayChangeListenerOps display_listener_ops = {
- .dpy_name = "spice",
- .dpy_gfx_update = display_update,
- .dpy_gfx_switch = display_switch,
- .dpy_refresh = display_refresh,
- .dpy_mouse_set = display_mouse_set,
- .dpy_cursor_define = display_mouse_define,
+ .dpy_name = "spice",
+ .dpy_gfx_update = display_update,
+ .dpy_gfx_switch = display_switch,
+ .dpy_gfx_check_format = qemu_pixman_check_format,
+ .dpy_refresh = display_refresh,
+ .dpy_mouse_set = display_mouse_set,
+ .dpy_cursor_define = display_mouse_define,
};
static void qemu_spice_display_init_one(QemuConsole *con)
diff --git a/ui/vnc.c b/ui/vnc.c
index 57070150d4..0385160a8b 100644
--- a/ui/vnc.c
+++ b/ui/vnc.c
@@ -2942,13 +2942,14 @@ static void vnc_listen_websocket_read(void *opaque)
#endif /* CONFIG_VNC_WS */
static const DisplayChangeListenerOps dcl_ops = {
- .dpy_name = "vnc",
- .dpy_refresh = vnc_refresh,
- .dpy_gfx_copy = vnc_dpy_copy,
- .dpy_gfx_update = vnc_dpy_update,
- .dpy_gfx_switch = vnc_dpy_switch,
- .dpy_mouse_set = vnc_mouse_set,
- .dpy_cursor_define = vnc_dpy_cursor_define,
+ .dpy_name = "vnc",
+ .dpy_refresh = vnc_refresh,
+ .dpy_gfx_copy = vnc_dpy_copy,
+ .dpy_gfx_update = vnc_dpy_update,
+ .dpy_gfx_switch = vnc_dpy_switch,
+ .dpy_gfx_check_format = qemu_pixman_check_format,
+ .dpy_mouse_set = vnc_mouse_set,
+ .dpy_cursor_define = vnc_dpy_cursor_define,
};
void vnc_display_init(DisplayState *ds)