]> Git Repo - qemu.git/blobdiff - ui/spice-display.c
spice: switch to queue for vga mode updates
[qemu.git] / ui / spice-display.c
index 15f0704eaf350d6346bc118c8b8172b2745d4bac..59c5fd764299351dfbc51724adee6105102b173e 100644 (file)
@@ -15,8 +15,6 @@
  * along with this program; if not, see <http://www.gnu.org/licenses/>.
  */
 
  * along with this program; if not, see <http://www.gnu.org/licenses/>.
  */
 
-#include <pthread.h>
-
 #include "qemu-common.h"
 #include "qemu-spice.h"
 #include "qemu-timer.h"
 #include "qemu-common.h"
 #include "qemu-spice.h"
 #include "qemu-timer.h"
@@ -24,6 +22,7 @@
 #include "monitor.h"
 #include "console.h"
 #include "sysemu.h"
 #include "monitor.h"
 #include "console.h"
 #include "sysemu.h"
+#include "trace.h"
 
 #include "spice-display.h"
 
 
 #include "spice-display.h"
 
@@ -62,7 +61,110 @@ void qemu_spice_rect_union(QXLRect *dest, const QXLRect *r)
     dest->right = MAX(dest->right, r->right);
 }
 
     dest->right = MAX(dest->right, r->right);
 }
 
