xref: /qemu/hw/display/qxl-render.c (revision 65cb7129f4160c7e07a0da107f888ec73ae96776)
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