spice and qxl bugfixes.

-----BEGIN PGP SIGNATURE-----
 Version: GnuPG v2.0.22 (GNU/Linux)
 
 iQIcBAABAgAGBQJXfNLqAAoJEEy22O7T6HE41IQQANvL1W2WNdzbhjKypNK/R4lU
 dXu1RYks0zs/R4e9jGz9f7BR13WltOkuADOWjyECmQ8KZGlX/Dr0H7UeSA74hs9U
 ZqMXZm1L0Hr8vJIp+JtqejSXKVFWzgb2jduAjA/Oedly8IGuRm6pY8XM6CnGcrAt
 w9A9NG3KKgWoYB5laF7UZUgs+QaREgZT2JGbQJOUxHA/q0Ony3NF4OjTJaT5QkLP
 yoVaBQ1LiXFgOJVub+6rAgturW3fmp/vcAeA5KTaRHqFHD0fbMBtaGnRwDdKtDf+
 8YqYWNCL/QfVL6B+uSEUdFn8TgApr7RiAIeAPgSqaz354Lm99/TJNd217CKgsJrE
 PHq7mXrHcll5PmDcBbXJISVl3a1/kxsgXV2yH1wweIW+MPxvu3bAHweKWKBJCIvw
 aZTBpc7WFNJ7BxoRbTpKL0dHG2TSYSvhjislQqcwftoR/glimX+nTnChJ75yQX8F
 0q5v3MG37yZFEdSNbaMQlfvm0FdLb1DZrTmvR/23IWfd6HfE9hpsyvM9cQL0wIJt
 tPmLv39yqABajfa0inVzyHaqZdui4hGtvwYHt7BeL8t8UC7LRD9v/L6mFK9pVhK2
 YWC/XEnzg0d+MF7zCDoD99coI3iS5jgpKuRo01nRGwhK7pnbvbcYYz2WqMx42f1I
 oZO0u11rjQ0v+9yNPpsM
 =ZUKP
 -----END PGP SIGNATURE-----

Merge remote-tracking branch 'remotes/spice/tags/pull-spice-20160706-1' into staging

spice and qxl bugfixes.

# gpg: Signature made Wed 06 Jul 2016 10:44:10 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/spice/tags/pull-spice-20160706-1:
  virgl: pass whole GL scanout dimensions
  spice: use the right head for multi-monitor
  virgl: count the calls to gl_block
  spice: avoid .set_mm_time on >= 0.12.6
  qxl: fix surface migration
  qxl: store memory region and offset instead of pointer for guest slots
  qxl: factor out qxl_get_check_slot_offset
  qxl: handle no updates in interface_update_area_complete
  qxl: use uint64_t for vram size

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Peter Maydell 2016-07-06 12:49:51 +01:00
commit 0c56c6ab68
14 changed files with 121 additions and 65 deletions

View File

@ -504,6 +504,7 @@ static void interface_set_compression_level(QXLInstance *sin, int level)
qxl_rom_set_dirty(qxl);
}
#if SPICE_NEEDS_SET_MM_TIME
static void interface_set_mm_time(QXLInstance *sin, uint32_t mm_time)
{
PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl);
@ -517,6 +518,7 @@ static void interface_set_mm_time(QXLInstance *sin, uint32_t mm_time)
qxl->rom->mm_clock = cpu_to_le32(mm_time);
qxl_rom_set_dirty(qxl);
}
#endif
static void interface_get_init_info(QXLInstance *sin, QXLDevInitInfo *info)
{
@ -893,7 +895,8 @@ static void interface_update_area_complete(QXLInstance *sin,
int qxl_i;
qemu_mutex_lock(&qxl->ssd.lock);
if (surface_id != 0 || !qxl->render_update_cookie_num) {
if (surface_id != 0 || !num_updated_rects ||
!qxl->render_update_cookie_num) {
qemu_mutex_unlock(&qxl->ssd.lock);
return;
}
@ -1068,7 +1071,9 @@ static const QXLInterface qxl_interface = {
.attache_worker = interface_attach_worker,
.set_compression_level = interface_set_compression_level,
#if SPICE_NEEDS_SET_MM_TIME
.set_mm_time = interface_set_mm_time,
#endif
.get_init_info = interface_get_init_info,
/* the callbacks below are called from spice server thread context */
@ -1243,6 +1248,7 @@ static int qxl_add_memslot(PCIQXLDevice *d, uint32_t slot_id, uint64_t delta,
int pci_region;
pcibus_t pci_start;
pcibus_t pci_end;
MemoryRegion *mr;
intptr_t virt_start;
QXLDevMemSlot memslot;
int i;
@ -1289,11 +1295,11 @@ static int qxl_add_memslot(PCIQXLDevice *d, uint32_t slot_id, uint64_t delta,
switch (pci_region) {
case QXL_RAM_RANGE_INDEX:
virt_start = (intptr_t)memory_region_get_ram_ptr(&d->vga.vram);
mr = &d->vga.vram;
break;
case QXL_VRAM_RANGE_INDEX:
case 4 /* vram 64bit */:
virt_start = (intptr_t)memory_region_get_ram_ptr(&d->vram_bar);
mr = &d->vram_bar;
break;
default:
/* should not happen */
@ -1301,6 +1307,7 @@ static int qxl_add_memslot(PCIQXLDevice *d, uint32_t slot_id, uint64_t delta,
return 1;
}
virt_start = (intptr_t)memory_region_get_ram_ptr(mr);
memslot.slot_id = slot_id;
memslot.slot_group_id = MEMSLOT_GROUP_GUEST; /* guest group */
memslot.virt_start = virt_start + (guest_start - pci_start);
@ -1310,7 +1317,8 @@ static int qxl_add_memslot(PCIQXLDevice *d, uint32_t slot_id, uint64_t delta,
qxl_rom_set_dirty(d);
qemu_spice_add_memslot(&d->ssd, &memslot, async);
d->guest_slots[slot_id].ptr = (void*)memslot.virt_start;
d->guest_slots[slot_id].mr = mr;
d->guest_slots[slot_id].offset = memslot.virt_start - virt_start;
d->guest_slots[slot_id].size = memslot.virt_end - memslot.virt_start;
d->guest_slots[slot_id].delta = delta;
d->guest_slots[slot_id].active = 1;
@ -1337,39 +1345,60 @@ static void qxl_reset_surfaces(PCIQXLDevice *d)
}
/* can be also called from spice server thread context */
void *qxl_phys2virt(PCIQXLDevice *qxl, QXLPHYSICAL pqxl, int group_id)
static bool qxl_get_check_slot_offset(PCIQXLDevice *qxl, QXLPHYSICAL pqxl,
uint32_t *s, uint64_t *o)
{
uint64_t phys = le64_to_cpu(pqxl);
uint32_t slot = (phys >> (64 - 8)) & 0xff;
uint64_t offset = phys & 0xffffffffffff;
switch (group_id) {
case MEMSLOT_GROUP_HOST:
return (void *)(intptr_t)offset;
case MEMSLOT_GROUP_GUEST:
if (slot >= NUM_MEMSLOTS) {
qxl_set_guest_bug(qxl, "slot too large %d >= %d", slot,
NUM_MEMSLOTS);
return NULL;
}
if (!qxl->guest_slots[slot].active) {
qxl_set_guest_bug(qxl, "inactive slot %d\n", slot);
return NULL;
}
if (offset < qxl->guest_slots[slot].delta) {
qxl_set_guest_bug(qxl,
if (slot >= NUM_MEMSLOTS) {
qxl_set_guest_bug(qxl, "slot too large %d >= %d", slot,
NUM_MEMSLOTS);
return false;
}
if (!qxl->guest_slots[slot].active) {
qxl_set_guest_bug(qxl, "inactive slot %d\n", slot);
return false;
}
if (offset < qxl->guest_slots[slot].delta) {
qxl_set_guest_bug(qxl,
"slot %d offset %"PRIu64" < delta %"PRIu64"\n",
slot, offset, qxl->guest_slots[slot].delta);
return NULL;
}
offset -= qxl->guest_slots[slot].delta;
if (offset > qxl->guest_slots[slot].size) {
qxl_set_guest_bug(qxl,
return false;
}
offset -= qxl->guest_slots[slot].delta;
if (offset > qxl->guest_slots[slot].size) {
qxl_set_guest_bug(qxl,
"slot %d offset %"PRIu64" > size %"PRIu64"\n",
slot, offset, qxl->guest_slots[slot].size);
return false;
}
*s = slot;
*o = offset;
return true;
}
/* can be also called from spice server thread context */
void *qxl_phys2virt(PCIQXLDevice *qxl, QXLPHYSICAL pqxl, int group_id)
{
uint64_t offset;
uint32_t slot;
void *ptr;
switch (group_id) {
case MEMSLOT_GROUP_HOST:
offset = le64_to_cpu(pqxl) & 0xffffffffffff;
return (void *)(intptr_t)offset;
case MEMSLOT_GROUP_GUEST:
if (!qxl_get_check_slot_offset(qxl, pqxl, &slot, &offset)) {
return NULL;
}
return qxl->guest_slots[slot].ptr + offset;
ptr = memory_region_get_ram_ptr(qxl->guest_slots[slot].mr);
ptr += qxl->guest_slots[slot].offset;
ptr += offset;
return ptr;
}
return NULL;
}
@ -1784,9 +1813,23 @@ static void qxl_hw_update(void *opaque)
qxl_render_update(qxl);
}
static void qxl_dirty_one_surface(PCIQXLDevice *qxl, QXLPHYSICAL pqxl,
uint32_t height, int32_t stride)
{
uint64_t offset;
uint32_t slot, size;
bool rc;
rc = qxl_get_check_slot_offset(qxl, pqxl, &slot, &offset);
assert(rc == true);
size = height * abs(stride);
trace_qxl_surfaces_dirty(qxl->id, (int)offset, size);
qxl_set_dirty(qxl->guest_slots[slot].mr,
qxl->guest_slots[slot].offset + offset, size);
}
static void qxl_dirty_surfaces(PCIQXLDevice *qxl)
{
uintptr_t vram_start;
int i;
if (qxl->mode != QXL_MODE_NATIVE && qxl->mode != QXL_MODE_COMPAT) {
@ -1794,16 +1837,13 @@ static void qxl_dirty_surfaces(PCIQXLDevice *qxl)
}
/* dirty the primary surface */
qxl_set_dirty(&qxl->vga.vram, qxl->shadow_rom.draw_area_offset,
qxl->shadow_rom.surface0_area_size);
vram_start = (uintptr_t)memory_region_get_ram_ptr(&qxl->vram_bar);
qxl_dirty_one_surface(qxl, qxl->guest_primary.surface.mem,
qxl->guest_primary.surface.height,
qxl->guest_primary.surface.stride);
/* dirty the off-screen surfaces */
for (i = 0; i < qxl->ssd.num_surfaces; i++) {
QXLSurfaceCmd *cmd;
intptr_t surface_offset;
int surface_size;
if (qxl->guest_surfaces.cmds[i] == 0) {
continue;
@ -1813,15 +1853,9 @@ static void qxl_dirty_surfaces(PCIQXLDevice *qxl)
MEMSLOT_GROUP_GUEST);
assert(cmd);
assert(cmd->type == QXL_SURFACE_CMD_CREATE);
surface_offset = (intptr_t)qxl_phys2virt(qxl,
cmd->u.surface_create.data,
MEMSLOT_GROUP_GUEST);
assert(surface_offset);
surface_offset -= vram_start;
surface_size = cmd->u.surface_create.height *
abs(cmd->u.surface_create.stride);
trace_qxl_surfaces_dirty(qxl->id, i, (int)surface_offset, surface_size);
qxl_set_dirty(&qxl->vram_bar, surface_offset, surface_size);
qxl_dirty_one_surface(qxl, cmd->u.surface_create.data,
cmd->u.surface_create.height,
cmd->u.surface_create.stride);
}
}
@ -1914,7 +1948,7 @@ static void qxl_init_ramsize(PCIQXLDevice *qxl)
/* vram (surfaces, 64bit, bar 4+5) */
if (qxl->vram_size_mb != -1) {
qxl->vram_size = qxl->vram_size_mb * 1024 * 1024;
qxl->vram_size = (uint64_t)qxl->vram_size_mb * 1024 * 1024;
}
if (qxl->vram_size < qxl->vram32_size) {
qxl->vram_size = qxl->vram32_size;
@ -2020,9 +2054,9 @@ static void qxl_realize_common(PCIQXLDevice *qxl, Error **errp)
dprint(qxl, 1, "ram/%s: %d MB [region 0]\n",
qxl->id == 0 ? "pri" : "sec",
qxl->vga.vram_size / (1024*1024));
dprint(qxl, 1, "vram/32: %d MB [region 1]\n",
dprint(qxl, 1, "vram/32: %" PRIx64 "d MB [region 1]\n",
qxl->vram32_size / (1024*1024));
dprint(qxl, 1, "vram/64: %d MB %s\n",
dprint(qxl, 1, "vram/64: %" PRIx64 "d MB %s\n",
qxl->vram_size / (1024*1024),
qxl->vram32_size < qxl->vram_size ? "[region 4]" : "[unmapped]");
@ -2276,7 +2310,7 @@ static VMStateDescription qxl_vmstate = {
static Property qxl_properties[] = {
DEFINE_PROP_UINT32("ram_size", PCIQXLDevice, vga.vram_size,
64 * 1024 * 1024),
DEFINE_PROP_UINT32("vram_size", PCIQXLDevice, vram32_size,
DEFINE_PROP_UINT64("vram_size", PCIQXLDevice, vram32_size,
64 * 1024 * 1024),
DEFINE_PROP_UINT32("revision", PCIQXLDevice, revision,
QXL_DEFAULT_REVISION),

View File

@ -53,7 +53,8 @@ typedef struct PCIQXLDevice {
struct guest_slots {
QXLMemSlot slot;
void *ptr;
MemoryRegion *mr;
uint64_t offset;
uint64_t size;
uint64_t delta;
uint32_t active;
@ -104,9 +105,9 @@ typedef struct PCIQXLDevice {
#endif
/* vram pci bar */
uint32_t vram_size;
uint64_t vram_size;
MemoryRegion vram_bar;
uint32_t vram32_size;
uint64_t vram32_size;
MemoryRegion vram32_bar;
/* io bar */

View File

@ -105,7 +105,7 @@ qxl_spice_reset_image_cache(int qid) "%d"
qxl_spice_reset_memslots(int qid) "%d"
qxl_spice_update_area(int qid, uint32_t surface_id, uint32_t left, uint32_t right, uint32_t top, uint32_t bottom) "%d sid=%d [%d,%d,%d,%d]"
qxl_spice_update_area_rest(int qid, uint32_t num_dirty_rects, uint32_t clear_dirty_region) "%d #d=%d clear=%d"
qxl_surfaces_dirty(int qid, int surface, int offset, int size) "%d surface=%d offset=%d size=%d"
qxl_surfaces_dirty(int qid, int offset, int size) "%d offset=%d size=%d"
qxl_send_events(int qid, uint32_t events) "%d %d"
qxl_send_events_vm_stopped(int qid, uint32_t events) "%d %d"
qxl_set_guest_bug(int qid) "%d"

View File

@ -171,13 +171,14 @@ static void virgl_cmd_set_scanout(VirtIOGPU *g,
virgl_renderer_force_ctx_0();
dpy_gl_scanout(g->scanout[ss.scanout_id].con, info.tex_id,
info.flags & 1 /* FIXME: Y_0_TOP */,
info.width, info.height,
ss.r.x, ss.r.y, ss.r.width, ss.r.height);
} else {
if (ss.scanout_id != 0) {
dpy_gfx_replace_surface(g->scanout[ss.scanout_id].con, NULL);
}
dpy_gl_scanout(g->scanout[ss.scanout_id].con, 0, false,
0, 0, 0, 0);
0, 0, 0, 0, 0, 0);
}
g->scanout[ss.scanout_id].resource_id = ss.resource_id;
}
@ -580,7 +581,7 @@ void virtio_gpu_virgl_reset(VirtIOGPU *g)
if (i != 0) {
dpy_gfx_replace_surface(g->scanout[i].con, NULL);
}
dpy_gl_scanout(g->scanout[i].con, 0, false, 0, 0, 0, 0);
dpy_gl_scanout(g->scanout[i].con, 0, false, 0, 0, 0, 0, 0, 0);
}
}

View File

@ -934,8 +934,14 @@ static void virtio_gpu_gl_block(void *opaque, bool block)
{
VirtIOGPU *g = opaque;
g->renderer_blocked = block;
if (!block) {
if (block) {
g->renderer_blocked++;
} else {
g->renderer_blocked--;
}
assert(g->renderer_blocked >= 0);
if (g->renderer_blocked == 0) {
virtio_gpu_process_cmdq(g);
}
}

View File

@ -107,7 +107,7 @@ typedef struct VirtIOGPU {
bool use_virgl_renderer;
bool renderer_inited;
bool renderer_blocked;
int renderer_blocked;
QEMUTimer *fence_poll;
QEMUTimer *print_stats;

View File

@ -217,6 +217,7 @@ typedef struct DisplayChangeListenerOps {
void (*dpy_gl_scanout)(DisplayChangeListener *dcl,
uint32_t backing_id, bool backing_y_0_top,
uint32_t backing_width, uint32_t backing_height,
uint32_t x, uint32_t y, uint32_t w, uint32_t h);
void (*dpy_gl_update)(DisplayChangeListener *dcl,
uint32_t x, uint32_t y, uint32_t w, uint32_t h);
@ -285,6 +286,7 @@ bool dpy_gfx_check_format(QemuConsole *con,
void dpy_gl_scanout(QemuConsole *con,
uint32_t backing_id, bool backing_y_0_top,
uint32_t backing_width, uint32_t backing_height,
uint32_t x, uint32_t y, uint32_t w, uint32_t h);
void dpy_gl_update(QemuConsole *con,
uint32_t x, uint32_t y, uint32_t w, uint32_t h);

View File

@ -101,6 +101,7 @@ QEMUGLContext gd_egl_create_context(DisplayChangeListener *dcl,
QEMUGLParams *params);
void gd_egl_scanout(DisplayChangeListener *dcl,
uint32_t backing_id, bool backing_y_0_top,
uint32_t backing_width, uint32_t backing_height,
uint32_t x, uint32_t y,
uint32_t w, uint32_t h);
void gd_egl_scanout_flush(DisplayChangeListener *dcl,

View File

@ -42,6 +42,9 @@ int qemu_spice_set_pw_expire(time_t expires);
int qemu_spice_migrate_info(const char *hostname, int port, int tls_port,
const char *subject);
#define SPICE_NEEDS_SET_MM_TIME \
(!defined(SPICE_SERVER_VERSION) || (SPICE_SERVER_VERSION < 0xc06))
#if SPICE_SERVER_VERSION >= 0x000c02
void qemu_spice_register_ports(void);
#else

View File

@ -64,6 +64,7 @@ QEMUGLContext sdl2_gl_get_current_context(DisplayChangeListener *dcl);
void sdl2_gl_scanout(DisplayChangeListener *dcl,
uint32_t backing_id, bool backing_y_0_top,
uint32_t backing_width, uint32_t backing_height,
uint32_t x, uint32_t y,
uint32_t w, uint32_t h);
void sdl2_gl_scanout_flush(DisplayChangeListener *dcl,

View File

@ -1709,11 +1709,13 @@ QEMUGLContext dpy_gl_ctx_get_current(QemuConsole *con)
void dpy_gl_scanout(QemuConsole *con,
uint32_t backing_id, bool backing_y_0_top,
uint32_t backing_width, uint32_t backing_height,
uint32_t x, uint32_t y, uint32_t width, uint32_t height)
{
assert(con->gl);
con->gl->ops->dpy_gl_scanout(con->gl, backing_id,
backing_y_0_top,
backing_width, backing_height,
x, y, width, height);
}

View File

@ -172,6 +172,7 @@ QEMUGLContext gd_egl_create_context(DisplayChangeListener *dcl,
void gd_egl_scanout(DisplayChangeListener *dcl,
uint32_t backing_id, bool backing_y_0_top,
uint32_t backing_width, uint32_t backing_height,
uint32_t x, uint32_t y,
uint32_t w, uint32_t h)
{

View File

@ -186,6 +186,7 @@ QEMUGLContext sdl2_gl_get_current_context(DisplayChangeListener *dcl)
void sdl2_gl_scanout(DisplayChangeListener *dcl,
uint32_t backing_id, bool backing_y_0_top,
uint32_t backing_width, uint32_t backing_height,
uint32_t x, uint32_t y,
uint32_t w, uint32_t h)
{

View File

@ -527,11 +527,13 @@ static void interface_set_compression_level(QXLInstance *sin, int level)
/* nothing to do */
}
#if SPICE_NEEDS_SET_MM_TIME
static void interface_set_mm_time(QXLInstance *sin, uint32_t mm_time)
{
dprint(3, "%s/%d:\n", __func__, sin->id);
/* nothing to do */
}
#endif
static void interface_get_init_info(QXLInstance *sin, QXLDevInitInfo *info)
{
@ -686,6 +688,7 @@ static int interface_client_monitors_config(QXLInstance *sin,
{
SimpleSpiceDisplay *ssd = container_of(sin, SimpleSpiceDisplay, qxl);
QemuUIInfo info;
int head;
if (!dpy_ui_info_supported(ssd->dcl.con)) {
return 0; /* == not supported by guest */
@ -695,14 +698,12 @@ static int interface_client_monitors_config(QXLInstance *sin,
return 1;
}
/*
* FIXME: multihead is tricky due to the way
* spice has multihead implemented.
*/
memset(&info, 0, sizeof(info));
if (mc->num_of_monitors > 0) {
info.width = mc->monitors[0].width;
info.height = mc->monitors[0].height;
head = qemu_console_get_head(ssd->dcl.con);
if (mc->num_of_monitors > head) {
info.width = mc->monitors[head].width;
info.height = mc->monitors[head].height;
}
dpy_set_ui_info(ssd->dcl.con, &info);
dprint(1, "%s/%d: size %dx%d\n", __func__, ssd->qxl.id,
@ -718,7 +719,9 @@ static const QXLInterface dpy_interface = {
.attache_worker = interface_attach_worker,
.set_compression_level = interface_set_compression_level,
#if SPICE_NEEDS_SET_MM_TIME
.set_mm_time = interface_set_mm_time,
#endif
.get_init_info = interface_get_init_info,
/* the callbacks below are called from spice server thread context */
@ -858,6 +861,8 @@ static QEMUGLContext qemu_spice_gl_create_context(DisplayChangeListener *dcl,
static void qemu_spice_gl_scanout(DisplayChangeListener *dcl,
uint32_t tex_id,
bool y_0_top,
uint32_t backing_width,
uint32_t backing_height,
uint32_t x, uint32_t y,
uint32_t w, uint32_t h)
{
@ -880,9 +885,7 @@ static void qemu_spice_gl_scanout(DisplayChangeListener *dcl,
assert(!tex_id || fd >= 0);
/* note: spice server will close the fd */
spice_qxl_gl_scanout(&ssd->qxl, fd,
surface_width(ssd->ds),
surface_height(ssd->ds),
spice_qxl_gl_scanout(&ssd->qxl, fd, backing_width, backing_height,
stride, fourcc, y_0_top);
qemu_spice_gl_monitor_config(ssd, x, y, w, h);