-static SimpleSpiceUpdate *qemu_spice_create_update(SimpleSpiceDisplay *ssd)
+QXLCookie *qxl_cookie_new(int type, uint64_t io)
+{
+    QXLCookie *cookie;
+
+    cookie = g_malloc0(sizeof(*cookie));
+    cookie->type = type;
+    cookie->io = io;
+    return cookie;
+}
+
+void qemu_spice_add_memslot(SimpleSpiceDisplay *ssd, QXLDevMemSlot *memslot,
+                            qxl_async_io async)
+{
+    trace_qemu_spice_add_memslot(ssd->qxl.id, memslot->slot_id,
+                                memslot->virt_start, memslot->virt_end,
+                                async);
+
+    if (async != QXL_SYNC) {
+        spice_qxl_add_memslot_async(&ssd->qxl, memslot,
+                (uintptr_t)qxl_cookie_new(QXL_COOKIE_TYPE_IO,
+                                          QXL_IO_MEMSLOT_ADD_ASYNC));
+    } else {
+        ssd->worker->add_memslot(ssd->worker, memslot);
+    }
+}
+
+void qemu_spice_del_memslot(SimpleSpiceDisplay *ssd, uint32_t gid, uint32_t sid)
+{
+    trace_qemu_spice_del_memslot(ssd->qxl.id, gid, sid);
+    ssd->worker->del_memslot(ssd->worker, gid, sid);
+}
+
+void qemu_spice_create_primary_surface(SimpleSpiceDisplay *ssd, uint32_t id,
+                                       QXLDevSurfaceCreate *surface,
+                                       qxl_async_io async)
+{
+    trace_qemu_spice_create_primary_surface(ssd->qxl.id, id, surface, async);
+    if (async != QXL_SYNC) {
+        spice_qxl_create_primary_surface_async(&ssd->qxl, id, surface,
+                (uintptr_t)qxl_cookie_new(QXL_COOKIE_TYPE_IO,
+                                          QXL_IO_CREATE_PRIMARY_ASYNC));
+    } else {
+        ssd->worker->create_primary_surface(ssd->worker, id, surface);
+    }
+}
+
+void qemu_spice_destroy_primary_surface(SimpleSpiceDisplay *ssd,
+                                        uint32_t id, qxl_async_io async)
+{
+    trace_qemu_spice_destroy_primary_surface(ssd->qxl.id, id, async);
+    if (async != QXL_SYNC) {
+        spice_qxl_destroy_primary_surface_async(&ssd->qxl, id,
+                (uintptr_t)qxl_cookie_new(QXL_COOKIE_TYPE_IO,
+                                          QXL_IO_DESTROY_PRIMARY_ASYNC));
+    } else {
+        ssd->worker->destroy_primary_surface(ssd->worker, id);
+    }
+}
+
+void qemu_spice_wakeup(SimpleSpiceDisplay *ssd)
+{
+    trace_qemu_spice_wakeup(ssd->qxl.id);
+    ssd->worker->wakeup(ssd->worker);
+}
+
+#if SPICE_SERVER_VERSION < 0x000b02 /* before 0.11.2 */
+static void qemu_spice_start(SimpleSpiceDisplay *ssd)
+{
+    trace_qemu_spice_start(ssd->qxl.id);
+    ssd->worker->start(ssd->worker);
+}
+
+static void qemu_spice_stop(SimpleSpiceDisplay *ssd)
+{
+    trace_qemu_spice_stop(ssd->qxl.id);
+    ssd->worker->stop(ssd->worker);
+}
+
+#else
+
+static int spice_display_is_running;
+
+void qemu_spice_display_start(void)
+{
+    spice_display_is_running = true;
+}
+
+void qemu_spice_display_stop(void)
+{
+    spice_display_is_running = false;
+}
+
+#endif
+
+int qemu_spice_display_is_running(SimpleSpiceDisplay *ssd)
+{
+#if SPICE_SERVER_VERSION < 0x000b02 /* before 0.11.2 */
+    return ssd->running;
+#else
+    return spice_display_is_running;
+#endif
+}
+
+static void qemu_spice_create_update(SimpleSpiceDisplay *ssd)
 {
     SimpleSpiceUpdate *update;
     QXLDrawable *drawable;
 {
     SimpleSpiceUpdate *update;
     QXLDrawable *drawable;
@@ -70,35 +172,40 @@ static SimpleSpiceUpdate *qemu_spice_create_update(SimpleSpiceDisplay *ssd)
     QXLCommand *cmd;
     uint8_t *src, *dst;
     int by, bw, bh;
     QXLCommand *cmd;
     uint8_t *src, *dst;
     int by, bw, bh;
+    struct timespec time_space;
 
     if (qemu_spice_rect_is_empty(&ssd->dirty)) {
 
     if (qemu_spice_rect_is_empty(&ssd->dirty)) {
-        return NULL;
+        return;
     };
 
     };
 
-    dprint(2, "%s: lr %d -> %d,  tb -> %d -> %d\n", __FUNCTION__,
+    trace_qemu_spice_create_update(
            ssd->dirty.left, ssd->dirty.right,
            ssd->dirty.top, ssd->dirty.bottom);
 
            ssd->dirty.left, ssd->dirty.right,
            ssd->dirty.top, ssd->dirty.bottom);
 
-    update   = qemu_mallocz(sizeof(*update));
+    update   = g_malloc0(sizeof(*update));
     drawable = &update->drawable;
     image    = &update->image;
     cmd      = &update->ext.cmd;
 
     bw       = ssd->dirty.right - ssd->dirty.left;
     bh       = ssd->dirty.bottom - ssd->dirty.top;
     drawable = &update->drawable;
     image    = &update->image;
     cmd      = &update->ext.cmd;
 
     bw       = ssd->dirty.right - ssd->dirty.left;
     bh       = ssd->dirty.bottom - ssd->dirty.top;
-    update->bitmap = qemu_malloc(bw * bh * 4);
+    update->bitmap = g_malloc(bw * bh * 4);
 
     drawable->bbox            = ssd->dirty;
     drawable->clip.type       = SPICE_CLIP_TYPE_NONE;
     drawable->effect          = QXL_EFFECT_OPAQUE;
 
     drawable->bbox            = ssd->dirty;
     drawable->clip.type       = SPICE_CLIP_TYPE_NONE;
     drawable->effect          = QXL_EFFECT_OPAQUE;
-    drawable->release_info.id = (intptr_t)update;
+    drawable->release_info.id = (uintptr_t)update;
     drawable->type            = QXL_DRAW_COPY;
     drawable->surfaces_dest[0] = -1;
     drawable->surfaces_dest[1] = -1;
     drawable->surfaces_dest[2] = -1;
     drawable->type            = QXL_DRAW_COPY;
     drawable->surfaces_dest[0] = -1;
     drawable->surfaces_dest[1] = -1;
     drawable->surfaces_dest[2] = -1;
+    clock_gettime(CLOCK_MONOTONIC, &time_space);
+    /* time in milliseconds from epoch. */
+    drawable->mm_time = time_space.tv_sec * 1000
+                      + time_space.tv_nsec / 1000 / 1000;
 
     drawable->u.copy.rop_descriptor  = SPICE_ROPD_OP_PUT;
 
     drawable->u.copy.rop_descriptor  = SPICE_ROPD_OP_PUT;
-    drawable->u.copy.src_bitmap      = (intptr_t)image;
+    drawable->u.copy.src_bitmap      = (uintptr_t)image;
     drawable->u.copy.src_area.right  = bw;
     drawable->u.copy.src_area.bottom = bh;
 
     drawable->u.copy.src_area.right  = bw;
     drawable->u.copy.src_area.bottom = bh;
 
@@ -108,7 +215,7 @@ static SimpleSpiceUpdate *qemu_spice_create_update(SimpleSpiceDisplay *ssd)
     image->bitmap.stride     = bw * 4;
     image->descriptor.width  = image->bitmap.x = bw;
     image->descriptor.height = image->bitmap.y = bh;
     image->bitmap.stride     = bw * 4;
     image->descriptor.width  = image->bitmap.x = bw;
     image->descriptor.height = image->bitmap.y = bh;
-    image->bitmap.data = (intptr_t)(update->bitmap);
+    image->bitmap.data = (uintptr_t)(update->bitmap);
     image->bitmap.palette = 0;
     image->bitmap.format = SPICE_BITMAP_FMT_32BIT;
 
     image->bitmap.palette = 0;
     image->bitmap.format = SPICE_BITMAP_FMT_32BIT;
 
@@ -129,22 +236,22 @@ static SimpleSpiceUpdate *qemu_spice_create_update(SimpleSpiceDisplay *ssd)
     }
 
     cmd->type = QXL_CMD_DRAW;
     }
 
     cmd->type = QXL_CMD_DRAW;
