Example #1
0
static void qxl_render_update_area_unlocked(PCIQXLDevice *qxl)
{
    VGACommonState *vga = &qxl->vga;
    int i;

    if (qxl->guest_primary.resized) {
        qxl->guest_primary.resized = 0;
        qxl->guest_primary.data = qxl_phys2virt(qxl,
                                                qxl->guest_primary.surface.mem,
                                                MEMSLOT_GROUP_GUEST);
        if (!qxl->guest_primary.data) {
            return;
        }
        qxl_set_rect_to_surface(qxl, &qxl->dirty[0]);
        qxl->num_dirty_rects = 1;
        trace_qxl_render_guest_primary_resized(
            qxl->guest_primary.surface.width,
            qxl->guest_primary.surface.height,
            qxl->guest_primary.qxl_stride,
            qxl->guest_primary.bytes_pp,
            qxl->guest_primary.bits_pp);
        if (qxl->guest_primary.qxl_stride > 0) {
            qemu_free_displaysurface(vga->ds);
            vga->ds->surface = qemu_create_displaysurface_from
                               (qxl->guest_primary.surface.width,
                                qxl->guest_primary.surface.height,
                                qxl->guest_primary.bits_pp,
                                qxl->guest_primary.abs_stride,
                                qxl->guest_primary.data);
        } else {
            qemu_resize_displaysurface(vga->ds,
                                       qxl->guest_primary.surface.width,
                                       qxl->guest_primary.surface.height);
        }
        dpy_resize(vga->ds);
    }

    if (!qxl->guest_primary.data) {
        return;
    }
    for (i = 0; i < qxl->num_dirty_rects; i++) {
        if (qemu_spice_rect_is_empty(qxl->dirty+i)) {
            break;
        }
        if (qxl->dirty[i].left < 0 ||
                qxl->dirty[i].top < 0 ||
                qxl->dirty[i].left > qxl->dirty[i].right ||
                qxl->dirty[i].top > qxl->dirty[i].bottom ||
                qxl->dirty[i].right > qxl->guest_primary.surface.width ||
                qxl->dirty[i].bottom > qxl->guest_primary.surface.height) {
            continue;
        }
        qxl_blit(qxl, qxl->dirty+i);
        dpy_update(vga->ds,
                   qxl->dirty[i].left, qxl->dirty[i].top,
                   qxl->dirty[i].right - qxl->dirty[i].left,
                   qxl->dirty[i].bottom - qxl->dirty[i].top);
    }
    qxl->num_dirty_rects = 0;
}
Example #2
0
static void vgafb_update_display(void *opaque)
{
    MilkymistVgafbState *s = opaque;
    int first = 0;
    int last = 0;
    drawfn fn;

    if (!vgafb_enabled(s)) {
        return;
    }

    int dest_width = s->regs[R_HRES];

    switch (ds_get_bits_per_pixel(s->ds)) {
    case 0:
        return;
    case 8:
        fn = draw_line_8;
        break;
    case 15:
        fn = draw_line_15;
        dest_width *= 2;
        break;
    case 16:
        fn = draw_line_16;
        dest_width *= 2;
        break;
    case 24:
        fn = draw_line_24;
        dest_width *= 3;
        break;
    case 32:
        fn = draw_line_32;
        dest_width *= 4;
        break;
    default:
        hw_error("milkymist_vgafb: bad color depth\n");
        break;
    }

    framebuffer_update_display(s->ds,
                               s->regs[R_BASEADDRESS] + s->fb_offset,
                               s->regs[R_HRES],
                               s->regs[R_VRES],
                               s->regs[R_HRES] * 2,
                               dest_width,
                               0,
                               s->invalidate,
                               fn,
                               NULL,
                               &first, &last);

    if (first >= 0) {
        dpy_update(s->ds, 0, first, s->regs[R_HRES], last - first + 1);
    }
    s->invalidate = 0;
}
Example #3
0
/* This copies data from the guest framebuffer region, into QEMU's copy
 * NB. QEMU's copy is stored in the pixel format of a) the local X 
 * server (SDL case) or b) the current VNC client pixel format.
 * When shifting between colour depths we preserve the MSB.
 */
static void xenfb_guest_copy(struct xenfb *xenfb, int x, int y, int w, int h)
{
    int line;

    if (!xenfb->ds->shared_buf) {
        if (xenfb->depth == xenfb->ds->depth) { /* Perfect match can use fast path */
            for (line = y ; line < (y+h) ; line++) {
                memcpy(xenfb->ds->data + (line * xenfb->ds->linesize) + (x * xenfb->ds->depth / 8),
                        xenfb->pixels + xenfb->offset + (line * xenfb->row_stride) + (x * xenfb->depth / 8),
                        w * xenfb->depth / 8);
            }
        } else { /* Mismatch requires slow pixel munging */
            /* 8 bit == r:3 g:3 b:2 */
            /* 16 bit == r:5 g:6 b:5 */
            /* 24 bit == r:8 g:8 b:8 */
            /* 32 bit == r:8 g:8 b:8 (padding:8) */
            if (xenfb->depth == 8) {
                if (xenfb->ds->depth == 16) {
                    BLT(uint8_t, uint16_t,   3, 3, 2,   5, 6, 5);
                } else if (xenfb->ds->depth == 32) {
                    BLT(uint8_t, uint32_t,   3, 3, 2,   8, 8, 8);
                }
            } else if (xenfb->depth == 16) {
                if (xenfb->ds->depth == 8) {
                    BLT(uint16_t, uint8_t,   5, 6, 5,   3, 3, 2);
                } else if (xenfb->ds->depth == 32) {
                    BLT(uint16_t, uint32_t,  5, 6, 5,   8, 8, 8);
                }
            } else if (xenfb->depth == 24 || xenfb->depth == 32) {
                if (xenfb->ds->depth == 8) {
                    BLT(uint32_t, uint8_t,   8, 8, 8,   3, 3, 2);
                } else if (xenfb->ds->depth == 16) {
                    BLT(uint32_t, uint16_t,  8, 8, 8,   5, 6, 5);
                } else if (xenfb->ds->depth == 32) {
                    BLT(uint32_t, uint32_t,  8, 8, 8,   8, 8, 8);
                }
            }
        }
    }
    dpy_update(xenfb->ds, x, y, w, h);
}
/*
 * This copies data from the guest framebuffer region, into QEMU's
 * displaysurface. qemu uses 16 or 32 bpp.  In case the pv framebuffer
 * uses something else we must convert and copy, otherwise we can
 * supply the buffer directly and no thing here.
 */
static void xenfb_guest_copy(struct XenFB *xenfb, int x, int y, int w, int h)
{
    int line, oops = 0;
    int bpp = ds_get_bits_per_pixel(xenfb->c.ds);
    int linesize = ds_get_linesize(xenfb->c.ds);
    uint8_t *data = ds_get_data(xenfb->c.ds);

    if (!is_buffer_shared(xenfb->c.ds->surface)) {
        switch (xenfb->depth) {
        case 8:
            if (bpp == 16) {
                BLT(uint8_t, uint16_t,   3, 3, 2,   5, 6, 5);
            } else if (bpp == 32) {
                BLT(uint8_t, uint32_t,   3, 3, 2,   8, 8, 8);
            } else {
                oops = 1;
            }
            break;
        case 24:
            if (bpp == 16) {
                BLT(uint32_t, uint16_t,  8, 8, 8,   5, 6, 5);
            } else if (bpp == 32) {
                BLT(uint32_t, uint32_t,  8, 8, 8,   8, 8, 8);
            } else {
                oops = 1;
            }
            break;
        default:
            oops = 1;
	}
    }
    if (oops) /* should not happen */
        xen_be_printf(&xenfb->c.xendev, 0, "%s: oops: convert %d -> %d bpp?\n",
                      __FUNCTION__, xenfb->depth, bpp);

    dpy_update(xenfb->c.ds, x, y, w, h);
}
Example #5
0
/* This copies data from the guest framebuffer region, into QEMU's copy
 * NB. QEMU's copy is stored in the pixel format of a) the local X 
 * server (SDL case) or b) the current VNC client pixel format.
 * When shifting between colour depths we preserve the MSB.
 */
static void xenfb_guest_copy(struct xenfb *xenfb, int x, int y, int w, int h)
{
    int line;

    if (xenfb->depth == xenfb->ds->depth) { /* Perfect match can use fast path */
        for (line = y ; line < (y+h) ; line++) {
            memcpy(xenfb->ds->data + (line * xenfb->ds->linesize) + (x * xenfb->ds->depth / 8),
                   xenfb->pixels + (line * xenfb->row_stride) + (x * xenfb->depth / 8),
                   w * xenfb->depth / 8);
        }
    } else { /* Mismatch requires slow pixel munging */
        if (xenfb->depth == 8) {
            /* 8 bit source == r:3 g:3 b:2 */
            if (xenfb->ds->depth == 16) {
                BLT(uint8_t, uint16_t,   5, 2, 0,   11, 5, 0,   7, 7, 3);
            } else if (xenfb->ds->depth == 32) {
                BLT(uint8_t, uint32_t,   5, 2, 0,   16, 8, 0,   7, 7, 3);
            }
        } else if (xenfb->depth == 16) {
            /* 16 bit source == r:5 g:6 b:5 */
            if (xenfb->ds->depth == 8) {
                BLT(uint16_t, uint8_t,    11, 5, 0,   5, 2, 0,    31, 63, 31);
            } else if (xenfb->ds->depth == 32) {
                BLT(uint16_t, uint32_t,   11, 5, 0,   16, 8, 0,   31, 63, 31);
            }
        } else if (xenfb->depth == 32) {
            /* 32 bit source == r:8 g:8 b:8 (padding:8) */
            if (xenfb->ds->depth == 8) {
                BLT(uint32_t, uint8_t,    16, 8, 0,   5, 2, 0,    255, 255, 255);
            } else if (xenfb->ds->depth == 16) {
                BLT(uint32_t, uint16_t,   16, 8, 0,   11, 5, 0,   255, 255, 255);
            }
        }
    }
    dpy_update(xenfb->ds, x, y, w, h);
}
Example #6
0
File: tcx.c Project: asias/qemu
static void tcx24_update_display(void *opaque)
{
    TCXState *ts = opaque;
    ram_addr_t page, page_min, page_max, cpage, page24;
    int y, y_start, dd, ds;
    uint8_t *d, *s;
    uint32_t *cptr, *s24;

    if (ds_get_bits_per_pixel(ts->ds) != 32)
            return;
    page = 0;
    page24 = ts->vram24_offset;
    cpage = ts->cplane_offset;
    y_start = -1;
    page_min = -1;
    page_max = 0;
    d = ds_get_data(ts->ds);
    s = ts->vram;
    s24 = ts->vram24;
    cptr = ts->cplane;
    dd = ds_get_linesize(ts->ds);
    ds = 1024;

    for(y = 0; y < ts->height; y += 4, page += TARGET_PAGE_SIZE,
            page24 += TARGET_PAGE_SIZE, cpage += TARGET_PAGE_SIZE) {
        if (check_dirty(ts, page, page24, cpage)) {
            if (y_start < 0)
                y_start = y;
            if (page < page_min)
                page_min = page;
            if (page > page_max)
                page_max = page;
            tcx24_draw_line32(ts, d, s, ts->width, cptr, s24);
            d += dd;
            s += ds;
            cptr += ds;
            s24 += ds;
            tcx24_draw_line32(ts, d, s, ts->width, cptr, s24);
            d += dd;
            s += ds;
            cptr += ds;
            s24 += ds;
            tcx24_draw_line32(ts, d, s, ts->width, cptr, s24);
            d += dd;
            s += ds;
            cptr += ds;
            s24 += ds;
            tcx24_draw_line32(ts, d, s, ts->width, cptr, s24);
            d += dd;
            s += ds;
            cptr += ds;
            s24 += ds;
        } else {
            if (y_start >= 0) {
                /* flush to display */
                dpy_update(ts->ds, 0, y_start,
                           ts->width, y - y_start);
                y_start = -1;
            }
            d += dd * 4;
            s += ds * 4;
            cptr += ds * 4;
            s24 += ds * 4;
        }
    }
    if (y_start >= 0) {
        /* flush to display */
        dpy_update(ts->ds, 0, y_start,
                   ts->width, y - y_start);
    }
    /* reset modified pages */
    if (page_max >= page_min) {
        reset_dirty(ts, page_min, page_max, page24, cpage);
    }
}
Example #7
0
File: tcx.c Project: asias/qemu
/* Fixed line length 1024 allows us to do nice tricks not possible on
   VGA... */
static void tcx_update_display(void *opaque)
{
    TCXState *ts = opaque;
    ram_addr_t page, page_min, page_max;
    int y, y_start, dd, ds;
    uint8_t *d, *s;
    void (*f)(TCXState *s1, uint8_t *dst, const uint8_t *src, int width);

    if (ds_get_bits_per_pixel(ts->ds) == 0)
        return;
    page = 0;
    y_start = -1;
    page_min = -1;
    page_max = 0;
    d = ds_get_data(ts->ds);
    s = ts->vram;
    dd = ds_get_linesize(ts->ds);
    ds = 1024;

    switch (ds_get_bits_per_pixel(ts->ds)) {
    case 32:
        f = tcx_draw_line32;
        break;
    case 15:
    case 16:
        f = tcx_draw_line16;
        break;
    default:
    case 8:
        f = tcx_draw_line8;
        break;
    case 0:
        return;
    }

    for(y = 0; y < ts->height; y += 4, page += TARGET_PAGE_SIZE) {
        if (memory_region_get_dirty(&ts->vram_mem, page, TARGET_PAGE_SIZE,
                                    DIRTY_MEMORY_VGA)) {
            if (y_start < 0)
                y_start = y;
            if (page < page_min)
                page_min = page;
            if (page > page_max)
                page_max = page;
            f(ts, d, s, ts->width);
            d += dd;
            s += ds;
            f(ts, d, s, ts->width);
            d += dd;
            s += ds;
            f(ts, d, s, ts->width);
            d += dd;
            s += ds;
            f(ts, d, s, ts->width);
            d += dd;
            s += ds;
        } else {
            if (y_start >= 0) {
                /* flush to display */
                dpy_update(ts->ds, 0, y_start,
                           ts->width, y - y_start);
                y_start = -1;
            }
            d += dd * 4;
            s += ds * 4;
        }
    }
    if (y_start >= 0) {
        /* flush to display */
        dpy_update(ts->ds, 0, y_start,
                   ts->width, y - y_start);
    }
    /* reset modified pages */
    if (page_max >= page_min) {
        memory_region_reset_dirty(&ts->vram_mem,
                                  page_min, page_max + TARGET_PAGE_SIZE,
                                  DIRTY_MEMORY_VGA);
    }
}
Example #8
0
static void pl110_update_display(void *opaque)
{
    pl110_state *s = (pl110_state *)opaque;
    drawfn* fntable;
    drawfn fn;
    int dest_width;
    int src_width;
    int bpp_offset;
    int first;
    int last;

    if (!pl110_enabled(s))
        return;

    switch (ds_get_bits_per_pixel(s->ds)) {
    case 0:
        return;
    case 8:
        fntable = pl110_draw_fn_8;
        dest_width = 1;
        break;
    case 15:
        fntable = pl110_draw_fn_15;
        dest_width = 2;
        break;
    case 16:
        fntable = pl110_draw_fn_16;
        dest_width = 2;
        break;
    case 24:
        fntable = pl110_draw_fn_24;
        dest_width = 3;
        break;
    case 32:
        fntable = pl110_draw_fn_32;
        dest_width = 4;
        break;
    default:
        fprintf(stderr, "pl110: Bad color depth\n");
        exit(1);
    }
    if (s->cr & PL110_CR_BGR)
        bpp_offset = 0;
    else
        bpp_offset = 18;

    if (s->cr & PL110_CR_BEBO)
        fn = fntable[s->bpp + 6 + bpp_offset];
    else if (s->cr & PL110_CR_BEPO)
        fn = fntable[s->bpp + 12 + bpp_offset];
    else
        fn = fntable[s->bpp + bpp_offset];

    src_width = s->cols;
    switch (s->bpp) {
    case BPP_1:
        src_width >>= 3;
        break;
    case BPP_2:
        src_width >>= 2;
        break;
    case BPP_4:
        src_width >>= 1;
        break;
    case BPP_8:
        break;
    case BPP_16:
        src_width <<= 1;
        break;
    case BPP_32:
        src_width <<= 2;
        break;
    }
    dest_width *= s->cols;
    first = 0;
    framebuffer_update_display(s->ds,
                               s->upbase, s->cols, s->rows,
                               src_width, dest_width, 0,
                               s->invalidate,
                               fn, s->pallette,
                               &first, &last);
    if (first >= 0) {
        dpy_update(s->ds, 0, first, s->cols, last - first + 1);
    }
    s->invalidate = 0;
}
Example #9
0
static void bcm2708_fb_update(void *_opaque)
{
	struct bcm2708_vc *vc = _opaque;
    drawfn* fntable;
    drawfn fn;
    int dest_width;
    int src_width;
    int bpp_offset;
    int first;
    int last;

    switch (ds_get_bits_per_pixel(vc->disp))
	{
    case 0:
        return;
    case 8:
        fntable = pl110_draw_fn_8;
        dest_width = 1;
        break;
    case 15:
        fntable = pl110_draw_fn_15;
        dest_width = 2;
        break;
    case 16:
        fntable = pl110_draw_fn_16;
        dest_width = 2;
        break;
    case 24:
        fntable = pl110_draw_fn_24;
        dest_width = 3;
        break;
    case 32:
        fntable = pl110_draw_fn_32;
        dest_width = 4;
        break;
    default:
        fprintf(stderr, "bcm2708: Bad color depth\n");
        exit(1);
    }

    bpp_offset = 0;
    fn = fntable[vc->fb_bpp + bpp_offset];

    src_width = vc->fb.xres;
    switch (vc->fb_bpp) {
    case BPP_1:
        src_width >>= 3;
        break;
    case BPP_2:
        src_width >>= 2;
        break;
    case BPP_4:
        src_width >>= 1;
        break;
    case BPP_8:
        break;
    case BPP_16:
    case BPP_16_565:
    case BPP_12:
        src_width <<= 1;
        break;
    case BPP_32:
        src_width <<= 2;
        break;
    }

    dest_width *= vc->fb.xres;
    first = 0;

	framebuffer_update_display(vc->disp, get_system_memory(),
			vc->fb.base, vc->fb.xres, vc->fb.yres,
			src_width, dest_width, 0,
			vc->fb_invalidate,
			fn, NULL,
			&first, &last);
	if (first >= 0) {
		dpy_update(vc->disp, 0, first, vc->fb.xres, last - first + 1);
	}

    vc->fb_invalidate = 0;
}
Example #10
0
static void pxa2xx_update_display(void *opaque)
{
    PXA2xxLCDState *s = (PXA2xxLCDState *) opaque;
    target_phys_addr_t fbptr;
    int miny, maxy;
    int ch;
    if (!(s->control[0] & LCCR0_ENB))
        return;

    pxa2xx_descriptor_load(s);

    pxa2xx_lcdc_resize(s);
    miny = s->yres;
    maxy = 0;
    s->transp = s->dma_ch[2].up || s->dma_ch[3].up;
    /* Note: With overlay planes the order depends on LCCR0 bit 25.  */
    for (ch = 0; ch < PXA_LCDDMA_CHANS; ch ++)
        if (s->dma_ch[ch].up) {
            if (!s->dma_ch[ch].source) {
                pxa2xx_dma_ber_set(s, ch);
                continue;
            }
            fbptr = s->dma_ch[ch].source;
            if (!(fbptr >= PXA2XX_SDRAM_BASE &&
                    fbptr <= PXA2XX_SDRAM_BASE + ram_size)) {
                pxa2xx_dma_ber_set(s, ch);
                continue;
            }

            if (s->dma_ch[ch].command & LDCMD_PAL) {
                cpu_physical_memory_read(fbptr, s->dma_ch[ch].pbuffer,
                    MAX(LDCMD_LENGTH(s->dma_ch[ch].command),
                        sizeof(s->dma_ch[ch].pbuffer)));
                pxa2xx_palette_parse(s, ch, s->bpp);
            } else {
                /* Do we need to reparse palette */
                if (LCCR4_PALFOR(s->control[4]) != s->pal_for)
                    pxa2xx_palette_parse(s, ch, s->bpp);

                /* ACK frame start */
                pxa2xx_dma_sof_set(s, ch);

                s->dma_ch[ch].redraw(s, fbptr, &miny, &maxy);
                s->invalidated = 0;

                /* ACK frame completed */
                pxa2xx_dma_eof_set(s, ch);
            }
        }

    if (s->control[0] & LCCR0_DIS) {
        /* ACK last frame completed */
        s->control[0] &= ~LCCR0_ENB;
        s->status[0] |= LCSR0_LDD;
    }

    if (miny >= 0) {
        switch (s->orientation) {
        case 0:
            dpy_update(s->ds, 0, miny, s->xres, maxy - miny + 1);
            break;
        case 90:
            dpy_update(s->ds, miny, 0, maxy - miny + 1, s->xres);
            break;
        case 180:
            maxy = s->yres - maxy - 1;
            miny = s->yres - miny - 1;
            dpy_update(s->ds, 0, maxy, s->xres, miny - maxy + 1);
            break;
        case 270:
            maxy = s->yres - maxy - 1;
            miny = s->yres - miny - 1;
            dpy_update(s->ds, maxy, 0, miny - maxy + 1, s->xres);
            break;
        }
    }
    pxa2xx_lcdc_int_update(s);

    qemu_irq_raise(s->vsync_cb);
}
Example #11
0
void qxl_render_update(PCIQXLDevice *qxl)
{
    VGACommonState *vga = &qxl->vga;
    QXLRect dirty[32], update;
    void *ptr;
    int i;

    if (qxl->guest_primary.resized) {
        qxl->guest_primary.resized = 0;

        if (qxl->guest_primary.flipped) {
            qemu_free(qxl->guest_primary.flipped);
            qxl->guest_primary.flipped = NULL;
        }
        qemu_free_displaysurface(vga->ds);

        qxl->guest_primary.data = qemu_get_ram_ptr(qxl->vga.vram_offset);
        if (qxl->guest_primary.stride < 0) {
            /* spice surface is upside down -> need extra buffer to flip */
            qxl->guest_primary.stride = -qxl->guest_primary.stride;
            qxl->guest_primary.flipped = qemu_malloc(qxl->guest_primary.surface.width *
                                                     qxl->guest_primary.stride);
            ptr = qxl->guest_primary.flipped;
        } else {
            ptr = qxl->guest_primary.data;
        }
        dprint(qxl, 1, "%s: %dx%d, stride %d, bpp %d, depth %d, flip %s\n",
               __FUNCTION__,
               qxl->guest_primary.surface.width,
               qxl->guest_primary.surface.height,
               qxl->guest_primary.stride,
               qxl->guest_primary.bytes_pp,
               qxl->guest_primary.bits_pp,
               qxl->guest_primary.flipped ? "yes" : "no");
        vga->ds->surface =
            qemu_create_displaysurface_from(qxl->guest_primary.surface.width,
                                            qxl->guest_primary.surface.height,
                                            qxl->guest_primary.bits_pp,
                                            qxl->guest_primary.stride,
                                            ptr);
        dpy_resize(vga->ds);
    }

    if (!qxl->guest_primary.commands) {
        return;
    }
    qxl->guest_primary.commands = 0;

    update.left   = 0;
    update.right  = qxl->guest_primary.surface.width;
    update.top    = 0;
    update.bottom = qxl->guest_primary.surface.height;

    memset(dirty, 0, sizeof(dirty));
    qxl->ssd.worker->update_area(qxl->ssd.worker, 0, &update,
                                 dirty, ARRAY_SIZE(dirty), 1);

    for (i = 0; i < ARRAY_SIZE(dirty); i++) {
        if (qemu_spice_rect_is_empty(dirty+i)) {
            break;
        }
        if (qxl->guest_primary.flipped) {
            qxl_flip(qxl, dirty+i);
        }
        dpy_update(vga->ds,
                   dirty[i].left, dirty[i].top,
                   dirty[i].right - dirty[i].left,
                   dirty[i].bottom - dirty[i].top);
    }
}
Example #12
0
void qxl_render_update(PCIQXLDevice *qxl)
{
    VGACommonState *vga = &qxl->vga;
    QXLRect dirty[32], update;
    void *ptr;
    int i, redraw = 0;

    if (!is_buffer_shared(vga->ds->surface)) {
        dprint(qxl, 1, "%s: restoring shared displaysurface\n", __func__);
        qxl->guest_primary.resized++;
        qxl->guest_primary.commands++;
        redraw = 1;
    }

    if (qxl->guest_primary.resized) {
        qxl->guest_primary.resized = 0;

        if (qxl->guest_primary.flipped) {
            g_free(qxl->guest_primary.flipped);
            qxl->guest_primary.flipped = NULL;
        }
        qemu_free_displaysurface(vga->ds);

        qxl->guest_primary.data = memory_region_get_ram_ptr(&qxl->vga.vram);
        if (qxl->guest_primary.qxl_stride < 0) {
            /* spice surface is upside down -> need extra buffer to flip */
            qxl->guest_primary.flipped =
                g_malloc(qxl->guest_primary.surface.width *
                         qxl->guest_primary.abs_stride);
            ptr = qxl->guest_primary.flipped;
        } else {
            ptr = qxl->guest_primary.data;
        }
        dprint(qxl, 1, "%s: %dx%d, stride %d, bpp %d, depth %d, flip %s\n",
               __FUNCTION__,
               qxl->guest_primary.surface.width,
               qxl->guest_primary.surface.height,
               qxl->guest_primary.qxl_stride,
               qxl->guest_primary.bytes_pp,
               qxl->guest_primary.bits_pp,
               qxl->guest_primary.flipped ? "yes" : "no");
        vga->ds->surface =
            qemu_create_displaysurface_from(qxl->guest_primary.surface.width,
                                            qxl->guest_primary.surface.height,
                                            qxl->guest_primary.bits_pp,
                                            qxl->guest_primary.abs_stride,
                                            ptr);
        dpy_resize(vga->ds);
    }

    if (!qxl->guest_primary.commands) {
        return;
    }
    qxl->guest_primary.commands = 0;

    update.left   = 0;
    update.right  = qxl->guest_primary.surface.width;
    update.top    = 0;
    update.bottom = qxl->guest_primary.surface.height;

    memset(dirty, 0, sizeof(dirty));
    qxl_spice_update_area(qxl, 0, &update,
                          dirty, ARRAY_SIZE(dirty), 1, QXL_SYNC);
    if (redraw) {
        memset(dirty, 0, sizeof(dirty));
        dirty[0] = update;
    }

    for (i = 0; i < ARRAY_SIZE(dirty); i++) {
        if (qemu_spice_rect_is_empty(dirty+i)) {
            break;
        }
        if (qxl->guest_primary.flipped) {
            qxl_flip(qxl, dirty+i);
        }
        dpy_update(vga->ds,
                   dirty[i].left, dirty[i].top,
                   dirty[i].right - dirty[i].left,
                   dirty[i].bottom - dirty[i].top);
    }
}