Not fully functional yet. Known issues: - if the guest creates a "top down" primary surface (windows does) the vns/sdl display will be upside down. - mouse pointer isn't rendered. --- hw/qxl.c | 121 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 files changed, 117 insertions(+), 4 deletions(-)
diff --git a/hw/qxl.c b/hw/qxl.c index ed7e975..d69ad17 100644 --- a/hw/qxl.c +++ b/hw/qxl.c @@ -61,6 +61,12 @@ typedef struct PCIQXLDevice { enum qxl_mode mode; int generation; + DisplaySurface *surface_native; + SpiceRect surface_rect; + uint32_t surface_id; + int surface_render; + int surface_commands; + /* thread signaling */ pthread_t main; int pipe[2]; @@ -325,6 +331,7 @@ static int interface_get_command(QXLInstance *sin, struct QXLCommandExt *ext) if (notify) { qxl_send_events(qxl, QXL_INTERRUPT_DISPLAY); } + qxl->surface_commands++; return true; case QXL_MODE_UNDEFINED: default: @@ -433,6 +440,7 @@ static int interface_get_cursor_command(QXLInstance *sin, struct QXLCommandExt * if (notify) { qxl_send_events(qxl, QXL_INTERRUPT_CURSOR); } + qxl->surface_commands++; return true; } else { return false; @@ -454,6 +462,13 @@ static void interface_get_update_area(QXLInstance *sin, const struct SpiceRect * { PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl); + if (qxl->surface_render) { + qxl->surface_render = 0; + *rect = &qxl->surface_rect; + *surface_id = &qxl->surface_id; + return; + } + *rect = &qxl->ram->update_area; *surface_id = &qxl->ram->update_surface; } @@ -711,6 +726,7 @@ static void qxl_del_memslot(PCIQXLDevice *d, uint32_t slot_id) static void qxl_create_guest_primary(PCIQXLDevice *d) { QXLDevSurfaceCreate surface; + void *ptr; assert(d->mode != QXL_MODE_NATIVE); qxl_exit_vga_mode(d); @@ -732,6 +748,30 @@ static void qxl_create_guest_primary(PCIQXLDevice *d) d->mode = QXL_MODE_NATIVE; d->ssd.worker->create_primary_surface(d->ssd.worker, 0, &surface); + + fprintf(stderr, "%s: width %d height %d depth %d stride %d\n", __FUNCTION__, + surface.width, surface.height, surface.depth, surface.stride); + + if (surface.stride < 0) { + /* FIXME: will display upside down */ + surface.stride = -surface.stride; + } + + if (d->surface_native) { + qemu_free(d->surface_native); + d->surface_native = NULL; + } + + ptr = qemu_get_ram_ptr(d->vga.vram_offset); + d->surface_native = + qemu_create_displaysurface_from(surface.width, surface.height, + surface.depth, surface.stride, ptr); + + d->surface_id = 0; + d->surface_rect.top = 0; + d->surface_rect.bottom = surface.height; + d->surface_rect.left = 0; + d->surface_rect.right = surface.width; } static void qxl_destroy_primary(PCIQXLDevice *d) @@ -826,10 +866,16 @@ static uint32_t ioport_read(void *opaque, uint32_t addr) static void qxl_map(PCIDevice *pci, int region_num, pcibus_t addr, pcibus_t size, int type) { + static const char *names[] = { + [ QXL_IO_RANGE_INDEX ] = "ioports", + [ QXL_RAM_RANGE_INDEX ] = "devram", + [ QXL_ROM_RANGE_INDEX ] = "rom", + [ QXL_VRAM_RANGE_INDEX ] = "vram", + }; PCIQXLDevice *qxl = DO_UPCAST(PCIQXLDevice, pci, pci); - dprintf(1, "%s: bar %d addr 0x%lx size 0x%lx\n", __FUNCTION__, - region_num, addr, size); + dprintf(1, "%s: bar %d [%s] addr 0x%lx size 0x%lx\n", __FUNCTION__, + region_num, names[region_num], addr, size); switch (region_num) { case QXL_IO_RANGE_INDEX: @@ -901,6 +947,67 @@ static void init_pipe_signaling(PCIQXLDevice *d) qemu_set_fd_handler(d->pipe[0], pipe_read, NULL, d); } +/* graphics console */ + +static void qxl_hw_update(void *opaque) +{ + PCIQXLDevice *qxl = opaque; + VGACommonState *vga = &qxl->vga; + + if (qxl->mode == QXL_MODE_VGA) { + vga->update(vga); + return; + } + + if (qxl->surface_native) { + qemu_free_displaysurface(vga->ds); + vga->ds->surface = qxl->surface_native; + qxl->surface_native = NULL; + dpy_resize(vga->ds); + } + + if (qxl->surface_commands) { + qxl->surface_commands = 0; + qxl->surface_render = 1; + qxl->ssd.worker->update_area(qxl->ssd.worker); + + /* FIXME: want more specific dirty region here */ + dpy_update(vga->ds, 0, 0, ds_get_width(vga->ds), ds_get_height(vga->ds)); + } +} + +static void qxl_hw_invalidate(void *opaque) +{ + PCIQXLDevice *qxl = opaque; + VGACommonState *vga = &qxl->vga; + + vga->invalidate(vga); +} + +static void qxl_hw_screen_dump(void *opaque, const char *filename) +{ + PCIQXLDevice *qxl = opaque; + VGACommonState *vga = &qxl->vga; + + if (qxl->mode == QXL_MODE_VGA) { + vga->screen_dump(vga, filename); + return; + } +} + +static void qxl_hw_text_update(void *opaque, console_ch_t *chardata) +{ + PCIQXLDevice *qxl = opaque; + VGACommonState *vga = &qxl->vga; + + if (qxl->mode == QXL_MODE_VGA) { + vga->text_update(vga, chardata); + return; + } +} + +/* display change listener */ + static void display_update(struct DisplayState *ds, int x, int y, int w, int h) { if (qxl0->mode == QXL_MODE_VGA) { @@ -950,13 +1057,19 @@ static int qxl_init(PCIDevice *dev) register_ioport_write(0x3ba, 1, 1, qxl_vga_ioport_write, vga); register_ioport_write(0x3da, 1, 1, qxl_vga_ioport_write, vga); - qxl0 = qxl; +#if 0 vga->ds = graphic_console_init(vga->update, vga->invalidate, vga->screen_dump, vga->text_update, vga); +#else + vga->ds = graphic_console_init(qxl_hw_update, qxl_hw_invalidate, + qxl_hw_screen_dump, qxl_hw_text_update, qxl); +#endif qxl->ssd.ds = vga->ds; qxl->ssd.bufsize = (16 * 1024 * 1024); qxl->ssd.buf = qemu_malloc(qxl->ssd.bufsize); pthread_mutex_init(&qxl->ssd.lock, NULL); + + qxl0 = qxl; register_displaychangelistener(vga->ds, &display_listener); if (qxl->pci.romfile == NULL) @@ -1021,7 +1134,7 @@ static PCIDeviceInfo qxl_info = { .init = qxl_init, .config_write = qxl_write_config, .qdev.props = (Property[]) { - DEFINE_PROP_UINT32("ram_size", PCIQXLDevice, vga.vram_size, 32 * 1024 * 1024), + DEFINE_PROP_UINT32("ram_size", PCIQXLDevice, vga.vram_size, 64 * 1024 * 1024), DEFINE_PROP_UINT32("vram_size", PCIQXLDevice, vram_size, 64 * 1024 * 1024), DEFINE_PROP_END_OF_LIST(), } -- 1.6.6.1