-    cmd->data = (intptr_t)drawable;
+    cmd->data = (uintptr_t)drawable;
 
     memset(&ssd->dirty, 0, sizeof(ssd->dirty));
 
     memset(&ssd->dirty, 0, sizeof(ssd->dirty));
-    return update;
+    QTAILQ_INSERT_TAIL(&ssd->updates, update, next);
 }
 
 /*
  * Called from spice server thread context (via interface_release_ressource)
  * We do *not* hold the global qemu mutex here, so extra care is needed
 }
 
 /*
  * Called from spice server thread context (via interface_release_ressource)
  * We do *not* hold the global qemu mutex here, so extra care is needed
- * when calling qemu functions.  Qemu interfaces used:
- *    - qemu_free (underlying glibc free is re-entrant).
+ * when calling qemu functions.  QEMU interfaces used:
+ *    - g_free (underlying glibc free is re-entrant).
  */
 void qemu_spice_destroy_update(SimpleSpiceDisplay *sdpy, SimpleSpiceUpdate *update)
 {
  */
 void qemu_spice_destroy_update(SimpleSpiceDisplay *sdpy, SimpleSpiceUpdate *update)
 {
-    qemu_free(update->bitmap);
-    qemu_free(update);
+    g_free(update->bitmap);
+    g_free(update);
 }
 
 void qemu_spice_create_host_memslot(SimpleSpiceDisplay *ssd)
 }
 
 void qemu_spice_create_host_memslot(SimpleSpiceDisplay *ssd)
@@ -156,13 +263,15 @@ void qemu_spice_create_host_memslot(SimpleSpiceDisplay *ssd)
     memset(&memslot, 0, sizeof(memslot));
     memslot.slot_group_id = MEMSLOT_GROUP_HOST;
     memslot.virt_end = ~0;
     memset(&memslot, 0, sizeof(memslot));
     memslot.slot_group_id = MEMSLOT_GROUP_HOST;
     memslot.virt_end = ~0;
