fix display update races, part one.
add xres + yres properties to qxl and virtio. misc fixes and cleanups. -----BEGIN PGP SIGNATURE----- Version: GnuPG v2.0.22 (GNU/Linux) iQIcBAABAgAGBQJY/ew5AAoJEEy22O7T6HE4sXIP/2UxIRxgqIG/Gj+WWp4hHI7L 9IharsFTO2OvZmwko+FdX8EKTJrDUNkCclei8FpYXmL3xnSALwYSokEjJV5wJ9r3 Owf+ymWgwLfr6k/pnHb4F6iBQk82m052ZXJB4nsAJV1RbCA2cEnyuF7IVA/uPZf7 HCjkXwJcg53XyVy7OzDilgZkNxFeioc4I32pjTBtWKmqsFqZqsLMJMZ5pD3ubpRz 7wfwBFvH910TjB7YVPfZN0l8b2X6dUiK1b+pQCqvogoDLhItxG6aN3J3sjDbOoSP 6Bwm815oPWziVWXHvPEoMhdorGhkoGpJXBdkSTeiW/CCdl6zF1EUJZc6yDWh+2SS ZKjV/aY0qPOxNMlaN4gf2scKVbn8nrsB/NnH53uczAUaelfn1v8S0aRr01i0z43v TWu87OszG14cQNssVjI8v80G+29Dr2bw0tFN2JAjVB7ZrNWCOkOgelxFEOBPK4EU eBeH1fUN0/QrTvRi2JS9b4GOW94LyY20AQPvQo7aqV9PVY+5qbiVi6BSavwdhjbR IAh8A60xIOTm3gyM2riKi5/0YBpyUFB6dnTVn5fLwipD9pjpdT/jQyn4Kl7ZSq7T q8gDJ99A/zKfte0y/JyL+iJ0JPNhzQwviTpemupDa9hbrHEkpIy7LKE74JXVicEO zBzIa3b+I9iogSLf3V5v =1F5z -----END PGP SIGNATURE----- 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>
This commit is contained in:
		
						commit
						eab1e53cac
					
				
							
								
								
									
										75
									
								
								exec.c
								
								
								
								
							
							
						
						
									
										75
									
								
								exec.c
								
								
								
								
							| 
						 | 
					@ -223,6 +223,12 @@ struct CPUAddressSpace {
 | 
				
			||||||
    MemoryListener tcg_as_listener;
 | 
					    MemoryListener tcg_as_listener;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct DirtyBitmapSnapshot {
 | 
				
			||||||
 | 
					    ram_addr_t start;
 | 
				
			||||||
 | 
					    ram_addr_t end;
 | 
				
			||||||
 | 
					    unsigned long dirty[];
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#if !defined(CONFIG_USER_ONLY)
 | 
					#if !defined(CONFIG_USER_ONLY)
 | 
				
			||||||
| 
						 | 
					@ -1061,6 +1067,75 @@ bool cpu_physical_memory_test_and_clear_dirty(ram_addr_t start,
 | 
				
			||||||
    return dirty;
 | 
					    return dirty;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					DirtyBitmapSnapshot *cpu_physical_memory_snapshot_and_clear_dirty
 | 
				
			||||||
 | 
					     (ram_addr_t start, ram_addr_t length, unsigned client)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    DirtyMemoryBlocks *blocks;
 | 
				
			||||||
 | 
					    unsigned long align = 1UL << (TARGET_PAGE_BITS + BITS_PER_LEVEL);
 | 
				
			||||||
 | 
					    ram_addr_t first = QEMU_ALIGN_DOWN(start, align);
 | 
				
			||||||
 | 
					    ram_addr_t last  = QEMU_ALIGN_UP(start + length, align);
 | 
				
			||||||
 | 
					    DirtyBitmapSnapshot *snap;
 | 
				
			||||||
 | 
					    unsigned long page, end, dest;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    snap = g_malloc0(sizeof(*snap) +
 | 
				
			||||||
 | 
					                     ((last - first) >> (TARGET_PAGE_BITS + 3)));
 | 
				
			||||||
 | 
					    snap->start = first;
 | 
				
			||||||
 | 
					    snap->end   = last;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    page = first >> TARGET_PAGE_BITS;
 | 
				
			||||||
 | 
					    end  = last  >> TARGET_PAGE_BITS;
 | 
				
			||||||
 | 
					    dest = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    rcu_read_lock();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    blocks = atomic_rcu_read(&ram_list.dirty_memory[client]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    while (page < end) {
 | 
				
			||||||
 | 
					        unsigned long idx = page / DIRTY_MEMORY_BLOCK_SIZE;
 | 
				
			||||||
 | 
					        unsigned long offset = page % DIRTY_MEMORY_BLOCK_SIZE;
 | 
				
			||||||
 | 
					        unsigned long num = MIN(end - page, DIRTY_MEMORY_BLOCK_SIZE - offset);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        assert(QEMU_IS_ALIGNED(offset, (1 << BITS_PER_LEVEL)));
 | 
				
			||||||
 | 
					        assert(QEMU_IS_ALIGNED(num,    (1 << BITS_PER_LEVEL)));
 | 
				
			||||||
 | 
					        offset >>= BITS_PER_LEVEL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        bitmap_copy_and_clear_atomic(snap->dirty + dest,
 | 
				
			||||||
 | 
					                                     blocks->blocks[idx] + offset,
 | 
				
			||||||
 | 
					                                     num);
 | 
				
			||||||
 | 
					        page += num;
 | 
				
			||||||
 | 
					        dest += num >> BITS_PER_LEVEL;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    rcu_read_unlock();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (tcg_enabled()) {
 | 
				
			||||||
 | 
					        tlb_reset_dirty_range_all(start, length);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return snap;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool cpu_physical_memory_snapshot_get_dirty(DirtyBitmapSnapshot *snap,
 | 
				
			||||||
 | 
					                                            ram_addr_t start,
 | 
				
			||||||
 | 
					                                            ram_addr_t length)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    unsigned long page, end;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    assert(start >= snap->start);
 | 
				
			||||||
 | 
					    assert(start + length <= snap->end);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    end = TARGET_PAGE_ALIGN(start + length - snap->start) >> TARGET_PAGE_BITS;
 | 
				
			||||||
 | 
					    page = (start - snap->start) >> TARGET_PAGE_BITS;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    while (page < end) {
 | 
				
			||||||
 | 
					        if (test_bit(page, snap->dirty)) {
 | 
				
			||||||
 | 
					            return true;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        page++;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return false;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Called from RCU critical section */
 | 
					/* Called from RCU critical section */
 | 
				
			||||||
hwaddr memory_region_section_get_iotlb(CPUState *cpu,
 | 
					hwaddr memory_region_section_get_iotlb(CPUState *cpu,
 | 
				
			||||||
                                       MemoryRegionSection *section,
 | 
					                                       MemoryRegionSection *section,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1263,6 +1263,7 @@ static void exynos4210_fimd_update(void *opaque)
 | 
				
			||||||
    Exynos4210fimdState *s = (Exynos4210fimdState *)opaque;
 | 
					    Exynos4210fimdState *s = (Exynos4210fimdState *)opaque;
 | 
				
			||||||
    DisplaySurface *surface;
 | 
					    DisplaySurface *surface;
 | 
				
			||||||
    Exynos4210fimdWindow *w;
 | 
					    Exynos4210fimdWindow *w;
 | 
				
			||||||
 | 
					    DirtyBitmapSnapshot *snap;
 | 
				
			||||||
    int i, line;
 | 
					    int i, line;
 | 
				
			||||||
    hwaddr fb_line_addr, inc_size;
 | 
					    hwaddr fb_line_addr, inc_size;
 | 
				
			||||||
    int scrn_height;
 | 
					    int scrn_height;
 | 
				
			||||||
| 
						 | 
					@ -1291,10 +1292,12 @@ static void exynos4210_fimd_update(void *opaque)
 | 
				
			||||||
            memory_region_sync_dirty_bitmap(w->mem_section.mr);
 | 
					            memory_region_sync_dirty_bitmap(w->mem_section.mr);
 | 
				
			||||||
            host_fb_addr = w->host_fb_addr;
 | 
					            host_fb_addr = w->host_fb_addr;
 | 
				
			||||||
            fb_line_addr = w->mem_section.offset_within_region;
 | 
					            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++) {
 | 
					            for (line = 0; line < scrn_height; line++) {
 | 
				
			||||||
                is_dirty = memory_region_get_dirty(w->mem_section.mr,
 | 
					                is_dirty = memory_region_snapshot_get_dirty(w->mem_section.mr,
 | 
				
			||||||
                            fb_line_addr, scrn_width, DIRTY_MEMORY_VGA);
 | 
					                            snap, fb_line_addr, scrn_width);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                if (s->invalidate || is_dirty) {
 | 
					                if (s->invalidate || is_dirty) {
 | 
				
			||||||
                    if (first_line == -1) {
 | 
					                    if (first_line == -1) {
 | 
				
			||||||
| 
						 | 
					@ -1309,9 +1312,7 @@ static void exynos4210_fimd_update(void *opaque)
 | 
				
			||||||
                fb_line_addr += inc_size;
 | 
					                fb_line_addr += inc_size;
 | 
				
			||||||
                is_dirty = false;
 | 
					                is_dirty = false;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            memory_region_reset_dirty(w->mem_section.mr,
 | 
					            g_free(snap);
 | 
				
			||||||
                w->mem_section.offset_within_region,
 | 
					 | 
				
			||||||
                w->fb_len, DIRTY_MEMORY_VGA);
 | 
					 | 
				
			||||||
            blend = true;
 | 
					            blend = true;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -67,7 +67,7 @@ void framebuffer_update_display(
 | 
				
			||||||
    int *first_row, /* Input and output.  */
 | 
					    int *first_row, /* Input and output.  */
 | 
				
			||||||
    int *last_row /* Output only */)
 | 
					    int *last_row /* Output only */)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    hwaddr src_len;
 | 
					    DirtyBitmapSnapshot *snap;
 | 
				
			||||||
    uint8_t *dest;
 | 
					    uint8_t *dest;
 | 
				
			||||||
    uint8_t *src;
 | 
					    uint8_t *src;
 | 
				
			||||||
    int first, last = 0;
 | 
					    int first, last = 0;
 | 
				
			||||||
| 
						 | 
					@ -78,7 +78,6 @@ void framebuffer_update_display(
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    i = *first_row;
 | 
					    i = *first_row;
 | 
				
			||||||
    *first_row = -1;
 | 
					    *first_row = -1;
 | 
				
			||||||
    src_len = (hwaddr)src_width * rows;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    mem = mem_section->mr;
 | 
					    mem = mem_section->mr;
 | 
				
			||||||
    if (!mem) {
 | 
					    if (!mem) {
 | 
				
			||||||
| 
						 | 
					@ -102,9 +101,10 @@ void framebuffer_update_display(
 | 
				
			||||||
    src += i * src_width;
 | 
					    src += i * src_width;
 | 
				
			||||||
    dest += i * dest_row_pitch;
 | 
					    dest += i * dest_row_pitch;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    snap = memory_region_snapshot_and_clear_dirty(mem, addr, src_width * rows,
 | 
				
			||||||
 | 
					                                                  DIRTY_MEMORY_VGA);
 | 
				
			||||||
    for (; i < rows; i++) {
 | 
					    for (; i < rows; i++) {
 | 
				
			||||||
        dirty = memory_region_get_dirty(mem, addr, src_width,
 | 
					        dirty = memory_region_snapshot_get_dirty(mem, snap, addr, src_width);
 | 
				
			||||||
                                             DIRTY_MEMORY_VGA);
 | 
					 | 
				
			||||||
        if (dirty || invalidate) {
 | 
					        if (dirty || invalidate) {
 | 
				
			||||||
            fn(opaque, dest, src, cols, dest_col_pitch);
 | 
					            fn(opaque, dest, src, cols, dest_col_pitch);
 | 
				
			||||||
            if (first == -1)
 | 
					            if (first == -1)
 | 
				
			||||||
| 
						 | 
					@ -115,11 +115,10 @@ void framebuffer_update_display(
 | 
				
			||||||
        src += src_width;
 | 
					        src += src_width;
 | 
				
			||||||
        dest += dest_row_pitch;
 | 
					        dest += dest_row_pitch;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    g_free(snap);
 | 
				
			||||||
    if (first < 0) {
 | 
					    if (first < 0) {
 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    memory_region_reset_dirty(mem, mem_section->offset_within_region, src_len,
 | 
					 | 
				
			||||||
                              DIRTY_MEMORY_VGA);
 | 
					 | 
				
			||||||
    *first_row = first;
 | 
					    *first_row = first;
 | 
				
			||||||
    *last_row = last;
 | 
					    *last_row = last;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -64,17 +64,8 @@ typedef struct G364State {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static inline int check_dirty(G364State *s, ram_addr_t page)
 | 
					static inline int check_dirty(G364State *s, ram_addr_t page)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    return memory_region_get_dirty(&s->mem_vram, page, G364_PAGE_SIZE,
 | 
					    return memory_region_test_and_clear_dirty(&s->mem_vram, page, G364_PAGE_SIZE,
 | 
				
			||||||
                                   DIRTY_MEMORY_VGA);
 | 
					                                              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);
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void g364fb_draw_graphic8(G364State *s)
 | 
					static void g364fb_draw_graphic8(G364State *s)
 | 
				
			||||||
| 
						 | 
					@ -83,7 +74,7 @@ static void g364fb_draw_graphic8(G364State *s)
 | 
				
			||||||
    int i, w;
 | 
					    int i, w;
 | 
				
			||||||
    uint8_t *vram;
 | 
					    uint8_t *vram;
 | 
				
			||||||
    uint8_t *data_display, *dd;
 | 
					    uint8_t *data_display, *dd;
 | 
				
			||||||
    ram_addr_t page, page_min, page_max;
 | 
					    ram_addr_t page;
 | 
				
			||||||
    int x, y;
 | 
					    int x, y;
 | 
				
			||||||
    int xmin, xmax;
 | 
					    int xmin, xmax;
 | 
				
			||||||
    int ymin, ymax;
 | 
					    int ymin, ymax;
 | 
				
			||||||
| 
						 | 
					@ -114,8 +105,6 @@ static void g364fb_draw_graphic8(G364State *s)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    page = 0;
 | 
					    page = 0;
 | 
				
			||||||
    page_min = (ram_addr_t)-1;
 | 
					 | 
				
			||||||
    page_max = 0;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    x = y = 0;
 | 
					    x = y = 0;
 | 
				
			||||||
    xmin = s->width;
 | 
					    xmin = s->width;
 | 
				
			||||||
| 
						 | 
					@ -137,9 +126,6 @@ static void g364fb_draw_graphic8(G364State *s)
 | 
				
			||||||
        if (check_dirty(s, page)) {
 | 
					        if (check_dirty(s, page)) {
 | 
				
			||||||
            if (y < ymin)
 | 
					            if (y < ymin)
 | 
				
			||||||
                ymin = ymax = y;
 | 
					                ymin = ymax = y;
 | 
				
			||||||
            if (page_min == (ram_addr_t)-1)
 | 
					 | 
				
			||||||
                page_min = page;
 | 
					 | 
				
			||||||
            page_max = page;
 | 
					 | 
				
			||||||
            if (x < xmin)
 | 
					            if (x < xmin)
 | 
				
			||||||
                xmin = x;
 | 
					                xmin = x;
 | 
				
			||||||
            for (i = 0; i < G364_PAGE_SIZE; i++) {
 | 
					            for (i = 0; i < G364_PAGE_SIZE; i++) {
 | 
				
			||||||
| 
						 | 
					@ -196,10 +182,7 @@ static void g364fb_draw_graphic8(G364State *s)
 | 
				
			||||||
                ymax = y;
 | 
					                ymax = y;
 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
            int dy;
 | 
					            int dy;
 | 
				
			||||||
            if (page_min != (ram_addr_t)-1) {
 | 
					            if (xmax || ymax) {
 | 
				
			||||||
                reset_dirty(s, page_min, page_max);
 | 
					 | 
				
			||||||
                page_min = (ram_addr_t)-1;
 | 
					 | 
				
			||||||
                page_max = 0;
 | 
					 | 
				
			||||||
                dpy_gfx_update(s->con, xmin, ymin,
 | 
					                dpy_gfx_update(s->con, xmin, ymin,
 | 
				
			||||||
                               xmax - xmin + 1, ymax - ymin + 1);
 | 
					                               xmax - xmin + 1, ymax - ymin + 1);
 | 
				
			||||||
                xmin = s->width;
 | 
					                xmin = s->width;
 | 
				
			||||||
| 
						 | 
					@ -219,9 +202,8 @@ static void g364fb_draw_graphic8(G364State *s)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
done:
 | 
					done:
 | 
				
			||||||
    if (page_min != (ram_addr_t)-1) {
 | 
					    if (xmax || ymax) {
 | 
				
			||||||
        dpy_gfx_update(s->con, xmin, ymin, xmax - xmin + 1, ymax - ymin + 1);
 | 
					        dpy_gfx_update(s->con, xmin, ymin, xmax - xmin + 1, ymax - ymin + 1);
 | 
				
			||||||
        reset_dirty(s, page_min, page_max);
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -305,6 +305,16 @@ void qxl_spice_reset_cursor(PCIQXLDevice *qxl)
 | 
				
			||||||
    qxl->ssd.cursor = cursor_builtin_hidden();
 | 
					    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)
 | 
					static ram_addr_t qxl_rom_size(void)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
#define QXL_REQUIRED_SZ (sizeof(QXLRom) + sizeof(QXLModes) + sizeof(qxl_modes))
 | 
					#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->num_pages          = cpu_to_le32(num_pages);
 | 
				
			||||||
    rom->ram_header_offset  = cpu_to_le32(d->vga.vram_size - ram_header_size);
 | 
					    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->shadow_rom = *rom;
 | 
				
			||||||
    d->rom        = rom;
 | 
					    d->rom        = rom;
 | 
				
			||||||
    d->modes      = modes;
 | 
					    d->modes      = modes;
 | 
				
			||||||
| 
						 | 
					@ -1011,16 +1033,6 @@ static void interface_set_client_capabilities(QXLInstance *sin,
 | 
				
			||||||
    qxl_send_events(qxl, QXL_INTERRUPT_CLIENT);
 | 
					    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,
 | 
					static bool qxl_rom_monitors_config_changed(QXLRom *rom,
 | 
				
			||||||
        VDAgentMonitorsConfig *monitors_config,
 | 
					        VDAgentMonitorsConfig *monitors_config,
 | 
				
			||||||
        unsigned int max_outputs)
 | 
					        unsigned int max_outputs)
 | 
				
			||||||
| 
						 | 
					@ -2397,6 +2409,8 @@ static Property qxl_properties[] = {
 | 
				
			||||||
#if SPICE_SERVER_VERSION >= 0x000c06 /* release 0.12.6 */
 | 
					#if SPICE_SERVER_VERSION >= 0x000c06 /* release 0.12.6 */
 | 
				
			||||||
        DEFINE_PROP_UINT16("max_outputs", PCIQXLDevice, max_outputs, 0),
 | 
					        DEFINE_PROP_UINT16("max_outputs", PCIQXLDevice, max_outputs, 0),
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					        DEFINE_PROP_UINT32("xres", PCIQXLDevice, xres, 0),
 | 
				
			||||||
 | 
					        DEFINE_PROP_UINT32("yres", PCIQXLDevice, yres, 0),
 | 
				
			||||||
        DEFINE_PROP_END_OF_LIST(),
 | 
					        DEFINE_PROP_END_OF_LIST(),
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -119,6 +119,8 @@ typedef struct PCIQXLDevice {
 | 
				
			||||||
    uint32_t          vram_size_mb;
 | 
					    uint32_t          vram_size_mb;
 | 
				
			||||||
    uint32_t          vram32_size_mb;
 | 
					    uint32_t          vram32_size_mb;
 | 
				
			||||||
    uint32_t          vgamem_size_mb;
 | 
					    uint32_t          vgamem_size_mb;
 | 
				
			||||||
 | 
					    uint32_t          xres;
 | 
				
			||||||
 | 
					    uint32_t          yres;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* qxl_render_update state */
 | 
					    /* qxl_render_update state */
 | 
				
			||||||
    int                render_update_cookie_num;
 | 
					    int                render_update_cookie_num;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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)
 | 
					void vga_sync_dirty_bitmap(VGACommonState *s)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    memory_region_sync_dirty_bitmap(&s->vram);
 | 
					    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);
 | 
					    DisplaySurface *surface = qemu_console_surface(s->con);
 | 
				
			||||||
    int y1, y, update, linesize, y_start, double_scan, mask, depth;
 | 
					    int y1, y, update, linesize, y_start, double_scan, mask, depth;
 | 
				
			||||||
    int width, height, shift_control, line_offset, bwidth, bits;
 | 
					    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;
 | 
					    int disp_width, multi_scan, multi_run;
 | 
				
			||||||
    uint8_t *d;
 | 
					    uint8_t *d;
 | 
				
			||||||
    uint32_t v, addr1, addr;
 | 
					    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);
 | 
					    full_update |= update_basic_params(s);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (!full_update)
 | 
					 | 
				
			||||||
        vga_sync_dirty_bitmap(s);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    s->get_resolution(s, &width, &height);
 | 
					    s->get_resolution(s, &width, &height);
 | 
				
			||||||
    disp_width = width;
 | 
					    disp_width = width;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1617,11 +1623,17 @@ static void vga_draw_graphic(VGACommonState *s, int full_update)
 | 
				
			||||||
    addr1 = (s->start_addr * 4);
 | 
					    addr1 = (s->start_addr * 4);
 | 
				
			||||||
    bwidth = (width * bits + 7) / 8;
 | 
					    bwidth = (width * bits + 7) / 8;
 | 
				
			||||||
    y_start = -1;
 | 
					    y_start = -1;
 | 
				
			||||||
    page_min = -1;
 | 
					 | 
				
			||||||
    page_max = 0;
 | 
					 | 
				
			||||||
    d = surface_data(surface);
 | 
					    d = surface_data(surface);
 | 
				
			||||||
    linesize = surface_stride(surface);
 | 
					    linesize = surface_stride(surface);
 | 
				
			||||||
    y1 = 0;
 | 
					    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++) {
 | 
					    for(y = 0; y < height; y++) {
 | 
				
			||||||
        addr = addr1;
 | 
					        addr = addr1;
 | 
				
			||||||
        if (!(s->cr[VGA_CRTC_MODE] & 1)) {
 | 
					        if (!(s->cr[VGA_CRTC_MODE] & 1)) {
 | 
				
			||||||
| 
						 | 
					@ -1636,17 +1648,17 @@ static void vga_draw_graphic(VGACommonState *s, int full_update)
 | 
				
			||||||
        update = full_update;
 | 
					        update = full_update;
 | 
				
			||||||
        page0 = addr;
 | 
					        page0 = addr;
 | 
				
			||||||
        page1 = addr + bwidth - 1;
 | 
					        page1 = addr + bwidth - 1;
 | 
				
			||||||
        update |= memory_region_get_dirty(&s->vram, page0, page1 - page0,
 | 
					        if (full_update) {
 | 
				
			||||||
                                          DIRTY_MEMORY_VGA);
 | 
					            update = 1;
 | 
				
			||||||
        /* explicit invalidation for the hardware cursor */
 | 
					        } else {
 | 
				
			||||||
        update |= (s->invalidated_y_table[y >> 5] >> (y & 0x1f)) & 1;
 | 
					            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 (update) {
 | 
				
			||||||
            if (y_start < 0)
 | 
					            if (y_start < 0)
 | 
				
			||||||
                y_start = y;
 | 
					                y_start = y;
 | 
				
			||||||
            if (page0 < page_min)
 | 
					 | 
				
			||||||
                page_min = page0;
 | 
					 | 
				
			||||||
            if (page1 > page_max)
 | 
					 | 
				
			||||||
                page_max = page1;
 | 
					 | 
				
			||||||
            if (!(is_buffer_shared(surface))) {
 | 
					            if (!(is_buffer_shared(surface))) {
 | 
				
			||||||
                vga_draw_line(s, d, s->vram_ptr + addr, width);
 | 
					                vga_draw_line(s, d, s->vram_ptr + addr, width);
 | 
				
			||||||
                if (s->cursor_draw_line)
 | 
					                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,
 | 
					        dpy_gfx_update(s->con, 0, y_start,
 | 
				
			||||||
                       disp_width, y - y_start);
 | 
					                       disp_width, y - y_start);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    /* reset modified pages */
 | 
					    g_free(snap);
 | 
				
			||||||
    if (page_max >= page_min) {
 | 
					    memset(s->invalidated_y_table, 0, sizeof(s->invalidated_y_table));
 | 
				
			||||||
        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);
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void vga_draw_blank(VGACommonState *s, int full_update)
 | 
					static void vga_draw_blank(VGACommonState *s, int full_update)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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)
 | 
					static pixman_format_code_t get_pixman_format(uint32_t virtio_gpu_format)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    switch (virtio_gpu_format) {
 | 
					    switch (virtio_gpu_format) {
 | 
				
			||||||
#ifdef HOST_WORDS_BIGENDIAN
 | 
					 | 
				
			||||||
    case VIRTIO_GPU_FORMAT_B8G8R8X8_UNORM:
 | 
					    case VIRTIO_GPU_FORMAT_B8G8R8X8_UNORM:
 | 
				
			||||||
        return PIXMAN_b8g8r8x8;
 | 
					        return PIXMAN_BE_b8g8r8x8;
 | 
				
			||||||
    case VIRTIO_GPU_FORMAT_B8G8R8A8_UNORM:
 | 
					    case VIRTIO_GPU_FORMAT_B8G8R8A8_UNORM:
 | 
				
			||||||
        return PIXMAN_b8g8r8a8;
 | 
					        return PIXMAN_BE_b8g8r8a8;
 | 
				
			||||||
    case VIRTIO_GPU_FORMAT_X8R8G8B8_UNORM:
 | 
					    case VIRTIO_GPU_FORMAT_X8R8G8B8_UNORM:
 | 
				
			||||||
        return PIXMAN_x8r8g8b8;
 | 
					        return PIXMAN_BE_x8r8g8b8;
 | 
				
			||||||
    case VIRTIO_GPU_FORMAT_A8R8G8B8_UNORM:
 | 
					    case VIRTIO_GPU_FORMAT_A8R8G8B8_UNORM:
 | 
				
			||||||
        return PIXMAN_a8r8g8b8;
 | 
					        return PIXMAN_BE_a8r8g8b8;
 | 
				
			||||||
    case VIRTIO_GPU_FORMAT_R8G8B8X8_UNORM:
 | 
					    case VIRTIO_GPU_FORMAT_R8G8B8X8_UNORM:
 | 
				
			||||||
        return PIXMAN_r8g8b8x8;
 | 
					        return PIXMAN_BE_r8g8b8x8;
 | 
				
			||||||
    case VIRTIO_GPU_FORMAT_R8G8B8A8_UNORM:
 | 
					    case VIRTIO_GPU_FORMAT_R8G8B8A8_UNORM:
 | 
				
			||||||
        return PIXMAN_r8g8b8a8;
 | 
					        return PIXMAN_BE_r8g8b8a8;
 | 
				
			||||||
    case VIRTIO_GPU_FORMAT_X8B8G8R8_UNORM:
 | 
					    case VIRTIO_GPU_FORMAT_X8B8G8R8_UNORM:
 | 
				
			||||||
        return PIXMAN_x8b8g8r8;
 | 
					        return PIXMAN_BE_x8b8g8r8;
 | 
				
			||||||
    case VIRTIO_GPU_FORMAT_A8B8G8R8_UNORM:
 | 
					    case VIRTIO_GPU_FORMAT_A8B8G8R8_UNORM:
 | 
				
			||||||
        return PIXMAN_a8b8g8r8;
 | 
					        return PIXMAN_BE_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
 | 
					 | 
				
			||||||
    default:
 | 
					    default:
 | 
				
			||||||
        return 0;
 | 
					        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,
 | 
					    virtio_init(VIRTIO_DEVICE(g), "virtio-gpu", VIRTIO_ID_GPU,
 | 
				
			||||||
                g->config_size);
 | 
					                g->config_size);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    g->req_state[0].width = 1024;
 | 
					    g->req_state[0].width = g->conf.xres;
 | 
				
			||||||
    g->req_state[0].height = 768;
 | 
					    g->req_state[0].height = g->conf.yres;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (virtio_gpu_virgl_enabled(g->conf)) {
 | 
					    if (virtio_gpu_virgl_enabled(g->conf)) {
 | 
				
			||||||
        /* use larger control queue in 3d mode */
 | 
					        /* use larger control queue in 3d mode */
 | 
				
			||||||
| 
						 | 
					@ -1291,6 +1272,8 @@ static Property virtio_gpu_properties[] = {
 | 
				
			||||||
    DEFINE_PROP_BIT("stats", VirtIOGPU, conf.flags,
 | 
					    DEFINE_PROP_BIT("stats", VirtIOGPU, conf.flags,
 | 
				
			||||||
                    VIRTIO_GPU_FLAG_STATS_ENABLED, false),
 | 
					                    VIRTIO_GPU_FLAG_STATS_ENABLED, false),
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					    DEFINE_PROP_UINT32("xres", VirtIOGPU, conf.xres, 1024),
 | 
				
			||||||
 | 
					    DEFINE_PROP_UINT32("yres", VirtIOGPU, conf.yres, 768),
 | 
				
			||||||
    DEFINE_PROP_END_OF_LIST(),
 | 
					    DEFINE_PROP_END_OF_LIST(),
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1118,9 +1118,9 @@ static void vmsvga_update_display(void *opaque)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    struct vmsvga_state_s *s = opaque;
 | 
					    struct vmsvga_state_s *s = opaque;
 | 
				
			||||||
    DisplaySurface *surface;
 | 
					    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);
 | 
					        s->vga.hw_ops->gfx_update(&s->vga);
 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					@ -1131,26 +1131,11 @@ static void vmsvga_update_display(void *opaque)
 | 
				
			||||||
    vmsvga_fifo_run(s);
 | 
					    vmsvga_fifo_run(s);
 | 
				
			||||||
    vmsvga_update_rect_flush(s);
 | 
					    vmsvga_update_rect_flush(s);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /*
 | 
					    if (s->invalidated) {
 | 
				
			||||||
     * 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) {
 | 
					 | 
				
			||||||
        s->invalidated = 0;
 | 
					        s->invalidated = 0;
 | 
				
			||||||
        dpy_gfx_update(s->vga.con, 0, 0,
 | 
					        dpy_gfx_update(s->vga.con, 0, 0,
 | 
				
			||||||
                   surface_width(surface), surface_height(surface));
 | 
					                   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)
 | 
					static void vmsvga_reset(DeviceState *dev)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -918,6 +918,53 @@ void memory_region_set_dirty(MemoryRegion *mr, hwaddr addr,
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
bool memory_region_test_and_clear_dirty(MemoryRegion *mr, hwaddr addr,
 | 
					bool memory_region_test_and_clear_dirty(MemoryRegion *mr, hwaddr addr,
 | 
				
			||||||
                                        hwaddr size, unsigned client);
 | 
					                                        hwaddr size, unsigned client);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * memory_region_snapshot_and_clear_dirty: Get a snapshot of the dirty
 | 
				
			||||||
 | 
					 *                                         bitmap and clear it.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Creates a snapshot of the dirty bitmap, clears the dirty bitmap and
 | 
				
			||||||
 | 
					 * returns the snapshot.  The snapshot can then be used to query dirty
 | 
				
			||||||
 | 
					 * status, using memory_region_snapshot_get_dirty.  Unlike
 | 
				
			||||||
 | 
					 * memory_region_test_and_clear_dirty this allows to query the same
 | 
				
			||||||
 | 
					 * page multiple times, which is especially useful for display updates
 | 
				
			||||||
 | 
					 * where the scanlines often are not page aligned.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * The dirty bitmap region which gets copyed into the snapshot (and
 | 
				
			||||||
 | 
					 * cleared afterwards) can be larger than requested.  The boundaries
 | 
				
			||||||
 | 
					 * are rounded up/down so complete bitmap longs (covering 64 pages on
 | 
				
			||||||
 | 
					 * 64bit hosts) can be copied over into the bitmap snapshot.  Which
 | 
				
			||||||
 | 
					 * isn't a problem for display updates as the extra pages are outside
 | 
				
			||||||
 | 
					 * the visible area, and in case the visible area changes a full
 | 
				
			||||||
 | 
					 * display redraw is due anyway.  Should other use cases for this
 | 
				
			||||||
 | 
					 * function emerge we might have to revisit this implementation
 | 
				
			||||||
 | 
					 * detail.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Use g_free to release DirtyBitmapSnapshot.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @mr: the memory region being queried.
 | 
				
			||||||
 | 
					 * @addr: the address (relative to the start of the region) being queried.
 | 
				
			||||||
 | 
					 * @size: the size of the range being queried.
 | 
				
			||||||
 | 
					 * @client: the user of the logging information; typically %DIRTY_MEMORY_VGA.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					DirtyBitmapSnapshot *memory_region_snapshot_and_clear_dirty(MemoryRegion *mr,
 | 
				
			||||||
 | 
					                                                            hwaddr addr,
 | 
				
			||||||
 | 
					                                                            hwaddr size,
 | 
				
			||||||
 | 
					                                                            unsigned client);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * memory_region_snapshot_get_dirty: Check whether a range of bytes is dirty
 | 
				
			||||||
 | 
					 *                                   in the specified dirty bitmap snapshot.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @mr: the memory region being queried.
 | 
				
			||||||
 | 
					 * @snap: the dirty bitmap snapshot
 | 
				
			||||||
 | 
					 * @addr: the address (relative to the start of the region) being queried.
 | 
				
			||||||
 | 
					 * @size: the size of the range being queried.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					bool memory_region_snapshot_get_dirty(MemoryRegion *mr,
 | 
				
			||||||
 | 
					                                      DirtyBitmapSnapshot *snap,
 | 
				
			||||||
 | 
					                                      hwaddr addr, hwaddr size);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * memory_region_sync_dirty_bitmap: Synchronize a region's dirty bitmap with
 | 
					 * memory_region_sync_dirty_bitmap: Synchronize a region's dirty bitmap with
 | 
				
			||||||
 *                                  any external TLBs (e.g. kvm)
 | 
					 *                                  any external TLBs (e.g. kvm)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -343,6 +343,13 @@ bool cpu_physical_memory_test_and_clear_dirty(ram_addr_t start,
 | 
				
			||||||
                                              ram_addr_t length,
 | 
					                                              ram_addr_t length,
 | 
				
			||||||
                                              unsigned client);
 | 
					                                              unsigned client);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					DirtyBitmapSnapshot *cpu_physical_memory_snapshot_and_clear_dirty
 | 
				
			||||||
 | 
					    (ram_addr_t start, ram_addr_t length, unsigned client);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool cpu_physical_memory_snapshot_get_dirty(DirtyBitmapSnapshot *snap,
 | 
				
			||||||
 | 
					                                            ram_addr_t start,
 | 
				
			||||||
 | 
					                                            ram_addr_t length);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static inline void cpu_physical_memory_clear_dirty_range(ram_addr_t start,
 | 
					static inline void cpu_physical_memory_clear_dirty_range(ram_addr_t start,
 | 
				
			||||||
                                                         ram_addr_t length)
 | 
					                                                         ram_addr_t length)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -72,6 +72,8 @@ struct virtio_gpu_conf {
 | 
				
			||||||
    uint64_t max_hostmem;
 | 
					    uint64_t max_hostmem;
 | 
				
			||||||
    uint32_t max_outputs;
 | 
					    uint32_t max_outputs;
 | 
				
			||||||
    uint32_t flags;
 | 
					    uint32_t flags;
 | 
				
			||||||
 | 
					    uint32_t xres;
 | 
				
			||||||
 | 
					    uint32_t yres;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct virtio_gpu_ctrl_command {
 | 
					struct virtio_gpu_ctrl_command {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -220,6 +220,8 @@ void bitmap_set(unsigned long *map, long i, long len);
 | 
				
			||||||
void bitmap_set_atomic(unsigned long *map, long i, long len);
 | 
					void bitmap_set_atomic(unsigned long *map, long i, long len);
 | 
				
			||||||
void bitmap_clear(unsigned long *map, long start, long nr);
 | 
					void bitmap_clear(unsigned long *map, long start, long nr);
 | 
				
			||||||
bool bitmap_test_and_clear_atomic(unsigned long *map, long start, long nr);
 | 
					bool bitmap_test_and_clear_atomic(unsigned long *map, long start, long nr);
 | 
				
			||||||
 | 
					void bitmap_copy_and_clear_atomic(unsigned long *dst, unsigned long *src,
 | 
				
			||||||
 | 
					                                  long nr);
 | 
				
			||||||
unsigned long bitmap_find_next_zero_area(unsigned long *map,
 | 
					unsigned long bitmap_find_next_zero_area(unsigned long *map,
 | 
				
			||||||
                                         unsigned long size,
 | 
					                                         unsigned long size,
 | 
				
			||||||
                                         unsigned long start,
 | 
					                                         unsigned long start,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -23,6 +23,7 @@ typedef struct CPUAddressSpace CPUAddressSpace;
 | 
				
			||||||
typedef struct CPUState CPUState;
 | 
					typedef struct CPUState CPUState;
 | 
				
			||||||
typedef struct DeviceListener DeviceListener;
 | 
					typedef struct DeviceListener DeviceListener;
 | 
				
			||||||
typedef struct DeviceState DeviceState;
 | 
					typedef struct DeviceState DeviceState;
 | 
				
			||||||
 | 
					typedef struct DirtyBitmapSnapshot DirtyBitmapSnapshot;
 | 
				
			||||||
typedef struct DisplayChangeListener DisplayChangeListener;
 | 
					typedef struct DisplayChangeListener DisplayChangeListener;
 | 
				
			||||||
typedef struct DisplayState DisplayState;
 | 
					typedef struct DisplayState DisplayState;
 | 
				
			||||||
typedef struct DisplaySurface DisplaySurface;
 | 
					typedef struct DisplaySurface DisplaySurface;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										17
									
								
								memory.c
								
								
								
								
							
							
						
						
									
										17
									
								
								memory.c
								
								
								
								
							| 
						 | 
					@ -1748,6 +1748,23 @@ bool memory_region_test_and_clear_dirty(MemoryRegion *mr, hwaddr addr,
 | 
				
			||||||
                memory_region_get_ram_addr(mr) + addr, size, client);
 | 
					                memory_region_get_ram_addr(mr) + addr, size, client);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					DirtyBitmapSnapshot *memory_region_snapshot_and_clear_dirty(MemoryRegion *mr,
 | 
				
			||||||
 | 
					                                                            hwaddr addr,
 | 
				
			||||||
 | 
					                                                            hwaddr size,
 | 
				
			||||||
 | 
					                                                            unsigned client)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    assert(mr->ram_block);
 | 
				
			||||||
 | 
					    return cpu_physical_memory_snapshot_and_clear_dirty(
 | 
				
			||||||
 | 
					                memory_region_get_ram_addr(mr) + addr, size, client);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool memory_region_snapshot_get_dirty(MemoryRegion *mr, DirtyBitmapSnapshot *snap,
 | 
				
			||||||
 | 
					                                      hwaddr addr, hwaddr size)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    assert(mr->ram_block);
 | 
				
			||||||
 | 
					    return cpu_physical_memory_snapshot_get_dirty(snap,
 | 
				
			||||||
 | 
					                memory_region_get_ram_addr(mr) + addr, size);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void memory_region_sync_dirty_bitmap(MemoryRegion *mr)
 | 
					void memory_region_sync_dirty_bitmap(MemoryRegion *mr)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1410,6 +1410,8 @@ void register_displaychangelistener(DisplayChangeListener *dcl)
 | 
				
			||||||
    static DisplaySurface *dummy;
 | 
					    static DisplaySurface *dummy;
 | 
				
			||||||
    QemuConsole *con;
 | 
					    QemuConsole *con;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    assert(!dcl->ds);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (dcl->ops->dpy_gl_ctx_create) {
 | 
					    if (dcl->ops->dpy_gl_ctx_create) {
 | 
				
			||||||
        /* display has opengl support */
 | 
					        /* display has opengl support */
 | 
				
			||||||
        assert(dcl->con);
 | 
					        assert(dcl->con);
 | 
				
			||||||
| 
						 | 
					@ -1538,6 +1540,8 @@ void dpy_gfx_replace_surface(QemuConsole *con,
 | 
				
			||||||
    DisplaySurface *old_surface = con->surface;
 | 
					    DisplaySurface *old_surface = con->surface;
 | 
				
			||||||
    DisplayChangeListener *dcl;
 | 
					    DisplayChangeListener *dcl;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    assert(old_surface != surface);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    con->surface = surface;
 | 
					    con->surface = surface;
 | 
				
			||||||
    QLIST_FOREACH(dcl, &s->listeners, next) {
 | 
					    QLIST_FOREACH(dcl, &s->listeners, next) {
 | 
				
			||||||
        if (con != (dcl->con ? dcl->con : active_console)) {
 | 
					        if (con != (dcl->con ? dcl->con : active_console)) {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -287,6 +287,17 @@ bool bitmap_test_and_clear_atomic(unsigned long *map, long start, long nr)
 | 
				
			||||||
    return dirty != 0;
 | 
					    return dirty != 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void bitmap_copy_and_clear_atomic(unsigned long *dst, unsigned long *src,
 | 
				
			||||||
 | 
					                                  long nr)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    while (nr > 0) {
 | 
				
			||||||
 | 
					        *dst = atomic_xchg(src, 0);
 | 
				
			||||||
 | 
					        dst++;
 | 
				
			||||||
 | 
					        src++;
 | 
				
			||||||
 | 
					        nr -= BITS_PER_LONG;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define ALIGN_MASK(x,mask)      (((x)+(mask))&~(mask))
 | 
					#define ALIGN_MASK(x,mask)      (((x)+(mask))&~(mask))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue