diff options
author | Peter Maydell <peter.maydell@linaro.org> | 2017-04-24 15:37:30 +0100 |
---|---|---|
committer | Peter Maydell <peter.maydell@linaro.org> | 2017-04-24 15:37:30 +0100 |
commit | eab1e53cacfb1d877317d5e7b416ddb43858d92e (patch) | |
tree | c91eff5084a4c5815e74d2c52444d1c50653ced7 /hw/display | |
parent | 4c55b1d0bad8a703f0499fe62e3761a0cd288da3 (diff) | |
parent | 729abb6a920e80c3866f60d1638f08f2eba98a9a (diff) |
Merge remote-tracking branch 'remotes/kraxel/tags/pull-vga-20170424-1' into staging
fix display update races, part one.
add xres + yres properties to qxl and virtio.
misc fixes and cleanups.
# gpg: Signature made Mon 24 Apr 2017 13:14:49 BST
# gpg: using RSA key 0x4CB6D8EED3E87138
# gpg: Good signature from "Gerd Hoffmann (work) <kraxel@redhat.com>"
# gpg: aka "Gerd Hoffmann <gerd@kraxel.org>"
# gpg: aka "Gerd Hoffmann (private) <kraxel@gmail.com>"
# Primary key fingerprint: A032 8CFF B93A 17A7 9901 FE7D 4CB6 D8EE D3E8 7138
* remotes/kraxel/tags/pull-vga-20170424-1:
virtio-gpu: add xres and yres properties
qxl: add xres and yres properties
vmsvga: fix vmsvga_update_display
g364fb: make display updates thread safe
exynos: make display updates thread safe
framebuffer: make display updates thread safe
vga: make display updates thread safe.
vga: add vga_scanline_invalidated helper
memory: add support getting and using a dirty bitmap copy.
bitmap: add bitmap_copy_and_clear_atomic
virtio-gpu: replace PIXMAN_* by PIXMAN_BE_*
console: add same displaychangelistener registration pre-condition
console: add same surface replace pre-condition
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Diffstat (limited to 'hw/display')
-rw-r--r-- | hw/display/exynos4210_fimd.c | 11 | ||||
-rw-r--r-- | hw/display/framebuffer.c | 11 | ||||
-rw-r--r-- | hw/display/g364fb.c | 28 | ||||
-rw-r--r-- | hw/display/qxl.c | 34 | ||||
-rw-r--r-- | hw/display/qxl.h | 2 | ||||
-rw-r--r-- | hw/display/vga.c | 50 | ||||
-rw-r--r-- | hw/display/virtio-gpu.c | 41 | ||||
-rw-r--r-- | hw/display/vmware_vga.c | 21 |
8 files changed, 85 insertions, 113 deletions
diff --git a/hw/display/exynos4210_fimd.c b/hw/display/exynos4210_fimd.c index e5be713406..fd0b2bec65 100644 --- a/hw/display/exynos4210_fimd.c +++ b/hw/display/exynos4210_fimd.c @@ -1263,6 +1263,7 @@ static void exynos4210_fimd_update(void *opaque) Exynos4210fimdState *s = (Exynos4210fimdState *)opaque; DisplaySurface *surface; Exynos4210fimdWindow *w; + DirtyBitmapSnapshot *snap; int i, line; hwaddr fb_line_addr, inc_size; int scrn_height; @@ -1291,10 +1292,12 @@ static void exynos4210_fimd_update(void *opaque) memory_region_sync_dirty_bitmap(w->mem_section.mr); host_fb_addr = w->host_fb_addr; fb_line_addr = w->mem_section.offset_within_region; + snap = memory_region_snapshot_and_clear_dirty(w->mem_section.mr, + fb_line_addr, inc_size * scrn_height, DIRTY_MEMORY_VGA); for (line = 0; line < scrn_height; line++) { - is_dirty = memory_region_get_dirty(w->mem_section.mr, - fb_line_addr, scrn_width, DIRTY_MEMORY_VGA); + is_dirty = memory_region_snapshot_get_dirty(w->mem_section.mr, + snap, fb_line_addr, scrn_width); if (s->invalidate || is_dirty) { if (first_line == -1) { @@ -1309,9 +1312,7 @@ static void exynos4210_fimd_update(void *opaque) fb_line_addr += inc_size; is_dirty = false; } - memory_region_reset_dirty(w->mem_section.mr, - w->mem_section.offset_within_region, - w->fb_len, DIRTY_MEMORY_VGA); + g_free(snap); blend = true; } } diff --git a/hw/display/framebuffer.c b/hw/display/framebuffer.c index 25aa46c8c7..d7310d25f2 100644 --- a/hw/display/framebuffer.c +++ b/hw/display/framebuffer.c @@ -67,7 +67,7 @@ void framebuffer_update_display( int *first_row, /* Input and output. */ int *last_row /* Output only */) { - hwaddr src_len; + DirtyBitmapSnapshot *snap; uint8_t *dest; uint8_t *src; int first, last = 0; @@ -78,7 +78,6 @@ void framebuffer_update_display( i = *first_row; *first_row = -1; - src_len = (hwaddr)src_width * rows; mem = mem_section->mr; if (!mem) { @@ -102,9 +101,10 @@ void framebuffer_update_display( src += i * src_width; dest += i * dest_row_pitch; + snap = memory_region_snapshot_and_clear_dirty(mem, addr, src_width * rows, + DIRTY_MEMORY_VGA); for (; i < rows; i++) { - dirty = memory_region_get_dirty(mem, addr, src_width, - DIRTY_MEMORY_VGA); + dirty = memory_region_snapshot_get_dirty(mem, snap, addr, src_width); if (dirty || invalidate) { fn(opaque, dest, src, cols, dest_col_pitch); if (first == -1) @@ -115,11 +115,10 @@ void framebuffer_update_display( src += src_width; dest += dest_row_pitch; } + g_free(snap); if (first < 0) { return; } - memory_region_reset_dirty(mem, mem_section->offset_within_region, src_len, - DIRTY_MEMORY_VGA); *first_row = first; *last_row = last; } diff --git a/hw/display/g364fb.c b/hw/display/g364fb.c index 8cdc205dd9..86557d14a9 100644 --- a/hw/display/g364fb.c +++ b/hw/display/g364fb.c @@ -64,17 +64,8 @@ typedef struct G364State { static inline int check_dirty(G364State *s, ram_addr_t page) { - return memory_region_get_dirty(&s->mem_vram, page, G364_PAGE_SIZE, - DIRTY_MEMORY_VGA); -} - -static inline void reset_dirty(G364State *s, - ram_addr_t page_min, ram_addr_t page_max) -{ - memory_region_reset_dirty(&s->mem_vram, - page_min, - page_max + G364_PAGE_SIZE - page_min - 1, - DIRTY_MEMORY_VGA); + return memory_region_test_and_clear_dirty(&s->mem_vram, page, G364_PAGE_SIZE, + DIRTY_MEMORY_VGA); } static void g364fb_draw_graphic8(G364State *s) @@ -83,7 +74,7 @@ static void g364fb_draw_graphic8(G364State *s) int i, w; uint8_t *vram; uint8_t *data_display, *dd; - ram_addr_t page, page_min, page_max; + ram_addr_t page; int x, y; int xmin, xmax; int ymin, ymax; @@ -114,8 +105,6 @@ static void g364fb_draw_graphic8(G364State *s) } page = 0; - page_min = (ram_addr_t)-1; - page_max = 0; x = y = 0; xmin = s->width; @@ -137,9 +126,6 @@ static void g364fb_draw_graphic8(G364State *s) if (check_dirty(s, page)) { if (y < ymin) ymin = ymax = y; - if (page_min == (ram_addr_t)-1) - page_min = page; - page_max = page; if (x < xmin) xmin = x; for (i = 0; i < G364_PAGE_SIZE; i++) { @@ -196,10 +182,7 @@ static void g364fb_draw_graphic8(G364State *s) ymax = y; } else { int dy; - if (page_min != (ram_addr_t)-1) { - reset_dirty(s, page_min, page_max); - page_min = (ram_addr_t)-1; - page_max = 0; + if (xmax || ymax) { dpy_gfx_update(s->con, xmin, ymin, xmax - xmin + 1, ymax - ymin + 1); xmin = s->width; @@ -219,9 +202,8 @@ static void g364fb_draw_graphic8(G364State *s) } done: - if (page_min != (ram_addr_t)-1) { + if (xmax || ymax) { dpy_gfx_update(s->con, xmin, ymin, xmax - xmin + 1, ymax - ymin + 1); - reset_dirty(s, page_min, page_max); } } diff --git a/hw/display/qxl.c b/hw/display/qxl.c index 9feae78e4e..4d94cecd72 100644 --- a/hw/display/qxl.c +++ b/hw/display/qxl.c @@ -305,6 +305,16 @@ void qxl_spice_reset_cursor(PCIQXLDevice *qxl) qxl->ssd.cursor = cursor_builtin_hidden(); } +static uint32_t qxl_crc32(const uint8_t *p, unsigned len) +{ + /* + * zlib xors the seed with 0xffffffff, and xors the result + * again with 0xffffffff; Both are not done with linux's crc32, + * which we want to be compatible with, so undo that. + */ + return crc32(0xffffffff, p, len) ^ 0xffffffff; +} + static ram_addr_t qxl_rom_size(void) { #define QXL_REQUIRED_SZ (sizeof(QXLRom) + sizeof(QXLModes) + sizeof(qxl_modes)) @@ -369,6 +379,18 @@ static void init_qxl_rom(PCIQXLDevice *d) rom->num_pages = cpu_to_le32(num_pages); rom->ram_header_offset = cpu_to_le32(d->vga.vram_size - ram_header_size); + if (d->xres && d->yres) { + /* needs linux kernel 4.12+ to work */ + rom->client_monitors_config.count = 1; + rom->client_monitors_config.heads[0].left = 0; + rom->client_monitors_config.heads[0].top = 0; + rom->client_monitors_config.heads[0].right = cpu_to_le32(d->xres); + rom->client_monitors_config.heads[0].bottom = cpu_to_le32(d->yres); + rom->client_monitors_config_crc = qxl_crc32( + (const uint8_t *)&rom->client_monitors_config, + sizeof(rom->client_monitors_config)); + } + d->shadow_rom = *rom; d->rom = rom; d->modes = modes; @@ -1011,16 +1033,6 @@ static void interface_set_client_capabilities(QXLInstance *sin, qxl_send_events(qxl, QXL_INTERRUPT_CLIENT); } -static uint32_t qxl_crc32(const uint8_t *p, unsigned len) -{ - /* - * zlib xors the seed with 0xffffffff, and xors the result - * again with 0xffffffff; Both are not done with linux's crc32, - * which we want to be compatible with, so undo that. - */ - return crc32(0xffffffff, p, len) ^ 0xffffffff; -} - static bool qxl_rom_monitors_config_changed(QXLRom *rom, VDAgentMonitorsConfig *monitors_config, unsigned int max_outputs) @@ -2397,6 +2409,8 @@ static Property qxl_properties[] = { #if SPICE_SERVER_VERSION >= 0x000c06 /* release 0.12.6 */ DEFINE_PROP_UINT16("max_outputs", PCIQXLDevice, max_outputs, 0), #endif + DEFINE_PROP_UINT32("xres", PCIQXLDevice, xres, 0), + DEFINE_PROP_UINT32("yres", PCIQXLDevice, yres, 0), DEFINE_PROP_END_OF_LIST(), }; diff --git a/hw/display/qxl.h b/hw/display/qxl.h index 77e5a36dc5..f6556adb73 100644 --- a/hw/display/qxl.h +++ b/hw/display/qxl.h @@ -119,6 +119,8 @@ typedef struct PCIQXLDevice { uint32_t vram_size_mb; uint32_t vram32_size_mb; uint32_t vgamem_size_mb; + uint32_t xres; + uint32_t yres; /* qxl_render_update state */ int render_update_cookie_num; diff --git a/hw/display/vga.c b/hw/display/vga.c index 69c3e1d674..b2516c8d21 100644 --- a/hw/display/vga.c +++ b/hw/display/vga.c @@ -1434,6 +1434,14 @@ void vga_invalidate_scanlines(VGACommonState *s, int y1, int y2) } } +static bool vga_scanline_invalidated(VGACommonState *s, int y) +{ + if (y >= VGA_MAX_HEIGHT) { + return false; + } + return s->invalidated_y_table[y >> 5] & (1 << (y & 0x1f)); +} + void vga_sync_dirty_bitmap(VGACommonState *s) { memory_region_sync_dirty_bitmap(&s->vram); @@ -1457,7 +1465,8 @@ static void vga_draw_graphic(VGACommonState *s, int full_update) DisplaySurface *surface = qemu_console_surface(s->con); int y1, y, update, linesize, y_start, double_scan, mask, depth; int width, height, shift_control, line_offset, bwidth, bits; - ram_addr_t page0, page1, page_min, page_max; + ram_addr_t page0, page1; + DirtyBitmapSnapshot *snap = NULL; int disp_width, multi_scan, multi_run; uint8_t *d; uint32_t v, addr1, addr; @@ -1472,9 +1481,6 @@ static void vga_draw_graphic(VGACommonState *s, int full_update) full_update |= update_basic_params(s); - if (!full_update) - vga_sync_dirty_bitmap(s); - s->get_resolution(s, &width, &height); disp_width = width; @@ -1617,11 +1623,17 @@ static void vga_draw_graphic(VGACommonState *s, int full_update) addr1 = (s->start_addr * 4); bwidth = (width * bits + 7) / 8; y_start = -1; - page_min = -1; - page_max = 0; d = surface_data(surface); linesize = surface_stride(surface); y1 = 0; + + if (!full_update) { + vga_sync_dirty_bitmap(s); + snap = memory_region_snapshot_and_clear_dirty(&s->vram, addr1, + bwidth * height, + DIRTY_MEMORY_VGA); + } + for(y = 0; y < height; y++) { addr = addr1; if (!(s->cr[VGA_CRTC_MODE] & 1)) { @@ -1636,17 +1648,17 @@ static void vga_draw_graphic(VGACommonState *s, int full_update) update = full_update; page0 = addr; page1 = addr + bwidth - 1; - update |= memory_region_get_dirty(&s->vram, page0, page1 - page0, - DIRTY_MEMORY_VGA); - /* explicit invalidation for the hardware cursor */ - update |= (s->invalidated_y_table[y >> 5] >> (y & 0x1f)) & 1; + if (full_update) { + update = 1; + } else { + update = memory_region_snapshot_get_dirty(&s->vram, snap, + page0, page1 - page0); + } + /* explicit invalidation for the hardware cursor (cirrus only) */ + update |= vga_scanline_invalidated(s, y); if (update) { if (y_start < 0) y_start = y; - if (page0 < page_min) - page_min = page0; - if (page1 > page_max) - page_max = page1; if (!(is_buffer_shared(surface))) { vga_draw_line(s, d, s->vram_ptr + addr, width); if (s->cursor_draw_line) @@ -1679,14 +1691,8 @@ static void vga_draw_graphic(VGACommonState *s, int full_update) dpy_gfx_update(s->con, 0, y_start, disp_width, y - y_start); } - /* reset modified pages */ - if (page_max >= page_min) { - memory_region_reset_dirty(&s->vram, - page_min, - page_max - page_min, - DIRTY_MEMORY_VGA); - } - memset(s->invalidated_y_table, 0, ((height + 31) >> 5) * 4); + g_free(snap); + memset(s->invalidated_y_table, 0, sizeof(s->invalidated_y_table)); } static void vga_draw_blank(VGACommonState *s, int full_update) diff --git a/hw/display/virtio-gpu.c b/hw/display/virtio-gpu.c index 9b530ab5b0..e1056f34df 100644 --- a/hw/display/virtio-gpu.c +++ b/hw/display/virtio-gpu.c @@ -258,41 +258,22 @@ void virtio_gpu_get_display_info(VirtIOGPU *g, static pixman_format_code_t get_pixman_format(uint32_t virtio_gpu_format) { switch (virtio_gpu_format) { -#ifdef HOST_WORDS_BIGENDIAN case VIRTIO_GPU_FORMAT_B8G8R8X8_UNORM: - return PIXMAN_b8g8r8x8; + return PIXMAN_BE_b8g8r8x8; case VIRTIO_GPU_FORMAT_B8G8R8A8_UNORM: - return PIXMAN_b8g8r8a8; + return PIXMAN_BE_b8g8r8a8; case VIRTIO_GPU_FORMAT_X8R8G8B8_UNORM: - return PIXMAN_x8r8g8b8; + return PIXMAN_BE_x8r8g8b8; case VIRTIO_GPU_FORMAT_A8R8G8B8_UNORM: - return PIXMAN_a8r8g8b8; + return PIXMAN_BE_a8r8g8b8; case VIRTIO_GPU_FORMAT_R8G8B8X8_UNORM: - return PIXMAN_r8g8b8x8; + return PIXMAN_BE_r8g8b8x8; case VIRTIO_GPU_FORMAT_R8G8B8A8_UNORM: - return PIXMAN_r8g8b8a8; + return PIXMAN_BE_r8g8b8a8; case VIRTIO_GPU_FORMAT_X8B8G8R8_UNORM: - return PIXMAN_x8b8g8r8; + return PIXMAN_BE_x8b8g8r8; case VIRTIO_GPU_FORMAT_A8B8G8R8_UNORM: - return PIXMAN_a8b8g8r8; -#else - case VIRTIO_GPU_FORMAT_B8G8R8X8_UNORM: - return PIXMAN_x8r8g8b8; - case VIRTIO_GPU_FORMAT_B8G8R8A8_UNORM: - return PIXMAN_a8r8g8b8; - case VIRTIO_GPU_FORMAT_X8R8G8B8_UNORM: - return PIXMAN_b8g8r8x8; - case VIRTIO_GPU_FORMAT_A8R8G8B8_UNORM: - return PIXMAN_b8g8r8a8; - case VIRTIO_GPU_FORMAT_R8G8B8X8_UNORM: - return PIXMAN_x8b8g8r8; - case VIRTIO_GPU_FORMAT_R8G8B8A8_UNORM: - return PIXMAN_a8b8g8r8; - case VIRTIO_GPU_FORMAT_X8B8G8R8_UNORM: - return PIXMAN_r8g8b8x8; - case VIRTIO_GPU_FORMAT_A8B8G8R8_UNORM: - return PIXMAN_r8g8b8a8; -#endif + return PIXMAN_BE_a8b8g8r8; default: return 0; } @@ -1170,8 +1151,8 @@ static void virtio_gpu_device_realize(DeviceState *qdev, Error **errp) virtio_init(VIRTIO_DEVICE(g), "virtio-gpu", VIRTIO_ID_GPU, g->config_size); - g->req_state[0].width = 1024; - g->req_state[0].height = 768; + g->req_state[0].width = g->conf.xres; + g->req_state[0].height = g->conf.yres; if (virtio_gpu_virgl_enabled(g->conf)) { /* use larger control queue in 3d mode */ @@ -1291,6 +1272,8 @@ static Property virtio_gpu_properties[] = { DEFINE_PROP_BIT("stats", VirtIOGPU, conf.flags, VIRTIO_GPU_FLAG_STATS_ENABLED, false), #endif + DEFINE_PROP_UINT32("xres", VirtIOGPU, conf.xres, 1024), + DEFINE_PROP_UINT32("yres", VirtIOGPU, conf.yres, 768), DEFINE_PROP_END_OF_LIST(), }; diff --git a/hw/display/vmware_vga.c b/hw/display/vmware_vga.c index 6599cf078d..ec5f27d67e 100644 --- a/hw/display/vmware_vga.c +++ b/hw/display/vmware_vga.c @@ -1118,9 +1118,9 @@ static void vmsvga_update_display(void *opaque) { struct vmsvga_state_s *s = opaque; DisplaySurface *surface; - bool dirty = false; - if (!s->enable) { + if (!s->enable || !s->config) { + /* in standard vga mode */ s->vga.hw_ops->gfx_update(&s->vga); return; } @@ -1131,26 +1131,11 @@ static void vmsvga_update_display(void *opaque) vmsvga_fifo_run(s); vmsvga_update_rect_flush(s); - /* - * Is it more efficient to look at vram VGA-dirty bits or wait - * for the driver to issue SVGA_CMD_UPDATE? - */ - if (memory_region_is_logging(&s->vga.vram, DIRTY_MEMORY_VGA)) { - vga_sync_dirty_bitmap(&s->vga); - dirty = memory_region_get_dirty(&s->vga.vram, 0, - surface_stride(surface) * surface_height(surface), - DIRTY_MEMORY_VGA); - } - if (s->invalidated || dirty) { + if (s->invalidated) { s->invalidated = 0; dpy_gfx_update(s->vga.con, 0, 0, surface_width(surface), surface_height(surface)); } - if (dirty) { - memory_region_reset_dirty(&s->vga.vram, 0, - surface_stride(surface) * surface_height(surface), - DIRTY_MEMORY_VGA); - } } static void vmsvga_reset(DeviceState *dev) |