-    ssd->worker->add_memslot(ssd->worker, &memslot);
+    qemu_spice_add_memslot(ssd, &memslot, QXL_SYNC);
 }
 
 void qemu_spice_create_host_primary(SimpleSpiceDisplay *ssd)
 {
     QXLDevSurfaceCreate surface;
 
 }
 
 void qemu_spice_create_host_primary(SimpleSpiceDisplay *ssd)
 {
     QXLDevSurfaceCreate surface;
 
+    memset(&surface, 0, sizeof(surface));
+
     dprint(1, "%s: %dx%d\n", __FUNCTION__,
            ds_get_width(ssd->ds), ds_get_height(ssd->ds));
 
     dprint(1, "%s: %dx%d\n", __FUNCTION__,
            ds_get_width(ssd->ds), ds_get_height(ssd->ds));
 
@@ -173,29 +282,47 @@ void qemu_spice_create_host_primary(SimpleSpiceDisplay *ssd)
     surface.mouse_mode = true;
     surface.flags      = 0;
     surface.type       = 0;
     surface.mouse_mode = true;
     surface.flags      = 0;
     surface.type       = 0;
-    surface.mem        = (intptr_t)ssd->buf;
+    surface.mem        = (uintptr_t)ssd->buf;
     surface.group_id   = MEMSLOT_GROUP_HOST;
 
     surface.group_id   = MEMSLOT_GROUP_HOST;
 
-    ssd->worker->create_primary_surface(ssd->worker, 0, &surface);
+    qemu_spice_create_primary_surface(ssd, 0, &surface, QXL_SYNC);
 }
 
 void qemu_spice_destroy_host_primary(SimpleSpiceDisplay *ssd)
 {
     dprint(1, "%s:\n", __FUNCTION__);
 
 }
 
 void qemu_spice_destroy_host_primary(SimpleSpiceDisplay *ssd)
 {
     dprint(1, "%s:\n", __FUNCTION__);
 
-    ssd->worker->destroy_primary_surface(ssd->worker, 0);
+    qemu_spice_destroy_primary_surface(ssd, 0, QXL_SYNC);
 }
 
 }
 
-void qemu_spice_vm_change_state_handler(void *opaque, int running, int reason)
+void qemu_spice_vm_change_state_handler(void *opaque, int running,
+                                        RunState state)
 {
 {
+#if SPICE_SERVER_VERSION < 0x000b02 /* before 0.11.2 */
     SimpleSpiceDisplay *ssd = opaque;
 
     if (running) {
     SimpleSpiceDisplay *ssd = opaque;
 
     if (running) {
-        ssd->worker->start(ssd->worker);
+        ssd->running = true;
+        qemu_spice_start(ssd);
     } else {
     } else {
-        ssd->worker->stop(ssd->worker);
+        qemu_spice_stop(ssd);
+        ssd->running = false;
+    }
+#endif
+}
+
+void qemu_spice_display_init_common(SimpleSpiceDisplay *ssd, DisplayState *ds)
+{
+    ssd->ds = ds;
+    qemu_mutex_init(&ssd->lock);
+    QTAILQ_INIT(&ssd->updates);
+    ssd->mouse_x = -1;
+    ssd->mouse_y = -1;
+    if (ssd->num_surfaces == 0) {
+        ssd->num_surfaces = 1024;
     }
     }
-    ssd->running = running;
+    ssd->bufsize = (16 * 1024 * 1024);
+    ssd->buf = g_malloc(ssd->bufsize);
 }
 
 /* display listener callbacks */
 }
 
 /* display listener callbacks */
