1a19cbfb3SGerd Hoffmann /*
2a19cbfb3SGerd Hoffmann * qxl local rendering (aka display on sdl/vnc)
3a19cbfb3SGerd Hoffmann *
4a19cbfb3SGerd Hoffmann * Copyright (C) 2010 Red Hat, Inc.
5a19cbfb3SGerd Hoffmann *
6a19cbfb3SGerd Hoffmann * maintained by Gerd Hoffmann <kraxel@redhat.com>
7a19cbfb3SGerd Hoffmann *
8a19cbfb3SGerd Hoffmann * This program is free software; you can redistribute it and/or
9a19cbfb3SGerd Hoffmann * modify it under the terms of the GNU General Public License as
10a19cbfb3SGerd Hoffmann * published by the Free Software Foundation; either version 2 or
11a19cbfb3SGerd Hoffmann * (at your option) version 3 of the License.
12a19cbfb3SGerd Hoffmann *
13a19cbfb3SGerd Hoffmann * This program is distributed in the hope that it will be useful,
14a19cbfb3SGerd Hoffmann * but WITHOUT ANY WARRANTY; without even the implied warranty of
15a19cbfb3SGerd Hoffmann * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16a19cbfb3SGerd Hoffmann * GNU General Public License for more details.
17a19cbfb3SGerd Hoffmann *
18a19cbfb3SGerd Hoffmann * You should have received a copy of the GNU General Public License
19a19cbfb3SGerd Hoffmann * along with this program; if not, see <http://www.gnu.org/licenses/>.
20a19cbfb3SGerd Hoffmann */
21a19cbfb3SGerd Hoffmann
2247df5154SPeter Maydell #include "qemu/osdep.h"
2347b43a1fSPaolo Bonzini #include "qxl.h"
24*32cad1ffSPhilippe Mathieu-Daudé #include "system/runstate.h"
25b1829cdeSStefan Weil #include "trace.h"
26a19cbfb3SGerd Hoffmann
qxl_blit(PCIQXLDevice * qxl,QXLRect * rect)27e2efc0a3SGerd Hoffmann static void qxl_blit(PCIQXLDevice *qxl, QXLRect *rect)
28a19cbfb3SGerd Hoffmann {
29c78f7137SGerd Hoffmann DisplaySurface *surface = qemu_console_surface(qxl->vga.con);
30c78f7137SGerd Hoffmann uint8_t *dst = surface_data(surface);
314c19ebb5SAlon Levy uint8_t *src;
32a19cbfb3SGerd Hoffmann int len, i;
33a19cbfb3SGerd Hoffmann
34abd749b5SGerd Hoffmann if (!surface_is_allocated(surface)) {
354c19ebb5SAlon Levy return;
364c19ebb5SAlon Levy }
37d53291cfSAlon Levy trace_qxl_render_blit(qxl->guest_primary.qxl_stride,
384c19ebb5SAlon Levy rect->left, rect->right, rect->top, rect->bottom);
394c19ebb5SAlon Levy src = qxl->guest_primary.data;
40e2efc0a3SGerd Hoffmann if (qxl->guest_primary.qxl_stride < 0) {
41e2efc0a3SGerd Hoffmann /* qxl surface is upside down, walk src scanlines
42e2efc0a3SGerd Hoffmann * in reverse order to flip it */
43a19cbfb3SGerd Hoffmann src += (qxl->guest_primary.surface.height - rect->top - 1) *
440e2487bdSGerd Hoffmann qxl->guest_primary.abs_stride;
45e2efc0a3SGerd Hoffmann } else {
46e2efc0a3SGerd Hoffmann src += rect->top * qxl->guest_primary.abs_stride;
47e2efc0a3SGerd Hoffmann }
480e2487bdSGerd Hoffmann dst += rect->top * qxl->guest_primary.abs_stride;
49a19cbfb3SGerd Hoffmann src += rect->left * qxl->guest_primary.bytes_pp;
50a19cbfb3SGerd Hoffmann dst += rect->left * qxl->guest_primary.bytes_pp;
51a19cbfb3SGerd Hoffmann len = (rect->right - rect->left) * qxl->guest_primary.bytes_pp;
52a19cbfb3SGerd Hoffmann
53a19cbfb3SGerd Hoffmann for (i = rect->top; i < rect->bottom; i++) {
54a19cbfb3SGerd Hoffmann memcpy(dst, src, len);
550e2487bdSGerd Hoffmann dst += qxl->guest_primary.abs_stride;
56e2efc0a3SGerd Hoffmann src += qxl->guest_primary.qxl_stride;
57a19cbfb3SGerd Hoffmann }
58a19cbfb3SGerd Hoffmann }
59a19cbfb3SGerd Hoffmann
qxl_render_resize(PCIQXLDevice * qxl)60a19cbfb3SGerd Hoffmann void qxl_render_resize(PCIQXLDevice *qxl)
61a19cbfb3SGerd Hoffmann {
62a19cbfb3SGerd Hoffmann QXLSurfaceCreate *sc = &qxl->guest_primary.surface;
63a19cbfb3SGerd Hoffmann
640e2487bdSGerd Hoffmann qxl->guest_primary.qxl_stride = sc->stride;
650e2487bdSGerd Hoffmann qxl->guest_primary.abs_stride = abs(sc->stride);
66a19cbfb3SGerd Hoffmann qxl->guest_primary.resized++;
67a19cbfb3SGerd Hoffmann switch (sc->format) {
68a19cbfb3SGerd Hoffmann case SPICE_SURFACE_FMT_16_555:
69a19cbfb3SGerd Hoffmann qxl->guest_primary.bytes_pp = 2;
70a19cbfb3SGerd Hoffmann qxl->guest_primary.bits_pp = 15;
71a19cbfb3SGerd Hoffmann break;
72a19cbfb3SGerd Hoffmann case SPICE_SURFACE_FMT_16_565:
73a19cbfb3SGerd Hoffmann qxl->guest_primary.bytes_pp = 2;
74a19cbfb3SGerd Hoffmann qxl->guest_primary.bits_pp = 16;
75a19cbfb3SGerd Hoffmann break;
76a19cbfb3SGerd Hoffmann case SPICE_SURFACE_FMT_32_xRGB:
77a19cbfb3SGerd Hoffmann case SPICE_SURFACE_FMT_32_ARGB:
78a19cbfb3SGerd Hoffmann qxl->guest_primary.bytes_pp = 4;
79a19cbfb3SGerd Hoffmann qxl->guest_primary.bits_pp = 32;
80a19cbfb3SGerd Hoffmann break;
81a19cbfb3SGerd Hoffmann default:
82a89f364aSAlistair Francis fprintf(stderr, "%s: unhandled format: %x\n", __func__,
83a19cbfb3SGerd Hoffmann qxl->guest_primary.surface.format);
84a19cbfb3SGerd Hoffmann qxl->guest_primary.bytes_pp = 4;
85a19cbfb3SGerd Hoffmann qxl->guest_primary.bits_pp = 32;
86a19cbfb3SGerd Hoffmann break;
87a19cbfb3SGerd Hoffmann }
88a19cbfb3SGerd Hoffmann }
89a19cbfb3SGerd Hoffmann
qxl_set_rect_to_surface(PCIQXLDevice * qxl,QXLRect * area)9081fb6f15SAlon Levy static void qxl_set_rect_to_surface(PCIQXLDevice *qxl, QXLRect *area)
9181fb6f15SAlon Levy {
9281fb6f15SAlon Levy area->left = 0;
9381fb6f15SAlon Levy area->right = qxl->guest_primary.surface.width;
9481fb6f15SAlon Levy area->top = 0;
9581fb6f15SAlon Levy area->bottom = qxl->guest_primary.surface.height;
9681fb6f15SAlon Levy }
9781fb6f15SAlon Levy
qxl_render_update_area_unlocked(PCIQXLDevice * qxl)9881fb6f15SAlon Levy static void qxl_render_update_area_unlocked(PCIQXLDevice *qxl)
99a19cbfb3SGerd Hoffmann {
100a19cbfb3SGerd Hoffmann VGACommonState *vga = &qxl->vga;
101da229ef3SGerd Hoffmann DisplaySurface *surface;
102979f7ef8SGerd Hoffmann int width = qxl->guest_head0_width ?: qxl->guest_primary.surface.width;
103979f7ef8SGerd Hoffmann int height = qxl->guest_head0_height ?: qxl->guest_primary.surface.height;
10481fb6f15SAlon Levy int i;
105a19cbfb3SGerd Hoffmann
106a19cbfb3SGerd Hoffmann if (qxl->guest_primary.resized) {
107a19cbfb3SGerd Hoffmann qxl->guest_primary.resized = 0;
108c58c7b95SGerd Hoffmann qxl->guest_primary.data = qxl_phys2virt(qxl,
109c58c7b95SGerd Hoffmann qxl->guest_primary.surface.mem,
1108efec0efSPhilippe Mathieu-Daudé MEMSLOT_GROUP_GUEST,
1118efec0efSPhilippe Mathieu-Daudé qxl->guest_primary.abs_stride
1128efec0efSPhilippe Mathieu-Daudé * height);
113c58c7b95SGerd Hoffmann if (!qxl->guest_primary.data) {
1144d631621SMarc-André Lureau goto end;
115c58c7b95SGerd Hoffmann }
11681fb6f15SAlon Levy qxl_set_rect_to_surface(qxl, &qxl->dirty[0]);
11781fb6f15SAlon Levy qxl->num_dirty_rects = 1;
118d53291cfSAlon Levy trace_qxl_render_guest_primary_resized(
119979f7ef8SGerd Hoffmann width,
120979f7ef8SGerd Hoffmann height,
1210e2487bdSGerd Hoffmann qxl->guest_primary.qxl_stride,
122a19cbfb3SGerd Hoffmann qxl->guest_primary.bytes_pp,
1234c19ebb5SAlon Levy qxl->guest_primary.bits_pp);
1244c19ebb5SAlon Levy if (qxl->guest_primary.qxl_stride > 0) {
12530f1e661SGerd Hoffmann pixman_format_code_t format =
12630f1e661SGerd Hoffmann qemu_default_pixman_format(qxl->guest_primary.bits_pp, true);
127da229ef3SGerd Hoffmann surface = qemu_create_displaysurface_from
128979f7ef8SGerd Hoffmann (width,
129979f7ef8SGerd Hoffmann height,
13030f1e661SGerd Hoffmann format,
1310e2487bdSGerd Hoffmann qxl->guest_primary.abs_stride,
13230f1e661SGerd Hoffmann qxl->guest_primary.data);
1334c19ebb5SAlon Levy } else {
134da229ef3SGerd Hoffmann surface = qemu_create_displaysurface
135979f7ef8SGerd Hoffmann (width,
136979f7ef8SGerd Hoffmann height);
137a19cbfb3SGerd Hoffmann }
138c78f7137SGerd Hoffmann dpy_gfx_replace_surface(vga->con, surface);
1394c19ebb5SAlon Levy }
140c58c7b95SGerd Hoffmann
141c58c7b95SGerd Hoffmann if (!qxl->guest_primary.data) {
1424d631621SMarc-André Lureau goto end;
143c58c7b95SGerd Hoffmann }
14481fb6f15SAlon Levy for (i = 0; i < qxl->num_dirty_rects; i++) {
14581fb6f15SAlon Levy if (qemu_spice_rect_is_empty(qxl->dirty+i)) {
146a19cbfb3SGerd Hoffmann break;
147a19cbfb3SGerd Hoffmann }
148503b3b33SGerd Hoffmann if (qxl->dirty[i].left < 0 ||
149503b3b33SGerd Hoffmann qxl->dirty[i].top < 0 ||
150503b3b33SGerd Hoffmann qxl->dirty[i].left > qxl->dirty[i].right ||
151788fbf04SGerd Hoffmann qxl->dirty[i].top > qxl->dirty[i].bottom ||
152979f7ef8SGerd Hoffmann qxl->dirty[i].right > width ||
153979f7ef8SGerd Hoffmann qxl->dirty[i].bottom > height) {
154788fbf04SGerd Hoffmann continue;
155788fbf04SGerd Hoffmann }
156e2efc0a3SGerd Hoffmann qxl_blit(qxl, qxl->dirty+i);
157c78f7137SGerd Hoffmann dpy_gfx_update(vga->con,
15881fb6f15SAlon Levy qxl->dirty[i].left, qxl->dirty[i].top,
15981fb6f15SAlon Levy qxl->dirty[i].right - qxl->dirty[i].left,
16081fb6f15SAlon Levy qxl->dirty[i].bottom - qxl->dirty[i].top);
161a19cbfb3SGerd Hoffmann }
16281fb6f15SAlon Levy qxl->num_dirty_rects = 0;
1634d631621SMarc-André Lureau
1644d631621SMarc-André Lureau end:
1654d631621SMarc-André Lureau if (qxl->render_update_cookie_num == 0) {
1664d631621SMarc-André Lureau graphic_hw_update_done(qxl->ssd.dcl.con);
1674d631621SMarc-André Lureau }
16881fb6f15SAlon Levy }
16981fb6f15SAlon Levy
17081fb6f15SAlon Levy /*
17181fb6f15SAlon Levy * use ssd.lock to protect render_update_cookie_num.
17281fb6f15SAlon Levy * qxl_render_update is called by io thread or vcpu thread, and the completion
17367cc32ebSVeres Lajos * callbacks are called by spice_server thread, deferring to bh called from the
17481fb6f15SAlon Levy * io thread.
17581fb6f15SAlon Levy */
qxl_render_update(PCIQXLDevice * qxl)17681fb6f15SAlon Levy void qxl_render_update(PCIQXLDevice *qxl)
17781fb6f15SAlon Levy {
17881fb6f15SAlon Levy QXLCookie *cookie;
17981fb6f15SAlon Levy
18081fb6f15SAlon Levy qemu_mutex_lock(&qxl->ssd.lock);
18181fb6f15SAlon Levy
1825bd5c27cSGerd Hoffmann if (!runstate_is_running() || !qxl->guest_primary.commands ||
1835bd5c27cSGerd Hoffmann qxl->mode == QXL_MODE_UNDEFINED) {
18481fb6f15SAlon Levy qxl_render_update_area_unlocked(qxl);
18581fb6f15SAlon Levy qemu_mutex_unlock(&qxl->ssd.lock);
186b577ab2dSMarc-André Lureau graphic_hw_update_done(qxl->ssd.dcl.con);
18781fb6f15SAlon Levy return;
18881fb6f15SAlon Levy }
18981fb6f15SAlon Levy
19081fb6f15SAlon Levy qxl->guest_primary.commands = 0;
19181fb6f15SAlon Levy qxl->render_update_cookie_num++;
19281fb6f15SAlon Levy qemu_mutex_unlock(&qxl->ssd.lock);
19381fb6f15SAlon Levy cookie = qxl_cookie_new(QXL_COOKIE_TYPE_RENDER_UPDATE_AREA,
19481fb6f15SAlon Levy 0);
19581fb6f15SAlon Levy qxl_set_rect_to_surface(qxl, &cookie->u.render.area);
19681fb6f15SAlon Levy qxl_spice_update_area(qxl, 0, &cookie->u.render.area, NULL,
19781fb6f15SAlon Levy 0, 1 /* clear_dirty_region */, QXL_ASYNC, cookie);
19881fb6f15SAlon Levy }
19981fb6f15SAlon Levy
qxl_render_update_area_bh(void * opaque)20081fb6f15SAlon Levy void qxl_render_update_area_bh(void *opaque)
20181fb6f15SAlon Levy {
20281fb6f15SAlon Levy PCIQXLDevice *qxl = opaque;
20381fb6f15SAlon Levy
20481fb6f15SAlon Levy qemu_mutex_lock(&qxl->ssd.lock);
20581fb6f15SAlon Levy qxl_render_update_area_unlocked(qxl);
20681fb6f15SAlon Levy qemu_mutex_unlock(&qxl->ssd.lock);
20781fb6f15SAlon Levy }
20881fb6f15SAlon Levy
qxl_render_update_area_done(PCIQXLDevice * qxl,QXLCookie * cookie)20981fb6f15SAlon Levy void qxl_render_update_area_done(PCIQXLDevice *qxl, QXLCookie *cookie)
21081fb6f15SAlon Levy {
21181fb6f15SAlon Levy qemu_mutex_lock(&qxl->ssd.lock);
212d53291cfSAlon Levy trace_qxl_render_update_area_done(cookie);
21381fb6f15SAlon Levy qemu_bh_schedule(qxl->update_area_bh);
21481fb6f15SAlon Levy qxl->render_update_cookie_num--;
21581fb6f15SAlon Levy qemu_mutex_unlock(&qxl->ssd.lock);
21681fb6f15SAlon Levy g_free(cookie);
217a19cbfb3SGerd Hoffmann }
218a19cbfb3SGerd Hoffmann
qxl_unpack_chunks(void * dest,size_t size,PCIQXLDevice * qxl,QXLDataChunk * chunk,uint32_t group_id)219b21330b5SGerd Hoffmann static void qxl_unpack_chunks(void *dest, size_t size, PCIQXLDevice *qxl,
220b21330b5SGerd Hoffmann QXLDataChunk *chunk, uint32_t group_id)
221b21330b5SGerd Hoffmann {
222b21330b5SGerd Hoffmann uint32_t max_chunks = 32;
223b21330b5SGerd Hoffmann size_t offset = 0;
224b21330b5SGerd Hoffmann size_t bytes;
225b21330b5SGerd Hoffmann
226b21330b5SGerd Hoffmann for (;;) {
227b21330b5SGerd Hoffmann bytes = MIN(size - offset, chunk->data_size);
228b21330b5SGerd Hoffmann memcpy(dest + offset, chunk->data, bytes);
229b21330b5SGerd Hoffmann offset += bytes;
230b21330b5SGerd Hoffmann if (offset == size) {
231b21330b5SGerd Hoffmann return;
232b21330b5SGerd Hoffmann }
2338efec0efSPhilippe Mathieu-Daudé chunk = qxl_phys2virt(qxl, chunk->next_chunk, group_id,
2348efec0efSPhilippe Mathieu-Daudé sizeof(QXLDataChunk) + chunk->data_size);
235b21330b5SGerd Hoffmann if (!chunk) {
236b21330b5SGerd Hoffmann return;
237b21330b5SGerd Hoffmann }
238b21330b5SGerd Hoffmann max_chunks--;
239b21330b5SGerd Hoffmann if (max_chunks == 0) {
240b21330b5SGerd Hoffmann return;
241b21330b5SGerd Hoffmann }
242b21330b5SGerd Hoffmann }
243b21330b5SGerd Hoffmann }
244b21330b5SGerd Hoffmann
qxl_cursor(PCIQXLDevice * qxl,QXLCursor * cursor,uint32_t group_id)245b21330b5SGerd Hoffmann static QEMUCursor *qxl_cursor(PCIQXLDevice *qxl, QXLCursor *cursor,
246b21330b5SGerd Hoffmann uint32_t group_id)
247a19cbfb3SGerd Hoffmann {
248a19cbfb3SGerd Hoffmann QEMUCursor *c;
24936ffc122SPeter Wu uint8_t *and_mask, *xor_mask;
25066d3f196SMarkus Armbruster size_t size;
251a19cbfb3SGerd Hoffmann
252a19cbfb3SGerd Hoffmann c = cursor_alloc(cursor->header.width, cursor->header.height);
253fa892e9aSMauro Matteo Cascella
254fa892e9aSMauro Matteo Cascella if (!c) {
255fa892e9aSMauro Matteo Cascella qxl_set_guest_bug(qxl, "%s: cursor %ux%u alloc error", __func__,
256fa892e9aSMauro Matteo Cascella cursor->header.width, cursor->header.height);
257fa892e9aSMauro Matteo Cascella goto fail;
258fa892e9aSMauro Matteo Cascella }
259fa892e9aSMauro Matteo Cascella
260a19cbfb3SGerd Hoffmann c->hot_x = cursor->header.hot_spot_x;
261a19cbfb3SGerd Hoffmann c->hot_y = cursor->header.hot_spot_y;
262a19cbfb3SGerd Hoffmann switch (cursor->header.type) {
26336ffc122SPeter Wu case SPICE_CURSOR_TYPE_MONO:
26436ffc122SPeter Wu /* Assume that the full cursor is available in a single chunk. */
26536ffc122SPeter Wu size = 2 * cursor_get_mono_bpl(c) * c->height;
26636ffc122SPeter Wu if (size != cursor->data_size) {
26736ffc122SPeter Wu fprintf(stderr, "%s: bad monochrome cursor %ux%u with size %u\n",
26836ffc122SPeter Wu __func__, c->width, c->height, cursor->data_size);
26936ffc122SPeter Wu goto fail;
27036ffc122SPeter Wu }
27136ffc122SPeter Wu and_mask = cursor->chunk.data;
27236ffc122SPeter Wu xor_mask = and_mask + cursor_get_mono_bpl(c) * c->height;
27336ffc122SPeter Wu cursor_set_mono(c, 0xffffff, 0x000000, xor_mask, 1, and_mask);
27436ffc122SPeter Wu if (qxl->debug > 2) {
27536ffc122SPeter Wu cursor_print_ascii_art(c, "qxl/mono");
27636ffc122SPeter Wu }
27736ffc122SPeter Wu break;
278a19cbfb3SGerd Hoffmann case SPICE_CURSOR_TYPE_ALPHA:
2799569f5cbSMauro Matteo Cascella size = sizeof(uint32_t) * c->width * c->height;
280b21330b5SGerd Hoffmann qxl_unpack_chunks(c->data, size, qxl, &cursor->chunk, group_id);
281a19cbfb3SGerd Hoffmann if (qxl->debug > 2) {
282a19cbfb3SGerd Hoffmann cursor_print_ascii_art(c, "qxl/alpha");
283a19cbfb3SGerd Hoffmann }
284a19cbfb3SGerd Hoffmann break;
285a19cbfb3SGerd Hoffmann default:
286a19cbfb3SGerd Hoffmann fprintf(stderr, "%s: not implemented: type %d\n",
287a89f364aSAlistair Francis __func__, cursor->header.type);
288a19cbfb3SGerd Hoffmann goto fail;
289a19cbfb3SGerd Hoffmann }
290a19cbfb3SGerd Hoffmann return c;
291a19cbfb3SGerd Hoffmann
292a19cbfb3SGerd Hoffmann fail:
293f4579e28SMarc-André Lureau cursor_unref(c);
294a19cbfb3SGerd Hoffmann return NULL;
295a19cbfb3SGerd Hoffmann }
296a19cbfb3SGerd Hoffmann
297a19cbfb3SGerd Hoffmann
298a19cbfb3SGerd Hoffmann /* called from spice server thread context only */
qxl_render_cursor(PCIQXLDevice * qxl,QXLCommandExt * ext)299fae2afb1SAlon Levy int qxl_render_cursor(PCIQXLDevice *qxl, QXLCommandExt *ext)
300a19cbfb3SGerd Hoffmann {
3018efec0efSPhilippe Mathieu-Daudé QXLCursorCmd *cmd = qxl_phys2virt(qxl, ext->cmd.data, ext->group_id,
3028efec0efSPhilippe Mathieu-Daudé sizeof(QXLCursorCmd));
303a19cbfb3SGerd Hoffmann QXLCursor *cursor;
304a19cbfb3SGerd Hoffmann QEMUCursor *c;
305a19cbfb3SGerd Hoffmann
306fae2afb1SAlon Levy if (!cmd) {
307fae2afb1SAlon Levy return 1;
308fae2afb1SAlon Levy }
309fae2afb1SAlon Levy
310a19cbfb3SGerd Hoffmann if (qxl->debug > 1 && cmd->type != QXL_CURSOR_MOVE) {
311a89f364aSAlistair Francis fprintf(stderr, "%s", __func__);
312a19cbfb3SGerd Hoffmann qxl_log_cmd_cursor(qxl, cmd, ext->group_id);
313a19cbfb3SGerd Hoffmann fprintf(stderr, "\n");
314a19cbfb3SGerd Hoffmann }
315a19cbfb3SGerd Hoffmann switch (cmd->type) {
316a19cbfb3SGerd Hoffmann case QXL_CURSOR_SET:
3178efec0efSPhilippe Mathieu-Daudé /* First read the QXLCursor to get QXLDataChunk::data_size ... */
3188efec0efSPhilippe Mathieu-Daudé cursor = qxl_phys2virt(qxl, cmd->u.set.shape, ext->group_id,
3198efec0efSPhilippe Mathieu-Daudé sizeof(QXLCursor));
3208efec0efSPhilippe Mathieu-Daudé if (!cursor) {
3218efec0efSPhilippe Mathieu-Daudé return 1;
3228efec0efSPhilippe Mathieu-Daudé }
3238efec0efSPhilippe Mathieu-Daudé /* Then read including the chunked data following QXLCursor. */
3248efec0efSPhilippe Mathieu-Daudé cursor = qxl_phys2virt(qxl, cmd->u.set.shape, ext->group_id,
3258efec0efSPhilippe Mathieu-Daudé sizeof(QXLCursor) + cursor->chunk.data_size);
326fae2afb1SAlon Levy if (!cursor) {
327fae2afb1SAlon Levy return 1;
328fae2afb1SAlon Levy }
329b21330b5SGerd Hoffmann c = qxl_cursor(qxl, cursor, ext->group_id);
330a19cbfb3SGerd Hoffmann if (c == NULL) {
331a19cbfb3SGerd Hoffmann c = cursor_builtin_left_ptr();
332a19cbfb3SGerd Hoffmann }
33307536094SGerd Hoffmann qemu_mutex_lock(&qxl->ssd.lock);
33407536094SGerd Hoffmann if (qxl->ssd.cursor) {
335f4579e28SMarc-André Lureau cursor_unref(qxl->ssd.cursor);
33607536094SGerd Hoffmann }
33707536094SGerd Hoffmann qxl->ssd.cursor = c;
33807536094SGerd Hoffmann qxl->ssd.mouse_x = cmd->u.set.position.x;
33907536094SGerd Hoffmann qxl->ssd.mouse_y = cmd->u.set.position.y;
34007536094SGerd Hoffmann qemu_mutex_unlock(&qxl->ssd.lock);
3410b2824e5SGerd Hoffmann qemu_bh_schedule(qxl->ssd.cursor_bh);
342a19cbfb3SGerd Hoffmann break;
343a19cbfb3SGerd Hoffmann case QXL_CURSOR_MOVE:
34407536094SGerd Hoffmann qemu_mutex_lock(&qxl->ssd.lock);
34507536094SGerd Hoffmann qxl->ssd.mouse_x = cmd->u.position.x;
34607536094SGerd Hoffmann qxl->ssd.mouse_y = cmd->u.position.y;
34707536094SGerd Hoffmann qemu_mutex_unlock(&qxl->ssd.lock);
3480b2824e5SGerd Hoffmann qemu_bh_schedule(qxl->ssd.cursor_bh);
349a19cbfb3SGerd Hoffmann break;
350a19cbfb3SGerd Hoffmann }
351fae2afb1SAlon Levy return 0;
352a19cbfb3SGerd Hoffmann }
353