aboutsummaryrefslogtreecommitdiff
path: root/hw/display
diff options
context:
space:
mode:
authorPeter Maydell <peter.maydell@linaro.org>2017-04-24 15:37:30 +0100
committerPeter Maydell <peter.maydell@linaro.org>2017-04-24 15:37:30 +0100
commiteab1e53cacfb1d877317d5e7b416ddb43858d92e (patch)
treec91eff5084a4c5815e74d2c52444d1c50653ced7 /hw/display
parent4c55b1d0bad8a703f0499fe62e3761a0cd288da3 (diff)
parent729abb6a920e80c3866f60d1638f08f2eba98a9a (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.c11
-rw-r--r--hw/display/framebuffer.c11
-rw-r--r--hw/display/g364fb.c28
-rw-r--r--hw/display/qxl.c34
-rw-r--r--hw/display/qxl.h2
-rw-r--r--hw/display/vga.c50
-rw-r--r--hw/display/virtio-gpu.c41
-rw-r--r--hw/display/vmware_vga.c21
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)