@@ -219,6 +346,8 @@ void qemu_spice_display_update(SimpleSpiceDisplay *ssd,
 
 void qemu_spice_display_resize(SimpleSpiceDisplay *ssd)
 {
 
 void qemu_spice_display_resize(SimpleSpiceDisplay *ssd)
 {
+    SimpleSpiceUpdate *update;
+
     dprint(1, "%s:\n", __FUNCTION__);
 
     memset(&ssd->dirty, 0, sizeof(ssd->dirty));
     dprint(1, "%s:\n", __FUNCTION__);
 
     memset(&ssd->dirty, 0, sizeof(ssd->dirty));
@@ -226,9 +355,9 @@ void qemu_spice_display_resize(SimpleSpiceDisplay *ssd)
     ssd->conv = NULL;
 
     qemu_mutex_lock(&ssd->lock);
     ssd->conv = NULL;
 
     qemu_mutex_lock(&ssd->lock);
-    if (ssd->update != NULL) {
-        qemu_spice_destroy_update(ssd, ssd->update);
-        ssd->update = NULL;
+    while ((update = QTAILQ_FIRST(&ssd->updates)) != NULL) {
+        QTAILQ_REMOVE(&ssd->updates, update, next);
+        qemu_spice_destroy_update(ssd, update);
     }
     qemu_mutex_unlock(&ssd->lock);
     qemu_spice_destroy_host_primary(ssd);
     }
     qemu_mutex_unlock(&ssd->lock);
     qemu_spice_destroy_host_primary(ssd);
@@ -238,16 +367,8 @@ void qemu_spice_display_resize(SimpleSpiceDisplay *ssd)
     ssd->notify++;
 }
 
     ssd->notify++;
 }
 
-void qemu_spice_display_refresh(SimpleSpiceDisplay *ssd)
+void qemu_spice_cursor_refresh_unlocked(SimpleSpiceDisplay *ssd)
 {
 {
-    dprint(3, "%s:\n", __FUNCTION__);
-    vga_hw_update();
-
-    qemu_mutex_lock(&ssd->lock);
-    if (ssd->update == NULL) {
-        ssd->update = qemu_spice_create_update(ssd);
-        ssd->notify++;
-    }
     if (ssd->cursor) {
         ssd->ds->cursor_define(ssd->cursor);
         cursor_put(ssd->cursor);
     if (ssd->cursor) {
         ssd->ds->cursor_define(ssd->cursor);
         cursor_put(ssd->cursor);
@@ -258,11 +379,24 @@ void qemu_spice_display_refresh(SimpleSpiceDisplay *ssd)
         ssd->mouse_x = -1;
         ssd->mouse_y = -1;
     }
         ssd->mouse_x = -1;
         ssd->mouse_y = -1;
     }
+}
+
+void qemu_spice_display_refresh(SimpleSpiceDisplay *ssd)
+{
+    dprint(3, "%s:\n", __func__);
+    vga_hw_update();
+
+    qemu_mutex_lock(&ssd->lock);
+    if (QTAILQ_EMPTY(&ssd->updates)) {
+        qemu_spice_create_update(ssd);
+        ssd->notify++;
+    }
+    qemu_spice_cursor_refresh_unlocked(ssd);
     qemu_mutex_unlock(&ssd->lock);
 
     if (ssd->notify) {
         ssd->notify = 0;
     qemu_mutex_unlock(&ssd->lock);
 
     if (ssd->notify) {
         ssd->notify = 0;
-        ssd->worker->wakeup(ssd->worker);
+        qemu_spice_wakeup(ssd);
         dprint(2, "%s: notify\n", __FUNCTION__);
     }
 }
         dprint(2, "%s: notify\n", __FUNCTION__);
     }
 }
@@ -299,7 +433,7 @@ static void interface_get_init_info(QXLInstance *sin, QXLDevInitInfo *info)
     info->num_memslots_groups = NUM_MEMSLOTS_GROUPS;
     info->internal_groupslot_id = 0;
     info->qxl_ram_size = ssd->bufsize;
     info->num_memslots_groups = NUM_MEMSLOTS_GROUPS;
     info->internal_groupslot_id = 0;
     info->qxl_ram_size = ssd->bufsize;
-    info->n_surfaces = NUM_SURFACES;
+    info->n_surfaces = ssd->num_surfaces;
 }
 
 static int interface_get_command(QXLInstance *sin, struct QXLCommandExt *ext)
 }
 
 static int interface_get_command(QXLInstance *sin, struct QXLCommandExt *ext)
@@ -311,9 +445,9 @@ static int interface_get_command(QXLInstance *sin, struct QXLCommandExt *ext)
     dprint(3, "%s:\n", __FUNCTION__);
 
     qemu_mutex_lock(&ssd->lock);
     dprint(3, "%s:\n", __FUNCTION__);
 
     qemu_mutex_lock(&ssd->lock);
-    if (ssd->update != NULL) {
-        update = ssd->update;
-        ssd->update = NULL;
+    update = QTAILQ_FIRST(&ssd->updates);
+    if (update != NULL) {
+        QTAILQ_REMOVE(&ssd->updates, update, next);
         *ext = update->ext;
         ret = true;
     }
         *ext = update->ext;
         ret = true;
     }
@@ -411,12 +545,7 @@ static DisplayChangeListener display_listener = {
 void qemu_spice_display_init(DisplayState *ds)
 {
     assert(sdpy.ds == NULL);
 void qemu_spice_display_init(DisplayState *ds)
 {
     assert(sdpy.ds == NULL);
-    sdpy.ds = ds;
-    qemu_mutex_init(&sdpy.lock);
-    sdpy.mouse_x = -1;
-    sdpy.mouse_y = -1;
-    sdpy.bufsize = (16 * 1024 * 1024);
-    sdpy.buf = qemu_malloc(sdpy.bufsize);
+    qemu_spice_display_init_common(&sdpy, ds);
     register_displaychangelistener(ds, &display_listener);
 
     sdpy.qxl.base.sif = &dpy_interface.base;
     register_displaychangelistener(ds, &display_listener);
 
     sdpy.qxl.base.sif = &dpy_interface.base;
This page took 0.036848 seconds and 4 git commands to generate.