]>
Commit | Line | Data |
---|---|---|
3dcc8d3b | 1 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 |
ddbcf45e WB |
2 | From: Gerd Hoffmann <kraxel@redhat.com> |
3 | Date: Fri, 21 Apr 2017 11:16:27 +0200 | |
3dcc8d3b | 4 | Subject: [PATCH] vga: make display updates thread safe. |
ddbcf45e WB |
5 | |
6 | The vga code clears the dirty bits *after* reading the framebuffer | |
7 | memory. So if the guest framebuffer updates hits the race window | |
8 | between vga reading the framebuffer and vga clearing the dirty bits | |
9 | vga will miss that update | |
10 | ||
11 | Fix it by using the new memory_region_copy_and_clear_dirty() | |
12 | memory_region_copy_get_dirty() functions. That way we clear the | |
13 | dirty bitmap before reading the framebuffer. Any guest display | |
14 | updates happening in parallel will be properly tracked in the | |
15 | dirty bitmap then and the next display refresh will pick them up. | |
16 | ||
17 | Problem triggers with mttcg only. Before mttcg was merged tcg | |
18 | never ran in parallel to vga emulation. Using kvm will hide the | |
19 | problem too, due to qemu operating on a userspace copy of the | |
20 | kernel's dirty bitmap. | |
21 | ||
22 | Signed-off-by: Gerd Hoffmann <kraxel@redhat.com> | |
23 | Message-id: 20170421091632.30900-5-kraxel@redhat.com | |
24 | Signed-off-by: Gerd Hoffmann <kraxel@redhat.com> | |
25 | --- | |
26 | hw/display/vga.c | 36 +++++++++++++++++------------------- | |
27 | 1 file changed, 17 insertions(+), 19 deletions(-) | |
28 | ||
29 | diff --git a/hw/display/vga.c b/hw/display/vga.c | |
30 | index 3991b88aac..b2516c8d21 100644 | |
31 | --- a/hw/display/vga.c | |
32 | +++ b/hw/display/vga.c | |
33 | @@ -1465,7 +1465,8 @@ static void vga_draw_graphic(VGACommonState *s, int full_update) | |
34 | DisplaySurface *surface = qemu_console_surface(s->con); | |
35 | int y1, y, update, linesize, y_start, double_scan, mask, depth; | |
36 | int width, height, shift_control, line_offset, bwidth, bits; | |
37 | - ram_addr_t page0, page1, page_min, page_max; | |
38 | + ram_addr_t page0, page1; | |
39 | + DirtyBitmapSnapshot *snap = NULL; | |
40 | int disp_width, multi_scan, multi_run; | |
41 | uint8_t *d; | |
42 | uint32_t v, addr1, addr; | |
43 | @@ -1480,9 +1481,6 @@ static void vga_draw_graphic(VGACommonState *s, int full_update) | |
44 | ||
45 | full_update |= update_basic_params(s); | |
46 | ||
47 | - if (!full_update) | |
48 | - vga_sync_dirty_bitmap(s); | |
49 | - | |
50 | s->get_resolution(s, &width, &height); | |
51 | disp_width = width; | |
52 | ||
53 | @@ -1625,11 +1623,17 @@ static void vga_draw_graphic(VGACommonState *s, int full_update) | |
54 | addr1 = (s->start_addr * 4); | |
55 | bwidth = (width * bits + 7) / 8; | |
56 | y_start = -1; | |
57 | - page_min = -1; | |
58 | - page_max = 0; | |
59 | d = surface_data(surface); | |
60 | linesize = surface_stride(surface); | |
61 | y1 = 0; | |
62 | + | |
63 | + if (!full_update) { | |
64 | + vga_sync_dirty_bitmap(s); | |
65 | + snap = memory_region_snapshot_and_clear_dirty(&s->vram, addr1, | |
66 | + bwidth * height, | |
67 | + DIRTY_MEMORY_VGA); | |
68 | + } | |
69 | + | |
70 | for(y = 0; y < height; y++) { | |
71 | addr = addr1; | |
72 | if (!(s->cr[VGA_CRTC_MODE] & 1)) { | |
73 | @@ -1644,17 +1648,17 @@ static void vga_draw_graphic(VGACommonState *s, int full_update) | |
74 | update = full_update; | |
75 | page0 = addr; | |
76 | page1 = addr + bwidth - 1; | |
77 | - update |= memory_region_get_dirty(&s->vram, page0, page1 - page0, | |
78 | - DIRTY_MEMORY_VGA); | |
79 | + if (full_update) { | |
80 | + update = 1; | |
81 | + } else { | |
82 | + update = memory_region_snapshot_get_dirty(&s->vram, snap, | |
83 | + page0, page1 - page0); | |
84 | + } | |
85 | /* explicit invalidation for the hardware cursor (cirrus only) */ | |
86 | update |= vga_scanline_invalidated(s, y); | |
87 | if (update) { | |
88 | if (y_start < 0) | |
89 | y_start = y; | |
90 | - if (page0 < page_min) | |
91 | - page_min = page0; | |
92 | - if (page1 > page_max) | |
93 | - page_max = page1; | |
94 | if (!(is_buffer_shared(surface))) { | |
95 | vga_draw_line(s, d, s->vram_ptr + addr, width); | |
96 | if (s->cursor_draw_line) | |
97 | @@ -1687,13 +1691,7 @@ static void vga_draw_graphic(VGACommonState *s, int full_update) | |
98 | dpy_gfx_update(s->con, 0, y_start, | |
99 | disp_width, y - y_start); | |
100 | } | |
101 | - /* reset modified pages */ | |
102 | - if (page_max >= page_min) { | |
103 | - memory_region_reset_dirty(&s->vram, | |
104 | - page_min, | |
105 | - page_max - page_min, | |
106 | - DIRTY_MEMORY_VGA); | |
107 | - } | |
108 | + g_free(snap); | |
109 | memset(s->invalidated_y_table, 0, sizeof(s->invalidated_y_table)); | |
110 | } | |
111 | ||
112 | -- | |
113 | 2.11.0 | |
114 |