(uintptr_t)qxl_cookie_new(QXL_COOKIE_TYPE_IO,
QXL_IO_MEMSLOT_ADD_ASYNC));
} else {
- ssd->worker->add_memslot(ssd->worker, memslot);
+ spice_qxl_add_memslot(&ssd->qxl, 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);
+ spice_qxl_del_memslot(&ssd->qxl, gid, sid);
}
void qemu_spice_create_primary_surface(SimpleSpiceDisplay *ssd, uint32_t id,
(uintptr_t)qxl_cookie_new(QXL_COOKIE_TYPE_IO,
QXL_IO_CREATE_PRIMARY_ASYNC));
} else {
- ssd->worker->create_primary_surface(ssd->worker, id, surface);
+ spice_qxl_create_primary_surface(&ssd->qxl, id, surface);
}
}
(uintptr_t)qxl_cookie_new(QXL_COOKIE_TYPE_IO,
QXL_IO_DESTROY_PRIMARY_ASYNC));
} else {
- ssd->worker->destroy_primary_surface(ssd->worker, id);
+ spice_qxl_destroy_primary_surface(&ssd->qxl, id);
}
}
void qemu_spice_wakeup(SimpleSpiceDisplay *ssd)
{
trace_qemu_spice_wakeup(ssd->qxl.id);
- ssd->worker->wakeup(ssd->worker);
-}
-
-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;
-}
-
-int qemu_spice_display_is_running(SimpleSpiceDisplay *ssd)
-{
- return spice_display_is_running;
+ spice_qxl_wakeup(&ssd->qxl);
}
static void qemu_spice_create_one_update(SimpleSpiceDisplay *ssd,
drawable->bbox = *rect;
drawable->clip.type = SPICE_CLIP_TYPE_NONE;
drawable->effect = QXL_EFFECT_OPAQUE;
- drawable->release_info.id = (uintptr_t)update;
+ drawable->release_info.id = (uintptr_t)(&update->ext);
drawable->type = QXL_DRAW_COPY;
drawable->surfaces_dest[0] = -1;
drawable->surfaces_dest[1] = -1;
return;
};
- if (ssd->surface == NULL) {
- ssd->surface = pixman_image_ref(ssd->ds->image);
- ssd->mirror = qemu_pixman_mirror_create(ssd->ds->format,
- ssd->ds->image);
- }
-
for (blk = 0; blk < blocks; blk++) {
dirty_top[blk] = -1;
}
memset(&ssd->dirty, 0, sizeof(ssd->dirty));
}
+static SimpleSpiceCursor*
+qemu_spice_create_cursor_update(SimpleSpiceDisplay *ssd,
+ QEMUCursor *c)
+{
+ size_t size = c ? c->width * c->height * 4 : 0;
+ SimpleSpiceCursor *update;
+ QXLCursorCmd *ccmd;
+ QXLCursor *cursor;
+ QXLCommand *cmd;
+
+ update = g_malloc0(sizeof(*update) + size);
+ ccmd = &update->cmd;
+ cursor = &update->cursor;
+ cmd = &update->ext.cmd;
+
+ if (c) {
+ ccmd->type = QXL_CURSOR_SET;
+ ccmd->u.set.position.x = ssd->ptr_x;
+ ccmd->u.set.position.y = ssd->ptr_y;
+ ccmd->u.set.visible = true;
+ ccmd->u.set.shape = (uintptr_t)cursor;
+ cursor->header.unique = ssd->unique++;
+ cursor->header.type = SPICE_CURSOR_TYPE_ALPHA;
+ cursor->header.width = c->width;
+ cursor->header.height = c->height;
+ cursor->header.hot_spot_x = c->hot_x;
+ cursor->header.hot_spot_y = c->hot_y;
+ cursor->data_size = size;
+ cursor->chunk.data_size = size;
+ memcpy(cursor->chunk.data, c->data, size);
+ } else {
+ ccmd->type = QXL_CURSOR_MOVE;
+ ccmd->u.position.x = ssd->ptr_x;
+ ccmd->u.position.y = ssd->ptr_y;
+ }
+ ccmd->release_info.id = (uintptr_t)(&update->ext);
+
+ cmd->type = QXL_CMD_CURSOR;
+ cmd->data = (uintptr_t)ccmd;
+
+ return update;
+}
+
/*
* Called from spice server thread context (via interface_release_resource)
* We do *not* hold the global qemu mutex here, so extra care is needed
{
QXLDevMemSlot memslot;
- dprint(1, "%s:\n", __FUNCTION__);
+ dprint(1, "%s/%d:\n", __func__, ssd->qxl.id);
memset(&memslot, 0, sizeof(memslot));
memslot.slot_group_id = MEMSLOT_GROUP_HOST;
void qemu_spice_create_host_primary(SimpleSpiceDisplay *ssd)
{
QXLDevSurfaceCreate surface;
+ uint64_t surface_size;
memset(&surface, 0, sizeof(surface));
- dprint(1, "%s: %dx%d\n", __FUNCTION__,
- surface_width(ssd->ds), surface_height(ssd->ds));
+ surface_size = (uint64_t) surface_width(ssd->ds) *
+ surface_height(ssd->ds) * 4;
+ assert(surface_size > 0);
+ assert(surface_size < INT_MAX);
+ if (ssd->bufsize < surface_size) {
+ ssd->bufsize = surface_size;
+ g_free(ssd->buf);
+ ssd->buf = g_malloc(ssd->bufsize);
+ }
+
+ dprint(1, "%s/%d: %ux%u (size %" PRIu64 "/%d)\n", __func__, ssd->qxl.id,
+ surface_width(ssd->ds), surface_height(ssd->ds),
+ surface_size, ssd->bufsize);
surface.format = SPICE_SURFACE_FMT_32_xRGB;
surface.width = surface_width(ssd->ds);
void qemu_spice_destroy_host_primary(SimpleSpiceDisplay *ssd)
{
- dprint(1, "%s:\n", __FUNCTION__);
+ dprint(1, "%s/%d:\n", __func__, ssd->qxl.id);
qemu_spice_destroy_primary_surface(ssd, 0, QXL_SYNC);
}
if (ssd->num_surfaces == 0) {
ssd->num_surfaces = 1024;
}
- ssd->bufsize = (16 * 1024 * 1024);
- ssd->buf = g_malloc(ssd->bufsize);
}
/* display listener callbacks */
{
QXLRect update_area;
- dprint(2, "%s: x %d y %d w %d h %d\n", __FUNCTION__, x, y, w, h);
+ dprint(2, "%s/%d: x %d y %d w %d h %d\n", __func__,
+ ssd->qxl.id, x, y, w, h);
update_area.left = x,
update_area.right = x + w;
update_area.top = y;
DisplaySurface *surface)
{
SimpleSpiceUpdate *update;
+ bool need_destroy;
+
+ if (surface && ssd->surface &&
+ surface_width(surface) == pixman_image_get_width(ssd->surface) &&
+ surface_height(surface) == pixman_image_get_height(ssd->surface)) {
+ /* no-resize fast path: just swap backing store */
+ dprint(1, "%s/%d: fast (%dx%d)\n", __func__, ssd->qxl.id,
+ surface_width(surface), surface_height(surface));
+ qemu_mutex_lock(&ssd->lock);
+ ssd->ds = surface;
+ pixman_image_unref(ssd->surface);
+ ssd->surface = pixman_image_ref(ssd->ds->image);
+ qemu_mutex_unlock(&ssd->lock);
+ qemu_spice_display_update(ssd, 0, 0,
+ surface_width(surface),
+ surface_height(surface));
+ return;
+ }
- dprint(1, "%s:\n", __FUNCTION__);
+ /* full mode switch */
+ dprint(1, "%s/%d: full (%dx%d -> %dx%d)\n", __func__, ssd->qxl.id,
+ ssd->surface ? pixman_image_get_width(ssd->surface) : 0,
+ ssd->surface ? pixman_image_get_height(ssd->surface) : 0,
+ surface ? surface_width(surface) : 0,
+ surface ? surface_height(surface) : 0);
memset(&ssd->dirty, 0, sizeof(ssd->dirty));
if (ssd->surface) {
}
qemu_mutex_lock(&ssd->lock);
+ need_destroy = (ssd->ds != NULL);
ssd->ds = surface;
+ ssd->surface = pixman_image_ref(ssd->ds->image);
+ ssd->mirror = qemu_pixman_mirror_create(ssd->ds->format,
+ ssd->ds->image);
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_spice_create_host_primary(ssd);
+ if (need_destroy) {
+ qemu_spice_destroy_host_primary(ssd);
+ }
+ if (ssd->ds) {
+ qemu_spice_create_host_primary(ssd);
+ }
memset(&ssd->dirty, 0, sizeof(ssd->dirty));
ssd->notify++;
}
-void qemu_spice_cursor_refresh_unlocked(SimpleSpiceDisplay *ssd)
+static void qemu_spice_cursor_refresh_unlocked(SimpleSpiceDisplay *ssd)
{
if (ssd->cursor) {
assert(ssd->dcl.con);
}
}
+void qemu_spice_cursor_refresh_bh(void *opaque)
+{
+ SimpleSpiceDisplay *ssd = opaque;
+
+ qemu_mutex_lock(&ssd->lock);
+ qemu_spice_cursor_refresh_unlocked(ssd);
+ qemu_mutex_unlock(&ssd->lock);
+}
+
void qemu_spice_display_refresh(SimpleSpiceDisplay *ssd)
{
- dprint(3, "%s:\n", __func__);
+ dprint(3, "%s/%d:\n", __func__, ssd->qxl.id);
graphic_hw_update(ssd->dcl.con);
qemu_mutex_lock(&ssd->lock);
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_spice_wakeup(ssd);
- dprint(2, "%s: notify\n", __FUNCTION__);
+ dprint(2, "%s/%d: notify\n", __func__, ssd->qxl.id);
}
}
{
SimpleSpiceDisplay *ssd = container_of(sin, SimpleSpiceDisplay, qxl);
- dprint(1, "%s:\n", __FUNCTION__);
+ dprint(1, "%s/%d:\n", __func__, ssd->qxl.id);
ssd->worker = qxl_worker;
}
static void interface_set_compression_level(QXLInstance *sin, int level)
{
- dprint(1, "%s:\n", __FUNCTION__);
+ dprint(1, "%s/%d:\n", __func__, sin->id);
/* nothing to do */
}
static void interface_set_mm_time(QXLInstance *sin, uint32_t mm_time)
{
- dprint(3, "%s:\n", __FUNCTION__);
+ dprint(3, "%s/%d:\n", __func__, sin->id);
/* nothing to do */
}
info->num_memslots = NUM_MEMSLOTS;
info->num_memslots_groups = NUM_MEMSLOTS_GROUPS;
info->internal_groupslot_id = 0;
- info->qxl_ram_size = ssd->bufsize;
+ info->qxl_ram_size = 16 * 1024 * 1024;
info->n_surfaces = ssd->num_surfaces;
}
SimpleSpiceUpdate *update;
int ret = false;
- dprint(3, "%s:\n", __FUNCTION__);
+ dprint(3, "%s/%d:\n", __func__, ssd->qxl.id);
qemu_mutex_lock(&ssd->lock);
update = QTAILQ_FIRST(&ssd->updates);
static int interface_req_cmd_notification(QXLInstance *sin)
{
- dprint(1, "%s:\n", __FUNCTION__);
+ dprint(1, "%s/%d:\n", __func__, sin->id);
return 1;
}
static void interface_release_resource(QXLInstance *sin,
- struct QXLReleaseInfoExt ext)
+ struct QXLReleaseInfoExt rext)
{
SimpleSpiceDisplay *ssd = container_of(sin, SimpleSpiceDisplay, qxl);
- uintptr_t id;
-
- dprint(2, "%s:\n", __FUNCTION__);
- id = ext.info->id;
- qemu_spice_destroy_update(ssd, (void*)id);
+ SimpleSpiceUpdate *update;
+ SimpleSpiceCursor *cursor;
+ QXLCommandExt *ext;
+
+ dprint(2, "%s/%d:\n", __func__, ssd->qxl.id);
+ ext = (void *)(intptr_t)(rext.info->id);
+ switch (ext->cmd.type) {
+ case QXL_CMD_DRAW:
+ update = container_of(ext, SimpleSpiceUpdate, ext);
+ qemu_spice_destroy_update(ssd, update);
+ break;
+ case QXL_CMD_CURSOR:
+ cursor = container_of(ext, SimpleSpiceCursor, ext);
+ g_free(cursor);
+ break;
+ default:
+ g_assert_not_reached();
+ }
}
static int interface_get_cursor_command(QXLInstance *sin, struct QXLCommandExt *ext)
{
- dprint(3, "%s:\n", __FUNCTION__);
- return false;
+ SimpleSpiceDisplay *ssd = container_of(sin, SimpleSpiceDisplay, qxl);
+ int ret;
+
+ dprint(3, "%s/%d:\n", __func__, ssd->qxl.id);
+
+ qemu_mutex_lock(&ssd->lock);
+ if (ssd->ptr_define) {
+ *ext = ssd->ptr_define->ext;
+ ssd->ptr_define = NULL;
+ ret = true;
+ } else if (ssd->ptr_move) {
+ *ext = ssd->ptr_move->ext;
+ ssd->ptr_move = NULL;
+ ret = true;
+ } else {
+ ret = false;
+ }
+ qemu_mutex_unlock(&ssd->lock);
+ return ret;
}
static int interface_req_cursor_notification(QXLInstance *sin)
}
static int interface_client_monitors_config(QXLInstance *sin,
- VDAgentMonitorsConfig *monitors_config)
+ VDAgentMonitorsConfig *mc)
{
- dprint(3, "%s:\n", __func__);
- return 0; /* == not supported by guest */
+ SimpleSpiceDisplay *ssd = container_of(sin, SimpleSpiceDisplay, qxl);
+ QemuUIInfo info;
+ int rc;
+
+ if (!mc) {
+ 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;
+ }
+ rc = dpy_set_ui_info(ssd->dcl.con, &info);
+ dprint(1, "%s/%d: size %dx%d, rc %d <--- ==========================\n",
+ __func__, ssd->qxl.id, info.width, info.height, rc);
+ if (rc != 0) {
+ return 0; /* == not supported by guest */
+ } else {
+ return 1;
+ }
}
static const QXLInterface dpy_interface = {
qemu_spice_display_refresh(ssd);
}
+static void display_mouse_set(DisplayChangeListener *dcl,
+ int x, int y, int on)
+{
+ SimpleSpiceDisplay *ssd = container_of(dcl, SimpleSpiceDisplay, dcl);
+
+ qemu_mutex_lock(&ssd->lock);
+ ssd->ptr_x = x;
+ ssd->ptr_y = x;
+ if (ssd->ptr_move) {
+ g_free(ssd->ptr_move);
+ }
+ ssd->ptr_move = qemu_spice_create_cursor_update(ssd, NULL);
+ qemu_mutex_unlock(&ssd->lock);
+}
+
+static void display_mouse_define(DisplayChangeListener *dcl,
+ QEMUCursor *c)
+{
+ SimpleSpiceDisplay *ssd = container_of(dcl, SimpleSpiceDisplay, dcl);
+
+ qemu_mutex_lock(&ssd->lock);
+ if (ssd->ptr_move) {
+ g_free(ssd->ptr_move);
+ ssd->ptr_move = NULL;
+ }
+ if (ssd->ptr_define) {
+ g_free(ssd->ptr_define);
+ }
+ ssd->ptr_define = qemu_spice_create_cursor_update(ssd, c);
+ qemu_mutex_unlock(&ssd->lock);
+}
+
static const DisplayChangeListenerOps display_listener_ops = {
- .dpy_name = "spice",
- .dpy_gfx_update = display_update,
- .dpy_gfx_switch = display_switch,
- .dpy_refresh = display_refresh,
+ .dpy_name = "spice",
+ .dpy_gfx_update = display_update,
+ .dpy_gfx_switch = display_switch,
+ .dpy_refresh = display_refresh,
+ .dpy_mouse_set = display_mouse_set,
+ .dpy_cursor_define = display_mouse_define,
};
-void qemu_spice_display_init(DisplayState *ds)
+static void qemu_spice_display_init_one(QemuConsole *con)
{
SimpleSpiceDisplay *ssd = g_new0(SimpleSpiceDisplay, 1);
qemu_spice_display_init_common(ssd);
ssd->qxl.base.sif = &dpy_interface.base;
- qemu_spice_add_interface(&ssd->qxl.base);
+ qemu_spice_add_display_interface(&ssd->qxl, con);
assert(ssd->worker);
qemu_spice_create_host_memslot(ssd);
ssd->dcl.ops = &display_listener_ops;
- ssd->dcl.con = qemu_console_lookup_by_index(0);
- register_displaychangelistener(ds, &ssd->dcl);
+ ssd->dcl.con = con;
+ register_displaychangelistener(&ssd->dcl);
+}
- qemu_spice_create_host_primary(ssd);
+void qemu_spice_display_init(void)
+{
+ QemuConsole *con;
+ int i;
+
+ for (i = 0;; i++) {
+ con = qemu_console_lookup_by_index(i);
+ if (!con || !qemu_console_is_graphic(con)) {
+ break;
+ }
+ if (qemu_spice_have_display_interface(con)) {
+ continue;
+ }
+ qemu_spice_display_init_one(con);
+ }
}