xref: /qemu/hw/display/virtio-gpu-rutabaga.c (revision 588a09da)
11dcc6adbSGurchetan Singh /* SPDX-License-Identifier: GPL-2.0-or-later */
21dcc6adbSGurchetan Singh 
31dcc6adbSGurchetan Singh #include "qemu/osdep.h"
41dcc6adbSGurchetan Singh #include "qapi/error.h"
51dcc6adbSGurchetan Singh #include "qemu/error-report.h"
61dcc6adbSGurchetan Singh #include "qemu/iov.h"
71dcc6adbSGurchetan Singh #include "trace.h"
81dcc6adbSGurchetan Singh #include "hw/virtio/virtio.h"
91dcc6adbSGurchetan Singh #include "hw/virtio/virtio-gpu.h"
101dcc6adbSGurchetan Singh #include "hw/virtio/virtio-gpu-pixman.h"
111dcc6adbSGurchetan Singh #include "hw/virtio/virtio-iommu.h"
121dcc6adbSGurchetan Singh 
131dcc6adbSGurchetan Singh #include <glib/gmem.h>
141dcc6adbSGurchetan Singh #include <rutabaga_gfx/rutabaga_gfx_ffi.h>
151dcc6adbSGurchetan Singh 
161dcc6adbSGurchetan Singh #define CHECK(condition, cmd)                                                 \
171dcc6adbSGurchetan Singh     do {                                                                      \
181dcc6adbSGurchetan Singh         if (!(condition)) {                                                   \
191dcc6adbSGurchetan Singh             error_report("CHECK failed in %s() %s:" "%d", __func__,           \
201dcc6adbSGurchetan Singh                          __FILE__, __LINE__);                                 \
211dcc6adbSGurchetan Singh             (cmd)->error = VIRTIO_GPU_RESP_ERR_UNSPEC;                        \
221dcc6adbSGurchetan Singh             return;                                                           \
231dcc6adbSGurchetan Singh        }                                                                      \
241dcc6adbSGurchetan Singh     } while (0)
251dcc6adbSGurchetan Singh 
261dcc6adbSGurchetan Singh struct rutabaga_aio_data {
271dcc6adbSGurchetan Singh     struct VirtIOGPURutabaga *vr;
281dcc6adbSGurchetan Singh     struct rutabaga_fence fence;
291dcc6adbSGurchetan Singh };
301dcc6adbSGurchetan Singh 
311dcc6adbSGurchetan Singh static void
virtio_gpu_rutabaga_update_cursor(VirtIOGPU * g,struct virtio_gpu_scanout * s,uint32_t resource_id)321dcc6adbSGurchetan Singh virtio_gpu_rutabaga_update_cursor(VirtIOGPU *g, struct virtio_gpu_scanout *s,
331dcc6adbSGurchetan Singh                                   uint32_t resource_id)
341dcc6adbSGurchetan Singh {
351dcc6adbSGurchetan Singh     struct virtio_gpu_simple_resource *res;
361dcc6adbSGurchetan Singh     struct rutabaga_transfer transfer = { 0 };
371dcc6adbSGurchetan Singh     struct iovec transfer_iovec;
381dcc6adbSGurchetan Singh 
391dcc6adbSGurchetan Singh     VirtIOGPURutabaga *vr = VIRTIO_GPU_RUTABAGA(g);
401dcc6adbSGurchetan Singh 
411dcc6adbSGurchetan Singh     res = virtio_gpu_find_resource(g, resource_id);
421dcc6adbSGurchetan Singh     if (!res) {
431dcc6adbSGurchetan Singh         return;
441dcc6adbSGurchetan Singh     }
451dcc6adbSGurchetan Singh 
461dcc6adbSGurchetan Singh     if (res->width != s->current_cursor->width ||
471dcc6adbSGurchetan Singh         res->height != s->current_cursor->height) {
481dcc6adbSGurchetan Singh         return;
491dcc6adbSGurchetan Singh     }
501dcc6adbSGurchetan Singh 
511dcc6adbSGurchetan Singh     transfer.x = 0;
521dcc6adbSGurchetan Singh     transfer.y = 0;
531dcc6adbSGurchetan Singh     transfer.z = 0;
541dcc6adbSGurchetan Singh     transfer.w = res->width;
551dcc6adbSGurchetan Singh     transfer.h = res->height;
561dcc6adbSGurchetan Singh     transfer.d = 1;
571dcc6adbSGurchetan Singh 
581dcc6adbSGurchetan Singh     transfer_iovec.iov_base = s->current_cursor->data;
591dcc6adbSGurchetan Singh     transfer_iovec.iov_len = res->width * res->height * 4;
601dcc6adbSGurchetan Singh 
611dcc6adbSGurchetan Singh     rutabaga_resource_transfer_read(vr->rutabaga, 0,
621dcc6adbSGurchetan Singh                                     resource_id, &transfer,
631dcc6adbSGurchetan Singh                                     &transfer_iovec);
641dcc6adbSGurchetan Singh }
651dcc6adbSGurchetan Singh 
661dcc6adbSGurchetan Singh static void
virtio_gpu_rutabaga_gl_flushed(VirtIOGPUBase * b)671dcc6adbSGurchetan Singh virtio_gpu_rutabaga_gl_flushed(VirtIOGPUBase *b)
681dcc6adbSGurchetan Singh {
691dcc6adbSGurchetan Singh     VirtIOGPU *g = VIRTIO_GPU(b);
701dcc6adbSGurchetan Singh     virtio_gpu_process_cmdq(g);
711dcc6adbSGurchetan Singh }
721dcc6adbSGurchetan Singh 
731dcc6adbSGurchetan Singh static void
rutabaga_cmd_create_resource_2d(VirtIOGPU * g,struct virtio_gpu_ctrl_command * cmd)741dcc6adbSGurchetan Singh rutabaga_cmd_create_resource_2d(VirtIOGPU *g,
751dcc6adbSGurchetan Singh                                 struct virtio_gpu_ctrl_command *cmd)
761dcc6adbSGurchetan Singh {
771dcc6adbSGurchetan Singh     int32_t result;
781dcc6adbSGurchetan Singh     struct rutabaga_create_3d rc_3d = { 0 };
791dcc6adbSGurchetan Singh     struct virtio_gpu_simple_resource *res;
801dcc6adbSGurchetan Singh     struct virtio_gpu_resource_create_2d c2d;
811dcc6adbSGurchetan Singh 
821dcc6adbSGurchetan Singh     VirtIOGPURutabaga *vr = VIRTIO_GPU_RUTABAGA(g);
831dcc6adbSGurchetan Singh 
841dcc6adbSGurchetan Singh     VIRTIO_GPU_FILL_CMD(c2d);
851dcc6adbSGurchetan Singh     trace_virtio_gpu_cmd_res_create_2d(c2d.resource_id, c2d.format,
861dcc6adbSGurchetan Singh                                        c2d.width, c2d.height);
871dcc6adbSGurchetan Singh 
881dcc6adbSGurchetan Singh     rc_3d.target = 2;
891dcc6adbSGurchetan Singh     rc_3d.format = c2d.format;
901dcc6adbSGurchetan Singh     rc_3d.bind = (1 << 1);
911dcc6adbSGurchetan Singh     rc_3d.width = c2d.width;
921dcc6adbSGurchetan Singh     rc_3d.height = c2d.height;
931dcc6adbSGurchetan Singh     rc_3d.depth = 1;
941dcc6adbSGurchetan Singh     rc_3d.array_size = 1;
951dcc6adbSGurchetan Singh     rc_3d.last_level = 0;
961dcc6adbSGurchetan Singh     rc_3d.nr_samples = 0;
971dcc6adbSGurchetan Singh     rc_3d.flags = VIRTIO_GPU_RESOURCE_FLAG_Y_0_TOP;
981dcc6adbSGurchetan Singh 
991dcc6adbSGurchetan Singh     result = rutabaga_resource_create_3d(vr->rutabaga, c2d.resource_id, &rc_3d);
1001dcc6adbSGurchetan Singh     CHECK(!result, cmd);
1011dcc6adbSGurchetan Singh 
1021dcc6adbSGurchetan Singh     res = g_new0(struct virtio_gpu_simple_resource, 1);
1031dcc6adbSGurchetan Singh     res->width = c2d.width;
1041dcc6adbSGurchetan Singh     res->height = c2d.height;
1051dcc6adbSGurchetan Singh     res->format = c2d.format;
1061dcc6adbSGurchetan Singh     res->resource_id = c2d.resource_id;
1071dcc6adbSGurchetan Singh 
1081dcc6adbSGurchetan Singh     QTAILQ_INSERT_HEAD(&g->reslist, res, next);
1091dcc6adbSGurchetan Singh }
1101dcc6adbSGurchetan Singh 
1111dcc6adbSGurchetan Singh static void
rutabaga_cmd_create_resource_3d(VirtIOGPU * g,struct virtio_gpu_ctrl_command * cmd)1121dcc6adbSGurchetan Singh rutabaga_cmd_create_resource_3d(VirtIOGPU *g,
1131dcc6adbSGurchetan Singh                                 struct virtio_gpu_ctrl_command *cmd)
1141dcc6adbSGurchetan Singh {
1151dcc6adbSGurchetan Singh     int32_t result;
1161dcc6adbSGurchetan Singh     struct rutabaga_create_3d rc_3d = { 0 };
1171dcc6adbSGurchetan Singh     struct virtio_gpu_simple_resource *res;
1181dcc6adbSGurchetan Singh     struct virtio_gpu_resource_create_3d c3d;
1191dcc6adbSGurchetan Singh 
1201dcc6adbSGurchetan Singh     VirtIOGPURutabaga *vr = VIRTIO_GPU_RUTABAGA(g);
1211dcc6adbSGurchetan Singh 
1221dcc6adbSGurchetan Singh     VIRTIO_GPU_FILL_CMD(c3d);
1231dcc6adbSGurchetan Singh 
1241dcc6adbSGurchetan Singh     trace_virtio_gpu_cmd_res_create_3d(c3d.resource_id, c3d.format,
1251dcc6adbSGurchetan Singh                                        c3d.width, c3d.height, c3d.depth);
1261dcc6adbSGurchetan Singh 
1271dcc6adbSGurchetan Singh     rc_3d.target = c3d.target;
1281dcc6adbSGurchetan Singh     rc_3d.format = c3d.format;
1291dcc6adbSGurchetan Singh     rc_3d.bind = c3d.bind;
1301dcc6adbSGurchetan Singh     rc_3d.width = c3d.width;
1311dcc6adbSGurchetan Singh     rc_3d.height = c3d.height;
1321dcc6adbSGurchetan Singh     rc_3d.depth = c3d.depth;
1331dcc6adbSGurchetan Singh     rc_3d.array_size = c3d.array_size;
1341dcc6adbSGurchetan Singh     rc_3d.last_level = c3d.last_level;
1351dcc6adbSGurchetan Singh     rc_3d.nr_samples = c3d.nr_samples;
1361dcc6adbSGurchetan Singh     rc_3d.flags = c3d.flags;
1371dcc6adbSGurchetan Singh 
1381dcc6adbSGurchetan Singh     result = rutabaga_resource_create_3d(vr->rutabaga, c3d.resource_id, &rc_3d);
1391dcc6adbSGurchetan Singh     CHECK(!result, cmd);
1401dcc6adbSGurchetan Singh 
1411dcc6adbSGurchetan Singh     res = g_new0(struct virtio_gpu_simple_resource, 1);
1421dcc6adbSGurchetan Singh     res->width = c3d.width;
1431dcc6adbSGurchetan Singh     res->height = c3d.height;
1441dcc6adbSGurchetan Singh     res->format = c3d.format;
1451dcc6adbSGurchetan Singh     res->resource_id = c3d.resource_id;
1461dcc6adbSGurchetan Singh 
1471dcc6adbSGurchetan Singh     QTAILQ_INSERT_HEAD(&g->reslist, res, next);
1481dcc6adbSGurchetan Singh }
1491dcc6adbSGurchetan Singh 
1501dcc6adbSGurchetan Singh static void
virtio_gpu_rutabaga_resource_unref(VirtIOGPU * g,struct virtio_gpu_simple_resource * res,Error ** errp)151*588a09daSManos Pitsidianakis virtio_gpu_rutabaga_resource_unref(VirtIOGPU *g,
152*588a09daSManos Pitsidianakis                                    struct virtio_gpu_simple_resource *res,
153*588a09daSManos Pitsidianakis                                    Error **errp)
154*588a09daSManos Pitsidianakis {
155*588a09daSManos Pitsidianakis     int32_t result;
156*588a09daSManos Pitsidianakis     VirtIOGPURutabaga *vr = VIRTIO_GPU_RUTABAGA(g);
157*588a09daSManos Pitsidianakis 
158*588a09daSManos Pitsidianakis     result = rutabaga_resource_unref(vr->rutabaga, res->resource_id);
159*588a09daSManos Pitsidianakis     if (result) {
160*588a09daSManos Pitsidianakis         error_setg_errno(errp,
161*588a09daSManos Pitsidianakis                         (int)result,
162*588a09daSManos Pitsidianakis                         "%s: rutabaga_resource_unref returned %"PRIi32
163*588a09daSManos Pitsidianakis                         " for resource_id = %"PRIu32, __func__, result,
164*588a09daSManos Pitsidianakis                         res->resource_id);
165*588a09daSManos Pitsidianakis     }
166*588a09daSManos Pitsidianakis 
167*588a09daSManos Pitsidianakis     if (res->image) {
168*588a09daSManos Pitsidianakis         pixman_image_unref(res->image);
169*588a09daSManos Pitsidianakis     }
170*588a09daSManos Pitsidianakis 
171*588a09daSManos Pitsidianakis     QTAILQ_REMOVE(&g->reslist, res, next);
172*588a09daSManos Pitsidianakis     g_free(res);
173*588a09daSManos Pitsidianakis }
174*588a09daSManos Pitsidianakis 
175*588a09daSManos Pitsidianakis static void
rutabaga_cmd_resource_unref(VirtIOGPU * g,struct virtio_gpu_ctrl_command * cmd)1761dcc6adbSGurchetan Singh rutabaga_cmd_resource_unref(VirtIOGPU *g,
1771dcc6adbSGurchetan Singh                             struct virtio_gpu_ctrl_command *cmd)
1781dcc6adbSGurchetan Singh {
179*588a09daSManos Pitsidianakis     int32_t result = 0;
1801dcc6adbSGurchetan Singh     struct virtio_gpu_simple_resource *res;
1811dcc6adbSGurchetan Singh     struct virtio_gpu_resource_unref unref;
182*588a09daSManos Pitsidianakis     Error *local_err = NULL;
1831dcc6adbSGurchetan Singh 
1841dcc6adbSGurchetan Singh     VIRTIO_GPU_FILL_CMD(unref);
1851dcc6adbSGurchetan Singh 
1861dcc6adbSGurchetan Singh     trace_virtio_gpu_cmd_res_unref(unref.resource_id);
1871dcc6adbSGurchetan Singh 
1881dcc6adbSGurchetan Singh     res = virtio_gpu_find_resource(g, unref.resource_id);
1891dcc6adbSGurchetan Singh     CHECK(res, cmd);
1901dcc6adbSGurchetan Singh 
191*588a09daSManos Pitsidianakis     virtio_gpu_rutabaga_resource_unref(g, res, &local_err);
192*588a09daSManos Pitsidianakis     if (local_err) {
193*588a09daSManos Pitsidianakis         error_report_err(local_err);
194*588a09daSManos Pitsidianakis         /* local_err was freed, do not reuse it. */
195*588a09daSManos Pitsidianakis         local_err = NULL;
196*588a09daSManos Pitsidianakis         result = 1;
1971dcc6adbSGurchetan Singh     }
198*588a09daSManos Pitsidianakis     CHECK(!result, cmd);
1991dcc6adbSGurchetan Singh }
2001dcc6adbSGurchetan Singh 
2011dcc6adbSGurchetan Singh static void
rutabaga_cmd_context_create(VirtIOGPU * g,struct virtio_gpu_ctrl_command * cmd)2021dcc6adbSGurchetan Singh rutabaga_cmd_context_create(VirtIOGPU *g,
2031dcc6adbSGurchetan Singh                             struct virtio_gpu_ctrl_command *cmd)
2041dcc6adbSGurchetan Singh {
2051dcc6adbSGurchetan Singh     int32_t result;
2061dcc6adbSGurchetan Singh     struct virtio_gpu_ctx_create cc;
2071dcc6adbSGurchetan Singh 
2081dcc6adbSGurchetan Singh     VirtIOGPURutabaga *vr = VIRTIO_GPU_RUTABAGA(g);
2091dcc6adbSGurchetan Singh 
2101dcc6adbSGurchetan Singh     VIRTIO_GPU_FILL_CMD(cc);
2111dcc6adbSGurchetan Singh     trace_virtio_gpu_cmd_ctx_create(cc.hdr.ctx_id,
2121dcc6adbSGurchetan Singh                                     cc.debug_name);
2131dcc6adbSGurchetan Singh 
2141dcc6adbSGurchetan Singh     result = rutabaga_context_create(vr->rutabaga, cc.hdr.ctx_id,
2151dcc6adbSGurchetan Singh                                      cc.context_init, cc.debug_name, cc.nlen);
2161dcc6adbSGurchetan Singh     CHECK(!result, cmd);
2171dcc6adbSGurchetan Singh }
2181dcc6adbSGurchetan Singh 
2191dcc6adbSGurchetan Singh static void
rutabaga_cmd_context_destroy(VirtIOGPU * g,struct virtio_gpu_ctrl_command * cmd)2201dcc6adbSGurchetan Singh rutabaga_cmd_context_destroy(VirtIOGPU *g,
2211dcc6adbSGurchetan Singh                              struct virtio_gpu_ctrl_command *cmd)
2221dcc6adbSGurchetan Singh {
2231dcc6adbSGurchetan Singh     int32_t result;
2241dcc6adbSGurchetan Singh     struct virtio_gpu_ctx_destroy cd;
2251dcc6adbSGurchetan Singh 
2261dcc6adbSGurchetan Singh     VirtIOGPURutabaga *vr = VIRTIO_GPU_RUTABAGA(g);
2271dcc6adbSGurchetan Singh 
2281dcc6adbSGurchetan Singh     VIRTIO_GPU_FILL_CMD(cd);
2291dcc6adbSGurchetan Singh     trace_virtio_gpu_cmd_ctx_destroy(cd.hdr.ctx_id);
2301dcc6adbSGurchetan Singh 
2311dcc6adbSGurchetan Singh     result = rutabaga_context_destroy(vr->rutabaga, cd.hdr.ctx_id);
2321dcc6adbSGurchetan Singh     CHECK(!result, cmd);
2331dcc6adbSGurchetan Singh }
2341dcc6adbSGurchetan Singh 
2351dcc6adbSGurchetan Singh static void
rutabaga_cmd_resource_flush(VirtIOGPU * g,struct virtio_gpu_ctrl_command * cmd)2361dcc6adbSGurchetan Singh rutabaga_cmd_resource_flush(VirtIOGPU *g, struct virtio_gpu_ctrl_command *cmd)
2371dcc6adbSGurchetan Singh {
2381dcc6adbSGurchetan Singh     int32_t result, i;
2391dcc6adbSGurchetan Singh     struct virtio_gpu_scanout *scanout = NULL;
2401dcc6adbSGurchetan Singh     struct virtio_gpu_simple_resource *res;
2411dcc6adbSGurchetan Singh     struct rutabaga_transfer transfer = { 0 };
2421dcc6adbSGurchetan Singh     struct iovec transfer_iovec;
2431dcc6adbSGurchetan Singh     struct virtio_gpu_resource_flush rf;
2441dcc6adbSGurchetan Singh     bool found = false;
2451dcc6adbSGurchetan Singh 
2461dcc6adbSGurchetan Singh     VirtIOGPUBase *vb = VIRTIO_GPU_BASE(g);
2471dcc6adbSGurchetan Singh     VirtIOGPURutabaga *vr = VIRTIO_GPU_RUTABAGA(g);
2481dcc6adbSGurchetan Singh     if (vr->headless) {
2491dcc6adbSGurchetan Singh         return;
2501dcc6adbSGurchetan Singh     }
2511dcc6adbSGurchetan Singh 
2521dcc6adbSGurchetan Singh     VIRTIO_GPU_FILL_CMD(rf);
2531dcc6adbSGurchetan Singh     trace_virtio_gpu_cmd_res_flush(rf.resource_id,
2541dcc6adbSGurchetan Singh                                    rf.r.width, rf.r.height, rf.r.x, rf.r.y);
2551dcc6adbSGurchetan Singh 
2561dcc6adbSGurchetan Singh     res = virtio_gpu_find_resource(g, rf.resource_id);
2571dcc6adbSGurchetan Singh     CHECK(res, cmd);
2581dcc6adbSGurchetan Singh 
2591dcc6adbSGurchetan Singh     for (i = 0; i < vb->conf.max_outputs; i++) {
2601dcc6adbSGurchetan Singh         scanout = &vb->scanout[i];
2611dcc6adbSGurchetan Singh         if (i == res->scanout_bitmask) {
2621dcc6adbSGurchetan Singh             found = true;
2631dcc6adbSGurchetan Singh             break;
2641dcc6adbSGurchetan Singh         }
2651dcc6adbSGurchetan Singh     }
2661dcc6adbSGurchetan Singh 
2671dcc6adbSGurchetan Singh     if (!found) {
2681dcc6adbSGurchetan Singh         return;
2691dcc6adbSGurchetan Singh     }
2701dcc6adbSGurchetan Singh 
2711dcc6adbSGurchetan Singh     transfer.x = 0;
2721dcc6adbSGurchetan Singh     transfer.y = 0;
2731dcc6adbSGurchetan Singh     transfer.z = 0;
2741dcc6adbSGurchetan Singh     transfer.w = res->width;
2751dcc6adbSGurchetan Singh     transfer.h = res->height;
2761dcc6adbSGurchetan Singh     transfer.d = 1;
2771dcc6adbSGurchetan Singh 
2781dcc6adbSGurchetan Singh     transfer_iovec.iov_base = pixman_image_get_data(res->image);
2791dcc6adbSGurchetan Singh     transfer_iovec.iov_len = res->width * res->height * 4;
2801dcc6adbSGurchetan Singh 
2811dcc6adbSGurchetan Singh     result = rutabaga_resource_transfer_read(vr->rutabaga, 0,
2821dcc6adbSGurchetan Singh                                              rf.resource_id, &transfer,
2831dcc6adbSGurchetan Singh                                              &transfer_iovec);
2841dcc6adbSGurchetan Singh     CHECK(!result, cmd);
2851dcc6adbSGurchetan Singh     dpy_gfx_update_full(scanout->con);
2861dcc6adbSGurchetan Singh }
2871dcc6adbSGurchetan Singh 
2881dcc6adbSGurchetan Singh static void
rutabaga_cmd_set_scanout(VirtIOGPU * g,struct virtio_gpu_ctrl_command * cmd)2891dcc6adbSGurchetan Singh rutabaga_cmd_set_scanout(VirtIOGPU *g, struct virtio_gpu_ctrl_command *cmd)
2901dcc6adbSGurchetan Singh {
2911dcc6adbSGurchetan Singh     struct virtio_gpu_simple_resource *res;
2921dcc6adbSGurchetan Singh     struct virtio_gpu_scanout *scanout = NULL;
2931dcc6adbSGurchetan Singh     struct virtio_gpu_set_scanout ss;
2941dcc6adbSGurchetan Singh 
2951dcc6adbSGurchetan Singh     VirtIOGPUBase *vb = VIRTIO_GPU_BASE(g);
2961dcc6adbSGurchetan Singh     VirtIOGPURutabaga *vr = VIRTIO_GPU_RUTABAGA(g);
2971dcc6adbSGurchetan Singh     if (vr->headless) {
2981dcc6adbSGurchetan Singh         return;
2991dcc6adbSGurchetan Singh     }
3001dcc6adbSGurchetan Singh 
3011dcc6adbSGurchetan Singh     VIRTIO_GPU_FILL_CMD(ss);
3021dcc6adbSGurchetan Singh     trace_virtio_gpu_cmd_set_scanout(ss.scanout_id, ss.resource_id,
3031dcc6adbSGurchetan Singh                                      ss.r.width, ss.r.height, ss.r.x, ss.r.y);
3041dcc6adbSGurchetan Singh 
3051dcc6adbSGurchetan Singh     CHECK(ss.scanout_id < VIRTIO_GPU_MAX_SCANOUTS, cmd);
3061dcc6adbSGurchetan Singh     scanout = &vb->scanout[ss.scanout_id];
3071dcc6adbSGurchetan Singh 
3081dcc6adbSGurchetan Singh     if (ss.resource_id == 0) {
3091dcc6adbSGurchetan Singh         dpy_gfx_replace_surface(scanout->con, NULL);
3101dcc6adbSGurchetan Singh         dpy_gl_scanout_disable(scanout->con);
3111dcc6adbSGurchetan Singh         return;
3121dcc6adbSGurchetan Singh     }
3131dcc6adbSGurchetan Singh 
3141dcc6adbSGurchetan Singh     res = virtio_gpu_find_resource(g, ss.resource_id);
3151dcc6adbSGurchetan Singh     CHECK(res, cmd);
3161dcc6adbSGurchetan Singh 
3171dcc6adbSGurchetan Singh     if (!res->image) {
3181dcc6adbSGurchetan Singh         pixman_format_code_t pformat;
3191dcc6adbSGurchetan Singh         pformat = virtio_gpu_get_pixman_format(res->format);
3201dcc6adbSGurchetan Singh         CHECK(pformat, cmd);
3211dcc6adbSGurchetan Singh 
3221dcc6adbSGurchetan Singh         res->image = pixman_image_create_bits(pformat,
3231dcc6adbSGurchetan Singh                                               res->width,
3241dcc6adbSGurchetan Singh                                               res->height,
3251dcc6adbSGurchetan Singh                                               NULL, 0);
3261dcc6adbSGurchetan Singh         CHECK(res->image, cmd);
3271dcc6adbSGurchetan Singh         pixman_image_ref(res->image);
3281dcc6adbSGurchetan Singh     }
3291dcc6adbSGurchetan Singh 
3301dcc6adbSGurchetan Singh     vb->enable = 1;
3311dcc6adbSGurchetan Singh 
3321dcc6adbSGurchetan Singh     /* realloc the surface ptr */
3331dcc6adbSGurchetan Singh     scanout->ds = qemu_create_displaysurface_pixman(res->image);
3341dcc6adbSGurchetan Singh     dpy_gfx_replace_surface(scanout->con, NULL);
3351dcc6adbSGurchetan Singh     dpy_gfx_replace_surface(scanout->con, scanout->ds);
3361dcc6adbSGurchetan Singh     res->scanout_bitmask = ss.scanout_id;
3371dcc6adbSGurchetan Singh }
3381dcc6adbSGurchetan Singh 
3391dcc6adbSGurchetan Singh static void
rutabaga_cmd_submit_3d(VirtIOGPU * g,struct virtio_gpu_ctrl_command * cmd)3401dcc6adbSGurchetan Singh rutabaga_cmd_submit_3d(VirtIOGPU *g,
3411dcc6adbSGurchetan Singh                        struct virtio_gpu_ctrl_command *cmd)
3421dcc6adbSGurchetan Singh {
3431dcc6adbSGurchetan Singh     int32_t result;
3441dcc6adbSGurchetan Singh     struct virtio_gpu_cmd_submit cs;
3451dcc6adbSGurchetan Singh     struct rutabaga_command rutabaga_cmd = { 0 };
3461dcc6adbSGurchetan Singh     g_autofree uint8_t *buf = NULL;
3471dcc6adbSGurchetan Singh     size_t s;
3481dcc6adbSGurchetan Singh 
3491dcc6adbSGurchetan Singh     VirtIOGPURutabaga *vr = VIRTIO_GPU_RUTABAGA(g);
3501dcc6adbSGurchetan Singh 
3511dcc6adbSGurchetan Singh     VIRTIO_GPU_FILL_CMD(cs);
3521dcc6adbSGurchetan Singh     trace_virtio_gpu_cmd_ctx_submit(cs.hdr.ctx_id, cs.size);
3531dcc6adbSGurchetan Singh 
3541dcc6adbSGurchetan Singh     buf = g_new0(uint8_t, cs.size);
3551dcc6adbSGurchetan Singh     s = iov_to_buf(cmd->elem.out_sg, cmd->elem.out_num,
3561dcc6adbSGurchetan Singh                    sizeof(cs), buf, cs.size);
3571dcc6adbSGurchetan Singh     CHECK(s == cs.size, cmd);
3581dcc6adbSGurchetan Singh 
3591dcc6adbSGurchetan Singh     rutabaga_cmd.ctx_id = cs.hdr.ctx_id;
3601dcc6adbSGurchetan Singh     rutabaga_cmd.cmd = buf;
3611dcc6adbSGurchetan Singh     rutabaga_cmd.cmd_size = cs.size;
3621dcc6adbSGurchetan Singh 
3631dcc6adbSGurchetan Singh     result = rutabaga_submit_command(vr->rutabaga, &rutabaga_cmd);
3641dcc6adbSGurchetan Singh     CHECK(!result, cmd);
3651dcc6adbSGurchetan Singh }
3661dcc6adbSGurchetan Singh 
3671dcc6adbSGurchetan Singh static void
rutabaga_cmd_transfer_to_host_2d(VirtIOGPU * g,struct virtio_gpu_ctrl_command * cmd)3681dcc6adbSGurchetan Singh rutabaga_cmd_transfer_to_host_2d(VirtIOGPU *g,
3691dcc6adbSGurchetan Singh                                  struct virtio_gpu_ctrl_command *cmd)
3701dcc6adbSGurchetan Singh {
3711dcc6adbSGurchetan Singh     int32_t result;
3721dcc6adbSGurchetan Singh     struct rutabaga_transfer transfer = { 0 };
3731dcc6adbSGurchetan Singh     struct virtio_gpu_transfer_to_host_2d t2d;
3741dcc6adbSGurchetan Singh 
3751dcc6adbSGurchetan Singh     VirtIOGPURutabaga *vr = VIRTIO_GPU_RUTABAGA(g);
3761dcc6adbSGurchetan Singh 
3771dcc6adbSGurchetan Singh     VIRTIO_GPU_FILL_CMD(t2d);
3781dcc6adbSGurchetan Singh     trace_virtio_gpu_cmd_res_xfer_toh_2d(t2d.resource_id);
3791dcc6adbSGurchetan Singh 
3801dcc6adbSGurchetan Singh     transfer.x = t2d.r.x;
3811dcc6adbSGurchetan Singh     transfer.y = t2d.r.y;
3821dcc6adbSGurchetan Singh     transfer.z = 0;
3831dcc6adbSGurchetan Singh     transfer.w = t2d.r.width;
3841dcc6adbSGurchetan Singh     transfer.h = t2d.r.height;
3851dcc6adbSGurchetan Singh     transfer.d = 1;
3861dcc6adbSGurchetan Singh 
3871dcc6adbSGurchetan Singh     result = rutabaga_resource_transfer_write(vr->rutabaga, 0, t2d.resource_id,
3881dcc6adbSGurchetan Singh                                               &transfer);
3891dcc6adbSGurchetan Singh     CHECK(!result, cmd);
3901dcc6adbSGurchetan Singh }
3911dcc6adbSGurchetan Singh 
3921dcc6adbSGurchetan Singh static void
rutabaga_cmd_transfer_to_host_3d(VirtIOGPU * g,struct virtio_gpu_ctrl_command * cmd)3931dcc6adbSGurchetan Singh rutabaga_cmd_transfer_to_host_3d(VirtIOGPU *g,
3941dcc6adbSGurchetan Singh                                  struct virtio_gpu_ctrl_command *cmd)
3951dcc6adbSGurchetan Singh {
3961dcc6adbSGurchetan Singh     int32_t result;
3971dcc6adbSGurchetan Singh     struct rutabaga_transfer transfer = { 0 };
3981dcc6adbSGurchetan Singh     struct virtio_gpu_transfer_host_3d t3d;
3991dcc6adbSGurchetan Singh 
4001dcc6adbSGurchetan Singh     VirtIOGPURutabaga *vr = VIRTIO_GPU_RUTABAGA(g);
4011dcc6adbSGurchetan Singh 
4021dcc6adbSGurchetan Singh     VIRTIO_GPU_FILL_CMD(t3d);
4031dcc6adbSGurchetan Singh     trace_virtio_gpu_cmd_res_xfer_toh_3d(t3d.resource_id);
4041dcc6adbSGurchetan Singh 
4051dcc6adbSGurchetan Singh     transfer.x = t3d.box.x;
4061dcc6adbSGurchetan Singh     transfer.y = t3d.box.y;
4071dcc6adbSGurchetan Singh     transfer.z = t3d.box.z;
4081dcc6adbSGurchetan Singh     transfer.w = t3d.box.w;
4091dcc6adbSGurchetan Singh     transfer.h = t3d.box.h;
4101dcc6adbSGurchetan Singh     transfer.d = t3d.box.d;
4111dcc6adbSGurchetan Singh     transfer.level = t3d.level;
4121dcc6adbSGurchetan Singh     transfer.stride = t3d.stride;
4131dcc6adbSGurchetan Singh     transfer.layer_stride = t3d.layer_stride;
4141dcc6adbSGurchetan Singh     transfer.offset = t3d.offset;
4151dcc6adbSGurchetan Singh 
4161dcc6adbSGurchetan Singh     result = rutabaga_resource_transfer_write(vr->rutabaga, t3d.hdr.ctx_id,
4171dcc6adbSGurchetan Singh                                               t3d.resource_id, &transfer);
4181dcc6adbSGurchetan Singh     CHECK(!result, cmd);
4191dcc6adbSGurchetan Singh }
4201dcc6adbSGurchetan Singh 
4211dcc6adbSGurchetan Singh static void
rutabaga_cmd_transfer_from_host_3d(VirtIOGPU * g,struct virtio_gpu_ctrl_command * cmd)4221dcc6adbSGurchetan Singh rutabaga_cmd_transfer_from_host_3d(VirtIOGPU *g,
4231dcc6adbSGurchetan Singh                                    struct virtio_gpu_ctrl_command *cmd)
4241dcc6adbSGurchetan Singh {
4251dcc6adbSGurchetan Singh     int32_t result;
4261dcc6adbSGurchetan Singh     struct rutabaga_transfer transfer = { 0 };
4271dcc6adbSGurchetan Singh     struct virtio_gpu_transfer_host_3d t3d;
4281dcc6adbSGurchetan Singh 
4291dcc6adbSGurchetan Singh     VirtIOGPURutabaga *vr = VIRTIO_GPU_RUTABAGA(g);
4301dcc6adbSGurchetan Singh 
4311dcc6adbSGurchetan Singh     VIRTIO_GPU_FILL_CMD(t3d);
4321dcc6adbSGurchetan Singh     trace_virtio_gpu_cmd_res_xfer_fromh_3d(t3d.resource_id);
4331dcc6adbSGurchetan Singh 
4341dcc6adbSGurchetan Singh     transfer.x = t3d.box.x;
4351dcc6adbSGurchetan Singh     transfer.y = t3d.box.y;
4361dcc6adbSGurchetan Singh     transfer.z = t3d.box.z;
4371dcc6adbSGurchetan Singh     transfer.w = t3d.box.w;
4381dcc6adbSGurchetan Singh     transfer.h = t3d.box.h;
4391dcc6adbSGurchetan Singh     transfer.d = t3d.box.d;
4401dcc6adbSGurchetan Singh     transfer.level = t3d.level;
4411dcc6adbSGurchetan Singh     transfer.stride = t3d.stride;
4421dcc6adbSGurchetan Singh     transfer.layer_stride = t3d.layer_stride;
4431dcc6adbSGurchetan Singh     transfer.offset = t3d.offset;
4441dcc6adbSGurchetan Singh 
4451dcc6adbSGurchetan Singh     result = rutabaga_resource_transfer_read(vr->rutabaga, t3d.hdr.ctx_id,
4461dcc6adbSGurchetan Singh                                              t3d.resource_id, &transfer, NULL);
4471dcc6adbSGurchetan Singh     CHECK(!result, cmd);
4481dcc6adbSGurchetan Singh }
4491dcc6adbSGurchetan Singh 
4501dcc6adbSGurchetan Singh static void
rutabaga_cmd_attach_backing(VirtIOGPU * g,struct virtio_gpu_ctrl_command * cmd)4511dcc6adbSGurchetan Singh rutabaga_cmd_attach_backing(VirtIOGPU *g, struct virtio_gpu_ctrl_command *cmd)
4521dcc6adbSGurchetan Singh {
4531dcc6adbSGurchetan Singh     struct rutabaga_iovecs vecs = { 0 };
4541dcc6adbSGurchetan Singh     struct virtio_gpu_simple_resource *res;
4551dcc6adbSGurchetan Singh     struct virtio_gpu_resource_attach_backing att_rb;
4561dcc6adbSGurchetan Singh     int ret;
4571dcc6adbSGurchetan Singh 
4581dcc6adbSGurchetan Singh     VirtIOGPURutabaga *vr = VIRTIO_GPU_RUTABAGA(g);
4591dcc6adbSGurchetan Singh 
4601dcc6adbSGurchetan Singh     VIRTIO_GPU_FILL_CMD(att_rb);
4611dcc6adbSGurchetan Singh     trace_virtio_gpu_cmd_res_back_attach(att_rb.resource_id);
4621dcc6adbSGurchetan Singh 
4631dcc6adbSGurchetan Singh     res = virtio_gpu_find_resource(g, att_rb.resource_id);
4641dcc6adbSGurchetan Singh     CHECK(res, cmd);
4651dcc6adbSGurchetan Singh     CHECK(!res->iov, cmd);
4661dcc6adbSGurchetan Singh 
4671dcc6adbSGurchetan Singh     ret = virtio_gpu_create_mapping_iov(g, att_rb.nr_entries, sizeof(att_rb),
4681dcc6adbSGurchetan Singh                                         cmd, NULL, &res->iov, &res->iov_cnt);
4691dcc6adbSGurchetan Singh     CHECK(!ret, cmd);
4701dcc6adbSGurchetan Singh 
4711dcc6adbSGurchetan Singh     vecs.iovecs = res->iov;
4721dcc6adbSGurchetan Singh     vecs.num_iovecs = res->iov_cnt;
4731dcc6adbSGurchetan Singh 
4741dcc6adbSGurchetan Singh     ret = rutabaga_resource_attach_backing(vr->rutabaga, att_rb.resource_id,
4751dcc6adbSGurchetan Singh                                            &vecs);
4761dcc6adbSGurchetan Singh     if (ret != 0) {
4771dcc6adbSGurchetan Singh         virtio_gpu_cleanup_mapping(g, res);
4781dcc6adbSGurchetan Singh     }
4791dcc6adbSGurchetan Singh 
4801dcc6adbSGurchetan Singh     CHECK(!ret, cmd);
4811dcc6adbSGurchetan Singh }
4821dcc6adbSGurchetan Singh 
4831dcc6adbSGurchetan Singh static void
rutabaga_cmd_detach_backing(VirtIOGPU * g,struct virtio_gpu_ctrl_command * cmd)4841dcc6adbSGurchetan Singh rutabaga_cmd_detach_backing(VirtIOGPU *g, struct virtio_gpu_ctrl_command *cmd)
4851dcc6adbSGurchetan Singh {
4861dcc6adbSGurchetan Singh     struct virtio_gpu_simple_resource *res;
4871dcc6adbSGurchetan Singh     struct virtio_gpu_resource_detach_backing detach_rb;
4881dcc6adbSGurchetan Singh 
4891dcc6adbSGurchetan Singh     VirtIOGPURutabaga *vr = VIRTIO_GPU_RUTABAGA(g);
4901dcc6adbSGurchetan Singh 
4911dcc6adbSGurchetan Singh     VIRTIO_GPU_FILL_CMD(detach_rb);
4921dcc6adbSGurchetan Singh     trace_virtio_gpu_cmd_res_back_detach(detach_rb.resource_id);
4931dcc6adbSGurchetan Singh 
4941dcc6adbSGurchetan Singh     res = virtio_gpu_find_resource(g, detach_rb.resource_id);
4951dcc6adbSGurchetan Singh     CHECK(res, cmd);
4961dcc6adbSGurchetan Singh 
4971dcc6adbSGurchetan Singh     rutabaga_resource_detach_backing(vr->rutabaga,
4981dcc6adbSGurchetan Singh                                      detach_rb.resource_id);
4991dcc6adbSGurchetan Singh 
5001dcc6adbSGurchetan Singh     virtio_gpu_cleanup_mapping(g, res);
5011dcc6adbSGurchetan Singh }
5021dcc6adbSGurchetan Singh 
5031dcc6adbSGurchetan Singh static void
rutabaga_cmd_ctx_attach_resource(VirtIOGPU * g,struct virtio_gpu_ctrl_command * cmd)5041dcc6adbSGurchetan Singh rutabaga_cmd_ctx_attach_resource(VirtIOGPU *g,
5051dcc6adbSGurchetan Singh                                  struct virtio_gpu_ctrl_command *cmd)
5061dcc6adbSGurchetan Singh {
5071dcc6adbSGurchetan Singh     int32_t result;
5081dcc6adbSGurchetan Singh     struct virtio_gpu_ctx_resource att_res;
5091dcc6adbSGurchetan Singh 
5101dcc6adbSGurchetan Singh     VirtIOGPURutabaga *vr = VIRTIO_GPU_RUTABAGA(g);
5111dcc6adbSGurchetan Singh 
5121dcc6adbSGurchetan Singh     VIRTIO_GPU_FILL_CMD(att_res);
5131dcc6adbSGurchetan Singh     trace_virtio_gpu_cmd_ctx_res_attach(att_res.hdr.ctx_id,
5141dcc6adbSGurchetan Singh                                         att_res.resource_id);
5151dcc6adbSGurchetan Singh 
5161dcc6adbSGurchetan Singh     result = rutabaga_context_attach_resource(vr->rutabaga, att_res.hdr.ctx_id,
5171dcc6adbSGurchetan Singh                                               att_res.resource_id);
5181dcc6adbSGurchetan Singh     CHECK(!result, cmd);
5191dcc6adbSGurchetan Singh }
5201dcc6adbSGurchetan Singh 
5211dcc6adbSGurchetan Singh static void
rutabaga_cmd_ctx_detach_resource(VirtIOGPU * g,struct virtio_gpu_ctrl_command * cmd)5221dcc6adbSGurchetan Singh rutabaga_cmd_ctx_detach_resource(VirtIOGPU *g,
5231dcc6adbSGurchetan Singh                                  struct virtio_gpu_ctrl_command *cmd)
5241dcc6adbSGurchetan Singh {
5251dcc6adbSGurchetan Singh     int32_t result;
5261dcc6adbSGurchetan Singh     struct virtio_gpu_ctx_resource det_res;
5271dcc6adbSGurchetan Singh 
5281dcc6adbSGurchetan Singh     VirtIOGPURutabaga *vr = VIRTIO_GPU_RUTABAGA(g);
5291dcc6adbSGurchetan Singh 
5301dcc6adbSGurchetan Singh     VIRTIO_GPU_FILL_CMD(det_res);
5311dcc6adbSGurchetan Singh     trace_virtio_gpu_cmd_ctx_res_detach(det_res.hdr.ctx_id,
5321dcc6adbSGurchetan Singh                                         det_res.resource_id);
5331dcc6adbSGurchetan Singh 
5341dcc6adbSGurchetan Singh     result = rutabaga_context_detach_resource(vr->rutabaga, det_res.hdr.ctx_id,
5351dcc6adbSGurchetan Singh                                               det_res.resource_id);
5361dcc6adbSGurchetan Singh     CHECK(!result, cmd);
5371dcc6adbSGurchetan Singh }
5381dcc6adbSGurchetan Singh 
5391dcc6adbSGurchetan Singh static void
rutabaga_cmd_get_capset_info(VirtIOGPU * g,struct virtio_gpu_ctrl_command * cmd)5401dcc6adbSGurchetan Singh rutabaga_cmd_get_capset_info(VirtIOGPU *g, struct virtio_gpu_ctrl_command *cmd)
5411dcc6adbSGurchetan Singh {
5421dcc6adbSGurchetan Singh     int32_t result;
5431dcc6adbSGurchetan Singh     struct virtio_gpu_get_capset_info info;
5441dcc6adbSGurchetan Singh     struct virtio_gpu_resp_capset_info resp;
5451dcc6adbSGurchetan Singh 
5461dcc6adbSGurchetan Singh     VirtIOGPURutabaga *vr = VIRTIO_GPU_RUTABAGA(g);
5471dcc6adbSGurchetan Singh 
5481dcc6adbSGurchetan Singh     VIRTIO_GPU_FILL_CMD(info);
5491dcc6adbSGurchetan Singh 
5501dcc6adbSGurchetan Singh     result = rutabaga_get_capset_info(vr->rutabaga, info.capset_index,
5511dcc6adbSGurchetan Singh                                       &resp.capset_id, &resp.capset_max_version,
5521dcc6adbSGurchetan Singh                                       &resp.capset_max_size);
5531dcc6adbSGurchetan Singh     CHECK(!result, cmd);
5541dcc6adbSGurchetan Singh 
5551dcc6adbSGurchetan Singh     resp.hdr.type = VIRTIO_GPU_RESP_OK_CAPSET_INFO;
5561dcc6adbSGurchetan Singh     virtio_gpu_ctrl_response(g, cmd, &resp.hdr, sizeof(resp));
5571dcc6adbSGurchetan Singh }
5581dcc6adbSGurchetan Singh 
5591dcc6adbSGurchetan Singh static void
rutabaga_cmd_get_capset(VirtIOGPU * g,struct virtio_gpu_ctrl_command * cmd)5601dcc6adbSGurchetan Singh rutabaga_cmd_get_capset(VirtIOGPU *g, struct virtio_gpu_ctrl_command *cmd)
5611dcc6adbSGurchetan Singh {
5621dcc6adbSGurchetan Singh     int32_t result;
5631dcc6adbSGurchetan Singh     struct virtio_gpu_get_capset gc;
5641dcc6adbSGurchetan Singh     struct virtio_gpu_resp_capset *resp;
5651dcc6adbSGurchetan Singh     uint32_t capset_size, capset_version;
5661dcc6adbSGurchetan Singh     uint32_t current_id, i;
5671dcc6adbSGurchetan Singh 
5681dcc6adbSGurchetan Singh     VirtIOGPURutabaga *vr = VIRTIO_GPU_RUTABAGA(g);
5691dcc6adbSGurchetan Singh 
5701dcc6adbSGurchetan Singh     VIRTIO_GPU_FILL_CMD(gc);
5711dcc6adbSGurchetan Singh     for (i = 0; i < vr->num_capsets; i++) {
5721dcc6adbSGurchetan Singh         result = rutabaga_get_capset_info(vr->rutabaga, i,
5731dcc6adbSGurchetan Singh                                           &current_id, &capset_version,
5741dcc6adbSGurchetan Singh                                           &capset_size);
5751dcc6adbSGurchetan Singh         CHECK(!result, cmd);
5761dcc6adbSGurchetan Singh 
5771dcc6adbSGurchetan Singh         if (current_id == gc.capset_id) {
5781dcc6adbSGurchetan Singh             break;
5791dcc6adbSGurchetan Singh         }
5801dcc6adbSGurchetan Singh     }
5811dcc6adbSGurchetan Singh 
5821dcc6adbSGurchetan Singh     CHECK(i < vr->num_capsets, cmd);
5831dcc6adbSGurchetan Singh 
5841dcc6adbSGurchetan Singh     resp = g_malloc0(sizeof(*resp) + capset_size);
5851dcc6adbSGurchetan Singh     resp->hdr.type = VIRTIO_GPU_RESP_OK_CAPSET;
5861dcc6adbSGurchetan Singh     rutabaga_get_capset(vr->rutabaga, gc.capset_id, gc.capset_version,
5871dcc6adbSGurchetan Singh                         resp->capset_data, capset_size);
5881dcc6adbSGurchetan Singh 
5891dcc6adbSGurchetan Singh     virtio_gpu_ctrl_response(g, cmd, &resp->hdr, sizeof(*resp) + capset_size);
5901dcc6adbSGurchetan Singh     g_free(resp);
5911dcc6adbSGurchetan Singh }
5921dcc6adbSGurchetan Singh 
5931dcc6adbSGurchetan Singh static void
rutabaga_cmd_resource_create_blob(VirtIOGPU * g,struct virtio_gpu_ctrl_command * cmd)5941dcc6adbSGurchetan Singh rutabaga_cmd_resource_create_blob(VirtIOGPU *g,
5951dcc6adbSGurchetan Singh                                   struct virtio_gpu_ctrl_command *cmd)
5961dcc6adbSGurchetan Singh {
5971dcc6adbSGurchetan Singh     int result;
5981dcc6adbSGurchetan Singh     struct rutabaga_iovecs vecs = { 0 };
5991dcc6adbSGurchetan Singh     g_autofree struct virtio_gpu_simple_resource *res = NULL;
6001dcc6adbSGurchetan Singh     struct virtio_gpu_resource_create_blob cblob;
6011dcc6adbSGurchetan Singh     struct rutabaga_create_blob rc_blob = { 0 };
6021dcc6adbSGurchetan Singh 
6031dcc6adbSGurchetan Singh     VirtIOGPURutabaga *vr = VIRTIO_GPU_RUTABAGA(g);
6041dcc6adbSGurchetan Singh 
6051dcc6adbSGurchetan Singh     VIRTIO_GPU_FILL_CMD(cblob);
6061dcc6adbSGurchetan Singh     trace_virtio_gpu_cmd_res_create_blob(cblob.resource_id, cblob.size);
6071dcc6adbSGurchetan Singh 
6081dcc6adbSGurchetan Singh     CHECK(cblob.resource_id != 0, cmd);
6091dcc6adbSGurchetan Singh 
6101dcc6adbSGurchetan Singh     res = g_new0(struct virtio_gpu_simple_resource, 1);
6111dcc6adbSGurchetan Singh 
6121dcc6adbSGurchetan Singh     res->resource_id = cblob.resource_id;
6131dcc6adbSGurchetan Singh     res->blob_size = cblob.size;
6141dcc6adbSGurchetan Singh 
6151dcc6adbSGurchetan Singh     if (cblob.blob_mem != VIRTIO_GPU_BLOB_MEM_HOST3D) {
6161dcc6adbSGurchetan Singh         result = virtio_gpu_create_mapping_iov(g, cblob.nr_entries,
6171dcc6adbSGurchetan Singh                                                sizeof(cblob), cmd, &res->addrs,
6181dcc6adbSGurchetan Singh                                                &res->iov, &res->iov_cnt);
6191dcc6adbSGurchetan Singh         CHECK(!result, cmd);
6201dcc6adbSGurchetan Singh     }
6211dcc6adbSGurchetan Singh 
6221dcc6adbSGurchetan Singh     rc_blob.blob_id = cblob.blob_id;
6231dcc6adbSGurchetan Singh     rc_blob.blob_mem = cblob.blob_mem;
6241dcc6adbSGurchetan Singh     rc_blob.blob_flags = cblob.blob_flags;
6251dcc6adbSGurchetan Singh     rc_blob.size = cblob.size;
6261dcc6adbSGurchetan Singh 
6271dcc6adbSGurchetan Singh     vecs.iovecs = res->iov;
6281dcc6adbSGurchetan Singh     vecs.num_iovecs = res->iov_cnt;
6291dcc6adbSGurchetan Singh 
6301dcc6adbSGurchetan Singh     result = rutabaga_resource_create_blob(vr->rutabaga, cblob.hdr.ctx_id,
6311dcc6adbSGurchetan Singh                                            cblob.resource_id, &rc_blob, &vecs,
6321dcc6adbSGurchetan Singh                                            NULL);
6331dcc6adbSGurchetan Singh 
6341dcc6adbSGurchetan Singh     if (result && cblob.blob_mem != VIRTIO_GPU_BLOB_MEM_HOST3D) {
6351dcc6adbSGurchetan Singh         virtio_gpu_cleanup_mapping(g, res);
6361dcc6adbSGurchetan Singh     }
6371dcc6adbSGurchetan Singh 
6381dcc6adbSGurchetan Singh     CHECK(!result, cmd);
6391dcc6adbSGurchetan Singh 
6401dcc6adbSGurchetan Singh     QTAILQ_INSERT_HEAD(&g->reslist, res, next);
6411dcc6adbSGurchetan Singh     res = NULL;
6421dcc6adbSGurchetan Singh }
6431dcc6adbSGurchetan Singh 
6441dcc6adbSGurchetan Singh static void
rutabaga_cmd_resource_map_blob(VirtIOGPU * g,struct virtio_gpu_ctrl_command * cmd)6451dcc6adbSGurchetan Singh rutabaga_cmd_resource_map_blob(VirtIOGPU *g,
6461dcc6adbSGurchetan Singh                                struct virtio_gpu_ctrl_command *cmd)
6471dcc6adbSGurchetan Singh {
6481dcc6adbSGurchetan Singh     int32_t result;
6491dcc6adbSGurchetan Singh     uint32_t map_info = 0;
6501dcc6adbSGurchetan Singh     uint32_t slot = 0;
6511dcc6adbSGurchetan Singh     struct virtio_gpu_simple_resource *res;
6521dcc6adbSGurchetan Singh     struct rutabaga_mapping mapping = { 0 };
6531dcc6adbSGurchetan Singh     struct virtio_gpu_resource_map_blob mblob;
6541dcc6adbSGurchetan Singh     struct virtio_gpu_resp_map_info resp = { 0 };
6551dcc6adbSGurchetan Singh 
6561dcc6adbSGurchetan Singh     VirtIOGPUBase *vb = VIRTIO_GPU_BASE(g);
6571dcc6adbSGurchetan Singh     VirtIOGPURutabaga *vr = VIRTIO_GPU_RUTABAGA(g);
6581dcc6adbSGurchetan Singh 
6591dcc6adbSGurchetan Singh     VIRTIO_GPU_FILL_CMD(mblob);
6601dcc6adbSGurchetan Singh 
6611dcc6adbSGurchetan Singh     CHECK(mblob.resource_id != 0, cmd);
6621dcc6adbSGurchetan Singh 
6631dcc6adbSGurchetan Singh     res = virtio_gpu_find_resource(g, mblob.resource_id);
6641dcc6adbSGurchetan Singh     CHECK(res, cmd);
6651dcc6adbSGurchetan Singh 
6661dcc6adbSGurchetan Singh     result = rutabaga_resource_map_info(vr->rutabaga, mblob.resource_id,
6671dcc6adbSGurchetan Singh                                         &map_info);
6681dcc6adbSGurchetan Singh     CHECK(!result, cmd);
6691dcc6adbSGurchetan Singh 
6701dcc6adbSGurchetan Singh     /*
6711dcc6adbSGurchetan Singh      * RUTABAGA_MAP_ACCESS_* flags are not part of the virtio-gpu spec, but do
6721dcc6adbSGurchetan Singh      * exist to potentially allow the hypervisor to restrict write access to
6731dcc6adbSGurchetan Singh      * memory. QEMU does not need to use this functionality at the moment.
6741dcc6adbSGurchetan Singh      */
6751dcc6adbSGurchetan Singh     resp.map_info = map_info & RUTABAGA_MAP_CACHE_MASK;
6761dcc6adbSGurchetan Singh 
6771dcc6adbSGurchetan Singh     result = rutabaga_resource_map(vr->rutabaga, mblob.resource_id, &mapping);
6781dcc6adbSGurchetan Singh     CHECK(!result, cmd);
6791dcc6adbSGurchetan Singh 
6801dcc6adbSGurchetan Singh     /*
6811dcc6adbSGurchetan Singh      * There is small risk of the MemoryRegion dereferencing the pointer after
6821dcc6adbSGurchetan Singh      * rutabaga unmaps it. Please see discussion here:
6831dcc6adbSGurchetan Singh      *
6841dcc6adbSGurchetan Singh      * https://lists.gnu.org/archive/html/qemu-devel/2023-09/msg05141.html
6851dcc6adbSGurchetan Singh      *
6861dcc6adbSGurchetan Singh      * It is highly unlikely to happen in practice and doesn't affect known
6871dcc6adbSGurchetan Singh      * use cases. However, it should be fixed and is noted here for posterity.
6881dcc6adbSGurchetan Singh      */
6891dcc6adbSGurchetan Singh     for (slot = 0; slot < MAX_SLOTS; slot++) {
6901dcc6adbSGurchetan Singh         if (vr->memory_regions[slot].used) {
6911dcc6adbSGurchetan Singh             continue;
6921dcc6adbSGurchetan Singh         }
6931dcc6adbSGurchetan Singh 
6941dcc6adbSGurchetan Singh         MemoryRegion *mr = &(vr->memory_regions[slot].mr);
6951dcc6adbSGurchetan Singh         memory_region_init_ram_ptr(mr, OBJECT(vr), "blob", mapping.size,
6961dcc6adbSGurchetan Singh                                    mapping.ptr);
6971dcc6adbSGurchetan Singh         memory_region_add_subregion(&vb->hostmem, mblob.offset, mr);
6981dcc6adbSGurchetan Singh         vr->memory_regions[slot].resource_id = mblob.resource_id;
6991dcc6adbSGurchetan Singh         vr->memory_regions[slot].used = 1;
7001dcc6adbSGurchetan Singh         break;
7011dcc6adbSGurchetan Singh     }
7021dcc6adbSGurchetan Singh 
7031dcc6adbSGurchetan Singh     if (slot >= MAX_SLOTS) {
7041dcc6adbSGurchetan Singh         result = rutabaga_resource_unmap(vr->rutabaga, mblob.resource_id);
7051dcc6adbSGurchetan Singh         CHECK(!result, cmd);
7061dcc6adbSGurchetan Singh     }
7071dcc6adbSGurchetan Singh 
7081dcc6adbSGurchetan Singh     CHECK(slot < MAX_SLOTS, cmd);
7091dcc6adbSGurchetan Singh 
7101dcc6adbSGurchetan Singh     resp.hdr.type = VIRTIO_GPU_RESP_OK_MAP_INFO;
7111dcc6adbSGurchetan Singh     virtio_gpu_ctrl_response(g, cmd, &resp.hdr, sizeof(resp));
7121dcc6adbSGurchetan Singh }
7131dcc6adbSGurchetan Singh 
7141dcc6adbSGurchetan Singh static void
rutabaga_cmd_resource_unmap_blob(VirtIOGPU * g,struct virtio_gpu_ctrl_command * cmd)7151dcc6adbSGurchetan Singh rutabaga_cmd_resource_unmap_blob(VirtIOGPU *g,
7161dcc6adbSGurchetan Singh                                  struct virtio_gpu_ctrl_command *cmd)
7171dcc6adbSGurchetan Singh {
7181dcc6adbSGurchetan Singh     int32_t result;
7191dcc6adbSGurchetan Singh     uint32_t slot = 0;
7201dcc6adbSGurchetan Singh     struct virtio_gpu_simple_resource *res;
7211dcc6adbSGurchetan Singh     struct virtio_gpu_resource_unmap_blob ublob;
7221dcc6adbSGurchetan Singh 
7231dcc6adbSGurchetan Singh     VirtIOGPUBase *vb = VIRTIO_GPU_BASE(g);
7241dcc6adbSGurchetan Singh     VirtIOGPURutabaga *vr = VIRTIO_GPU_RUTABAGA(g);
7251dcc6adbSGurchetan Singh 
7261dcc6adbSGurchetan Singh     VIRTIO_GPU_FILL_CMD(ublob);
7271dcc6adbSGurchetan Singh 
7281dcc6adbSGurchetan Singh     CHECK(ublob.resource_id != 0, cmd);
7291dcc6adbSGurchetan Singh 
7301dcc6adbSGurchetan Singh     res = virtio_gpu_find_resource(g, ublob.resource_id);
7311dcc6adbSGurchetan Singh     CHECK(res, cmd);
7321dcc6adbSGurchetan Singh 
7331dcc6adbSGurchetan Singh     for (slot = 0; slot < MAX_SLOTS; slot++) {
7341dcc6adbSGurchetan Singh         if (vr->memory_regions[slot].resource_id != ublob.resource_id) {
7351dcc6adbSGurchetan Singh             continue;
7361dcc6adbSGurchetan Singh         }
7371dcc6adbSGurchetan Singh 
7381dcc6adbSGurchetan Singh         MemoryRegion *mr = &(vr->memory_regions[slot].mr);
7391dcc6adbSGurchetan Singh         memory_region_del_subregion(&vb->hostmem, mr);
7401dcc6adbSGurchetan Singh 
7411dcc6adbSGurchetan Singh         vr->memory_regions[slot].resource_id = 0;
7421dcc6adbSGurchetan Singh         vr->memory_regions[slot].used = 0;
7431dcc6adbSGurchetan Singh         break;
7441dcc6adbSGurchetan Singh     }
7451dcc6adbSGurchetan Singh 
7461dcc6adbSGurchetan Singh     CHECK(slot < MAX_SLOTS, cmd);
7471dcc6adbSGurchetan Singh     result = rutabaga_resource_unmap(vr->rutabaga, res->resource_id);
7481dcc6adbSGurchetan Singh     CHECK(!result, cmd);
7491dcc6adbSGurchetan Singh }
7501dcc6adbSGurchetan Singh 
7511dcc6adbSGurchetan Singh static void
virtio_gpu_rutabaga_process_cmd(VirtIOGPU * g,struct virtio_gpu_ctrl_command * cmd)7521dcc6adbSGurchetan Singh virtio_gpu_rutabaga_process_cmd(VirtIOGPU *g,
7531dcc6adbSGurchetan Singh                                 struct virtio_gpu_ctrl_command *cmd)
7541dcc6adbSGurchetan Singh {
7551dcc6adbSGurchetan Singh     struct rutabaga_fence fence = { 0 };
7561dcc6adbSGurchetan Singh     int32_t result;
7571dcc6adbSGurchetan Singh 
7581dcc6adbSGurchetan Singh     VirtIOGPURutabaga *vr = VIRTIO_GPU_RUTABAGA(g);
7591dcc6adbSGurchetan Singh 
7601dcc6adbSGurchetan Singh     VIRTIO_GPU_FILL_CMD(cmd->cmd_hdr);
7611dcc6adbSGurchetan Singh 
7621dcc6adbSGurchetan Singh     switch (cmd->cmd_hdr.type) {
7631dcc6adbSGurchetan Singh     case VIRTIO_GPU_CMD_CTX_CREATE:
7641dcc6adbSGurchetan Singh         rutabaga_cmd_context_create(g, cmd);
7651dcc6adbSGurchetan Singh         break;
7661dcc6adbSGurchetan Singh     case VIRTIO_GPU_CMD_CTX_DESTROY:
7671dcc6adbSGurchetan Singh         rutabaga_cmd_context_destroy(g, cmd);
7681dcc6adbSGurchetan Singh         break;
7691dcc6adbSGurchetan Singh     case VIRTIO_GPU_CMD_RESOURCE_CREATE_2D:
7701dcc6adbSGurchetan Singh         rutabaga_cmd_create_resource_2d(g, cmd);
7711dcc6adbSGurchetan Singh         break;
7721dcc6adbSGurchetan Singh     case VIRTIO_GPU_CMD_RESOURCE_CREATE_3D:
7731dcc6adbSGurchetan Singh         rutabaga_cmd_create_resource_3d(g, cmd);
7741dcc6adbSGurchetan Singh         break;
7751dcc6adbSGurchetan Singh     case VIRTIO_GPU_CMD_SUBMIT_3D:
7761dcc6adbSGurchetan Singh         rutabaga_cmd_submit_3d(g, cmd);
7771dcc6adbSGurchetan Singh         break;
7781dcc6adbSGurchetan Singh     case VIRTIO_GPU_CMD_TRANSFER_TO_HOST_2D:
7791dcc6adbSGurchetan Singh         rutabaga_cmd_transfer_to_host_2d(g, cmd);
7801dcc6adbSGurchetan Singh         break;
7811dcc6adbSGurchetan Singh     case VIRTIO_GPU_CMD_TRANSFER_TO_HOST_3D:
7821dcc6adbSGurchetan Singh         rutabaga_cmd_transfer_to_host_3d(g, cmd);
7831dcc6adbSGurchetan Singh         break;
7841dcc6adbSGurchetan Singh     case VIRTIO_GPU_CMD_TRANSFER_FROM_HOST_3D:
7851dcc6adbSGurchetan Singh         rutabaga_cmd_transfer_from_host_3d(g, cmd);
7861dcc6adbSGurchetan Singh         break;
7871dcc6adbSGurchetan Singh     case VIRTIO_GPU_CMD_RESOURCE_ATTACH_BACKING:
7881dcc6adbSGurchetan Singh         rutabaga_cmd_attach_backing(g, cmd);
7891dcc6adbSGurchetan Singh         break;
7901dcc6adbSGurchetan Singh     case VIRTIO_GPU_CMD_RESOURCE_DETACH_BACKING:
7911dcc6adbSGurchetan Singh         rutabaga_cmd_detach_backing(g, cmd);
7921dcc6adbSGurchetan Singh         break;
7931dcc6adbSGurchetan Singh     case VIRTIO_GPU_CMD_SET_SCANOUT:
7941dcc6adbSGurchetan Singh         rutabaga_cmd_set_scanout(g, cmd);
7951dcc6adbSGurchetan Singh         break;
7961dcc6adbSGurchetan Singh     case VIRTIO_GPU_CMD_RESOURCE_FLUSH:
7971dcc6adbSGurchetan Singh         rutabaga_cmd_resource_flush(g, cmd);
7981dcc6adbSGurchetan Singh         break;
7991dcc6adbSGurchetan Singh     case VIRTIO_GPU_CMD_RESOURCE_UNREF:
8001dcc6adbSGurchetan Singh         rutabaga_cmd_resource_unref(g, cmd);
8011dcc6adbSGurchetan Singh         break;
8021dcc6adbSGurchetan Singh     case VIRTIO_GPU_CMD_CTX_ATTACH_RESOURCE:
8031dcc6adbSGurchetan Singh         rutabaga_cmd_ctx_attach_resource(g, cmd);
8041dcc6adbSGurchetan Singh         break;
8051dcc6adbSGurchetan Singh     case VIRTIO_GPU_CMD_CTX_DETACH_RESOURCE:
8061dcc6adbSGurchetan Singh         rutabaga_cmd_ctx_detach_resource(g, cmd);
8071dcc6adbSGurchetan Singh         break;
8081dcc6adbSGurchetan Singh     case VIRTIO_GPU_CMD_GET_CAPSET_INFO:
8091dcc6adbSGurchetan Singh         rutabaga_cmd_get_capset_info(g, cmd);
8101dcc6adbSGurchetan Singh         break;
8111dcc6adbSGurchetan Singh     case VIRTIO_GPU_CMD_GET_CAPSET:
8121dcc6adbSGurchetan Singh         rutabaga_cmd_get_capset(g, cmd);
8131dcc6adbSGurchetan Singh         break;
8141dcc6adbSGurchetan Singh     case VIRTIO_GPU_CMD_GET_DISPLAY_INFO:
8151dcc6adbSGurchetan Singh         virtio_gpu_get_display_info(g, cmd);
8161dcc6adbSGurchetan Singh         break;
8171dcc6adbSGurchetan Singh     case VIRTIO_GPU_CMD_GET_EDID:
8181dcc6adbSGurchetan Singh         virtio_gpu_get_edid(g, cmd);
8191dcc6adbSGurchetan Singh         break;
8201dcc6adbSGurchetan Singh     case VIRTIO_GPU_CMD_RESOURCE_CREATE_BLOB:
8211dcc6adbSGurchetan Singh         rutabaga_cmd_resource_create_blob(g, cmd);
8221dcc6adbSGurchetan Singh         break;
8231dcc6adbSGurchetan Singh     case VIRTIO_GPU_CMD_RESOURCE_MAP_BLOB:
8241dcc6adbSGurchetan Singh         rutabaga_cmd_resource_map_blob(g, cmd);
8251dcc6adbSGurchetan Singh         break;
8261dcc6adbSGurchetan Singh     case VIRTIO_GPU_CMD_RESOURCE_UNMAP_BLOB:
8271dcc6adbSGurchetan Singh         rutabaga_cmd_resource_unmap_blob(g, cmd);
8281dcc6adbSGurchetan Singh         break;
8291dcc6adbSGurchetan Singh     default:
8301dcc6adbSGurchetan Singh         cmd->error = VIRTIO_GPU_RESP_ERR_UNSPEC;
8311dcc6adbSGurchetan Singh         break;
8321dcc6adbSGurchetan Singh     }
8331dcc6adbSGurchetan Singh 
8341dcc6adbSGurchetan Singh     if (cmd->finished) {
8351dcc6adbSGurchetan Singh         return;
8361dcc6adbSGurchetan Singh     }
8371dcc6adbSGurchetan Singh     if (cmd->error) {
8381dcc6adbSGurchetan Singh         error_report("%s: ctrl 0x%x, error 0x%x", __func__,
8391dcc6adbSGurchetan Singh                      cmd->cmd_hdr.type, cmd->error);
8401dcc6adbSGurchetan Singh         virtio_gpu_ctrl_response_nodata(g, cmd, cmd->error);
8411dcc6adbSGurchetan Singh         return;
8421dcc6adbSGurchetan Singh     }
8431dcc6adbSGurchetan Singh     if (!(cmd->cmd_hdr.flags & VIRTIO_GPU_FLAG_FENCE)) {
8441dcc6adbSGurchetan Singh         virtio_gpu_ctrl_response_nodata(g, cmd, VIRTIO_GPU_RESP_OK_NODATA);
8451dcc6adbSGurchetan Singh         return;
8461dcc6adbSGurchetan Singh     }
8471dcc6adbSGurchetan Singh 
8481dcc6adbSGurchetan Singh     fence.flags = cmd->cmd_hdr.flags;
8491dcc6adbSGurchetan Singh     fence.ctx_id = cmd->cmd_hdr.ctx_id;
8501dcc6adbSGurchetan Singh     fence.fence_id = cmd->cmd_hdr.fence_id;
8511dcc6adbSGurchetan Singh     fence.ring_idx = cmd->cmd_hdr.ring_idx;
8521dcc6adbSGurchetan Singh 
8531dcc6adbSGurchetan Singh     trace_virtio_gpu_fence_ctrl(cmd->cmd_hdr.fence_id, cmd->cmd_hdr.type);
8541dcc6adbSGurchetan Singh 
8551dcc6adbSGurchetan Singh     result = rutabaga_create_fence(vr->rutabaga, &fence);
8561dcc6adbSGurchetan Singh     CHECK(!result, cmd);
8571dcc6adbSGurchetan Singh }
8581dcc6adbSGurchetan Singh 
8591dcc6adbSGurchetan Singh static void
virtio_gpu_rutabaga_aio_cb(void * opaque)8601dcc6adbSGurchetan Singh virtio_gpu_rutabaga_aio_cb(void *opaque)
8611dcc6adbSGurchetan Singh {
8621dcc6adbSGurchetan Singh     struct rutabaga_aio_data *data = opaque;
8631dcc6adbSGurchetan Singh     VirtIOGPU *g = VIRTIO_GPU(data->vr);
8641dcc6adbSGurchetan Singh     struct rutabaga_fence fence_data = data->fence;
8651dcc6adbSGurchetan Singh     struct virtio_gpu_ctrl_command *cmd, *tmp;
8661dcc6adbSGurchetan Singh 
8671dcc6adbSGurchetan Singh     uint32_t signaled_ctx_specific = fence_data.flags &
8681dcc6adbSGurchetan Singh                                      RUTABAGA_FLAG_INFO_RING_IDX;
8691dcc6adbSGurchetan Singh 
8701dcc6adbSGurchetan Singh     QTAILQ_FOREACH_SAFE(cmd, &g->fenceq, next, tmp) {
8711dcc6adbSGurchetan Singh         /*
8721dcc6adbSGurchetan Singh          * Due to context specific timelines.
8731dcc6adbSGurchetan Singh          */
8741dcc6adbSGurchetan Singh         uint32_t target_ctx_specific = cmd->cmd_hdr.flags &
8751dcc6adbSGurchetan Singh                                        RUTABAGA_FLAG_INFO_RING_IDX;
8761dcc6adbSGurchetan Singh 
8771dcc6adbSGurchetan Singh         if (signaled_ctx_specific != target_ctx_specific) {
8781dcc6adbSGurchetan Singh             continue;
8791dcc6adbSGurchetan Singh         }
8801dcc6adbSGurchetan Singh 
8811dcc6adbSGurchetan Singh         if (signaled_ctx_specific &&
8821dcc6adbSGurchetan Singh            (cmd->cmd_hdr.ring_idx != fence_data.ring_idx)) {
8831dcc6adbSGurchetan Singh             continue;
8841dcc6adbSGurchetan Singh         }
8851dcc6adbSGurchetan Singh 
8861dcc6adbSGurchetan Singh         if (cmd->cmd_hdr.fence_id > fence_data.fence_id) {
8871dcc6adbSGurchetan Singh             continue;
8881dcc6adbSGurchetan Singh         }
8891dcc6adbSGurchetan Singh 
8901dcc6adbSGurchetan Singh         trace_virtio_gpu_fence_resp(cmd->cmd_hdr.fence_id);
8911dcc6adbSGurchetan Singh         virtio_gpu_ctrl_response_nodata(g, cmd, VIRTIO_GPU_RESP_OK_NODATA);
8921dcc6adbSGurchetan Singh         QTAILQ_REMOVE(&g->fenceq, cmd, next);
8931dcc6adbSGurchetan Singh         g_free(cmd);
8941dcc6adbSGurchetan Singh     }
8951dcc6adbSGurchetan Singh 
8961dcc6adbSGurchetan Singh     g_free(data);
8971dcc6adbSGurchetan Singh }
8981dcc6adbSGurchetan Singh 
8991dcc6adbSGurchetan Singh static void
virtio_gpu_rutabaga_fence_cb(uint64_t user_data,const struct rutabaga_fence * fence)9001dcc6adbSGurchetan Singh virtio_gpu_rutabaga_fence_cb(uint64_t user_data,
9011dcc6adbSGurchetan Singh                              const struct rutabaga_fence *fence)
9021dcc6adbSGurchetan Singh {
9031dcc6adbSGurchetan Singh     struct rutabaga_aio_data *data;
9041dcc6adbSGurchetan Singh     VirtIOGPU *g = (VirtIOGPU *)user_data;
9051dcc6adbSGurchetan Singh     VirtIOGPURutabaga *vr = VIRTIO_GPU_RUTABAGA(g);
9061dcc6adbSGurchetan Singh 
9071dcc6adbSGurchetan Singh     /*
9081dcc6adbSGurchetan Singh      * gfxstream and both cross-domain (and even newer versions virglrenderer:
9091dcc6adbSGurchetan Singh      * see VIRGL_RENDERER_ASYNC_FENCE_CB) like to signal fence completion on
9101dcc6adbSGurchetan Singh      * threads ("callback threads") that are different from the thread that
9111dcc6adbSGurchetan Singh      * processes the command queue ("main thread").
9121dcc6adbSGurchetan Singh      *
9131dcc6adbSGurchetan Singh      * crosvm and other virtio-gpu 1.1 implementations enable callback threads
9141dcc6adbSGurchetan Singh      * via locking.  However, on QEMU a deadlock is observed if
9151dcc6adbSGurchetan Singh      * virtio_gpu_ctrl_response_nodata(..) [used in the fence callback] is used
9161dcc6adbSGurchetan Singh      * from a thread that is not the main thread.
9171dcc6adbSGurchetan Singh      *
9181dcc6adbSGurchetan Singh      * The reason is QEMU's internal locking is designed to work with QEMU
9191dcc6adbSGurchetan Singh      * threads (see rcu_register_thread()) and not generic C/C++/Rust threads.
9201dcc6adbSGurchetan Singh      * For now, we can workaround this by scheduling the return of the
9211dcc6adbSGurchetan Singh      * fence descriptors on the main thread.
9221dcc6adbSGurchetan Singh      */
9231dcc6adbSGurchetan Singh 
9241dcc6adbSGurchetan Singh     data = g_new0(struct rutabaga_aio_data, 1);
9251dcc6adbSGurchetan Singh     data->vr = vr;
9261dcc6adbSGurchetan Singh     data->fence = *fence;
9271dcc6adbSGurchetan Singh     aio_bh_schedule_oneshot(qemu_get_aio_context(),
9281dcc6adbSGurchetan Singh                             virtio_gpu_rutabaga_aio_cb,
9291dcc6adbSGurchetan Singh                             data);
9301dcc6adbSGurchetan Singh }
9311dcc6adbSGurchetan Singh 
9321dcc6adbSGurchetan Singh static void
virtio_gpu_rutabaga_debug_cb(uint64_t user_data,const struct rutabaga_debug * debug)9331dcc6adbSGurchetan Singh virtio_gpu_rutabaga_debug_cb(uint64_t user_data,
9341dcc6adbSGurchetan Singh                              const struct rutabaga_debug *debug)
9351dcc6adbSGurchetan Singh {
9361dcc6adbSGurchetan Singh     switch (debug->debug_type) {
9371dcc6adbSGurchetan Singh     case RUTABAGA_DEBUG_ERROR:
9381dcc6adbSGurchetan Singh         error_report("%s", debug->message);
9391dcc6adbSGurchetan Singh         break;
9401dcc6adbSGurchetan Singh     case RUTABAGA_DEBUG_WARN:
9411dcc6adbSGurchetan Singh         warn_report("%s", debug->message);
9421dcc6adbSGurchetan Singh         break;
9431dcc6adbSGurchetan Singh     case RUTABAGA_DEBUG_INFO:
9441dcc6adbSGurchetan Singh         info_report("%s", debug->message);
9451dcc6adbSGurchetan Singh         break;
9461dcc6adbSGurchetan Singh     default:
9471dcc6adbSGurchetan Singh         error_report("unknown debug type: %u", debug->debug_type);
9481dcc6adbSGurchetan Singh     }
9491dcc6adbSGurchetan Singh }
9501dcc6adbSGurchetan Singh 
virtio_gpu_rutabaga_init(VirtIOGPU * g,Error ** errp)9511dcc6adbSGurchetan Singh static bool virtio_gpu_rutabaga_init(VirtIOGPU *g, Error **errp)
9521dcc6adbSGurchetan Singh {
9531dcc6adbSGurchetan Singh     int result;
9541dcc6adbSGurchetan Singh     struct rutabaga_builder builder = { 0 };
9551dcc6adbSGurchetan Singh     struct rutabaga_channel channel = { 0 };
9561dcc6adbSGurchetan Singh     struct rutabaga_channels channels = { 0 };
9571dcc6adbSGurchetan Singh 
9581dcc6adbSGurchetan Singh     VirtIOGPURutabaga *vr = VIRTIO_GPU_RUTABAGA(g);
9591dcc6adbSGurchetan Singh     vr->rutabaga = NULL;
9601dcc6adbSGurchetan Singh 
9611dcc6adbSGurchetan Singh     builder.wsi = RUTABAGA_WSI_SURFACELESS;
9621dcc6adbSGurchetan Singh     /*
9631dcc6adbSGurchetan Singh      * Currently, if WSI is specified, the only valid strings are "surfaceless"
9641dcc6adbSGurchetan Singh      * or "headless".  Surfaceless doesn't create a native window surface, but
9651dcc6adbSGurchetan Singh      * does copy from the render target to the Pixman buffer if a virtio-gpu
9661dcc6adbSGurchetan Singh      * 2D hypercall is issued.  Surfacless is the default.
9671dcc6adbSGurchetan Singh      *
9681dcc6adbSGurchetan Singh      * Headless is like surfaceless, but doesn't copy to the Pixman buffer. The
9691dcc6adbSGurchetan Singh      * use case is automated testing environments where there is no need to view
9701dcc6adbSGurchetan Singh      * results.
9711dcc6adbSGurchetan Singh      *
9721dcc6adbSGurchetan Singh      * In the future, more performant virtio-gpu 2D UI integration may be added.
9731dcc6adbSGurchetan Singh      */
9741dcc6adbSGurchetan Singh     if (vr->wsi) {
9751dcc6adbSGurchetan Singh         if (g_str_equal(vr->wsi, "surfaceless")) {
9761dcc6adbSGurchetan Singh             vr->headless = false;
9771dcc6adbSGurchetan Singh         } else if (g_str_equal(vr->wsi, "headless")) {
9781dcc6adbSGurchetan Singh             vr->headless = true;
9791dcc6adbSGurchetan Singh         } else {
9801dcc6adbSGurchetan Singh             error_setg(errp, "invalid wsi option selected");
9811dcc6adbSGurchetan Singh             return false;
9821dcc6adbSGurchetan Singh         }
9831dcc6adbSGurchetan Singh     }
9841dcc6adbSGurchetan Singh 
9851dcc6adbSGurchetan Singh     builder.fence_cb = virtio_gpu_rutabaga_fence_cb;
9861dcc6adbSGurchetan Singh     builder.debug_cb = virtio_gpu_rutabaga_debug_cb;
9871dcc6adbSGurchetan Singh     builder.capset_mask = vr->capset_mask;
9881dcc6adbSGurchetan Singh     builder.user_data = (uint64_t)g;
9891dcc6adbSGurchetan Singh 
9901dcc6adbSGurchetan Singh     /*
9911dcc6adbSGurchetan Singh      * If the user doesn't specify the wayland socket path, we try to infer
9921dcc6adbSGurchetan Singh      * the socket via a process similar to the one used by libwayland.
9931dcc6adbSGurchetan Singh      * libwayland does the following:
9941dcc6adbSGurchetan Singh      *
9951dcc6adbSGurchetan Singh      * 1) If $WAYLAND_DISPLAY is set, attempt to connect to
9961dcc6adbSGurchetan Singh      *    $XDG_RUNTIME_DIR/$WAYLAND_DISPLAY
9971dcc6adbSGurchetan Singh      * 2) Otherwise, attempt to connect to $XDG_RUNTIME_DIR/wayland-0
9981dcc6adbSGurchetan Singh      * 3) Otherwise, don't pass a wayland socket to rutabaga. If a guest
9991dcc6adbSGurchetan Singh      *    wayland proxy is launched, it will fail to work.
10001dcc6adbSGurchetan Singh      */
10011dcc6adbSGurchetan Singh     channel.channel_type = RUTABAGA_CHANNEL_TYPE_WAYLAND;
10021dcc6adbSGurchetan Singh     g_autofree gchar *path = NULL;
10031dcc6adbSGurchetan Singh     if (!vr->wayland_socket_path) {
10041dcc6adbSGurchetan Singh         const gchar *runtime_dir = g_get_user_runtime_dir();
10051dcc6adbSGurchetan Singh         const gchar *display = g_getenv("WAYLAND_DISPLAY");
10061dcc6adbSGurchetan Singh         if (!display) {
10071dcc6adbSGurchetan Singh             display = "wayland-0";
10081dcc6adbSGurchetan Singh         }
10091dcc6adbSGurchetan Singh 
10101dcc6adbSGurchetan Singh         if (runtime_dir) {
10111dcc6adbSGurchetan Singh             path = g_build_filename(runtime_dir, display, NULL);
10121dcc6adbSGurchetan Singh             channel.channel_name = path;
10131dcc6adbSGurchetan Singh         }
10141dcc6adbSGurchetan Singh     } else {
10151dcc6adbSGurchetan Singh         channel.channel_name = vr->wayland_socket_path;
10161dcc6adbSGurchetan Singh     }
10171dcc6adbSGurchetan Singh 
10181dcc6adbSGurchetan Singh     if ((builder.capset_mask & (1 << RUTABAGA_CAPSET_CROSS_DOMAIN))) {
10191dcc6adbSGurchetan Singh         if (channel.channel_name) {
10201dcc6adbSGurchetan Singh             channels.channels = &channel;
10211dcc6adbSGurchetan Singh             channels.num_channels = 1;
10221dcc6adbSGurchetan Singh             builder.channels = &channels;
10231dcc6adbSGurchetan Singh         }
10241dcc6adbSGurchetan Singh     }
10251dcc6adbSGurchetan Singh 
10261dcc6adbSGurchetan Singh     result = rutabaga_init(&builder, &vr->rutabaga);
10271dcc6adbSGurchetan Singh     if (result) {
10281dcc6adbSGurchetan Singh         error_setg_errno(errp, -result, "Failed to init rutabaga");
10291dcc6adbSGurchetan Singh         return false;
10301dcc6adbSGurchetan Singh     }
10311dcc6adbSGurchetan Singh 
10321dcc6adbSGurchetan Singh     return true;
10331dcc6adbSGurchetan Singh }
10341dcc6adbSGurchetan Singh 
virtio_gpu_rutabaga_get_num_capsets(VirtIOGPU * g)10351dcc6adbSGurchetan Singh static int virtio_gpu_rutabaga_get_num_capsets(VirtIOGPU *g)
10361dcc6adbSGurchetan Singh {
10371dcc6adbSGurchetan Singh     int result;
10381dcc6adbSGurchetan Singh     uint32_t num_capsets;
10391dcc6adbSGurchetan Singh     VirtIOGPURutabaga *vr = VIRTIO_GPU_RUTABAGA(g);
10401dcc6adbSGurchetan Singh 
10411dcc6adbSGurchetan Singh     result = rutabaga_get_num_capsets(vr->rutabaga, &num_capsets);
10421dcc6adbSGurchetan Singh     if (result) {
10431dcc6adbSGurchetan Singh         error_report("Failed to get capsets");
10441dcc6adbSGurchetan Singh         return 0;
10451dcc6adbSGurchetan Singh     }
10461dcc6adbSGurchetan Singh     vr->num_capsets = num_capsets;
10471dcc6adbSGurchetan Singh     return num_capsets;
10481dcc6adbSGurchetan Singh }
10491dcc6adbSGurchetan Singh 
virtio_gpu_rutabaga_handle_ctrl(VirtIODevice * vdev,VirtQueue * vq)10501dcc6adbSGurchetan Singh static void virtio_gpu_rutabaga_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq)
10511dcc6adbSGurchetan Singh {
10521dcc6adbSGurchetan Singh     VirtIOGPU *g = VIRTIO_GPU(vdev);
10531dcc6adbSGurchetan Singh     struct virtio_gpu_ctrl_command *cmd;
10541dcc6adbSGurchetan Singh 
10551dcc6adbSGurchetan Singh     if (!virtio_queue_ready(vq)) {
10561dcc6adbSGurchetan Singh         return;
10571dcc6adbSGurchetan Singh     }
10581dcc6adbSGurchetan Singh 
10591dcc6adbSGurchetan Singh     cmd = virtqueue_pop(vq, sizeof(struct virtio_gpu_ctrl_command));
10601dcc6adbSGurchetan Singh     while (cmd) {
10611dcc6adbSGurchetan Singh         cmd->vq = vq;
10621dcc6adbSGurchetan Singh         cmd->error = 0;
10631dcc6adbSGurchetan Singh         cmd->finished = false;
10641dcc6adbSGurchetan Singh         QTAILQ_INSERT_TAIL(&g->cmdq, cmd, next);
10651dcc6adbSGurchetan Singh         cmd = virtqueue_pop(vq, sizeof(struct virtio_gpu_ctrl_command));
10661dcc6adbSGurchetan Singh     }
10671dcc6adbSGurchetan Singh 
10681dcc6adbSGurchetan Singh     virtio_gpu_process_cmdq(g);
10691dcc6adbSGurchetan Singh }
10701dcc6adbSGurchetan Singh 
virtio_gpu_rutabaga_realize(DeviceState * qdev,Error ** errp)10711dcc6adbSGurchetan Singh static void virtio_gpu_rutabaga_realize(DeviceState *qdev, Error **errp)
10721dcc6adbSGurchetan Singh {
10731dcc6adbSGurchetan Singh     int num_capsets;
10741dcc6adbSGurchetan Singh     VirtIOGPUBase *bdev = VIRTIO_GPU_BASE(qdev);
10751dcc6adbSGurchetan Singh     VirtIOGPU *gpudev = VIRTIO_GPU(qdev);
10761dcc6adbSGurchetan Singh 
10771dcc6adbSGurchetan Singh #if HOST_BIG_ENDIAN
10781dcc6adbSGurchetan Singh     error_setg(errp, "rutabaga is not supported on bigendian platforms");
10791dcc6adbSGurchetan Singh     return;
10801dcc6adbSGurchetan Singh #endif
10811dcc6adbSGurchetan Singh 
10821dcc6adbSGurchetan Singh     if (!virtio_gpu_rutabaga_init(gpudev, errp)) {
10831dcc6adbSGurchetan Singh         return;
10841dcc6adbSGurchetan Singh     }
10851dcc6adbSGurchetan Singh 
10861dcc6adbSGurchetan Singh     num_capsets = virtio_gpu_rutabaga_get_num_capsets(gpudev);
10871dcc6adbSGurchetan Singh     if (!num_capsets) {
10881dcc6adbSGurchetan Singh         return;
10891dcc6adbSGurchetan Singh     }
10901dcc6adbSGurchetan Singh 
10911dcc6adbSGurchetan Singh     bdev->conf.flags |= (1 << VIRTIO_GPU_FLAG_RUTABAGA_ENABLED);
10921dcc6adbSGurchetan Singh     bdev->conf.flags |= (1 << VIRTIO_GPU_FLAG_BLOB_ENABLED);
10931dcc6adbSGurchetan Singh     bdev->conf.flags |= (1 << VIRTIO_GPU_FLAG_CONTEXT_INIT_ENABLED);
10941dcc6adbSGurchetan Singh 
10951dcc6adbSGurchetan Singh     bdev->virtio_config.num_capsets = num_capsets;
10961dcc6adbSGurchetan Singh     virtio_gpu_device_realize(qdev, errp);
10971dcc6adbSGurchetan Singh }
10981dcc6adbSGurchetan Singh 
10991dcc6adbSGurchetan Singh static Property virtio_gpu_rutabaga_properties[] = {
11001dcc6adbSGurchetan Singh     DEFINE_PROP_BIT64("gfxstream-vulkan", VirtIOGPURutabaga, capset_mask,
11011dcc6adbSGurchetan Singh                       RUTABAGA_CAPSET_GFXSTREAM_VULKAN, false),
11021dcc6adbSGurchetan Singh     DEFINE_PROP_BIT64("cross-domain", VirtIOGPURutabaga, capset_mask,
11031dcc6adbSGurchetan Singh                       RUTABAGA_CAPSET_CROSS_DOMAIN, false),
11041dcc6adbSGurchetan Singh     DEFINE_PROP_BIT64("x-gfxstream-gles", VirtIOGPURutabaga, capset_mask,
11051dcc6adbSGurchetan Singh                       RUTABAGA_CAPSET_GFXSTREAM_GLES, false),
11061dcc6adbSGurchetan Singh     DEFINE_PROP_BIT64("x-gfxstream-composer", VirtIOGPURutabaga, capset_mask,
11071dcc6adbSGurchetan Singh                       RUTABAGA_CAPSET_GFXSTREAM_COMPOSER, false),
11081dcc6adbSGurchetan Singh     DEFINE_PROP_STRING("wayland-socket-path", VirtIOGPURutabaga,
11091dcc6adbSGurchetan Singh                        wayland_socket_path),
11101dcc6adbSGurchetan Singh     DEFINE_PROP_STRING("wsi", VirtIOGPURutabaga, wsi),
11111dcc6adbSGurchetan Singh     DEFINE_PROP_END_OF_LIST(),
11121dcc6adbSGurchetan Singh };
11131dcc6adbSGurchetan Singh 
virtio_gpu_rutabaga_class_init(ObjectClass * klass,void * data)11141dcc6adbSGurchetan Singh static void virtio_gpu_rutabaga_class_init(ObjectClass *klass, void *data)
11151dcc6adbSGurchetan Singh {
11161dcc6adbSGurchetan Singh     DeviceClass *dc = DEVICE_CLASS(klass);
11171dcc6adbSGurchetan Singh     VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass);
11181dcc6adbSGurchetan Singh     VirtIOGPUBaseClass *vbc = VIRTIO_GPU_BASE_CLASS(klass);
11191dcc6adbSGurchetan Singh     VirtIOGPUClass *vgc = VIRTIO_GPU_CLASS(klass);
11201dcc6adbSGurchetan Singh 
11211dcc6adbSGurchetan Singh     vbc->gl_flushed = virtio_gpu_rutabaga_gl_flushed;
11221dcc6adbSGurchetan Singh     vgc->handle_ctrl = virtio_gpu_rutabaga_handle_ctrl;
11231dcc6adbSGurchetan Singh     vgc->process_cmd = virtio_gpu_rutabaga_process_cmd;
11241dcc6adbSGurchetan Singh     vgc->update_cursor_data = virtio_gpu_rutabaga_update_cursor;
1125*588a09daSManos Pitsidianakis     vgc->resource_destroy = virtio_gpu_rutabaga_resource_unref;
11261dcc6adbSGurchetan Singh     vdc->realize = virtio_gpu_rutabaga_realize;
11271dcc6adbSGurchetan Singh     device_class_set_props(dc, virtio_gpu_rutabaga_properties);
11281dcc6adbSGurchetan Singh }
11291dcc6adbSGurchetan Singh 
11301dcc6adbSGurchetan Singh static const TypeInfo virtio_gpu_rutabaga_info[] = {
11311dcc6adbSGurchetan Singh     {
11321dcc6adbSGurchetan Singh         .name = TYPE_VIRTIO_GPU_RUTABAGA,
11331dcc6adbSGurchetan Singh         .parent = TYPE_VIRTIO_GPU,
11341dcc6adbSGurchetan Singh         .instance_size = sizeof(VirtIOGPURutabaga),
11351dcc6adbSGurchetan Singh         .class_init = virtio_gpu_rutabaga_class_init,
11361dcc6adbSGurchetan Singh     },
11371dcc6adbSGurchetan Singh };
11381dcc6adbSGurchetan Singh 
11391dcc6adbSGurchetan Singh DEFINE_TYPES(virtio_gpu_rutabaga_info)
11401dcc6adbSGurchetan Singh 
11411dcc6adbSGurchetan Singh module_obj(TYPE_VIRTIO_GPU_RUTABAGA);
11421dcc6adbSGurchetan Singh module_kconfig(VIRTIO_GPU);
11431dcc6adbSGurchetan Singh module_dep("hw-display-virtio-gpu");
1144