qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v13 0/9] rutabaga_gfx + gfxstream
@ 2023-08-29  0:36 Gurchetan Singh
  2023-08-29  0:36 ` [PATCH v13 1/9] virtio: Add shared memory capability Gurchetan Singh
                   ` (9 more replies)
  0 siblings, 10 replies; 27+ messages in thread
From: Gurchetan Singh @ 2023-08-29  0:36 UTC (permalink / raw)
  To: qemu-devel
  Cc: marcandre.lureau, akihiko.odaki, ray.huang, alex.bennee, shentey,
	hi, ernunes, manos.pitsidianakis, philmd, mark.cave-ayland

From: Gurchetan Singh <gurchetansingh@google.com>

Changes since v12:
- Added r-b tags from Antonio Caggiano and Akihiko Odaki
- Removed review version from commit messages
- I think we're good to merge since we've had multiple people test and review this series??

How to build both rutabaga and gfxstream guest/host libs:

https://crosvm.dev/book/appendix/rutabaga_gfx.html

Branch containing this patch series:

https://gitlab.com/gurchetansingh/qemu/-/commits/qemu-gfxstream-v13

Antonio Caggiano (2):
  virtio-gpu: CONTEXT_INIT feature
  virtio-gpu: blob prep

Dr. David Alan Gilbert (1):
  virtio: Add shared memory capability

Gerd Hoffmann (1):
  virtio-gpu: hostmem

Gurchetan Singh (5):
  gfxstream + rutabaga prep: added need defintions, fields, and options
  gfxstream + rutabaga: add initial support for gfxstream
  gfxstream + rutabaga: meson support
  gfxstream + rutabaga: enable rutabaga
  docs/system: add basic virtio-gpu documentation

 docs/system/device-emulation.rst     |    1 +
 docs/system/devices/virtio-gpu.rst   |  112 +++
 hw/display/meson.build               |   22 +
 hw/display/virtio-gpu-base.c         |    6 +-
 hw/display/virtio-gpu-pci-rutabaga.c |   47 ++
 hw/display/virtio-gpu-pci.c          |   14 +
 hw/display/virtio-gpu-rutabaga.c     | 1119 ++++++++++++++++++++++++++
 hw/display/virtio-gpu.c              |   16 +-
 hw/display/virtio-vga-rutabaga.c     |   50 ++
 hw/display/virtio-vga.c              |   33 +-
 hw/virtio/virtio-pci.c               |   18 +
 include/hw/virtio/virtio-gpu-bswap.h |   15 +
 include/hw/virtio/virtio-gpu.h       |   41 +
 include/hw/virtio/virtio-pci.h       |    4 +
 meson.build                          |    7 +
 meson_options.txt                    |    2 +
 scripts/meson-buildoptions.sh        |    3 +
 softmmu/qdev-monitor.c               |    3 +
 softmmu/vl.c                         |    1 +
 19 files changed, 1495 insertions(+), 19 deletions(-)
 create mode 100644 docs/system/devices/virtio-gpu.rst
 create mode 100644 hw/display/virtio-gpu-pci-rutabaga.c
 create mode 100644 hw/display/virtio-gpu-rutabaga.c
 create mode 100644 hw/display/virtio-vga-rutabaga.c

-- 
2.42.0.rc2.253.gd59a3bf2b4-goog



^ permalink raw reply	[flat|nested] 27+ messages in thread

* [PATCH v13 1/9] virtio: Add shared memory capability
  2023-08-29  0:36 [PATCH v13 0/9] rutabaga_gfx + gfxstream Gurchetan Singh
@ 2023-08-29  0:36 ` Gurchetan Singh
  2023-08-29  0:36 ` [PATCH v13 2/9] virtio-gpu: CONTEXT_INIT feature Gurchetan Singh
                   ` (8 subsequent siblings)
  9 siblings, 0 replies; 27+ messages in thread
From: Gurchetan Singh @ 2023-08-29  0:36 UTC (permalink / raw)
  To: qemu-devel
  Cc: marcandre.lureau, akihiko.odaki, ray.huang, alex.bennee, shentey,
	hi, ernunes, manos.pitsidianakis, philmd, mark.cave-ayland

From: "Dr. David Alan Gilbert" <dgilbert@redhat.com>

Define a new capability type 'VIRTIO_PCI_CAP_SHARED_MEMORY_CFG' to allow
defining shared memory regions with sizes and offsets of 2^32 and more.
Multiple instances of the capability are allowed and distinguished
by a device-specific 'id'.

Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
Signed-off-by: Antonio Caggiano <antonio.caggiano@collabora.com>
Signed-off-by: Gurchetan Singh <gurchetansingh@chromium.org>
Tested-by: Alyssa Ross <hi@alyssa.is>
Tested-by: Huang Rui <ray.huang@amd.com>
Tested-by: Akihiko Odaki <akihiko.odaki@daynix.com>
Acked-by: Huang Rui <ray.huang@amd.com>
Reviewed-by: Gurchetan Singh <gurchetansingh@chromium.org>
Reviewed-by: Akihiko Odaki <akihiko.odaki@daynix.com>
---
 hw/virtio/virtio-pci.c         | 18 ++++++++++++++++++
 include/hw/virtio/virtio-pci.h |  4 ++++
 2 files changed, 22 insertions(+)

diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c
index edbc0daa18..da8c9ea12d 100644
--- a/hw/virtio/virtio-pci.c
+++ b/hw/virtio/virtio-pci.c
@@ -1435,6 +1435,24 @@ static int virtio_pci_add_mem_cap(VirtIOPCIProxy *proxy,
     return offset;
 }
 
+int virtio_pci_add_shm_cap(VirtIOPCIProxy *proxy,
+                           uint8_t bar, uint64_t offset, uint64_t length,
+                           uint8_t id)
+{
+    struct virtio_pci_cap64 cap = {
+        .cap.cap_len = sizeof cap,
+        .cap.cfg_type = VIRTIO_PCI_CAP_SHARED_MEMORY_CFG,
+    };
+
+    cap.cap.bar = bar;
+    cap.cap.length = cpu_to_le32(length);
+    cap.length_hi = cpu_to_le32(length >> 32);
+    cap.cap.offset = cpu_to_le32(offset);
+    cap.offset_hi = cpu_to_le32(offset >> 32);
+    cap.cap.id = id;
+    return virtio_pci_add_mem_cap(proxy, &cap.cap);
+}
+
 static uint64_t virtio_pci_common_read(void *opaque, hwaddr addr,
                                        unsigned size)
 {
diff --git a/include/hw/virtio/virtio-pci.h b/include/hw/virtio/virtio-pci.h
index ab2051b64b..5a3f182f99 100644
--- a/include/hw/virtio/virtio-pci.h
+++ b/include/hw/virtio/virtio-pci.h
@@ -264,4 +264,8 @@ unsigned virtio_pci_optimal_num_queues(unsigned fixed_queues);
 void virtio_pci_set_guest_notifier_fd_handler(VirtIODevice *vdev, VirtQueue *vq,
                                               int n, bool assign,
                                               bool with_irqfd);
+
+int virtio_pci_add_shm_cap(VirtIOPCIProxy *proxy, uint8_t bar, uint64_t offset,
+                           uint64_t length, uint8_t id);
+
 #endif
-- 
2.42.0.rc2.253.gd59a3bf2b4-goog



^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PATCH v13 2/9] virtio-gpu: CONTEXT_INIT feature
  2023-08-29  0:36 [PATCH v13 0/9] rutabaga_gfx + gfxstream Gurchetan Singh
  2023-08-29  0:36 ` [PATCH v13 1/9] virtio: Add shared memory capability Gurchetan Singh
@ 2023-08-29  0:36 ` Gurchetan Singh
  2023-08-29  0:36 ` [PATCH v13 3/9] virtio-gpu: hostmem Gurchetan Singh
                   ` (7 subsequent siblings)
  9 siblings, 0 replies; 27+ messages in thread
From: Gurchetan Singh @ 2023-08-29  0:36 UTC (permalink / raw)
  To: qemu-devel
  Cc: marcandre.lureau, akihiko.odaki, ray.huang, alex.bennee, shentey,
	hi, ernunes, manos.pitsidianakis, philmd, mark.cave-ayland

From: Antonio Caggiano <antonio.caggiano@collabora.com>

The feature can be enabled when a backend wants it.

Signed-off-by: Antonio Caggiano <antonio.caggiano@collabora.com>
Signed-off-by: Gurchetan Singh <gurchetansingh@chromium.org>
Tested-by: Alyssa Ross <hi@alyssa.is>
Tested-by: Akihiko Odaki <akihiko.odaki@daynix.com>
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Reviewed-by: Akihiko Odaki <akihiko.odaki@daynix.com>
---
 hw/display/virtio-gpu-base.c   | 3 +++
 include/hw/virtio/virtio-gpu.h | 3 +++
 2 files changed, 6 insertions(+)

diff --git a/hw/display/virtio-gpu-base.c b/hw/display/virtio-gpu-base.c
index ca1fb7b16f..4f2b0ba1f3 100644
--- a/hw/display/virtio-gpu-base.c
+++ b/hw/display/virtio-gpu-base.c
@@ -232,6 +232,9 @@ virtio_gpu_base_get_features(VirtIODevice *vdev, uint64_t features,
     if (virtio_gpu_blob_enabled(g->conf)) {
         features |= (1 << VIRTIO_GPU_F_RESOURCE_BLOB);
     }
+    if (virtio_gpu_context_init_enabled(g->conf)) {
+        features |= (1 << VIRTIO_GPU_F_CONTEXT_INIT);
+    }
 
     return features;
 }
diff --git a/include/hw/virtio/virtio-gpu.h b/include/hw/virtio/virtio-gpu.h
index 390c4642b8..8377c365ef 100644
--- a/include/hw/virtio/virtio-gpu.h
+++ b/include/hw/virtio/virtio-gpu.h
@@ -93,6 +93,7 @@ enum virtio_gpu_base_conf_flags {
     VIRTIO_GPU_FLAG_EDID_ENABLED,
     VIRTIO_GPU_FLAG_DMABUF_ENABLED,
     VIRTIO_GPU_FLAG_BLOB_ENABLED,
+    VIRTIO_GPU_FLAG_CONTEXT_INIT_ENABLED,
 };
 
 #define virtio_gpu_virgl_enabled(_cfg) \
@@ -105,6 +106,8 @@ enum virtio_gpu_base_conf_flags {
     (_cfg.flags & (1 << VIRTIO_GPU_FLAG_DMABUF_ENABLED))
 #define virtio_gpu_blob_enabled(_cfg) \
     (_cfg.flags & (1 << VIRTIO_GPU_FLAG_BLOB_ENABLED))
+#define virtio_gpu_context_init_enabled(_cfg) \
+    (_cfg.flags & (1 << VIRTIO_GPU_FLAG_CONTEXT_INIT_ENABLED))
 
 struct virtio_gpu_base_conf {
     uint32_t max_outputs;
-- 
2.42.0.rc2.253.gd59a3bf2b4-goog



^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PATCH v13 3/9] virtio-gpu: hostmem
  2023-08-29  0:36 [PATCH v13 0/9] rutabaga_gfx + gfxstream Gurchetan Singh
  2023-08-29  0:36 ` [PATCH v13 1/9] virtio: Add shared memory capability Gurchetan Singh
  2023-08-29  0:36 ` [PATCH v13 2/9] virtio-gpu: CONTEXT_INIT feature Gurchetan Singh
@ 2023-08-29  0:36 ` Gurchetan Singh
  2023-08-29  0:36 ` [PATCH v13 4/9] virtio-gpu: blob prep Gurchetan Singh
                   ` (6 subsequent siblings)
  9 siblings, 0 replies; 27+ messages in thread
From: Gurchetan Singh @ 2023-08-29  0:36 UTC (permalink / raw)
  To: qemu-devel
  Cc: marcandre.lureau, akihiko.odaki, ray.huang, alex.bennee, shentey,
	hi, ernunes, manos.pitsidianakis, philmd, mark.cave-ayland

From: Gerd Hoffmann <kraxel@redhat.com>

Use VIRTIO_GPU_SHM_ID_HOST_VISIBLE as id for virtio-gpu.

Signed-off-by: Antonio Caggiano <antonio.caggiano@collabora.com>
Tested-by: Alyssa Ross <hi@alyssa.is>
Tested-by: Akihiko Odaki <akihiko.odaki@daynix.com>
Acked-by: Michael S. Tsirkin <mst@redhat.com>
Reviewed-by: Akihiko Odaki <akihiko.odaki@daynix.com>
---
 hw/display/virtio-gpu-pci.c    | 14 ++++++++++++++
 hw/display/virtio-gpu.c        |  1 +
 hw/display/virtio-vga.c        | 33 ++++++++++++++++++++++++---------
 include/hw/virtio/virtio-gpu.h |  5 +++++
 4 files changed, 44 insertions(+), 9 deletions(-)

diff --git a/hw/display/virtio-gpu-pci.c b/hw/display/virtio-gpu-pci.c
index 93f214ff58..da6a99f038 100644
--- a/hw/display/virtio-gpu-pci.c
+++ b/hw/display/virtio-gpu-pci.c
@@ -33,6 +33,20 @@ static void virtio_gpu_pci_base_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
     DeviceState *vdev = DEVICE(g);
     int i;
 
+    if (virtio_gpu_hostmem_enabled(g->conf)) {
+        vpci_dev->msix_bar_idx = 1;
+        vpci_dev->modern_mem_bar_idx = 2;
+        memory_region_init(&g->hostmem, OBJECT(g), "virtio-gpu-hostmem",
+                           g->conf.hostmem);
+        pci_register_bar(&vpci_dev->pci_dev, 4,
+                         PCI_BASE_ADDRESS_SPACE_MEMORY |
+                         PCI_BASE_ADDRESS_MEM_PREFETCH |
+                         PCI_BASE_ADDRESS_MEM_TYPE_64,
+                         &g->hostmem);
+        virtio_pci_add_shm_cap(vpci_dev, 4, 0, g->conf.hostmem,
+                               VIRTIO_GPU_SHM_ID_HOST_VISIBLE);
+    }
+
     virtio_pci_force_virtio_1(vpci_dev);
     if (!qdev_realize(vdev, BUS(&vpci_dev->bus), errp)) {
         return;
diff --git a/hw/display/virtio-gpu.c b/hw/display/virtio-gpu.c
index bbd5c6561a..48ef0d9fad 100644
--- a/hw/display/virtio-gpu.c
+++ b/hw/display/virtio-gpu.c
@@ -1509,6 +1509,7 @@ static Property virtio_gpu_properties[] = {
                      256 * MiB),
     DEFINE_PROP_BIT("blob", VirtIOGPU, parent_obj.conf.flags,
                     VIRTIO_GPU_FLAG_BLOB_ENABLED, false),
+    DEFINE_PROP_SIZE("hostmem", VirtIOGPU, parent_obj.conf.hostmem, 0),
     DEFINE_PROP_END_OF_LIST(),
 };
 
diff --git a/hw/display/virtio-vga.c b/hw/display/virtio-vga.c
index e6fb0aa876..c8552ff760 100644
--- a/hw/display/virtio-vga.c
+++ b/hw/display/virtio-vga.c
@@ -115,17 +115,32 @@ static void virtio_vga_base_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
     pci_register_bar(&vpci_dev->pci_dev, 0,
                      PCI_BASE_ADDRESS_MEM_PREFETCH, &vga->vram);
 
-    /*
-     * Configure virtio bar and regions
-     *
-     * We use bar #2 for the mmio regions, to be compatible with stdvga.
-     * virtio regions are moved to the end of bar #2, to make room for
-     * the stdvga mmio registers at the start of bar #2.
-     */
-    vpci_dev->modern_mem_bar_idx = 2;
-    vpci_dev->msix_bar_idx = 4;
     vpci_dev->modern_io_bar_idx = 5;
 
+    if (!virtio_gpu_hostmem_enabled(g->conf)) {
+        /*
+         * Configure virtio bar and regions
+         *
+         * We use bar #2 for the mmio regions, to be compatible with stdvga.
+         * virtio regions are moved to the end of bar #2, to make room for
+         * the stdvga mmio registers at the start of bar #2.
+         */
+        vpci_dev->modern_mem_bar_idx = 2;
+        vpci_dev->msix_bar_idx = 4;
+    } else {
+        vpci_dev->msix_bar_idx = 1;
+        vpci_dev->modern_mem_bar_idx = 2;
+        memory_region_init(&g->hostmem, OBJECT(g), "virtio-gpu-hostmem",
+                           g->conf.hostmem);
+        pci_register_bar(&vpci_dev->pci_dev, 4,
+                         PCI_BASE_ADDRESS_SPACE_MEMORY |
+                         PCI_BASE_ADDRESS_MEM_PREFETCH |
+                         PCI_BASE_ADDRESS_MEM_TYPE_64,
+                         &g->hostmem);
+        virtio_pci_add_shm_cap(vpci_dev, 4, 0, g->conf.hostmem,
+                               VIRTIO_GPU_SHM_ID_HOST_VISIBLE);
+    }
+
     if (!(vpci_dev->flags & VIRTIO_PCI_FLAG_PAGE_PER_VQ)) {
         /*
          * with page-per-vq=off there is no padding space we can use
diff --git a/include/hw/virtio/virtio-gpu.h b/include/hw/virtio/virtio-gpu.h
index 8377c365ef..de4f624e94 100644
--- a/include/hw/virtio/virtio-gpu.h
+++ b/include/hw/virtio/virtio-gpu.h
@@ -108,12 +108,15 @@ enum virtio_gpu_base_conf_flags {
     (_cfg.flags & (1 << VIRTIO_GPU_FLAG_BLOB_ENABLED))
 #define virtio_gpu_context_init_enabled(_cfg) \
     (_cfg.flags & (1 << VIRTIO_GPU_FLAG_CONTEXT_INIT_ENABLED))
+#define virtio_gpu_hostmem_enabled(_cfg) \
+    (_cfg.hostmem > 0)
 
 struct virtio_gpu_base_conf {
     uint32_t max_outputs;
     uint32_t flags;
     uint32_t xres;
     uint32_t yres;
+    uint64_t hostmem;
 };
 
 struct virtio_gpu_ctrl_command {
@@ -137,6 +140,8 @@ struct VirtIOGPUBase {
     int renderer_blocked;
     int enable;
 
+    MemoryRegion hostmem;
+
     struct virtio_gpu_scanout scanout[VIRTIO_GPU_MAX_SCANOUTS];
 
     int enabled_output_bitmask;
-- 
2.42.0.rc2.253.gd59a3bf2b4-goog



^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PATCH v13 4/9] virtio-gpu: blob prep
  2023-08-29  0:36 [PATCH v13 0/9] rutabaga_gfx + gfxstream Gurchetan Singh
                   ` (2 preceding siblings ...)
  2023-08-29  0:36 ` [PATCH v13 3/9] virtio-gpu: hostmem Gurchetan Singh
@ 2023-08-29  0:36 ` Gurchetan Singh
  2023-08-29  0:36 ` [PATCH v13 5/9] gfxstream + rutabaga prep: added need defintions, fields, and options Gurchetan Singh
                   ` (5 subsequent siblings)
  9 siblings, 0 replies; 27+ messages in thread
From: Gurchetan Singh @ 2023-08-29  0:36 UTC (permalink / raw)
  To: qemu-devel
  Cc: marcandre.lureau, akihiko.odaki, ray.huang, alex.bennee, shentey,
	hi, ernunes, manos.pitsidianakis, philmd, mark.cave-ayland

From: Antonio Caggiano <antonio.caggiano@collabora.com>

This adds preparatory functions needed to:

     - decode blob cmds
     - tracking iovecs

Signed-off-by: Antonio Caggiano <antonio.caggiano@collabora.com>
Signed-off-by: Dmitry Osipenko <dmitry.osipenko@collabora.com>
Signed-off-by: Gurchetan Singh <gurchetansingh@chromium.org>
Tested-by: Alyssa Ross <hi@alyssa.is>
Tested-by: Emmanouil Pitsidianakis <manos.pitsidianakis@linaro.org>
Tested-by: Akihiko Odaki <akihiko.odaki@daynix.com>
Reviewed-by: Emmanouil Pitsidianakis <manos.pitsidianakis@linaro.org>
Reviewed-by: Akihiko Odaki <akihiko.odaki@daynix.com>
---
 hw/display/virtio-gpu.c              | 10 +++-------
 include/hw/virtio/virtio-gpu-bswap.h | 15 +++++++++++++++
 include/hw/virtio/virtio-gpu.h       |  5 +++++
 3 files changed, 23 insertions(+), 7 deletions(-)

diff --git a/hw/display/virtio-gpu.c b/hw/display/virtio-gpu.c
index 48ef0d9fad..3e658f1fef 100644
--- a/hw/display/virtio-gpu.c
+++ b/hw/display/virtio-gpu.c
@@ -33,15 +33,11 @@
 
 #define VIRTIO_GPU_VM_VERSION 1
 
-static struct virtio_gpu_simple_resource*
-virtio_gpu_find_resource(VirtIOGPU *g, uint32_t resource_id);
 static struct virtio_gpu_simple_resource *
 virtio_gpu_find_check_resource(VirtIOGPU *g, uint32_t resource_id,
                                bool require_backing,
                                const char *caller, uint32_t *error);
 
-static void virtio_gpu_cleanup_mapping(VirtIOGPU *g,
-                                       struct virtio_gpu_simple_resource *res);
 static void virtio_gpu_reset_bh(void *opaque);
 
 void virtio_gpu_update_cursor_data(VirtIOGPU *g,
@@ -116,7 +112,7 @@ static void update_cursor(VirtIOGPU *g, struct virtio_gpu_update_cursor *cursor)
                   cursor->resource_id ? 1 : 0);
 }
 
-static struct virtio_gpu_simple_resource *
+struct virtio_gpu_simple_resource *
 virtio_gpu_find_resource(VirtIOGPU *g, uint32_t resource_id)
 {
     struct virtio_gpu_simple_resource *res;
@@ -904,8 +900,8 @@ void virtio_gpu_cleanup_mapping_iov(VirtIOGPU *g,
     g_free(iov);
 }
 
-static void virtio_gpu_cleanup_mapping(VirtIOGPU *g,
-                                       struct virtio_gpu_simple_resource *res)
+void virtio_gpu_cleanup_mapping(VirtIOGPU *g,
+                                struct virtio_gpu_simple_resource *res)
 {
     virtio_gpu_cleanup_mapping_iov(g, res->iov, res->iov_cnt);
     res->iov = NULL;
diff --git a/include/hw/virtio/virtio-gpu-bswap.h b/include/hw/virtio/virtio-gpu-bswap.h
index 637a0585d0..dd1975e2d4 100644
--- a/include/hw/virtio/virtio-gpu-bswap.h
+++ b/include/hw/virtio/virtio-gpu-bswap.h
@@ -70,6 +70,21 @@ virtio_gpu_create_blob_bswap(struct virtio_gpu_resource_create_blob *cblob)
     le64_to_cpus(&cblob->size);
 }
 
+static inline void
+virtio_gpu_map_blob_bswap(struct virtio_gpu_resource_map_blob *mblob)
+{
+    virtio_gpu_ctrl_hdr_bswap(&mblob->hdr);
+    le32_to_cpus(&mblob->resource_id);
+    le64_to_cpus(&mblob->offset);
+}
+
+static inline void
+virtio_gpu_unmap_blob_bswap(struct virtio_gpu_resource_unmap_blob *ublob)
+{
+    virtio_gpu_ctrl_hdr_bswap(&ublob->hdr);
+    le32_to_cpus(&ublob->resource_id);
+}
+
 static inline void
 virtio_gpu_scanout_blob_bswap(struct virtio_gpu_set_scanout_blob *ssb)
 {
diff --git a/include/hw/virtio/virtio-gpu.h b/include/hw/virtio/virtio-gpu.h
index de4f624e94..55973e112f 100644
--- a/include/hw/virtio/virtio-gpu.h
+++ b/include/hw/virtio/virtio-gpu.h
@@ -257,6 +257,9 @@ void virtio_gpu_base_fill_display_info(VirtIOGPUBase *g,
 void virtio_gpu_base_generate_edid(VirtIOGPUBase *g, int scanout,
                                    struct virtio_gpu_resp_edid *edid);
 /* virtio-gpu.c */
+struct virtio_gpu_simple_resource *
+virtio_gpu_find_resource(VirtIOGPU *g, uint32_t resource_id);
+
 void virtio_gpu_ctrl_response(VirtIOGPU *g,
                               struct virtio_gpu_ctrl_command *cmd,
                               struct virtio_gpu_ctrl_hdr *resp,
@@ -275,6 +278,8 @@ int virtio_gpu_create_mapping_iov(VirtIOGPU *g,
                                   uint32_t *niov);
 void virtio_gpu_cleanup_mapping_iov(VirtIOGPU *g,
                                     struct iovec *iov, uint32_t count);
+void virtio_gpu_cleanup_mapping(VirtIOGPU *g,
+                                struct virtio_gpu_simple_resource *res);
 void virtio_gpu_process_cmdq(VirtIOGPU *g);
 void virtio_gpu_device_realize(DeviceState *qdev, Error **errp);
 void virtio_gpu_reset(VirtIODevice *vdev);
-- 
2.42.0.rc2.253.gd59a3bf2b4-goog



^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PATCH v13 5/9] gfxstream + rutabaga prep: added need defintions, fields, and options
  2023-08-29  0:36 [PATCH v13 0/9] rutabaga_gfx + gfxstream Gurchetan Singh
                   ` (3 preceding siblings ...)
  2023-08-29  0:36 ` [PATCH v13 4/9] virtio-gpu: blob prep Gurchetan Singh
@ 2023-08-29  0:36 ` Gurchetan Singh
  2023-08-29  0:36 ` [PATCH v13 6/9] gfxstream + rutabaga: add initial support for gfxstream Gurchetan Singh
                   ` (4 subsequent siblings)
  9 siblings, 0 replies; 27+ messages in thread
From: Gurchetan Singh @ 2023-08-29  0:36 UTC (permalink / raw)
  To: qemu-devel
  Cc: marcandre.lureau, akihiko.odaki, ray.huang, alex.bennee, shentey,
	hi, ernunes, manos.pitsidianakis, philmd, mark.cave-ayland

This modifies the common virtio-gpu.h file have the fields and
defintions needed by gfxstream/rutabaga, by VirtioGpuRutabaga.

Signed-off-by: Gurchetan Singh <gurchetansingh@chromium.org>
Tested-by: Alyssa Ross <hi@alyssa.is>
Tested-by: Emmanouil Pitsidianakis <manos.pitsidianakis@linaro.org>
Tested-by: Akihiko Odaki <akihiko.odaki@daynix.com>
Reviewed-by: Emmanouil Pitsidianakis <manos.pitsidianakis@linaro.org>
Reviewed-by: Antonio Caggiano <quic_acaggian@quicinc.com>
Reviewed-by: Akihiko Odaki <akihiko.odaki@daynix.com>
---
 include/hw/virtio/virtio-gpu.h | 28 ++++++++++++++++++++++++++++
 1 file changed, 28 insertions(+)

diff --git a/include/hw/virtio/virtio-gpu.h b/include/hw/virtio/virtio-gpu.h
index 55973e112f..de06bcdba4 100644
--- a/include/hw/virtio/virtio-gpu.h
+++ b/include/hw/virtio/virtio-gpu.h
@@ -38,6 +38,9 @@ OBJECT_DECLARE_SIMPLE_TYPE(VirtIOGPUGL, VIRTIO_GPU_GL)
 #define TYPE_VHOST_USER_GPU "vhost-user-gpu"
 OBJECT_DECLARE_SIMPLE_TYPE(VhostUserGPU, VHOST_USER_GPU)
 
+#define TYPE_VIRTIO_GPU_RUTABAGA "virtio-gpu-rutabaga-device"
+OBJECT_DECLARE_SIMPLE_TYPE(VirtIOGPURutabaga, VIRTIO_GPU_RUTABAGA)
+
 struct virtio_gpu_simple_resource {
     uint32_t resource_id;
     uint32_t width;
@@ -94,6 +97,7 @@ enum virtio_gpu_base_conf_flags {
     VIRTIO_GPU_FLAG_DMABUF_ENABLED,
     VIRTIO_GPU_FLAG_BLOB_ENABLED,
     VIRTIO_GPU_FLAG_CONTEXT_INIT_ENABLED,
+    VIRTIO_GPU_FLAG_RUTABAGA_ENABLED,
 };
 
 #define virtio_gpu_virgl_enabled(_cfg) \
@@ -108,6 +112,8 @@ enum virtio_gpu_base_conf_flags {
     (_cfg.flags & (1 << VIRTIO_GPU_FLAG_BLOB_ENABLED))
 #define virtio_gpu_context_init_enabled(_cfg) \
     (_cfg.flags & (1 << VIRTIO_GPU_FLAG_CONTEXT_INIT_ENABLED))
+#define virtio_gpu_rutabaga_enabled(_cfg) \
+    (_cfg.flags & (1 << VIRTIO_GPU_FLAG_RUTABAGA_ENABLED))
 #define virtio_gpu_hostmem_enabled(_cfg) \
     (_cfg.hostmem > 0)
 
@@ -232,6 +238,28 @@ struct VhostUserGPU {
     bool backend_blocked;
 };
 
+#define MAX_SLOTS 4096
+
+struct MemoryRegionInfo {
+    int used;
+    MemoryRegion mr;
+    uint32_t resource_id;
+};
+
+struct rutabaga;
+
+struct VirtIOGPURutabaga {
+    VirtIOGPU parent_obj;
+
+    struct MemoryRegionInfo memory_regions[MAX_SLOTS];
+    char *capset_names;
+    char *wayland_socket_path;
+    char *wsi;
+    bool headless;
+    uint32_t num_capsets;
+    struct rutabaga *rutabaga;
+};
+
 #define VIRTIO_GPU_FILL_CMD(out) do {                                   \
         size_t s;                                                       \
         s = iov_to_buf(cmd->elem.out_sg, cmd->elem.out_num, 0,          \
-- 
2.42.0.rc2.253.gd59a3bf2b4-goog



^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PATCH v13 6/9] gfxstream + rutabaga: add initial support for gfxstream
  2023-08-29  0:36 [PATCH v13 0/9] rutabaga_gfx + gfxstream Gurchetan Singh
                   ` (4 preceding siblings ...)
  2023-08-29  0:36 ` [PATCH v13 5/9] gfxstream + rutabaga prep: added need defintions, fields, and options Gurchetan Singh
@ 2023-08-29  0:36 ` Gurchetan Singh
  2023-09-20 11:42   ` Akihiko Odaki
  2023-09-27 11:45   ` Thomas Huth
  2023-08-29  0:36 ` [PATCH v13 7/9] gfxstream + rutabaga: meson support Gurchetan Singh
                   ` (3 subsequent siblings)
  9 siblings, 2 replies; 27+ messages in thread
From: Gurchetan Singh @ 2023-08-29  0:36 UTC (permalink / raw)
  To: qemu-devel
  Cc: marcandre.lureau, akihiko.odaki, ray.huang, alex.bennee, shentey,
	hi, ernunes, manos.pitsidianakis, philmd, mark.cave-ayland

This adds initial support for gfxstream and cross-domain.  Both
features rely on virtio-gpu blob resources and context types, which
are also implemented in this patch.

gfxstream has a long and illustrious history in Android graphics
paravirtualization.  It has been powering graphics in the Android
Studio Emulator for more than a decade, which is the main developer
platform.

Originally conceived by Jesse Hall, it was first known as "EmuGL" [a].
The key design characteristic was a 1:1 threading model and
auto-generation, which fit nicely with the OpenGLES spec.  It also
allowed easy layering with ANGLE on the host, which provides the GLES
implementations on Windows or MacOS enviroments.

gfxstream has traditionally been maintained by a single engineer, and
between 2015 to 2021, the goldfish throne passed to Frank Yang.
Historians often remark this glorious reign ("pax gfxstreama" is the
academic term) was comparable to that of Augustus and both Queen
Elizabeths.  Just to name a few accomplishments in a resplendent
panoply: higher versions of GLES, address space graphics, snapshot
support and CTS compliant Vulkan [b].

One major drawback was the use of out-of-tree goldfish drivers.
Android engineers didn't know much about DRM/KMS and especially TTM so
a simple guest to host pipe was conceived.

Luckily, virtio-gpu 3D started to emerge in 2016 due to the work of
the Mesa/virglrenderer communities.  In 2018, the initial virtio-gpu
port of gfxstream was done by Cuttlefish enthusiast Alistair Delva.
It was a symbol compatible replacement of virglrenderer [c] and named
"AVDVirglrenderer".  This implementation forms the basis of the
current gfxstream host implementation still in use today.

cross-domain support follows a similar arc.  Originally conceived by
Wayland aficionado David Reveman and crosvm enjoyer Zach Reizner in
2018, it initially relied on the downstream "virtio-wl" device.

In 2020 and 2021, virtio-gpu was extended to include blob resources
and multiple timelines by yours truly, features gfxstream/cross-domain
both require to function correctly.

Right now, we stand at the precipice of a truly fantastic possibility:
the Android Emulator powered by upstream QEMU and upstream Linux
kernel.  gfxstream will then be packaged properfully, and app
developers can even fix gfxstream bugs on their own if they encounter
them.

It's been quite the ride, my friends.  Where will gfxstream head next,
nobody really knows.  I wouldn't be surprised if it's around for
another decade, maintained by a new generation of Android graphics
enthusiasts.

Technical details:
  - Very simple initial display integration: just used Pixman
  - Largely, 1:1 mapping of virtio-gpu hypercalls to rutabaga function
    calls

Next steps for Android VMs:
  - The next step would be improving display integration and UI interfaces
    with the goal of the QEMU upstream graphics being in an emulator
    release [d].

Next steps for Linux VMs for display virtualization:
  - For widespread distribution, someone needs to package Sommelier or the
    wayland-proxy-virtwl [e] ideally into Debian main. In addition, newer
    versions of the Linux kernel come with DRM_VIRTIO_GPU_KMS option,
    which allows disabling KMS hypercalls.  If anyone cares enough, it'll
    probably be possible to build a custom VM variant that uses this display
    virtualization strategy.

[a] https://android-review.googlesource.com/c/platform/development/+/34470
[b] https://android-review.googlesource.com/q/topic:%22vulkan-hostconnection-start%22
[c] https://android-review.googlesource.com/c/device/generic/goldfish-opengl/+/761927
[d] https://developer.android.com/studio/releases/emulator
[e] https://github.com/talex5/wayland-proxy-virtwl

Signed-off-by: Gurchetan Singh <gurchetansingh@chromium.org>
Tested-by: Alyssa Ross <hi@alyssa.is>
Tested-by: Emmanouil Pitsidianakis <manos.pitsidianakis@linaro.org>
Tested-by: Akihiko Odaki <akihiko.odaki@daynix.com>
Reviewed-by: Emmanouil Pitsidianakis <manos.pitsidianakis@linaro.org>
Reviewed-by: Antonio Caggiano <quic_acaggian@quicinc.com>
Reviewed-by: Akihiko Odaki <akihiko.odaki@daynix.com>
---
 hw/display/virtio-gpu-pci-rutabaga.c |   47 ++
 hw/display/virtio-gpu-rutabaga.c     | 1119 ++++++++++++++++++++++++++
 hw/display/virtio-vga-rutabaga.c     |   50 ++
 3 files changed, 1216 insertions(+)
 create mode 100644 hw/display/virtio-gpu-pci-rutabaga.c
 create mode 100644 hw/display/virtio-gpu-rutabaga.c
 create mode 100644 hw/display/virtio-vga-rutabaga.c

diff --git a/hw/display/virtio-gpu-pci-rutabaga.c b/hw/display/virtio-gpu-pci-rutabaga.c
new file mode 100644
index 0000000000..c96729e198
--- /dev/null
+++ b/hw/display/virtio-gpu-pci-rutabaga.c
@@ -0,0 +1,47 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#include "qemu/osdep.h"
+#include "qapi/error.h"
+#include "qemu/module.h"
+#include "hw/pci/pci.h"
+#include "hw/qdev-properties.h"
+#include "hw/virtio/virtio.h"
+#include "hw/virtio/virtio-bus.h"
+#include "hw/virtio/virtio-gpu-pci.h"
+#include "qom/object.h"
+
+#define TYPE_VIRTIO_GPU_RUTABAGA_PCI "virtio-gpu-rutabaga-pci"
+OBJECT_DECLARE_SIMPLE_TYPE(VirtIOGPURutabagaPCI, VIRTIO_GPU_RUTABAGA_PCI)
+
+struct VirtIOGPURutabagaPCI {
+    VirtIOGPUPCIBase parent_obj;
+
+    VirtIOGPURutabaga vdev;
+};
+
+static void virtio_gpu_rutabaga_initfn(Object *obj)
+{
+    VirtIOGPURutabagaPCI *dev = VIRTIO_GPU_RUTABAGA_PCI(obj);
+
+    virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
+                                TYPE_VIRTIO_GPU_RUTABAGA);
+    VIRTIO_GPU_PCI_BASE(obj)->vgpu = VIRTIO_GPU_BASE(&dev->vdev);
+}
+
+static const TypeInfo virtio_gpu_rutabaga_pci_info[] = {
+    {
+        .name = TYPE_VIRTIO_GPU_RUTABAGA_PCI,
+        .parent = TYPE_VIRTIO_GPU_PCI_BASE,
+        .instance_size = sizeof(VirtIOGPURutabagaPCI),
+        .instance_init = virtio_gpu_rutabaga_initfn,
+        .interfaces = (InterfaceInfo[]) {
+            { INTERFACE_CONVENTIONAL_PCI_DEVICE },
+        }
+    },
+};
+
+DEFINE_TYPES(virtio_gpu_rutabaga_pci_info)
+
+module_obj(TYPE_VIRTIO_GPU_RUTABAGA_PCI);
+module_kconfig(VIRTIO_PCI);
+module_dep("hw-display-virtio-gpu-pci");
diff --git a/hw/display/virtio-gpu-rutabaga.c b/hw/display/virtio-gpu-rutabaga.c
new file mode 100644
index 0000000000..a105e06214
--- /dev/null
+++ b/hw/display/virtio-gpu-rutabaga.c
@@ -0,0 +1,1119 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#include "qemu/osdep.h"
+#include "qapi/error.h"
+#include "qemu/error-report.h"
+#include "qemu/iov.h"
+#include "trace.h"
+#include "hw/virtio/virtio.h"
+#include "hw/virtio/virtio-gpu.h"
+#include "hw/virtio/virtio-gpu-pixman.h"
+#include "hw/virtio/virtio-iommu.h"
+
+#include <glib/gmem.h>
+#include <rutabaga_gfx/rutabaga_gfx_ffi.h>
+
+#define CHECK(condition, cmd)                                                 \
+    do {                                                                      \
+        if (!(condition)) {                                                   \
+            error_report("CHECK failed in %s() %s:" "%d", __func__,           \
+                         __FILE__, __LINE__);                                 \
+            (cmd)->error = VIRTIO_GPU_RESP_ERR_UNSPEC;                        \
+            return;                                                           \
+       }                                                                      \
+    } while (0)
+
+/*
+ * This is the size of the char array in struct sock_addr_un. No Wayland socket
+ * can be created with a path longer than this, including the null terminator.
+ */
+#define UNIX_PATH_MAX sizeof((struct sockaddr_un) {} .sun_path)
+
+struct rutabaga_aio_data {
+    struct VirtIOGPURutabaga *vr;
+    struct rutabaga_fence fence;
+};
+
+static void
+virtio_gpu_rutabaga_update_cursor(VirtIOGPU *g, struct virtio_gpu_scanout *s,
+                                  uint32_t resource_id)
+{
+    struct virtio_gpu_simple_resource *res;
+    struct rutabaga_transfer transfer = { 0 };
+    struct iovec transfer_iovec;
+
+    VirtIOGPURutabaga *vr = VIRTIO_GPU_RUTABAGA(g);
+
+    res = virtio_gpu_find_resource(g, resource_id);
+    if (!res) {
+        return;
+    }
+
+    if (res->width != s->current_cursor->width ||
+        res->height != s->current_cursor->height) {
+        return;
+    }
+
+    transfer.x = 0;
+    transfer.y = 0;
+    transfer.z = 0;
+    transfer.w = res->width;
+    transfer.h = res->height;
+    transfer.d = 1;
+
+    transfer_iovec.iov_base = s->current_cursor->data;
+    transfer_iovec.iov_len = res->width * res->height * 4;
+
+    rutabaga_resource_transfer_read(vr->rutabaga, 0,
+                                    resource_id, &transfer,
+                                    &transfer_iovec);
+}
+
+static void
+virtio_gpu_rutabaga_gl_flushed(VirtIOGPUBase *b)
+{
+    VirtIOGPU *g = VIRTIO_GPU(b);
+    virtio_gpu_process_cmdq(g);
+}
+
+static void
+rutabaga_cmd_create_resource_2d(VirtIOGPU *g,
+                                struct virtio_gpu_ctrl_command *cmd)
+{
+    int32_t result;
+    struct rutabaga_create_3d rc_3d = { 0 };
+    struct virtio_gpu_simple_resource *res;
+    struct virtio_gpu_resource_create_2d c2d;
+
+    VirtIOGPURutabaga *vr = VIRTIO_GPU_RUTABAGA(g);
+
+    VIRTIO_GPU_FILL_CMD(c2d);
+    trace_virtio_gpu_cmd_res_create_2d(c2d.resource_id, c2d.format,
+                                       c2d.width, c2d.height);
+
+    rc_3d.target = 2;
+    rc_3d.format = c2d.format;
+    rc_3d.bind = (1 << 1);
+    rc_3d.width = c2d.width;
+    rc_3d.height = c2d.height;
+    rc_3d.depth = 1;
+    rc_3d.array_size = 1;
+    rc_3d.last_level = 0;
+    rc_3d.nr_samples = 0;
+    rc_3d.flags = VIRTIO_GPU_RESOURCE_FLAG_Y_0_TOP;
+
+    result = rutabaga_resource_create_3d(vr->rutabaga, c2d.resource_id, &rc_3d);
+    CHECK(!result, cmd);
+
+    res = g_new0(struct virtio_gpu_simple_resource, 1);
+    res->width = c2d.width;
+    res->height = c2d.height;
+    res->format = c2d.format;
+    res->resource_id = c2d.resource_id;
+
+    QTAILQ_INSERT_HEAD(&g->reslist, res, next);
+}
+
+static void
+rutabaga_cmd_create_resource_3d(VirtIOGPU *g,
+                                struct virtio_gpu_ctrl_command *cmd)
+{
+    int32_t result;
+    struct rutabaga_create_3d rc_3d = { 0 };
+    struct virtio_gpu_simple_resource *res;
+    struct virtio_gpu_resource_create_3d c3d;
+
+    VirtIOGPURutabaga *vr = VIRTIO_GPU_RUTABAGA(g);
+
+    VIRTIO_GPU_FILL_CMD(c3d);
+
+    trace_virtio_gpu_cmd_res_create_3d(c3d.resource_id, c3d.format,
+                                       c3d.width, c3d.height, c3d.depth);
+
+    rc_3d.target = c3d.target;
+    rc_3d.format = c3d.format;
+    rc_3d.bind = c3d.bind;
+    rc_3d.width = c3d.width;
+    rc_3d.height = c3d.height;
+    rc_3d.depth = c3d.depth;
+    rc_3d.array_size = c3d.array_size;
+    rc_3d.last_level = c3d.last_level;
+    rc_3d.nr_samples = c3d.nr_samples;
+    rc_3d.flags = c3d.flags;
+
+    result = rutabaga_resource_create_3d(vr->rutabaga, c3d.resource_id, &rc_3d);
+    CHECK(!result, cmd);
+
+    res = g_new0(struct virtio_gpu_simple_resource, 1);
+    res->width = c3d.width;
+    res->height = c3d.height;
+    res->format = c3d.format;
+    res->resource_id = c3d.resource_id;
+
+    QTAILQ_INSERT_HEAD(&g->reslist, res, next);
+}
+
+static void
+rutabaga_cmd_resource_unref(VirtIOGPU *g,
+                            struct virtio_gpu_ctrl_command *cmd)
+{
+    int32_t result;
+    struct virtio_gpu_simple_resource *res;
+    struct virtio_gpu_resource_unref unref;
+
+    VirtIOGPURutabaga *vr = VIRTIO_GPU_RUTABAGA(g);
+
+    VIRTIO_GPU_FILL_CMD(unref);
+
+    trace_virtio_gpu_cmd_res_unref(unref.resource_id);
+
+    res = virtio_gpu_find_resource(g, unref.resource_id);
+    CHECK(res, cmd);
+
+    result = rutabaga_resource_unref(vr->rutabaga, unref.resource_id);
+    CHECK(!result, cmd);
+
+    if (res->image) {
+        pixman_image_unref(res->image);
+    }
+
+    QTAILQ_REMOVE(&g->reslist, res, next);
+    g_free(res);
+}
+
+static void
+rutabaga_cmd_context_create(VirtIOGPU *g,
+                            struct virtio_gpu_ctrl_command *cmd)
+{
+    int32_t result;
+    struct virtio_gpu_ctx_create cc;
+
+    VirtIOGPURutabaga *vr = VIRTIO_GPU_RUTABAGA(g);
+
+    VIRTIO_GPU_FILL_CMD(cc);
+    trace_virtio_gpu_cmd_ctx_create(cc.hdr.ctx_id,
+                                    cc.debug_name);
+
+    result = rutabaga_context_create(vr->rutabaga, cc.hdr.ctx_id,
+                                     cc.context_init, cc.debug_name, cc.nlen);
+    CHECK(!result, cmd);
+}
+
+static void
+rutabaga_cmd_context_destroy(VirtIOGPU *g,
+                             struct virtio_gpu_ctrl_command *cmd)
+{
+    int32_t result;
+    struct virtio_gpu_ctx_destroy cd;
+
+    VirtIOGPURutabaga *vr = VIRTIO_GPU_RUTABAGA(g);
+
+    VIRTIO_GPU_FILL_CMD(cd);
+    trace_virtio_gpu_cmd_ctx_destroy(cd.hdr.ctx_id);
+
+    result = rutabaga_context_destroy(vr->rutabaga, cd.hdr.ctx_id);
+    CHECK(!result, cmd);
+}
+
+static void
+rutabaga_cmd_resource_flush(VirtIOGPU *g, struct virtio_gpu_ctrl_command *cmd)
+{
+    int32_t result, i;
+    struct virtio_gpu_scanout *scanout = NULL;
+    struct virtio_gpu_simple_resource *res;
+    struct rutabaga_transfer transfer = { 0 };
+    struct iovec transfer_iovec;
+    struct virtio_gpu_resource_flush rf;
+    bool found = false;
+
+    VirtIOGPUBase *vb = VIRTIO_GPU_BASE(g);
+    VirtIOGPURutabaga *vr = VIRTIO_GPU_RUTABAGA(g);
+    if (vr->headless) {
+        return;
+    }
+
+    VIRTIO_GPU_FILL_CMD(rf);
+    trace_virtio_gpu_cmd_res_flush(rf.resource_id,
+                                   rf.r.width, rf.r.height, rf.r.x, rf.r.y);
+
+    res = virtio_gpu_find_resource(g, rf.resource_id);
+    CHECK(res, cmd);
+
+    for (i = 0; i < vb->conf.max_outputs; i++) {
+        scanout = &vb->scanout[i];
+        if (i == res->scanout_bitmask) {
+            found = true;
+            break;
+        }
+    }
+
+    if (!found) {
+        return;
+    }
+
+    transfer.x = 0;
+    transfer.y = 0;
+    transfer.z = 0;
+    transfer.w = res->width;
+    transfer.h = res->height;
+    transfer.d = 1;
+
+    transfer_iovec.iov_base = pixman_image_get_data(res->image);
+    transfer_iovec.iov_len = res->width * res->height * 4;
+
+    result = rutabaga_resource_transfer_read(vr->rutabaga, 0,
+                                             rf.resource_id, &transfer,
+                                             &transfer_iovec);
+    CHECK(!result, cmd);
+    dpy_gfx_update_full(scanout->con);
+}
+
+static void
+rutabaga_cmd_set_scanout(VirtIOGPU *g, struct virtio_gpu_ctrl_command *cmd)
+{
+    struct virtio_gpu_simple_resource *res;
+    struct virtio_gpu_scanout *scanout = NULL;
+    struct virtio_gpu_set_scanout ss;
+
+    VirtIOGPUBase *vb = VIRTIO_GPU_BASE(g);
+    VirtIOGPURutabaga *vr = VIRTIO_GPU_RUTABAGA(g);
+    if (vr->headless) {
+        return;
+    }
+
+    VIRTIO_GPU_FILL_CMD(ss);
+    trace_virtio_gpu_cmd_set_scanout(ss.scanout_id, ss.resource_id,
+                                     ss.r.width, ss.r.height, ss.r.x, ss.r.y);
+
+    CHECK(ss.scanout_id < VIRTIO_GPU_MAX_SCANOUTS, cmd);
+    scanout = &vb->scanout[ss.scanout_id];
+
+    if (ss.resource_id == 0) {
+        dpy_gfx_replace_surface(scanout->con, NULL);
+        dpy_gl_scanout_disable(scanout->con);
+        return;
+    }
+
+    res = virtio_gpu_find_resource(g, ss.resource_id);
+    CHECK(res, cmd);
+
+    if (!res->image) {
+        pixman_format_code_t pformat;
+        pformat = virtio_gpu_get_pixman_format(res->format);
+        CHECK(pformat, cmd);
+
+        res->image = pixman_image_create_bits(pformat,
+                                              res->width,
+                                              res->height,
+                                              NULL, 0);
+        CHECK(res->image, cmd);
+        pixman_image_ref(res->image);
+    }
+
+    vb->enable = 1;
+
+    /* realloc the surface ptr */
+    scanout->ds = qemu_create_displaysurface_pixman(res->image);
+    dpy_gfx_replace_surface(scanout->con, NULL);
+    dpy_gfx_replace_surface(scanout->con, scanout->ds);
+    res->scanout_bitmask = ss.scanout_id;
+}
+
+static void
+rutabaga_cmd_submit_3d(VirtIOGPU *g,
+                       struct virtio_gpu_ctrl_command *cmd)
+{
+    int32_t result;
+    struct virtio_gpu_cmd_submit cs;
+    struct rutabaga_command rutabaga_cmd = { 0 };
+    g_autofree uint8_t *buf = NULL;
+    size_t s;
+
+    VirtIOGPURutabaga *vr = VIRTIO_GPU_RUTABAGA(g);
+
+    VIRTIO_GPU_FILL_CMD(cs);
+    trace_virtio_gpu_cmd_ctx_submit(cs.hdr.ctx_id, cs.size);
+
+    buf = g_new0(uint8_t, cs.size);
+    s = iov_to_buf(cmd->elem.out_sg, cmd->elem.out_num,
+                   sizeof(cs), buf, cs.size);
+    CHECK(s == cs.size, cmd);
+
+    rutabaga_cmd.ctx_id = cs.hdr.ctx_id;
+    rutabaga_cmd.cmd = buf;
+    rutabaga_cmd.cmd_size = cs.size;
+
+    result = rutabaga_submit_command(vr->rutabaga, &rutabaga_cmd);
+    CHECK(!result, cmd);
+}
+
+static void
+rutabaga_cmd_transfer_to_host_2d(VirtIOGPU *g,
+                                 struct virtio_gpu_ctrl_command *cmd)
+{
+    int32_t result;
+    struct rutabaga_transfer transfer = { 0 };
+    struct virtio_gpu_transfer_to_host_2d t2d;
+
+    VirtIOGPURutabaga *vr = VIRTIO_GPU_RUTABAGA(g);
+
+    VIRTIO_GPU_FILL_CMD(t2d);
+    trace_virtio_gpu_cmd_res_xfer_toh_2d(t2d.resource_id);
+
+    transfer.x = t2d.r.x;
+    transfer.y = t2d.r.y;
+    transfer.z = 0;
+    transfer.w = t2d.r.width;
+    transfer.h = t2d.r.height;
+    transfer.d = 1;
+
+    result = rutabaga_resource_transfer_write(vr->rutabaga, 0, t2d.resource_id,
+                                              &transfer);
+    CHECK(!result, cmd);
+}
+
+static void
+rutabaga_cmd_transfer_to_host_3d(VirtIOGPU *g,
+                                 struct virtio_gpu_ctrl_command *cmd)
+{
+    int32_t result;
+    struct rutabaga_transfer transfer = { 0 };
+    struct virtio_gpu_transfer_host_3d t3d;
+
+    VirtIOGPURutabaga *vr = VIRTIO_GPU_RUTABAGA(g);
+
+    VIRTIO_GPU_FILL_CMD(t3d);
+    trace_virtio_gpu_cmd_res_xfer_toh_3d(t3d.resource_id);
+
+    transfer.x = t3d.box.x;
+    transfer.y = t3d.box.y;
+    transfer.z = t3d.box.z;
+    transfer.w = t3d.box.w;
+    transfer.h = t3d.box.h;
+    transfer.d = t3d.box.d;
+    transfer.level = t3d.level;
+    transfer.stride = t3d.stride;
+    transfer.layer_stride = t3d.layer_stride;
+    transfer.offset = t3d.offset;
+
+    result = rutabaga_resource_transfer_write(vr->rutabaga, t3d.hdr.ctx_id,
+                                              t3d.resource_id, &transfer);
+    CHECK(!result, cmd);
+}
+
+static void
+rutabaga_cmd_transfer_from_host_3d(VirtIOGPU *g,
+                                   struct virtio_gpu_ctrl_command *cmd)
+{
+    int32_t result;
+    struct rutabaga_transfer transfer = { 0 };
+    struct virtio_gpu_transfer_host_3d t3d;
+
+    VirtIOGPURutabaga *vr = VIRTIO_GPU_RUTABAGA(g);
+
+    VIRTIO_GPU_FILL_CMD(t3d);
+    trace_virtio_gpu_cmd_res_xfer_fromh_3d(t3d.resource_id);
+
+    transfer.x = t3d.box.x;
+    transfer.y = t3d.box.y;
+    transfer.z = t3d.box.z;
+    transfer.w = t3d.box.w;
+    transfer.h = t3d.box.h;
+    transfer.d = t3d.box.d;
+    transfer.level = t3d.level;
+    transfer.stride = t3d.stride;
+    transfer.layer_stride = t3d.layer_stride;
+    transfer.offset = t3d.offset;
+
+    result = rutabaga_resource_transfer_read(vr->rutabaga, t3d.hdr.ctx_id,
+                                             t3d.resource_id, &transfer, NULL);
+    CHECK(!result, cmd);
+}
+
+static void
+rutabaga_cmd_attach_backing(VirtIOGPU *g, struct virtio_gpu_ctrl_command *cmd)
+{
+    struct rutabaga_iovecs vecs = { 0 };
+    struct virtio_gpu_simple_resource *res;
+    struct virtio_gpu_resource_attach_backing att_rb;
+    int ret;
+
+    VirtIOGPURutabaga *vr = VIRTIO_GPU_RUTABAGA(g);
+
+    VIRTIO_GPU_FILL_CMD(att_rb);
+    trace_virtio_gpu_cmd_res_back_attach(att_rb.resource_id);
+
+    res = virtio_gpu_find_resource(g, att_rb.resource_id);
+    CHECK(res, cmd);
+    CHECK(!res->iov, cmd);
+
+    ret = virtio_gpu_create_mapping_iov(g, att_rb.nr_entries, sizeof(att_rb),
+                                        cmd, NULL, &res->iov, &res->iov_cnt);
+    CHECK(!ret, cmd);
+
+    vecs.iovecs = res->iov;
+    vecs.num_iovecs = res->iov_cnt;
+
+    ret = rutabaga_resource_attach_backing(vr->rutabaga, att_rb.resource_id,
+                                           &vecs);
+    if (ret != 0) {
+        virtio_gpu_cleanup_mapping(g, res);
+    }
+
+    CHECK(!ret, cmd);
+}
+
+static void
+rutabaga_cmd_detach_backing(VirtIOGPU *g, struct virtio_gpu_ctrl_command *cmd)
+{
+    struct virtio_gpu_simple_resource *res;
+    struct virtio_gpu_resource_detach_backing detach_rb;
+
+    VirtIOGPURutabaga *vr = VIRTIO_GPU_RUTABAGA(g);
+
+    VIRTIO_GPU_FILL_CMD(detach_rb);
+    trace_virtio_gpu_cmd_res_back_detach(detach_rb.resource_id);
+
+    res = virtio_gpu_find_resource(g, detach_rb.resource_id);
+    CHECK(res, cmd);
+
+    rutabaga_resource_detach_backing(vr->rutabaga,
+                                     detach_rb.resource_id);
+
+    virtio_gpu_cleanup_mapping(g, res);
+}
+
+static void
+rutabaga_cmd_ctx_attach_resource(VirtIOGPU *g,
+                                 struct virtio_gpu_ctrl_command *cmd)
+{
+    int32_t result;
+    struct virtio_gpu_ctx_resource att_res;
+
+    VirtIOGPURutabaga *vr = VIRTIO_GPU_RUTABAGA(g);
+
+    VIRTIO_GPU_FILL_CMD(att_res);
+    trace_virtio_gpu_cmd_ctx_res_attach(att_res.hdr.ctx_id,
+                                        att_res.resource_id);
+
+    result = rutabaga_context_attach_resource(vr->rutabaga, att_res.hdr.ctx_id,
+                                              att_res.resource_id);
+    CHECK(!result, cmd);
+}
+
+static void
+rutabaga_cmd_ctx_detach_resource(VirtIOGPU *g,
+                                 struct virtio_gpu_ctrl_command *cmd)
+{
+    int32_t result;
+    struct virtio_gpu_ctx_resource det_res;
+
+    VirtIOGPURutabaga *vr = VIRTIO_GPU_RUTABAGA(g);
+
+    VIRTIO_GPU_FILL_CMD(det_res);
+    trace_virtio_gpu_cmd_ctx_res_detach(det_res.hdr.ctx_id,
+                                        det_res.resource_id);
+
+    result = rutabaga_context_detach_resource(vr->rutabaga, det_res.hdr.ctx_id,
+                                              det_res.resource_id);
+    CHECK(!result, cmd);
+}
+
+static void
+rutabaga_cmd_get_capset_info(VirtIOGPU *g, struct virtio_gpu_ctrl_command *cmd)
+{
+    int32_t result;
+    struct virtio_gpu_get_capset_info info;
+    struct virtio_gpu_resp_capset_info resp;
+
+    VirtIOGPURutabaga *vr = VIRTIO_GPU_RUTABAGA(g);
+
+    VIRTIO_GPU_FILL_CMD(info);
+
+    result = rutabaga_get_capset_info(vr->rutabaga, info.capset_index,
+                                      &resp.capset_id, &resp.capset_max_version,
+                                      &resp.capset_max_size);
+    CHECK(!result, cmd);
+
+    resp.hdr.type = VIRTIO_GPU_RESP_OK_CAPSET_INFO;
+    virtio_gpu_ctrl_response(g, cmd, &resp.hdr, sizeof(resp));
+}
+
+static void
+rutabaga_cmd_get_capset(VirtIOGPU *g, struct virtio_gpu_ctrl_command *cmd)
+{
+    int32_t result;
+    struct virtio_gpu_get_capset gc;
+    struct virtio_gpu_resp_capset *resp;
+    uint32_t capset_size, capset_version;
+    uint32_t current_id, i;
+
+    VirtIOGPURutabaga *vr = VIRTIO_GPU_RUTABAGA(g);
+
+    VIRTIO_GPU_FILL_CMD(gc);
+    for (i = 0; i < vr->num_capsets; i++) {
+        result = rutabaga_get_capset_info(vr->rutabaga, i,
+                                          &current_id, &capset_version,
+                                          &capset_size);
+        CHECK(!result, cmd);
+
+        if (current_id == gc.capset_id) {
+            break;
+        }
+    }
+
+    CHECK(i < vr->num_capsets, cmd);
+
+    resp = g_malloc0(sizeof(*resp) + capset_size);
+    resp->hdr.type = VIRTIO_GPU_RESP_OK_CAPSET;
+    rutabaga_get_capset(vr->rutabaga, gc.capset_id, gc.capset_version,
+                        resp->capset_data, capset_size);
+
+    virtio_gpu_ctrl_response(g, cmd, &resp->hdr, sizeof(*resp) + capset_size);
+    g_free(resp);
+}
+
+static void
+rutabaga_cmd_resource_create_blob(VirtIOGPU *g,
+                                  struct virtio_gpu_ctrl_command *cmd)
+{
+    int result;
+    struct rutabaga_iovecs vecs = { 0 };
+    g_autofree struct virtio_gpu_simple_resource *res = NULL;
+    struct virtio_gpu_resource_create_blob cblob;
+    struct rutabaga_create_blob rc_blob = { 0 };
+
+    VirtIOGPURutabaga *vr = VIRTIO_GPU_RUTABAGA(g);
+
+    VIRTIO_GPU_FILL_CMD(cblob);
+    trace_virtio_gpu_cmd_res_create_blob(cblob.resource_id, cblob.size);
+
+    CHECK(cblob.resource_id != 0, cmd);
+
+    res = g_new0(struct virtio_gpu_simple_resource, 1);
+
+    res->resource_id = cblob.resource_id;
+    res->blob_size = cblob.size;
+
+    if (cblob.blob_mem != VIRTIO_GPU_BLOB_MEM_HOST3D) {
+        result = virtio_gpu_create_mapping_iov(g, cblob.nr_entries,
+                                               sizeof(cblob), cmd, &res->addrs,
+                                               &res->iov, &res->iov_cnt);
+        CHECK(!result, cmd);
+    }
+
+    rc_blob.blob_id = cblob.blob_id;
+    rc_blob.blob_mem = cblob.blob_mem;
+    rc_blob.blob_flags = cblob.blob_flags;
+    rc_blob.size = cblob.size;
+
+    vecs.iovecs = res->iov;
+    vecs.num_iovecs = res->iov_cnt;
+
+    result = rutabaga_resource_create_blob(vr->rutabaga, cblob.hdr.ctx_id,
+                                           cblob.resource_id, &rc_blob, &vecs,
+                                           NULL);
+
+    if (result && cblob.blob_mem != VIRTIO_GPU_BLOB_MEM_HOST3D) {
+        virtio_gpu_cleanup_mapping(g, res);
+    }
+
+    CHECK(!result, cmd);
+
+    QTAILQ_INSERT_HEAD(&g->reslist, res, next);
+    res = NULL;
+}
+
+static void
+rutabaga_cmd_resource_map_blob(VirtIOGPU *g,
+                               struct virtio_gpu_ctrl_command *cmd)
+{
+    int32_t result;
+    uint32_t map_info = 0;
+    uint32_t slot = 0;
+    struct virtio_gpu_simple_resource *res;
+    struct rutabaga_mapping mapping = { 0 };
+    struct virtio_gpu_resource_map_blob mblob;
+    struct virtio_gpu_resp_map_info resp = { 0 };
+
+    VirtIOGPUBase *vb = VIRTIO_GPU_BASE(g);
+    VirtIOGPURutabaga *vr = VIRTIO_GPU_RUTABAGA(g);
+
+    VIRTIO_GPU_FILL_CMD(mblob);
+
+    CHECK(mblob.resource_id != 0, cmd);
+
+    res = virtio_gpu_find_resource(g, mblob.resource_id);
+    CHECK(res, cmd);
+
+    result = rutabaga_resource_map_info(vr->rutabaga, mblob.resource_id,
+                                        &map_info);
+    CHECK(!result, cmd);
+
+    /*
+     * RUTABAGA_MAP_ACCESS_* flags are not part of the virtio-gpu spec, but do
+     * exist to potentially allow the hypervisor to restrict write access to
+     * memory. QEMU does not need to use this functionality at the moment.
+     */
+    resp.map_info = map_info & RUTABAGA_MAP_CACHE_MASK;
+
+    result = rutabaga_resource_map(vr->rutabaga, mblob.resource_id, &mapping);
+    CHECK(!result, cmd);
+
+    for (slot = 0; slot < MAX_SLOTS; slot++) {
+        if (vr->memory_regions[slot].used) {
+            continue;
+        }
+
+        MemoryRegion *mr = &(vr->memory_regions[slot].mr);
+        memory_region_init_ram_ptr(mr, OBJECT(vr), "blob", mapping.size,
+                                   mapping.ptr);
+        memory_region_add_subregion(&vb->hostmem, mblob.offset, mr);
+        vr->memory_regions[slot].resource_id = mblob.resource_id;
+        vr->memory_regions[slot].used = 1;
+        break;
+    }
+
+    if (slot >= MAX_SLOTS) {
+        result = rutabaga_resource_unmap(vr->rutabaga, mblob.resource_id);
+        CHECK(!result, cmd);
+    }
+
+    CHECK(slot < MAX_SLOTS, cmd);
+
+    resp.hdr.type = VIRTIO_GPU_RESP_OK_MAP_INFO;
+    virtio_gpu_ctrl_response(g, cmd, &resp.hdr, sizeof(resp));
+}
+
+static void
+rutabaga_cmd_resource_unmap_blob(VirtIOGPU *g,
+                                 struct virtio_gpu_ctrl_command *cmd)
+{
+    int32_t result;
+    uint32_t slot = 0;
+    struct virtio_gpu_simple_resource *res;
+    struct virtio_gpu_resource_unmap_blob ublob;
+
+    VirtIOGPUBase *vb = VIRTIO_GPU_BASE(g);
+    VirtIOGPURutabaga *vr = VIRTIO_GPU_RUTABAGA(g);
+
+    VIRTIO_GPU_FILL_CMD(ublob);
+
+    CHECK(ublob.resource_id != 0, cmd);
+
+    res = virtio_gpu_find_resource(g, ublob.resource_id);
+    CHECK(res, cmd);
+
+    for (slot = 0; slot < MAX_SLOTS; slot++) {
+        if (vr->memory_regions[slot].resource_id != ublob.resource_id) {
+            continue;
+        }
+
+        MemoryRegion *mr = &(vr->memory_regions[slot].mr);
+        memory_region_del_subregion(&vb->hostmem, mr);
+
+        vr->memory_regions[slot].resource_id = 0;
+        vr->memory_regions[slot].used = 0;
+        break;
+    }
+
+    CHECK(slot < MAX_SLOTS, cmd);
+    result = rutabaga_resource_unmap(vr->rutabaga, res->resource_id);
+    CHECK(!result, cmd);
+}
+
+static void
+virtio_gpu_rutabaga_process_cmd(VirtIOGPU *g,
+                                struct virtio_gpu_ctrl_command *cmd)
+{
+    struct rutabaga_fence fence = { 0 };
+    int32_t result;
+
+    VirtIOGPURutabaga *vr = VIRTIO_GPU_RUTABAGA(g);
+
+    VIRTIO_GPU_FILL_CMD(cmd->cmd_hdr);
+
+    switch (cmd->cmd_hdr.type) {
+    case VIRTIO_GPU_CMD_CTX_CREATE:
+        rutabaga_cmd_context_create(g, cmd);
+        break;
+    case VIRTIO_GPU_CMD_CTX_DESTROY:
+        rutabaga_cmd_context_destroy(g, cmd);
+        break;
+    case VIRTIO_GPU_CMD_RESOURCE_CREATE_2D:
+        rutabaga_cmd_create_resource_2d(g, cmd);
+        break;
+    case VIRTIO_GPU_CMD_RESOURCE_CREATE_3D:
+        rutabaga_cmd_create_resource_3d(g, cmd);
+        break;
+    case VIRTIO_GPU_CMD_SUBMIT_3D:
+        rutabaga_cmd_submit_3d(g, cmd);
+        break;
+    case VIRTIO_GPU_CMD_TRANSFER_TO_HOST_2D:
+        rutabaga_cmd_transfer_to_host_2d(g, cmd);
+        break;
+    case VIRTIO_GPU_CMD_TRANSFER_TO_HOST_3D:
+        rutabaga_cmd_transfer_to_host_3d(g, cmd);
+        break;
+    case VIRTIO_GPU_CMD_TRANSFER_FROM_HOST_3D:
+        rutabaga_cmd_transfer_from_host_3d(g, cmd);
+        break;
+    case VIRTIO_GPU_CMD_RESOURCE_ATTACH_BACKING:
+        rutabaga_cmd_attach_backing(g, cmd);
+        break;
+    case VIRTIO_GPU_CMD_RESOURCE_DETACH_BACKING:
+        rutabaga_cmd_detach_backing(g, cmd);
+        break;
+    case VIRTIO_GPU_CMD_SET_SCANOUT:
+        rutabaga_cmd_set_scanout(g, cmd);
+        break;
+    case VIRTIO_GPU_CMD_RESOURCE_FLUSH:
+        rutabaga_cmd_resource_flush(g, cmd);
+        break;
+    case VIRTIO_GPU_CMD_RESOURCE_UNREF:
+        rutabaga_cmd_resource_unref(g, cmd);
+        break;
+    case VIRTIO_GPU_CMD_CTX_ATTACH_RESOURCE:
+        rutabaga_cmd_ctx_attach_resource(g, cmd);
+        break;
+    case VIRTIO_GPU_CMD_CTX_DETACH_RESOURCE:
+        rutabaga_cmd_ctx_detach_resource(g, cmd);
+        break;
+    case VIRTIO_GPU_CMD_GET_CAPSET_INFO:
+        rutabaga_cmd_get_capset_info(g, cmd);
+        break;
+    case VIRTIO_GPU_CMD_GET_CAPSET:
+        rutabaga_cmd_get_capset(g, cmd);
+        break;
+    case VIRTIO_GPU_CMD_GET_DISPLAY_INFO:
+        virtio_gpu_get_display_info(g, cmd);
+        break;
+    case VIRTIO_GPU_CMD_GET_EDID:
+        virtio_gpu_get_edid(g, cmd);
+        break;
+    case VIRTIO_GPU_CMD_RESOURCE_CREATE_BLOB:
+        rutabaga_cmd_resource_create_blob(g, cmd);
+        break;
+    case VIRTIO_GPU_CMD_RESOURCE_MAP_BLOB:
+        rutabaga_cmd_resource_map_blob(g, cmd);
+        break;
+    case VIRTIO_GPU_CMD_RESOURCE_UNMAP_BLOB:
+        rutabaga_cmd_resource_unmap_blob(g, cmd);
+        break;
+    default:
+        cmd->error = VIRTIO_GPU_RESP_ERR_UNSPEC;
+        break;
+    }
+
+    if (cmd->finished) {
+        return;
+    }
+    if (cmd->error) {
+        error_report("%s: ctrl 0x%x, error 0x%x", __func__,
+                     cmd->cmd_hdr.type, cmd->error);
+        virtio_gpu_ctrl_response_nodata(g, cmd, cmd->error);
+        return;
+    }
+    if (!(cmd->cmd_hdr.flags & VIRTIO_GPU_FLAG_FENCE)) {
+        virtio_gpu_ctrl_response_nodata(g, cmd, VIRTIO_GPU_RESP_OK_NODATA);
+        return;
+    }
+
+    fence.flags = cmd->cmd_hdr.flags;
+    fence.ctx_id = cmd->cmd_hdr.ctx_id;
+    fence.fence_id = cmd->cmd_hdr.fence_id;
+    fence.ring_idx = cmd->cmd_hdr.ring_idx;
+
+    trace_virtio_gpu_fence_ctrl(cmd->cmd_hdr.fence_id, cmd->cmd_hdr.type);
+
+    result = rutabaga_create_fence(vr->rutabaga, &fence);
+    CHECK(!result, cmd);
+}
+
+static void
+virtio_gpu_rutabaga_aio_cb(void *opaque)
+{
+    struct rutabaga_aio_data *data = opaque;
+    VirtIOGPU *g = VIRTIO_GPU(data->vr);
+    struct rutabaga_fence fence_data = data->fence;
+    struct virtio_gpu_ctrl_command *cmd, *tmp;
+
+    uint32_t signaled_ctx_specific = fence_data.flags &
+                                     RUTABAGA_FLAG_INFO_RING_IDX;
+
+    QTAILQ_FOREACH_SAFE(cmd, &g->fenceq, next, tmp) {
+        /*
+         * Due to context specific timelines.
+         */
+        uint32_t target_ctx_specific = cmd->cmd_hdr.flags &
+                                       RUTABAGA_FLAG_INFO_RING_IDX;
+
+        if (signaled_ctx_specific != target_ctx_specific) {
+            continue;
+        }
+
+        if (signaled_ctx_specific &&
+           (cmd->cmd_hdr.ring_idx != fence_data.ring_idx)) {
+            continue;
+        }
+
+        if (cmd->cmd_hdr.fence_id > fence_data.fence_id) {
+            continue;
+        }
+
+        trace_virtio_gpu_fence_resp(cmd->cmd_hdr.fence_id);
+        virtio_gpu_ctrl_response_nodata(g, cmd, VIRTIO_GPU_RESP_OK_NODATA);
+        QTAILQ_REMOVE(&g->fenceq, cmd, next);
+        g_free(cmd);
+    }
+
+    g_free(data);
+}
+
+static void
+virtio_gpu_rutabaga_fence_cb(uint64_t user_data,
+                             const struct rutabaga_fence *fence) {
+    struct rutabaga_aio_data *data;
+    VirtIOGPU *g = (VirtIOGPU *)user_data;
+    VirtIOGPURutabaga *vr = VIRTIO_GPU_RUTABAGA(g);
+
+    /*
+     * gfxstream and both cross-domain (and even newer versions virglrenderer:
+     * see VIRGL_RENDERER_ASYNC_FENCE_CB) like to signal fence completion on
+     * threads ("callback threads") that are different from the thread that
+     * processes the command queue ("main thread").
+     *
+     * crosvm and other virtio-gpu 1.1 implementations enable callback threads
+     * via locking.  However, on QEMU a deadlock is observed if
+     * virtio_gpu_ctrl_response_nodata(..) [used in the fence callback] is used
+     * from a thread that is not the main thread.
+     *
+     * The reason is QEMU's internal locking is designed to work with QEMU
+     * threads (see rcu_register_thread()) and not generic C/C++/Rust threads.
+     * For now, we can workaround this by scheduling the return of the
+     * fence descriptors on the main thread.
+     */
+
+    data = g_new0(struct rutabaga_aio_data, 1);
+    data->vr = vr;
+    data->fence = *fence;
+    aio_bh_schedule_oneshot(qemu_get_aio_context(),
+                            virtio_gpu_rutabaga_aio_cb,
+                            data);
+}
+
+static void
+virtio_gpu_rutabaga_debug_cb(uint64_t user_data,
+                             const struct rutabaga_debug *debug) {
+
+    if (debug->debug_type == RUTABAGA_DEBUG_ERROR) {
+        error_report("%s", debug->message);
+    } else if (debug->debug_type == RUTABAGA_DEBUG_WARN) {
+        warn_report("%s", debug->message);
+    } else if (debug->debug_type == RUTABAGA_DEBUG_INFO) {
+        info_report("%s", debug->message);
+    }
+}
+
+static bool virtio_gpu_rutabaga_init(VirtIOGPU *g, Error **errp)
+{
+    int result;
+    uint64_t capset_mask;
+    struct rutabaga_builder builder = { 0 };
+    char wayland_socket_path[UNIX_PATH_MAX];
+    struct rutabaga_channel channel = { 0 };
+    struct rutabaga_channels channels = { 0 };
+
+    VirtIOGPURutabaga *vr = VIRTIO_GPU_RUTABAGA(g);
+    vr->rutabaga = NULL;
+
+    if (!vr->capset_names) {
+        error_setg(errp, "a capset name from the virtio-gpu spec is required");
+        return false;
+    }
+
+    builder.wsi = RUTABAGA_WSI_SURFACELESS;
+    /*
+     * Currently, if WSI is specified, the only valid strings are "surfaceless"
+     * or "headless".  Surfaceless doesn't create a native window surface, but
+     * does copy from the render target to the Pixman buffer if a virtio-gpu
+     * 2D hypercall is issued.  Surfacless is the default.
+     *
+     * Headless is like surfaceless, but doesn't copy to the Pixman buffer. The
+     * use case is automated testing environments where there is no need to view
+     * results.
+     *
+     * In the future, more performant virtio-gpu 2D UI integration may be added.
+     */
+    if (vr->wsi) {
+        if (g_str_equal(vr->wsi, "surfaceless")) {
+            vr->headless = false;
+        } else if (g_str_equal(vr->wsi, "headless")) {
+            vr->headless = true;
+        } else {
+            error_setg(errp, "invalid wsi option selected");
+            return false;
+        }
+    }
+
+    result = rutabaga_calculate_capset_mask(vr->capset_names, &capset_mask);
+    if (result) {
+        error_setg_errno(errp, -result, "invalid capset names: %s",
+                         vr->capset_names);
+        return false;
+    }
+
+    builder.fence_cb = virtio_gpu_rutabaga_fence_cb;
+    builder.debug_cb = virtio_gpu_rutabaga_debug_cb;
+    builder.capset_mask = capset_mask;
+    builder.user_data = (uint64_t)g;
+
+    /*
+     * If the user doesn't specify the wayland socket path, we try to infer
+     * the socket via a process similar to the one used by libwayland.
+     * libwayland does the following:
+     *
+     * 1) If $WAYLAND_DISPLAY is set, attempt to connect to
+     *    $XDG_RUNTIME_DIR/$WAYLAND_DISPLAY
+     * 2) Otherwise, attempt to connect to $XDG_RUNTIME_DIR/wayland-0
+     * 3) Otherwise, don't pass a wayland socket to rutabaga. If a guest
+     *    wayland proxy is launched, it will fail to work.
+     */
+    channel.channel_type = RUTABAGA_CHANNEL_TYPE_WAYLAND;
+    if (!vr->wayland_socket_path) {
+        const char *runtime_dir = getenv("XDG_RUNTIME_DIR");
+        const char *display = getenv("WAYLAND_DISPLAY");
+        if (!display) {
+            display = "wayland-0";
+        }
+
+        if (runtime_dir) {
+            result = snprintf(wayland_socket_path, UNIX_PATH_MAX,
+                              "%s/%s", runtime_dir, display);
+            if (result > 0 && result < UNIX_PATH_MAX) {
+                channel.channel_name = wayland_socket_path;
+            }
+        }
+    } else {
+        channel.channel_name = vr->wayland_socket_path;
+    }
+
+    if ((builder.capset_mask & (1 << RUTABAGA_CAPSET_CROSS_DOMAIN))) {
+        if (channel.channel_name) {
+            channels.channels = &channel;
+            channels.num_channels = 1;
+            builder.channels = &channels;
+        }
+    }
+
+    result = rutabaga_init(&builder, &vr->rutabaga);
+    if (result) {
+        error_setg_errno(errp, -result, "Failed to init rutabaga");
+        return result;
+    }
+
+    return true;
+}
+
+static int virtio_gpu_rutabaga_get_num_capsets(VirtIOGPU *g)
+{
+    int result;
+    uint32_t num_capsets;
+    VirtIOGPURutabaga *vr = VIRTIO_GPU_RUTABAGA(g);
+
+    result = rutabaga_get_num_capsets(vr->rutabaga, &num_capsets);
+    if (result) {
+        error_report("Failed to get capsets");
+        return 0;
+    }
+    vr->num_capsets = num_capsets;
+    return num_capsets;
+}
+
+static void virtio_gpu_rutabaga_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq)
+{
+    VirtIOGPU *g = VIRTIO_GPU(vdev);
+    struct virtio_gpu_ctrl_command *cmd;
+
+    if (!virtio_queue_ready(vq)) {
+        return;
+    }
+
+    cmd = virtqueue_pop(vq, sizeof(struct virtio_gpu_ctrl_command));
+    while (cmd) {
+        cmd->vq = vq;
+        cmd->error = 0;
+        cmd->finished = false;
+        QTAILQ_INSERT_TAIL(&g->cmdq, cmd, next);
+        cmd = virtqueue_pop(vq, sizeof(struct virtio_gpu_ctrl_command));
+    }
+
+    virtio_gpu_process_cmdq(g);
+}
+
+static void virtio_gpu_rutabaga_realize(DeviceState *qdev, Error **errp)
+{
+    int num_capsets;
+    VirtIOGPUBase *bdev = VIRTIO_GPU_BASE(qdev);
+    VirtIOGPU *gpudev = VIRTIO_GPU(qdev);
+
+#if HOST_BIG_ENDIAN
+    error_setg(errp, "rutabaga is not supported on bigendian platforms");
+    return;
+#endif
+
+    if (!virtio_gpu_rutabaga_init(gpudev, errp)) {
+        return;
+    }
+
+    num_capsets = virtio_gpu_rutabaga_get_num_capsets(gpudev);
+    if (!num_capsets) {
+        return;
+    }
+
+    bdev->conf.flags |= (1 << VIRTIO_GPU_FLAG_RUTABAGA_ENABLED);
+    bdev->conf.flags |= (1 << VIRTIO_GPU_FLAG_BLOB_ENABLED);
+    bdev->conf.flags |= (1 << VIRTIO_GPU_FLAG_CONTEXT_INIT_ENABLED);
+
+    bdev->virtio_config.num_capsets = num_capsets;
+    virtio_gpu_device_realize(qdev, errp);
+}
+
+static Property virtio_gpu_rutabaga_properties[] = {
+    DEFINE_PROP_STRING("capset_names", VirtIOGPURutabaga, capset_names),
+    DEFINE_PROP_STRING("wayland_socket_path", VirtIOGPURutabaga,
+                       wayland_socket_path),
+    DEFINE_PROP_STRING("wsi", VirtIOGPURutabaga, wsi),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void virtio_gpu_rutabaga_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass);
+    VirtIOGPUBaseClass *vbc = VIRTIO_GPU_BASE_CLASS(klass);
+    VirtIOGPUClass *vgc = VIRTIO_GPU_CLASS(klass);
+
+    vbc->gl_flushed = virtio_gpu_rutabaga_gl_flushed;
+    vgc->handle_ctrl = virtio_gpu_rutabaga_handle_ctrl;
+    vgc->process_cmd = virtio_gpu_rutabaga_process_cmd;
+    vgc->update_cursor_data = virtio_gpu_rutabaga_update_cursor;
+
+    vdc->realize = virtio_gpu_rutabaga_realize;
+    device_class_set_props(dc, virtio_gpu_rutabaga_properties);
+}
+
+static const TypeInfo virtio_gpu_rutabaga_info[] = {
+    {
+        .name = TYPE_VIRTIO_GPU_RUTABAGA,
+        .parent = TYPE_VIRTIO_GPU,
+        .instance_size = sizeof(VirtIOGPURutabaga),
+        .class_init = virtio_gpu_rutabaga_class_init,
+    },
+};
+
+DEFINE_TYPES(virtio_gpu_rutabaga_info)
+
+module_obj(TYPE_VIRTIO_GPU_RUTABAGA);
+module_kconfig(VIRTIO_GPU);
+module_dep("hw-display-virtio-gpu");
diff --git a/hw/display/virtio-vga-rutabaga.c b/hw/display/virtio-vga-rutabaga.c
new file mode 100644
index 0000000000..a7bef6da24
--- /dev/null
+++ b/hw/display/virtio-vga-rutabaga.c
@@ -0,0 +1,50 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#include "qemu/osdep.h"
+#include "hw/pci/pci.h"
+#include "hw/qdev-properties.h"
+#include "hw/virtio/virtio-gpu.h"
+#include "hw/display/vga.h"
+#include "qapi/error.h"
+#include "qemu/module.h"
+#include "virtio-vga.h"
+#include "qom/object.h"
+
+#define TYPE_VIRTIO_VGA_RUTABAGA "virtio-vga-rutabaga"
+
+OBJECT_DECLARE_SIMPLE_TYPE(VirtIOVGARutabaga, VIRTIO_VGA_RUTABAGA)
+
+struct VirtIOVGARutabaga {
+    VirtIOVGABase parent_obj;
+
+    VirtIOGPURutabaga vdev;
+};
+
+static void virtio_vga_rutabaga_inst_initfn(Object *obj)
+{
+    VirtIOVGARutabaga *dev = VIRTIO_VGA_RUTABAGA(obj);
+
+    virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
+                                TYPE_VIRTIO_GPU_RUTABAGA);
+    VIRTIO_VGA_BASE(dev)->vgpu = VIRTIO_GPU_BASE(&dev->vdev);
+}
+
+static VirtioPCIDeviceTypeInfo virtio_vga_rutabaga_info = {
+    .generic_name  = TYPE_VIRTIO_VGA_RUTABAGA,
+    .parent        = TYPE_VIRTIO_VGA_BASE,
+    .instance_size = sizeof(VirtIOVGARutabaga),
+    .instance_init = virtio_vga_rutabaga_inst_initfn,
+};
+module_obj(TYPE_VIRTIO_VGA_RUTABAGA);
+module_kconfig(VIRTIO_VGA);
+
+static void virtio_vga_register_types(void)
+{
+    if (have_vga) {
+        virtio_pci_types_register(&virtio_vga_rutabaga_info);
+    }
+}
+
+type_init(virtio_vga_register_types)
+
+module_dep("hw-display-virtio-vga");
-- 
2.42.0.rc2.253.gd59a3bf2b4-goog



^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PATCH v13 7/9] gfxstream + rutabaga: meson support
  2023-08-29  0:36 [PATCH v13 0/9] rutabaga_gfx + gfxstream Gurchetan Singh
                   ` (5 preceding siblings ...)
  2023-08-29  0:36 ` [PATCH v13 6/9] gfxstream + rutabaga: add initial support for gfxstream Gurchetan Singh
@ 2023-08-29  0:36 ` Gurchetan Singh
  2023-08-29  0:36 ` [PATCH v13 8/9] gfxstream + rutabaga: enable rutabaga Gurchetan Singh
                   ` (2 subsequent siblings)
  9 siblings, 0 replies; 27+ messages in thread
From: Gurchetan Singh @ 2023-08-29  0:36 UTC (permalink / raw)
  To: qemu-devel
  Cc: marcandre.lureau, akihiko.odaki, ray.huang, alex.bennee, shentey,
	hi, ernunes, manos.pitsidianakis, philmd, mark.cave-ayland

- Add meson detection of rutabaga_gfx
- Build virtio-gpu-rutabaga.c + associated vga/pci files when
  present

Signed-off-by: Gurchetan Singh <gurchetansingh@chromium.org>
Tested-by: Alyssa Ross <hi@alyssa.is>
Tested-by: Emmanouil Pitsidianakis <manos.pitsidianakis@linaro.org>
Tested-by: Akihiko Odaki <akihiko.odaki@daynix.com>
Reviewed-by: Emmanouil Pitsidianakis <manos.pitsidianakis@linaro.org>
Reviewed-by: Antonio Caggiano <quic_acaggian@quicinc.com>
Reviewed-by: Akihiko Odaki <akihiko.odaki@daynix.com>
---
 hw/display/meson.build        | 22 ++++++++++++++++++++++
 meson.build                   |  7 +++++++
 meson_options.txt             |  2 ++
 scripts/meson-buildoptions.sh |  3 +++
 4 files changed, 34 insertions(+)

diff --git a/hw/display/meson.build b/hw/display/meson.build
index 413ba4ab24..e362d625dd 100644
--- a/hw/display/meson.build
+++ b/hw/display/meson.build
@@ -79,6 +79,13 @@ if config_all_devices.has_key('CONFIG_VIRTIO_GPU')
                          if_true: [files('virtio-gpu-gl.c', 'virtio-gpu-virgl.c'), pixman, virgl])
     hw_display_modules += {'virtio-gpu-gl': virtio_gpu_gl_ss}
   endif
+
+  if rutabaga.found()
+    virtio_gpu_rutabaga_ss = ss.source_set()
+    virtio_gpu_rutabaga_ss.add(when: ['CONFIG_VIRTIO_GPU', rutabaga],
+                               if_true: [files('virtio-gpu-rutabaga.c'), pixman])
+    hw_display_modules += {'virtio-gpu-rutabaga': virtio_gpu_rutabaga_ss}
+  endif
 endif
 
 if config_all_devices.has_key('CONFIG_VIRTIO_PCI')
@@ -95,6 +102,12 @@ if config_all_devices.has_key('CONFIG_VIRTIO_PCI')
                              if_true: [files('virtio-gpu-pci-gl.c'), pixman])
     hw_display_modules += {'virtio-gpu-pci-gl': virtio_gpu_pci_gl_ss}
   endif
+  if rutabaga.found()
+    virtio_gpu_pci_rutabaga_ss = ss.source_set()
+    virtio_gpu_pci_rutabaga_ss.add(when: ['CONFIG_VIRTIO_GPU', 'CONFIG_VIRTIO_PCI', rutabaga],
+                                   if_true: [files('virtio-gpu-pci-rutabaga.c'), pixman])
+    hw_display_modules += {'virtio-gpu-pci-rutabaga': virtio_gpu_pci_rutabaga_ss}
+  endif
 endif
 
 if config_all_devices.has_key('CONFIG_VIRTIO_VGA')
@@ -113,6 +126,15 @@ if config_all_devices.has_key('CONFIG_VIRTIO_VGA')
   virtio_vga_gl_ss.add(when: 'CONFIG_ACPI', if_true: files('acpi-vga.c'),
                                             if_false: files('acpi-vga-stub.c'))
   hw_display_modules += {'virtio-vga-gl': virtio_vga_gl_ss}
+
+  if rutabaga.found()
+    virtio_vga_rutabaga_ss = ss.source_set()
+    virtio_vga_rutabaga_ss.add(when: ['CONFIG_VIRTIO_VGA', rutabaga],
+                               if_true: [files('virtio-vga-rutabaga.c'), pixman])
+    virtio_vga_rutabaga_ss.add(when: 'CONFIG_ACPI', if_true: files('acpi-vga.c'),
+                                                    if_false: files('acpi-vga-stub.c'))
+    hw_display_modules += {'virtio-vga-rutabaga': virtio_vga_rutabaga_ss}
+  endif
 endif
 
 system_ss.add(when: 'CONFIG_OMAP', if_true: files('omap_lcdc.c'))
diff --git a/meson.build b/meson.build
index 98e68ef0b1..293f388e53 100644
--- a/meson.build
+++ b/meson.build
@@ -1069,6 +1069,12 @@ if not get_option('virglrenderer').auto() or have_system or have_vhost_user_gpu
                                        dependencies: virgl))
   endif
 endif
+rutabaga = not_found
+if not get_option('rutabaga_gfx').auto() or have_system or have_vhost_user_gpu
+  rutabaga = dependency('rutabaga_gfx_ffi',
+                         method: 'pkg-config',
+                         required: get_option('rutabaga_gfx'))
+endif
 blkio = not_found
 if not get_option('blkio').auto() or have_block
   blkio = dependency('blkio',
@@ -4272,6 +4278,7 @@ summary_info += {'libtasn1':          tasn1}
 summary_info += {'PAM':               pam}
 summary_info += {'iconv support':     iconv}
 summary_info += {'virgl support':     virgl}
+summary_info += {'rutabaga support':  rutabaga}
 summary_info += {'blkio support':     blkio}
 summary_info += {'curl support':      curl}
 summary_info += {'Multipath support': mpathpersist}
diff --git a/meson_options.txt b/meson_options.txt
index aaea5ddd77..dea3bf7d9c 100644
--- a/meson_options.txt
+++ b/meson_options.txt
@@ -224,6 +224,8 @@ option('vmnet', type : 'feature', value : 'auto',
        description: 'vmnet.framework network backend support')
 option('virglrenderer', type : 'feature', value : 'auto',
        description: 'virgl rendering support')
+option('rutabaga_gfx', type : 'feature', value : 'auto',
+       description: 'rutabaga_gfx support')
 option('png', type : 'feature', value : 'auto',
        description: 'PNG support with libpng')
 option('vnc', type : 'feature', value : 'auto',
diff --git a/scripts/meson-buildoptions.sh b/scripts/meson-buildoptions.sh
index 9da3fe299b..9a95b4f782 100644
--- a/scripts/meson-buildoptions.sh
+++ b/scripts/meson-buildoptions.sh
@@ -154,6 +154,7 @@ meson_options_help() {
   printf "%s\n" '  rbd             Ceph block device driver'
   printf "%s\n" '  rdma            Enable RDMA-based migration'
   printf "%s\n" '  replication     replication support'
+  printf "%s\n" '  rutabaga-gfx    rutabaga_gfx support'
   printf "%s\n" '  sdl             SDL user interface'
   printf "%s\n" '  sdl-image       SDL Image support for icons'
   printf "%s\n" '  seccomp         seccomp support'
@@ -419,6 +420,8 @@ _meson_option_parse() {
     --disable-replication) printf "%s" -Dreplication=disabled ;;
     --enable-rng-none) printf "%s" -Drng_none=true ;;
     --disable-rng-none) printf "%s" -Drng_none=false ;;
+    --enable-rutabaga-gfx) printf "%s" -Drutabaga_gfx=enabled ;;
+    --disable-rutabaga-gfx) printf "%s" -Drutabaga_gfx=disabled ;;
     --enable-safe-stack) printf "%s" -Dsafe_stack=true ;;
     --disable-safe-stack) printf "%s" -Dsafe_stack=false ;;
     --enable-sanitizers) printf "%s" -Dsanitizers=true ;;
-- 
2.42.0.rc2.253.gd59a3bf2b4-goog



^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PATCH v13 8/9] gfxstream + rutabaga: enable rutabaga
  2023-08-29  0:36 [PATCH v13 0/9] rutabaga_gfx + gfxstream Gurchetan Singh
                   ` (6 preceding siblings ...)
  2023-08-29  0:36 ` [PATCH v13 7/9] gfxstream + rutabaga: meson support Gurchetan Singh
@ 2023-08-29  0:36 ` Gurchetan Singh
  2023-08-29  0:36 ` [PATCH v13 9/9] docs/system: add basic virtio-gpu documentation Gurchetan Singh
  2023-08-31  2:25 ` [PATCH v13 0/9] rutabaga_gfx + gfxstream Huang Rui
  9 siblings, 0 replies; 27+ messages in thread
From: Gurchetan Singh @ 2023-08-29  0:36 UTC (permalink / raw)
  To: qemu-devel
  Cc: marcandre.lureau, akihiko.odaki, ray.huang, alex.bennee, shentey,
	hi, ernunes, manos.pitsidianakis, philmd, mark.cave-ayland

This change enables rutabaga to receive virtio-gpu-3d hypercalls
when it is active.

Signed-off-by: Gurchetan Singh <gurchetansingh@chromium.org>
Tested-by: Alyssa Ross <hi@alyssa.is>
Tested-by: Emmanouil Pitsidianakis <manos.pitsidianakis@linaro.org>
Tested-by: Akihiko Odaki <akihiko.odaki@daynix.com>
Reviewed-by: Antonio Caggiano <quic_acaggian@quicinc.com>
Reviewed-by: Emmanouil Pitsidianakis <manos.pitsidianakis@linaro.org>
Reviewed-by: Akihiko Odaki <akihiko.odaki@daynix.com>
---
 hw/display/virtio-gpu-base.c | 3 ++-
 hw/display/virtio-gpu.c      | 5 +++--
 softmmu/qdev-monitor.c       | 3 +++
 softmmu/vl.c                 | 1 +
 4 files changed, 9 insertions(+), 3 deletions(-)

diff --git a/hw/display/virtio-gpu-base.c b/hw/display/virtio-gpu-base.c
index 4f2b0ba1f3..50c5373b65 100644
--- a/hw/display/virtio-gpu-base.c
+++ b/hw/display/virtio-gpu-base.c
@@ -223,7 +223,8 @@ virtio_gpu_base_get_features(VirtIODevice *vdev, uint64_t features,
 {
     VirtIOGPUBase *g = VIRTIO_GPU_BASE(vdev);
 
-    if (virtio_gpu_virgl_enabled(g->conf)) {
+    if (virtio_gpu_virgl_enabled(g->conf) ||
+        virtio_gpu_rutabaga_enabled(g->conf)) {
         features |= (1 << VIRTIO_GPU_F_VIRGL);
     }
     if (virtio_gpu_edid_enabled(g->conf)) {
diff --git a/hw/display/virtio-gpu.c b/hw/display/virtio-gpu.c
index 3e658f1fef..fe094addef 100644
--- a/hw/display/virtio-gpu.c
+++ b/hw/display/virtio-gpu.c
@@ -1361,8 +1361,9 @@ void virtio_gpu_device_realize(DeviceState *qdev, Error **errp)
     VirtIOGPU *g = VIRTIO_GPU(qdev);
 
     if (virtio_gpu_blob_enabled(g->parent_obj.conf)) {
-        if (!virtio_gpu_have_udmabuf()) {
-            error_setg(errp, "cannot enable blob resources without udmabuf");
+        if (!virtio_gpu_rutabaga_enabled(g->parent_obj.conf) &&
+            !virtio_gpu_have_udmabuf()) {
+            error_setg(errp, "need rutabaga or udmabuf for blob resources");
             return;
         }
 
diff --git a/softmmu/qdev-monitor.c b/softmmu/qdev-monitor.c
index 74f4e41338..1b8005ae55 100644
--- a/softmmu/qdev-monitor.c
+++ b/softmmu/qdev-monitor.c
@@ -86,6 +86,9 @@ static const QDevAlias qdev_alias_table[] = {
     { "virtio-gpu-pci", "virtio-gpu", QEMU_ARCH_VIRTIO_PCI },
     { "virtio-gpu-gl-device", "virtio-gpu-gl", QEMU_ARCH_VIRTIO_MMIO },
     { "virtio-gpu-gl-pci", "virtio-gpu-gl", QEMU_ARCH_VIRTIO_PCI },
+    { "virtio-gpu-rutabaga-device", "virtio-gpu-rutabaga",
+      QEMU_ARCH_VIRTIO_MMIO },
+    { "virtio-gpu-rutabaga-pci", "virtio-gpu-rutabaga", QEMU_ARCH_VIRTIO_PCI },
     { "virtio-input-host-device", "virtio-input-host", QEMU_ARCH_VIRTIO_MMIO },
     { "virtio-input-host-ccw", "virtio-input-host", QEMU_ARCH_VIRTIO_CCW },
     { "virtio-input-host-pci", "virtio-input-host", QEMU_ARCH_VIRTIO_PCI },
diff --git a/softmmu/vl.c b/softmmu/vl.c
index b0b96f67fa..2f98eefdf3 100644
--- a/softmmu/vl.c
+++ b/softmmu/vl.c
@@ -216,6 +216,7 @@ static struct {
     { .driver = "ati-vga",              .flag = &default_vga       },
     { .driver = "vhost-user-vga",       .flag = &default_vga       },
     { .driver = "virtio-vga-gl",        .flag = &default_vga       },
+    { .driver = "virtio-vga-rutabaga",  .flag = &default_vga       },
 };
 
 static QemuOptsList qemu_rtc_opts = {
-- 
2.42.0.rc2.253.gd59a3bf2b4-goog



^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PATCH v13 9/9] docs/system: add basic virtio-gpu documentation
  2023-08-29  0:36 [PATCH v13 0/9] rutabaga_gfx + gfxstream Gurchetan Singh
                   ` (7 preceding siblings ...)
  2023-08-29  0:36 ` [PATCH v13 8/9] gfxstream + rutabaga: enable rutabaga Gurchetan Singh
@ 2023-08-29  0:36 ` Gurchetan Singh
  2023-08-31  2:25 ` [PATCH v13 0/9] rutabaga_gfx + gfxstream Huang Rui
  9 siblings, 0 replies; 27+ messages in thread
From: Gurchetan Singh @ 2023-08-29  0:36 UTC (permalink / raw)
  To: qemu-devel
  Cc: marcandre.lureau, akihiko.odaki, ray.huang, alex.bennee, shentey,
	hi, ernunes, manos.pitsidianakis, philmd, mark.cave-ayland

This adds basic documentation for virtio-gpu.

Suggested-by: Akihiko Odaki <akihiko.odaki@daynix.com>
Signed-off-by: Gurchetan Singh <gurchetansingh@chromium.org>
Tested-by: Alyssa Ross <hi@alyssa.is>
Tested-by: Emmanouil Pitsidianakis <manos.pitsidianakis@linaro.org>
Tested-by: Akihiko Odaki <akihiko.odaki@daynix.com>
Reviewed-by: Emmanouil Pitsidianakis <manos.pitsidianakis@linaro.org>
Reviewed-by: Antonio Caggiano <quic_acaggian@quicinc.com>
Reviewed-by: Akihiko Odaki <akihiko.odaki@daynix.com>
---
 docs/system/device-emulation.rst   |   1 +
 docs/system/devices/virtio-gpu.rst | 112 +++++++++++++++++++++++++++++
 2 files changed, 113 insertions(+)
 create mode 100644 docs/system/devices/virtio-gpu.rst

diff --git a/docs/system/device-emulation.rst b/docs/system/device-emulation.rst
index 4491c4cbf7..1167f3a9f2 100644
--- a/docs/system/device-emulation.rst
+++ b/docs/system/device-emulation.rst
@@ -91,6 +91,7 @@ Emulated Devices
    devices/nvme.rst
    devices/usb.rst
    devices/vhost-user.rst
+   devices/virtio-gpu.rst
    devices/virtio-pmem.rst
    devices/vhost-user-rng.rst
    devices/canokey.rst
diff --git a/docs/system/devices/virtio-gpu.rst b/docs/system/devices/virtio-gpu.rst
new file mode 100644
index 0000000000..21465e4ce2
--- /dev/null
+++ b/docs/system/devices/virtio-gpu.rst
@@ -0,0 +1,112 @@
+..
+   SPDX-License-Identifier: GPL-2.0-or-later
+
+virtio-gpu
+==========
+
+This document explains the setup and usage of the virtio-gpu device.
+The virtio-gpu device paravirtualizes the GPU and display controller.
+
+Linux kernel support
+--------------------
+
+virtio-gpu requires a guest Linux kernel built with the
+``CONFIG_DRM_VIRTIO_GPU`` option.
+
+QEMU virtio-gpu variants
+------------------------
+
+QEMU virtio-gpu device variants come in the following form:
+
+ * ``virtio-vga[-BACKEND]``
+ * ``virtio-gpu[-BACKEND][-INTERFACE]``
+ * ``vhost-user-vga``
+ * ``vhost-user-pci``
+
+**Backends:** QEMU provides a 2D virtio-gpu backend, and two accelerated
+backends: virglrenderer ('gl' device label) and rutabaga_gfx ('rutabaga'
+device label).  There is a vhost-user backend that runs the graphics stack
+in a separate process for improved isolation.
+
+**Interfaces:** QEMU further categorizes virtio-gpu device variants based
+on the interface exposed to the guest. The interfaces can be classified
+into VGA and non-VGA variants. The VGA ones are prefixed with virtio-vga
+or vhost-user-vga while the non-VGA ones are prefixed with virtio-gpu or
+vhost-user-gpu.
+
+The VGA ones always use the PCI interface, but for the non-VGA ones, the
+user can further pick between MMIO or PCI. For MMIO, the user can suffix
+the device name with -device, though vhost-user-gpu does not support MMIO.
+For PCI, the user can suffix it with -pci. Without these suffixes, the
+platform default will be chosen.
+
+virtio-gpu 2d
+-------------
+
+The default 2D backend only performs 2D operations. The guest needs to
+employ a software renderer for 3D graphics.
+
+Typically, the software renderer is provided by `Mesa`_ or `SwiftShader`_.
+Mesa's implementations (LLVMpipe, Lavapipe and virgl below) work out of box
+on typical modern Linux distributions.
+
+.. parsed-literal::
+    -device virtio-gpu
+
+.. _Mesa: https://www.mesa3d.org/
+.. _SwiftShader: https://github.com/google/swiftshader
+
+virtio-gpu virglrenderer
+------------------------
+
+When using virgl accelerated graphics mode in the guest, OpenGL API calls
+are translated into an intermediate representation (see `Gallium3D`_). The
+intermediate representation is communicated to the host and the
+`virglrenderer`_ library on the host translates the intermediate
+representation back to OpenGL API calls.
+
+.. parsed-literal::
+    -device virtio-gpu-gl
+
+.. _Gallium3D: https://www.freedesktop.org/wiki/Software/gallium/
+.. _virglrenderer: https://gitlab.freedesktop.org/virgl/virglrenderer/
+
+virtio-gpu rutabaga
+-------------------
+
+virtio-gpu can also leverage rutabaga_gfx to provide `gfxstream`_
+rendering and `Wayland display passthrough`_.  With the gfxstream rendering
+mode, GLES and Vulkan calls are forwarded to the host with minimal
+modification.
+
+The crosvm book provides directions on how to build a `gfxstream-enabled
+rutabaga`_ and launch a `guest Wayland proxy`_.
+
+This device does require host blob support (``hostmem`` field below). The
+``hostmem`` field specifies the size of virtio-gpu host memory window.
+This is typically between 256M and 8G.
+
+At least one capset (see colon separated ``capset_names`` below) must be
+specified when starting the device.  The currently supported
+``capset_names`` are ``gfxstream-vulkan`` and ``cross-domain`` on Linux
+guests. For Android guests, ``gfxstream-gles`` is also supported.
+
+The device will try to auto-detect the wayland socket path if the
+``cross-domain`` capset name is set.  The user may optionally specify
+``wayland_socket_path`` for non-standard paths.
+
+The ``wsi`` option can be set to ``surfaceless`` or ``headless``.
+Surfaceless doesn't create a native window surface, but does copy from the
+render target to the Pixman buffer if a virtio-gpu 2D hypercall is issued.
+Headless is like surfaceless, but doesn't copy to the Pixman buffer.
+Surfaceless is the default if ``wsi`` is not specified.
+
+.. parsed-literal::
+    -device virtio-gpu-rutabaga,capset_names=gfxstream-vulkan:cross-domain,
+       hostmem=8G,wayland_socket_path=/tmp/nonstandard/mock_wayland.sock,
+       wsi=headless
+
+.. _gfxstream: https://android.googlesource.com/platform/hardware/google/gfxstream/
+.. _Wayland display passthrough: https://www.youtube.com/watch?v=OZJiHMtIQ2M
+.. _gfxstream-enabled rutabaga: https://crosvm.dev/book/appendix/rutabaga_gfx.html
+.. _guest Wayland proxy: https://crosvm.dev/book/devices/wayland.html
-- 
2.42.0.rc2.253.gd59a3bf2b4-goog



^ permalink raw reply related	[flat|nested] 27+ messages in thread

* Re: [PATCH v13 0/9] rutabaga_gfx + gfxstream
  2023-08-29  0:36 [PATCH v13 0/9] rutabaga_gfx + gfxstream Gurchetan Singh
                   ` (8 preceding siblings ...)
  2023-08-29  0:36 ` [PATCH v13 9/9] docs/system: add basic virtio-gpu documentation Gurchetan Singh
@ 2023-08-31  2:25 ` Huang Rui
  2023-09-06  1:20   ` Gurchetan Singh
  9 siblings, 1 reply; 27+ messages in thread
From: Huang Rui @ 2023-08-31  2:25 UTC (permalink / raw)
  To: Gurchetan Singh
  Cc: qemu-devel, marcandre.lureau, akihiko.odaki, alex.bennee,
	shentey, hi, ernunes, manos.pitsidianakis, philmd,
	mark.cave-ayland

On Tue, Aug 29, 2023 at 08:36:20AM +0800, Gurchetan Singh wrote:
> From: Gurchetan Singh <gurchetansingh@google.com>
> 
> Changes since v12:
> - Added r-b tags from Antonio Caggiano and Akihiko Odaki
> - Removed review version from commit messages
> - I think we're good to merge since we've had multiple people test and review this series??
> 
> How to build both rutabaga and gfxstream guest/host libs:
> 
> https://crosvm.dev/book/appendix/rutabaga_gfx.html
> 
> Branch containing this patch series:
> 
> https://gitlab.com/gurchetansingh/qemu/-/commits/qemu-gfxstream-v13
> 
> Antonio Caggiano (2):
>   virtio-gpu: CONTEXT_INIT feature
>   virtio-gpu: blob prep
> 
> Dr. David Alan Gilbert (1):
>   virtio: Add shared memory capability
> 
> Gerd Hoffmann (1):
>   virtio-gpu: hostmem

Patch 1 -> 4 are

Acked-and-Tested-by: Huang Rui <ray.huang@amd.com>

> 
> Gurchetan Singh (5):
>   gfxstream + rutabaga prep: added need defintions, fields, and options
>   gfxstream + rutabaga: add initial support for gfxstream
>   gfxstream + rutabaga: meson support
>   gfxstream + rutabaga: enable rutabaga
>   docs/system: add basic virtio-gpu documentation
> 
>  docs/system/device-emulation.rst     |    1 +
>  docs/system/devices/virtio-gpu.rst   |  112 +++
>  hw/display/meson.build               |   22 +
>  hw/display/virtio-gpu-base.c         |    6 +-
>  hw/display/virtio-gpu-pci-rutabaga.c |   47 ++
>  hw/display/virtio-gpu-pci.c          |   14 +
>  hw/display/virtio-gpu-rutabaga.c     | 1119 ++++++++++++++++++++++++++
>  hw/display/virtio-gpu.c              |   16 +-
>  hw/display/virtio-vga-rutabaga.c     |   50 ++
>  hw/display/virtio-vga.c              |   33 +-
>  hw/virtio/virtio-pci.c               |   18 +
>  include/hw/virtio/virtio-gpu-bswap.h |   15 +
>  include/hw/virtio/virtio-gpu.h       |   41 +
>  include/hw/virtio/virtio-pci.h       |    4 +
>  meson.build                          |    7 +
>  meson_options.txt                    |    2 +
>  scripts/meson-buildoptions.sh        |    3 +
>  softmmu/qdev-monitor.c               |    3 +
>  softmmu/vl.c                         |    1 +
>  19 files changed, 1495 insertions(+), 19 deletions(-)
>  create mode 100644 docs/system/devices/virtio-gpu.rst
>  create mode 100644 hw/display/virtio-gpu-pci-rutabaga.c
>  create mode 100644 hw/display/virtio-gpu-rutabaga.c
>  create mode 100644 hw/display/virtio-vga-rutabaga.c
> 
> -- 
> 2.42.0.rc2.253.gd59a3bf2b4-goog
> 


^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH v13 0/9] rutabaga_gfx + gfxstream
  2023-08-31  2:25 ` [PATCH v13 0/9] rutabaga_gfx + gfxstream Huang Rui
@ 2023-09-06  1:20   ` Gurchetan Singh
  2023-09-06  6:25     ` Marc-André Lureau
  2023-09-12 13:59     ` Marc-André Lureau
  0 siblings, 2 replies; 27+ messages in thread
From: Gurchetan Singh @ 2023-09-06  1:20 UTC (permalink / raw)
  To: Huang Rui
  Cc: qemu-devel, marcandre.lureau, akihiko.odaki, alex.bennee,
	shentey, hi, ernunes, manos.pitsidianakis, philmd,
	mark.cave-ayland, Gerd Hoffmann

[-- Attachment #1: Type: text/plain, Size: 3042 bytes --]

On Wed, Aug 30, 2023 at 7:26 PM Huang Rui <ray.huang@amd.com> wrote:

> On Tue, Aug 29, 2023 at 08:36:20AM +0800, Gurchetan Singh wrote:
> > From: Gurchetan Singh <gurchetansingh@google.com>
> >
> > Changes since v12:
> > - Added r-b tags from Antonio Caggiano and Akihiko Odaki
> > - Removed review version from commit messages
> > - I think we're good to merge since we've had multiple people test and
> review this series??
> >
> > How to build both rutabaga and gfxstream guest/host libs:
> >
> > https://crosvm.dev/book/appendix/rutabaga_gfx.html
> >
> > Branch containing this patch series:
> >
> > https://gitlab.com/gurchetansingh/qemu/-/commits/qemu-gfxstream-v13
> >
> > Antonio Caggiano (2):
> >   virtio-gpu: CONTEXT_INIT feature
> >   virtio-gpu: blob prep
> >
> > Dr. David Alan Gilbert (1):
> >   virtio: Add shared memory capability
> >
> > Gerd Hoffmann (1):
> >   virtio-gpu: hostmem
>
> Patch 1 -> 4 are
>
> Acked-and-Tested-by: Huang Rui <ray.huang@amd.com>
>

Thanks Ray, I've rebased
https://gitlab.com/gurchetansingh/qemu/-/commits/qemu-gfxstream-v13 and
added the additional acks in the commit message.

UI/gfx maintainers, since everything is reviewed and there hasn't been any
additional review comments, may we merge the gfxstream + rutabaga_gfx
series?  Thank you!




>
> >
> > Gurchetan Singh (5):
> >   gfxstream + rutabaga prep: added need defintions, fields, and options
> >   gfxstream + rutabaga: add initial support for gfxstream
> >   gfxstream + rutabaga: meson support
> >   gfxstream + rutabaga: enable rutabaga
> >   docs/system: add basic virtio-gpu documentation
> >
> >  docs/system/device-emulation.rst     |    1 +
> >  docs/system/devices/virtio-gpu.rst   |  112 +++
> >  hw/display/meson.build               |   22 +
> >  hw/display/virtio-gpu-base.c         |    6 +-
> >  hw/display/virtio-gpu-pci-rutabaga.c |   47 ++
> >  hw/display/virtio-gpu-pci.c          |   14 +
> >  hw/display/virtio-gpu-rutabaga.c     | 1119 ++++++++++++++++++++++++++
> >  hw/display/virtio-gpu.c              |   16 +-
> >  hw/display/virtio-vga-rutabaga.c     |   50 ++
> >  hw/display/virtio-vga.c              |   33 +-
> >  hw/virtio/virtio-pci.c               |   18 +
> >  include/hw/virtio/virtio-gpu-bswap.h |   15 +
> >  include/hw/virtio/virtio-gpu.h       |   41 +
> >  include/hw/virtio/virtio-pci.h       |    4 +
> >  meson.build                          |    7 +
> >  meson_options.txt                    |    2 +
> >  scripts/meson-buildoptions.sh        |    3 +
> >  softmmu/qdev-monitor.c               |    3 +
> >  softmmu/vl.c                         |    1 +
> >  19 files changed, 1495 insertions(+), 19 deletions(-)
> >  create mode 100644 docs/system/devices/virtio-gpu.rst
> >  create mode 100644 hw/display/virtio-gpu-pci-rutabaga.c
> >  create mode 100644 hw/display/virtio-gpu-rutabaga.c
> >  create mode 100644 hw/display/virtio-vga-rutabaga.c
> >
> > --
> > 2.42.0.rc2.253.gd59a3bf2b4-goog
> >
>

[-- Attachment #2: Type: text/html, Size: 4503 bytes --]

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH v13 0/9] rutabaga_gfx + gfxstream
  2023-09-06  1:20   ` Gurchetan Singh
@ 2023-09-06  6:25     ` Marc-André Lureau
  2023-09-13 21:03       ` Bernhard Beschow
  2023-09-12 13:59     ` Marc-André Lureau
  1 sibling, 1 reply; 27+ messages in thread
From: Marc-André Lureau @ 2023-09-06  6:25 UTC (permalink / raw)
  To: Gurchetan Singh, Michael S. Tsirkin
  Cc: Huang Rui, qemu-devel, akihiko.odaki, alex.bennee, shentey, hi,
	ernunes, manos.pitsidianakis, philmd, mark.cave-ayland,
	Gerd Hoffmann

Hi

On Wed, Sep 6, 2023 at 5:22 AM Gurchetan Singh
<gurchetansingh@chromium.org> wrote:
>
>
>
> On Wed, Aug 30, 2023 at 7:26 PM Huang Rui <ray.huang@amd.com> wrote:
>>
>> On Tue, Aug 29, 2023 at 08:36:20AM +0800, Gurchetan Singh wrote:
>> > From: Gurchetan Singh <gurchetansingh@google.com>
>> >
>> > Changes since v12:
>> > - Added r-b tags from Antonio Caggiano and Akihiko Odaki
>> > - Removed review version from commit messages
>> > - I think we're good to merge since we've had multiple people test and review this series??
>> >
>> > How to build both rutabaga and gfxstream guest/host libs:
>> >
>> > https://crosvm.dev/book/appendix/rutabaga_gfx.html
>> >
>> > Branch containing this patch series:
>> >
>> > https://gitlab.com/gurchetansingh/qemu/-/commits/qemu-gfxstream-v13
>> >
>> > Antonio Caggiano (2):
>> >   virtio-gpu: CONTEXT_INIT feature
>> >   virtio-gpu: blob prep
>> >
>> > Dr. David Alan Gilbert (1):
>> >   virtio: Add shared memory capability
>> >
>> > Gerd Hoffmann (1):
>> >   virtio-gpu: hostmem
>>
>> Patch 1 -> 4 are
>>
>> Acked-and-Tested-by: Huang Rui <ray.huang@amd.com>
>
>
> Thanks Ray, I've rebased https://gitlab.com/gurchetansingh/qemu/-/commits/qemu-gfxstream-v13 and added the additional acks in the commit message.
>
> UI/gfx maintainers, since everything is reviewed and there hasn't been any additional review comments, may we merge the gfxstream + rutabaga_gfx series?  Thank you!
>

I can take it, or Michael (since Gerd is not focused on QEMU atm).

Michael, are you prepping a virtio PR?

thanks

-- 
Marc-André Lureau


^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH v13 0/9] rutabaga_gfx + gfxstream
  2023-09-06  1:20   ` Gurchetan Singh
  2023-09-06  6:25     ` Marc-André Lureau
@ 2023-09-12 13:59     ` Marc-André Lureau
  2023-09-13  1:08       ` Gurchetan Singh
  1 sibling, 1 reply; 27+ messages in thread
From: Marc-André Lureau @ 2023-09-12 13:59 UTC (permalink / raw)
  To: Gurchetan Singh
  Cc: Huang Rui, qemu-devel, akihiko.odaki, alex.bennee, shentey, hi,
	ernunes, manos.pitsidianakis, philmd, mark.cave-ayland,
	Gerd Hoffmann

Hi Gurchetan

On Wed, Sep 6, 2023 at 5:22 AM Gurchetan Singh
<gurchetansingh@chromium.org> wrote:
>
>
>
> On Wed, Aug 30, 2023 at 7:26 PM Huang Rui <ray.huang@amd.com> wrote:
>>
>> On Tue, Aug 29, 2023 at 08:36:20AM +0800, Gurchetan Singh wrote:
>> > From: Gurchetan Singh <gurchetansingh@google.com>
>> >
>> > Changes since v12:
>> > - Added r-b tags from Antonio Caggiano and Akihiko Odaki
>> > - Removed review version from commit messages
>> > - I think we're good to merge since we've had multiple people test and review this series??
>> >
>> > How to build both rutabaga and gfxstream guest/host libs:
>> >
>> > https://crosvm.dev/book/appendix/rutabaga_gfx.html
>> >
>> > Branch containing this patch series:
>> >
>> > https://gitlab.com/gurchetansingh/qemu/-/commits/qemu-gfxstream-v13
>> >
>> > Antonio Caggiano (2):
>> >   virtio-gpu: CONTEXT_INIT feature
>> >   virtio-gpu: blob prep
>> >
>> > Dr. David Alan Gilbert (1):
>> >   virtio: Add shared memory capability
>> >
>> > Gerd Hoffmann (1):
>> >   virtio-gpu: hostmem
>>
>> Patch 1 -> 4 are
>>
>> Acked-and-Tested-by: Huang Rui <ray.huang@amd.com>
>
>
> Thanks Ray, I've rebased https://gitlab.com/gurchetansingh/qemu/-/commits/qemu-gfxstream-v13 and added the additional acks in the commit message.
>
> UI/gfx maintainers, since everything is reviewed and there hasn't been any additional review comments, may we merge the gfxstream + rutabaga_gfx series?  Thank you!
>
>

Packaging aemu and gfxstream is a bit problematic. I have some WIP
Fedora packages.

AEMU:
- installs files under /usr/include/host-common and
/usr/include/snapshot. Can this be moved under /usr/include/aemu
instead?
- builds only static versions of libaemu-host-common.a and
liblogging-base.a (distros don't like static libs much)
- could liblogging-base(.a,.so,..) also have "aemu" name in it?
- libaemu-base.so is not versioned
- I can't find a release tarball, nor the (v0.1.2) release tag
- could have a README file

I am not very familiar with cmake, so it's not obvious how to make the
required changes. Would you like me to open an issue (where?) or try
to make some patches?

gfxstream:
- libgfxtream_backend.so is not versioned
- I can't find a release tarball, nor the (v0.1.2) release tag


(packaging is important so we can build the new code in CI too!)

thanks

-- 
Marc-André Lureau


^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH v13 0/9] rutabaga_gfx + gfxstream
  2023-09-12 13:59     ` Marc-André Lureau
@ 2023-09-13  1:08       ` Gurchetan Singh
  2023-09-13 13:49         ` Marc-André Lureau
  0 siblings, 1 reply; 27+ messages in thread
From: Gurchetan Singh @ 2023-09-13  1:08 UTC (permalink / raw)
  To: Marc-André Lureau
  Cc: Huang Rui, qemu-devel, akihiko.odaki, alex.bennee, shentey, hi,
	ernunes, manos.pitsidianakis, philmd, mark.cave-ayland,
	Gerd Hoffmann

[-- Attachment #1: Type: text/plain, Size: 4320 bytes --]

On Tue, Sep 12, 2023 at 6:59 AM Marc-André Lureau <
marcandre.lureau@gmail.com> wrote:

> Hi Gurchetan
>
> On Wed, Sep 6, 2023 at 5:22 AM Gurchetan Singh
> <gurchetansingh@chromium.org> wrote:
> >
> >
> >
> > On Wed, Aug 30, 2023 at 7:26 PM Huang Rui <ray.huang@amd.com> wrote:
> >>
> >> On Tue, Aug 29, 2023 at 08:36:20AM +0800, Gurchetan Singh wrote:
> >> > From: Gurchetan Singh <gurchetansingh@google.com>
> >> >
> >> > Changes since v12:
> >> > - Added r-b tags from Antonio Caggiano and Akihiko Odaki
> >> > - Removed review version from commit messages
> >> > - I think we're good to merge since we've had multiple people test
> and review this series??
> >> >
> >> > How to build both rutabaga and gfxstream guest/host libs:
> >> >
> >> > https://crosvm.dev/book/appendix/rutabaga_gfx.html
> >> >
> >> > Branch containing this patch series:
> >> >
> >> > https://gitlab.com/gurchetansingh/qemu/-/commits/qemu-gfxstream-v13
> >> >
> >> > Antonio Caggiano (2):
> >> >   virtio-gpu: CONTEXT_INIT feature
> >> >   virtio-gpu: blob prep
> >> >
> >> > Dr. David Alan Gilbert (1):
> >> >   virtio: Add shared memory capability
> >> >
> >> > Gerd Hoffmann (1):
> >> >   virtio-gpu: hostmem
> >>
> >> Patch 1 -> 4 are
> >>
> >> Acked-and-Tested-by: Huang Rui <ray.huang@amd.com>
> >
> >
> > Thanks Ray, I've rebased
> https://gitlab.com/gurchetansingh/qemu/-/commits/qemu-gfxstream-v13 and
> added the additional acks in the commit message.
> >
> > UI/gfx maintainers, since everything is reviewed and there hasn't been
> any additional review comments, may we merge the gfxstream + rutabaga_gfx
> series?  Thank you!
> >
> >
>
> Packaging aemu and gfxstream is a bit problematic. I have some WIP
> Fedora packages.
>
> AEMU:
> - installs files under /usr/include/host-common and
> /usr/include/snapshot. Can this be moved under /usr/include/aemu
> instead?
> - builds only static versions of libaemu-host-common.a and
> liblogging-base.a (distros don't like static libs much)
> - could liblogging-base(.a,.so,..) also have "aemu" name in it?
> - libaemu-base.so is not versioned
> - I can't find a release tarball, nor the (v0.1.2) release tag
> - could have a README file
>
> I am not very familiar with cmake, so it's not obvious how to make the
> required changes. Would you like me to open an issue (where?) or try
> to make some patches?
>

I filed an internal bug with all the issues you listed: Android side should
fix this internally.

I see a few options for packaging:

1) Punt on gfxstream/AEMU packaging, just do rutabaga

gfxstream is mostly useful for Android guests, and I didn't expect anyone
to actually package it at this point since most here are interested in
Linux guests (where gfxstream VK is headless only right now).  Plus
ioctl-fowarding > API forwarding for security and performance, so I'm not
sure if it'll have any sticking power even if everything is supported
(outside of a few niche use cases).

Though, I sense interest in Wayland passthrough for dual Linux use cases.
I put up:

crrev.com/c/4860836 <http://crrev.com/c4860836>

that'll allow packaging on rutabaga_gfx and even CI testing without
gfxstream, since it is designed to function without it.  We could issue
another rutabaga-release tag, or you can simply add a patch (a common
packaging practice) on the Fedora package with the "UPSTEAM label".

2) Actually package gfxstream only

Probably an intermediate solution that doesn't introduce versioning/static
library issues would be just to have a copy of AEMU in the gfxstream repo,
and link it statically.  Will need another release tag/commit of
gfxstream.

3) Don't package at all

For my particular use case since we have to build QEMU for sources, this is
fine.  If upstream breaks virtio-gpu-rutabaga.c, we'll send a patch and fix
it.  Being in-tree is most important.

Let me know what you prefer!


>
> gfxstream:
> - libgfxtream_backend.so is not versioned
> - I can't find a release tarball, nor the (v0.1.2) release tag
>


https://android-review.googlesource.com/c/platform/hardware/google/gfxstream/+/2749095


>
>
> (packaging is important so we can build the new code in CI too!)
>
> thanks
>
> --
> Marc-André Lureau
>

[-- Attachment #2: Type: text/html, Size: 6482 bytes --]

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH v13 0/9] rutabaga_gfx + gfxstream
  2023-09-13  1:08       ` Gurchetan Singh
@ 2023-09-13 13:49         ` Marc-André Lureau
  2023-09-14  4:10           ` Gurchetan Singh
  0 siblings, 1 reply; 27+ messages in thread
From: Marc-André Lureau @ 2023-09-13 13:49 UTC (permalink / raw)
  To: Gurchetan Singh
  Cc: Huang Rui, qemu-devel, akihiko.odaki, alex.bennee, shentey, hi,
	ernunes, manos.pitsidianakis, philmd, mark.cave-ayland,
	Gerd Hoffmann

Hi

On Wed, Sep 13, 2023 at 5:08 AM Gurchetan Singh
<gurchetansingh@chromium.org> wrote:
> On Tue, Sep 12, 2023 at 6:59 AM Marc-André Lureau <marcandre.lureau@gmail.com> wrote:
>> Packaging aemu and gfxstream is a bit problematic. I have some WIP
>> Fedora packages.
>>
>> AEMU:
>> - installs files under /usr/include/host-common and
>> /usr/include/snapshot. Can this be moved under /usr/include/aemu
>> instead?
>> - builds only static versions of libaemu-host-common.a and
>> liblogging-base.a (distros don't like static libs much)
>> - could liblogging-base(.a,.so,..) also have "aemu" name in it?
>> - libaemu-base.so is not versioned
>> - I can't find a release tarball, nor the (v0.1.2) release tag
>> - could have a README file
>>
>> I am not very familiar with cmake, so it's not obvious how to make the
>> required changes. Would you like me to open an issue (where?) or try
>> to make some patches?
>
>
> I filed an internal bug with all the issues you listed: Android side should fix this internally.
>
> I see a few options for packaging:
>
> 1) Punt on gfxstream/AEMU packaging, just do rutabaga
>
> gfxstream is mostly useful for Android guests, and I didn't expect anyone to actually package it at this point since most here are interested in Linux guests (where gfxstream VK is headless only right now).  Plus ioctl-fowarding > API forwarding for security and performance, so I'm not sure if it'll have any sticking power even if everything is supported (outside of a few niche use cases).
>
> Though, I sense interest in Wayland passthrough for dual Linux use cases.  I put up:
>
> crrev.com/c/4860836
>
> that'll allow packaging on rutabaga_gfx and even CI testing without gfxstream, since it is designed to function without it.  We could issue another rutabaga-release tag, or you can simply add a patch (a common packaging practice) on the Fedora package with the "UPSTEAM label".
>
> 2) Actually package gfxstream only
>
> Probably an intermediate solution that doesn't introduce versioning/static library issues would be just to have a copy of AEMU in the gfxstream repo, and link it statically.  Will need another release tag/commit of gfxstream.
>
> 3) Don't package at all
>
> For my particular use case since we have to build QEMU for sources, this is fine.  If upstream breaks virtio-gpu-rutabaga.c, we'll send a patch and fix it.  Being in-tree is most important.
>
> Let me know what you prefer!
>

I would rather have standard packaging of the various projects, so we
can test and develop easily.

For rutabaga, I ended up having to patch a little bit the shared
library, to fix SONAME:

diff --git a/ffi/Makefile b/ffi/Makefile
index d2f0d38..7efc8f3 100644
--- a/ffi/Makefile
+++ b/ffi/Makefile
@@ -47,13 +47,13 @@ build:

 install: build
 ifeq ($(UNAME), Linux)
-    install -D -m 755 -t $(DESTDIR)$(libdir) $(OUT)/$(LIB_NAME)
+    install -D -m 755 $(OUT)/$(LIB_NAME)
$(DESTDIR)$(libdir)/$(LIB_NAME).$(RUTABAGA_VERSION)
 endif
 ifeq ($(UNAME), Darwin)
-        install_name_tool -id $(DESTDIR)$(libdir)/$(LIB_NAME)
$(DESTDIR)$(libdir)/$(LIB_NAME)
+        install_name_tool -id
$(DESTDIR)$(libdir)/$(LIB_NAME).$(RUTABAGA_VERSION)
$(DESTDIR)$(libdir)/$(LIB_NAME)
 endif
-    ln -sf $(DESTDIR)$(libdir)/$(LIB_NAME)
$(DESTDIR)$(libdir)/$(LIB_NAME).$(RUTABAGA_VERSION)
-    ln -sf $(DESTDIR)$(libdir)/$(LIB_NAME)
$(DESTDIR)$(libdir)/$(LIB_NAME).$(RUTABAGA_VERSION_MAJOR)
+    ln -s $(LIB_NAME).$(RUTABAGA_VERSION)
$(DESTDIR)$(libdir)/$(LIB_NAME).$(RUTABAGA_VERSION_MAJOR)
+    ln -s $(LIB_NAME).$(RUTABAGA_VERSION) $(DESTDIR)$(libdir)/$(LIB_NAME)
 ifeq ($(UNAME), Linux)
     install -D -m 0644 $(SRC)/share/rutabaga_gfx_ffi.pc
$(DESTDIR)$(libdir)/pkgconfig/rutabaga_gfx_ffi.pc
     install -D -m 0644 $(SRC)/include/rutabaga_gfx_ffi.h
$(DESTDIR)$(includedir)/rutabaga_gfx_ffi.h
diff --git a/ffi/build.rs b/ffi/build.rs
new file mode 100644
index 0000000..efa18d3
--- /dev/null
+++ b/ffi/build.rs
@@ -0,0 +1,3 @@
+fn main() {
+       println!("cargo:rustc-cdylib-link-arg=-Wl,-soname,librutabaga_gfx_ffi.so.0");
+}


The package is a bit unconventional, since it's a rust project
providing a C shared library. I am not sure I did Fedora packaging
right, let see:
https://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=2238751


-- 
Marc-André Lureau


^ permalink raw reply related	[flat|nested] 27+ messages in thread

* Re: [PATCH v13 0/9] rutabaga_gfx + gfxstream
  2023-09-06  6:25     ` Marc-André Lureau
@ 2023-09-13 21:03       ` Bernhard Beschow
  0 siblings, 0 replies; 27+ messages in thread
From: Bernhard Beschow @ 2023-09-13 21:03 UTC (permalink / raw)
  To: Marc-André Lureau, Gurchetan Singh, Michael S. Tsirkin
  Cc: Huang Rui, qemu-devel, akihiko.odaki, alex.bennee, hi, ernunes,
	manos.pitsidianakis, philmd, mark.cave-ayland, Gerd Hoffmann



Am 6. September 2023 06:25:39 UTC schrieb "Marc-André Lureau" <marcandre.lureau@gmail.com>:
>Hi
>
>On Wed, Sep 6, 2023 at 5:22 AM Gurchetan Singh
><gurchetansingh@chromium.org> wrote:
>>
>>
>>
>> On Wed, Aug 30, 2023 at 7:26 PM Huang Rui <ray.huang@amd.com> wrote:
>>>
>>> On Tue, Aug 29, 2023 at 08:36:20AM +0800, Gurchetan Singh wrote:
>>> > From: Gurchetan Singh <gurchetansingh@google.com>
>>> >
>>> > Changes since v12:
>>> > - Added r-b tags from Antonio Caggiano and Akihiko Odaki
>>> > - Removed review version from commit messages
>>> > - I think we're good to merge since we've had multiple people test and review this series??
>>> >
>>> > How to build both rutabaga and gfxstream guest/host libs:
>>> >
>>> > https://crosvm.dev/book/appendix/rutabaga_gfx.html
>>> >
>>> > Branch containing this patch series:
>>> >
>>> > https://gitlab.com/gurchetansingh/qemu/-/commits/qemu-gfxstream-v13
>>> >
>>> > Antonio Caggiano (2):
>>> >   virtio-gpu: CONTEXT_INIT feature
>>> >   virtio-gpu: blob prep
>>> >
>>> > Dr. David Alan Gilbert (1):
>>> >   virtio: Add shared memory capability
>>> >
>>> > Gerd Hoffmann (1):
>>> >   virtio-gpu: hostmem
>>>
>>> Patch 1 -> 4 are
>>>
>>> Acked-and-Tested-by: Huang Rui <ray.huang@amd.com>
>>
>>
>> Thanks Ray, I've rebased https://gitlab.com/gurchetansingh/qemu/-/commits/qemu-gfxstream-v13 and added the additional acks in the commit message.
>>
>> UI/gfx maintainers, since everything is reviewed and there hasn't been any additional review comments, may we merge the gfxstream + rutabaga_gfx series?  Thank you!
>>
>
>I can take it, or Michael (since Gerd is not focused on QEMU atm).

I've added a review comment on v11: https://lore.kernel.org/qemu-devel/B1A4DF8C-3078-48AD-BC8B-F2FD7BA413CF@gmail.com/

Best regards,
Bernhard

>
>Michael, are you prepping a virtio PR?
>
>thanks
>


^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH v13 0/9] rutabaga_gfx + gfxstream
  2023-09-13 13:49         ` Marc-André Lureau
@ 2023-09-14  4:10           ` Gurchetan Singh
  0 siblings, 0 replies; 27+ messages in thread
From: Gurchetan Singh @ 2023-09-14  4:10 UTC (permalink / raw)
  To: Marc-André Lureau
  Cc: Huang Rui, qemu-devel, akihiko.odaki, alex.bennee, shentey, hi,
	ernunes, manos.pitsidianakis, philmd, mark.cave-ayland,
	Gerd Hoffmann

[-- Attachment #1: Type: text/plain, Size: 5236 bytes --]

On Wed, Sep 13, 2023 at 6:49 AM Marc-André Lureau <
marcandre.lureau@gmail.com> wrote:

> Hi
>
> On Wed, Sep 13, 2023 at 5:08 AM Gurchetan Singh
> <gurchetansingh@chromium.org> wrote:
> > On Tue, Sep 12, 2023 at 6:59 AM Marc-André Lureau <
> marcandre.lureau@gmail.com> wrote:
> >> Packaging aemu and gfxstream is a bit problematic. I have some WIP
> >> Fedora packages.

>>
> >> AEMU:
> >> - installs files under /usr/include/host-common and
> >> /usr/include/snapshot. Can this be moved under /usr/include/aemu
> >> instead?
> >> - builds only static versions of libaemu-host-common.a and
> >> liblogging-base.a (distros don't like static libs much)
> >> - could liblogging-base(.a,.so,..) also have "aemu" name in it?
> >> - libaemu-base.so is not versioned
> >> - I can't find a release tarball, nor the (v0.1.2) release tag
> >> - could have a README file
> >>
> >> I am not very familiar with cmake, so it's not obvious how to make the
> >> required changes. Would you like me to open an issue (where?) or try
> >> to make some patches?
> >
> >
> > I filed an internal bug with all the issues you listed: Android side
> should fix this internally.
> >
> > I see a few options for packaging:
> >
> > 1) Punt on gfxstream/AEMU packaging, just do rutabaga
> >
> > gfxstream is mostly useful for Android guests, and I didn't expect
> anyone to actually package it at this point since most here are interested
> in Linux guests (where gfxstream VK is headless only right now).  Plus
> ioctl-fowarding > API forwarding for security and performance, so I'm not
> sure if it'll have any sticking power even if everything is supported
> (outside of a few niche use cases).
> >
> > Though, I sense interest in Wayland passthrough for dual Linux use
> cases.  I put up:
> >
> > crrev.com/c/4860836
> >
> > that'll allow packaging on rutabaga_gfx and even CI testing without
> gfxstream, since it is designed to function without it.  We could issue
> another rutabaga-release tag, or you can simply add a patch (a common
> packaging practice) on the Fedora package with the "UPSTEAM label".
> >
> > 2) Actually package gfxstream only
> >
> > Probably an intermediate solution that doesn't introduce
> versioning/static library issues would be just to have a copy of AEMU in
> the gfxstream repo, and link it statically.  Will need another release
> tag/commit of gfxstream.
> >
> > 3) Don't package at all
> >
> > For my particular use case since we have to build QEMU for sources, this
> is fine.  If upstream breaks virtio-gpu-rutabaga.c, we'll send a patch and
> fix it.  Being in-tree is most important.
> >
> > Let me know what you prefer!
> >
>
> I would rather have standard packaging of the various projects, so we
> can test and develop easily.
>

Ack.  Here are the requested changes:

- https://android-review.googlesource.com/q/topic:%22aemu-package-fix%22
- crrev.com/c/4865171

The main change is:

https://android-review.googlesource.com/c/platform/hardware/google/aemu/+/2751066

Once that's okay for packaging, I'll ping harder on v0.1.2 gfxstream/AEMU
release tags.  Let me know if you want another release tag for rutabaga, or
if just patching in upstream changes would be acceptable.

For rutabaga, I ended up having to patch a little bit the shared
> library, to fix SONAME:
>

Landed as crrev.com/c/4863380.


>
> diff --git a/ffi/Makefile b/ffi/Makefile
> index d2f0d38..7efc8f3 100644
> --- a/ffi/Makefile
> +++ b/ffi/Makefile
> @@ -47,13 +47,13 @@ build:
>
>  install: build
>  ifeq ($(UNAME), Linux)
> -    install -D -m 755 -t $(DESTDIR)$(libdir) $(OUT)/$(LIB_NAME)
> +    install -D -m 755 $(OUT)/$(LIB_NAME)
> $(DESTDIR)$(libdir)/$(LIB_NAME).$(RUTABAGA_VERSION)
>  endif
>  ifeq ($(UNAME), Darwin)
> -        install_name_tool -id $(DESTDIR)$(libdir)/$(LIB_NAME)
> $(DESTDIR)$(libdir)/$(LIB_NAME)
> +        install_name_tool -id
> $(DESTDIR)$(libdir)/$(LIB_NAME).$(RUTABAGA_VERSION)
> $(DESTDIR)$(libdir)/$(LIB_NAME)
>  endif
> -    ln -sf $(DESTDIR)$(libdir)/$(LIB_NAME)
> $(DESTDIR)$(libdir)/$(LIB_NAME).$(RUTABAGA_VERSION)
> -    ln -sf $(DESTDIR)$(libdir)/$(LIB_NAME)
> $(DESTDIR)$(libdir)/$(LIB_NAME).$(RUTABAGA_VERSION_MAJOR)
> +    ln -s $(LIB_NAME).$(RUTABAGA_VERSION)
> $(DESTDIR)$(libdir)/$(LIB_NAME).$(RUTABAGA_VERSION_MAJOR)
> +    ln -s $(LIB_NAME).$(RUTABAGA_VERSION) $(DESTDIR)$(libdir)/$(LIB_NAME)
>  ifeq ($(UNAME), Linux)
>      install -D -m 0644 $(SRC)/share/rutabaga_gfx_ffi.pc
> $(DESTDIR)$(libdir)/pkgconfig/rutabaga_gfx_ffi.pc
>      install -D -m 0644 $(SRC)/include/rutabaga_gfx_ffi.h
> $(DESTDIR)$(includedir)/rutabaga_gfx_ffi.h
> diff --git a/ffi/build.rs b/ffi/build.rs
> new file mode 100644
> index 0000000..efa18d3
> --- /dev/null
> +++ b/ffi/build.rs
> @@ -0,0 +1,3 @@
> +fn main() {
> +
>  println!("cargo:rustc-cdylib-link-arg=-Wl,-soname,librutabaga_gfx_ffi.so.0");
> +}
>
>
> The package is a bit unconventional, since it's a rust project
> providing a C shared library. I am not sure I did Fedora packaging
> right, let see:
> https://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=2238751
>
>
> --
> Marc-André Lureau
>

[-- Attachment #2: Type: text/html, Size: 7373 bytes --]

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH v13 6/9] gfxstream + rutabaga: add initial support for gfxstream
  2023-08-29  0:36 ` [PATCH v13 6/9] gfxstream + rutabaga: add initial support for gfxstream Gurchetan Singh
@ 2023-09-20 11:42   ` Akihiko Odaki
  2023-09-20 12:04     ` Mark Cave-Ayland
  2023-09-27 11:45   ` Thomas Huth
  1 sibling, 1 reply; 27+ messages in thread
From: Akihiko Odaki @ 2023-09-20 11:42 UTC (permalink / raw)
  To: Gurchetan Singh, qemu-devel, Xenia Ragiadakou
  Cc: marcandre.lureau, ray.huang, alex.bennee, shentey, hi, ernunes,
	manos.pitsidianakis, philmd, mark.cave-ayland, Huang Rui,
	Xenia Ragiadakou, Huang Rui, Gerd Hoffmann, Michael S . Tsirkin,
	Stefano Stabellini, Anthony PERARD, Antonio Caggiano,
	Dr . David Alan Gilbert, Robert Beckett, Dmitry Osipenko,
	Alex Bennée, qemu-devel, xen-devel, Gurchetan Singh,
	Albert Esteve, ernunes, Philippe Mathieu-Daudé,
	Alyssa Ross, Roger Pau Monné,
	Alex Deucher, Christian König, Pierre-Eric Pelloux-Prayer,
	Honglei Huang, Julia Zhang, Chen Jiqian

On 2023/08/29 9:36, Gurchetan Singh wrote:
> This adds initial support for gfxstream and cross-domain.  Both
> features rely on virtio-gpu blob resources and context types, which
> are also implemented in this patch.
> 
> gfxstream has a long and illustrious history in Android graphics
> paravirtualization.  It has been powering graphics in the Android
> Studio Emulator for more than a decade, which is the main developer
> platform.
> 
> Originally conceived by Jesse Hall, it was first known as "EmuGL" [a].
> The key design characteristic was a 1:1 threading model and
> auto-generation, which fit nicely with the OpenGLES spec.  It also
> allowed easy layering with ANGLE on the host, which provides the GLES
> implementations on Windows or MacOS enviroments.
> 
> gfxstream has traditionally been maintained by a single engineer, and
> between 2015 to 2021, the goldfish throne passed to Frank Yang.
> Historians often remark this glorious reign ("pax gfxstreama" is the
> academic term) was comparable to that of Augustus and both Queen
> Elizabeths.  Just to name a few accomplishments in a resplendent
> panoply: higher versions of GLES, address space graphics, snapshot
> support and CTS compliant Vulkan [b].
> 
> One major drawback was the use of out-of-tree goldfish drivers.
> Android engineers didn't know much about DRM/KMS and especially TTM so
> a simple guest to host pipe was conceived.
> 
> Luckily, virtio-gpu 3D started to emerge in 2016 due to the work of
> the Mesa/virglrenderer communities.  In 2018, the initial virtio-gpu
> port of gfxstream was done by Cuttlefish enthusiast Alistair Delva.
> It was a symbol compatible replacement of virglrenderer [c] and named
> "AVDVirglrenderer".  This implementation forms the basis of the
> current gfxstream host implementation still in use today.
> 
> cross-domain support follows a similar arc.  Originally conceived by
> Wayland aficionado David Reveman and crosvm enjoyer Zach Reizner in
> 2018, it initially relied on the downstream "virtio-wl" device.
> 
> In 2020 and 2021, virtio-gpu was extended to include blob resources
> and multiple timelines by yours truly, features gfxstream/cross-domain
> both require to function correctly.
> 
> Right now, we stand at the precipice of a truly fantastic possibility:
> the Android Emulator powered by upstream QEMU and upstream Linux
> kernel.  gfxstream will then be packaged properfully, and app
> developers can even fix gfxstream bugs on their own if they encounter
> them.
> 
> It's been quite the ride, my friends.  Where will gfxstream head next,
> nobody really knows.  I wouldn't be surprised if it's around for
> another decade, maintained by a new generation of Android graphics
> enthusiasts.
> 
> Technical details:
>    - Very simple initial display integration: just used Pixman
>    - Largely, 1:1 mapping of virtio-gpu hypercalls to rutabaga function
>      calls
> 
> Next steps for Android VMs:
>    - The next step would be improving display integration and UI interfaces
>      with the goal of the QEMU upstream graphics being in an emulator
>      release [d].
> 
> Next steps for Linux VMs for display virtualization:
>    - For widespread distribution, someone needs to package Sommelier or the
>      wayland-proxy-virtwl [e] ideally into Debian main. In addition, newer
>      versions of the Linux kernel come with DRM_VIRTIO_GPU_KMS option,
>      which allows disabling KMS hypercalls.  If anyone cares enough, it'll
>      probably be possible to build a custom VM variant that uses this display
>      virtualization strategy.
> 
> [a] https://android-review.googlesource.com/c/platform/development/+/34470
> [b] https://android-review.googlesource.com/q/topic:%22vulkan-hostconnection-start%22
> [c] https://android-review.googlesource.com/c/device/generic/goldfish-opengl/+/761927
> [d] https://developer.android.com/studio/releases/emulator
> [e] https://github.com/talex5/wayland-proxy-virtwl
> 
> Signed-off-by: Gurchetan Singh <gurchetansingh@chromium.org>
> Tested-by: Alyssa Ross <hi@alyssa.is>
> Tested-by: Emmanouil Pitsidianakis <manos.pitsidianakis@linaro.org>
> Tested-by: Akihiko Odaki <akihiko.odaki@daynix.com>
> Reviewed-by: Emmanouil Pitsidianakis <manos.pitsidianakis@linaro.org>
> Reviewed-by: Antonio Caggiano <quic_acaggian@quicinc.com>
> Reviewed-by: Akihiko Odaki <akihiko.odaki@daynix.com>
> ---
>   hw/display/virtio-gpu-pci-rutabaga.c |   47 ++
>   hw/display/virtio-gpu-rutabaga.c     | 1119 ++++++++++++++++++++++++++
>   hw/display/virtio-vga-rutabaga.c     |   50 ++
>   3 files changed, 1216 insertions(+)
>   create mode 100644 hw/display/virtio-gpu-pci-rutabaga.c
>   create mode 100644 hw/display/virtio-gpu-rutabaga.c
>   create mode 100644 hw/display/virtio-vga-rutabaga.c
> 
> diff --git a/hw/display/virtio-gpu-pci-rutabaga.c b/hw/display/virtio-gpu-pci-rutabaga.c
> new file mode 100644
> index 0000000000..c96729e198
> --- /dev/null
> +++ b/hw/display/virtio-gpu-pci-rutabaga.c
> @@ -0,0 +1,47 @@
> +/* SPDX-License-Identifier: GPL-2.0-or-later */
> +
> +#include "qemu/osdep.h"
> +#include "qapi/error.h"
> +#include "qemu/module.h"
> +#include "hw/pci/pci.h"
> +#include "hw/qdev-properties.h"
> +#include "hw/virtio/virtio.h"
> +#include "hw/virtio/virtio-bus.h"
> +#include "hw/virtio/virtio-gpu-pci.h"
> +#include "qom/object.h"
> +
> +#define TYPE_VIRTIO_GPU_RUTABAGA_PCI "virtio-gpu-rutabaga-pci"
> +OBJECT_DECLARE_SIMPLE_TYPE(VirtIOGPURutabagaPCI, VIRTIO_GPU_RUTABAGA_PCI)
> +
> +struct VirtIOGPURutabagaPCI {
> +    VirtIOGPUPCIBase parent_obj;
> +
> +    VirtIOGPURutabaga vdev;
> +};
> +
> +static void virtio_gpu_rutabaga_initfn(Object *obj)
> +{
> +    VirtIOGPURutabagaPCI *dev = VIRTIO_GPU_RUTABAGA_PCI(obj);
> +
> +    virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
> +                                TYPE_VIRTIO_GPU_RUTABAGA);
> +    VIRTIO_GPU_PCI_BASE(obj)->vgpu = VIRTIO_GPU_BASE(&dev->vdev);
> +}
> +
> +static const TypeInfo virtio_gpu_rutabaga_pci_info[] = {
> +    {
> +        .name = TYPE_VIRTIO_GPU_RUTABAGA_PCI,
> +        .parent = TYPE_VIRTIO_GPU_PCI_BASE,
> +        .instance_size = sizeof(VirtIOGPURutabagaPCI),
> +        .instance_init = virtio_gpu_rutabaga_initfn,
> +        .interfaces = (InterfaceInfo[]) {
> +            { INTERFACE_CONVENTIONAL_PCI_DEVICE },
> +        }
> +    },
> +};
> +
> +DEFINE_TYPES(virtio_gpu_rutabaga_pci_info)
> +
> +module_obj(TYPE_VIRTIO_GPU_RUTABAGA_PCI);
> +module_kconfig(VIRTIO_PCI);
> +module_dep("hw-display-virtio-gpu-pci");
> diff --git a/hw/display/virtio-gpu-rutabaga.c b/hw/display/virtio-gpu-rutabaga.c
> new file mode 100644
> index 0000000000..a105e06214
> --- /dev/null
> +++ b/hw/display/virtio-gpu-rutabaga.c
> @@ -0,0 +1,1119 @@
> +/* SPDX-License-Identifier: GPL-2.0-or-later */
> +
> +#include "qemu/osdep.h"
> +#include "qapi/error.h"
> +#include "qemu/error-report.h"
> +#include "qemu/iov.h"
> +#include "trace.h"
> +#include "hw/virtio/virtio.h"
> +#include "hw/virtio/virtio-gpu.h"
> +#include "hw/virtio/virtio-gpu-pixman.h"
> +#include "hw/virtio/virtio-iommu.h"
> +
> +#include <glib/gmem.h>
> +#include <rutabaga_gfx/rutabaga_gfx_ffi.h>
> +
> +#define CHECK(condition, cmd)                                                 \
> +    do {                                                                      \
> +        if (!(condition)) {                                                   \
> +            error_report("CHECK failed in %s() %s:" "%d", __func__,           \
> +                         __FILE__, __LINE__);                                 \
> +            (cmd)->error = VIRTIO_GPU_RESP_ERR_UNSPEC;                        \
> +            return;                                                           \
> +       }                                                                      \
> +    } while (0)
> +
> +/*
> + * This is the size of the char array in struct sock_addr_un. No Wayland socket
> + * can be created with a path longer than this, including the null terminator.
> + */
> +#define UNIX_PATH_MAX sizeof((struct sockaddr_un) {} .sun_path)
> +
> +struct rutabaga_aio_data {
> +    struct VirtIOGPURutabaga *vr;
> +    struct rutabaga_fence fence;
> +};
> +
> +static void
> +virtio_gpu_rutabaga_update_cursor(VirtIOGPU *g, struct virtio_gpu_scanout *s,
> +                                  uint32_t resource_id)
> +{
> +    struct virtio_gpu_simple_resource *res;
> +    struct rutabaga_transfer transfer = { 0 };
> +    struct iovec transfer_iovec;
> +
> +    VirtIOGPURutabaga *vr = VIRTIO_GPU_RUTABAGA(g);
> +
> +    res = virtio_gpu_find_resource(g, resource_id);
> +    if (!res) {
> +        return;
> +    }
> +
> +    if (res->width != s->current_cursor->width ||
> +        res->height != s->current_cursor->height) {
> +        return;
> +    }
> +
> +    transfer.x = 0;
> +    transfer.y = 0;
> +    transfer.z = 0;
> +    transfer.w = res->width;
> +    transfer.h = res->height;
> +    transfer.d = 1;
> +
> +    transfer_iovec.iov_base = s->current_cursor->data;
> +    transfer_iovec.iov_len = res->width * res->height * 4;
> +
> +    rutabaga_resource_transfer_read(vr->rutabaga, 0,
> +                                    resource_id, &transfer,
> +                                    &transfer_iovec);
> +}
> +
> +static void
> +virtio_gpu_rutabaga_gl_flushed(VirtIOGPUBase *b)
> +{
> +    VirtIOGPU *g = VIRTIO_GPU(b);
> +    virtio_gpu_process_cmdq(g);
> +}
> +
> +static void
> +rutabaga_cmd_create_resource_2d(VirtIOGPU *g,
> +                                struct virtio_gpu_ctrl_command *cmd)
> +{
> +    int32_t result;
> +    struct rutabaga_create_3d rc_3d = { 0 };
> +    struct virtio_gpu_simple_resource *res;
> +    struct virtio_gpu_resource_create_2d c2d;
> +
> +    VirtIOGPURutabaga *vr = VIRTIO_GPU_RUTABAGA(g);
> +
> +    VIRTIO_GPU_FILL_CMD(c2d);
> +    trace_virtio_gpu_cmd_res_create_2d(c2d.resource_id, c2d.format,
> +                                       c2d.width, c2d.height);
> +
> +    rc_3d.target = 2;
> +    rc_3d.format = c2d.format;
> +    rc_3d.bind = (1 << 1);
> +    rc_3d.width = c2d.width;
> +    rc_3d.height = c2d.height;
> +    rc_3d.depth = 1;
> +    rc_3d.array_size = 1;
> +    rc_3d.last_level = 0;
> +    rc_3d.nr_samples = 0;
> +    rc_3d.flags = VIRTIO_GPU_RESOURCE_FLAG_Y_0_TOP;
> +
> +    result = rutabaga_resource_create_3d(vr->rutabaga, c2d.resource_id, &rc_3d);
> +    CHECK(!result, cmd);
> +
> +    res = g_new0(struct virtio_gpu_simple_resource, 1);
> +    res->width = c2d.width;
> +    res->height = c2d.height;
> +    res->format = c2d.format;
> +    res->resource_id = c2d.resource_id;
> +
> +    QTAILQ_INSERT_HEAD(&g->reslist, res, next);
> +}
> +
> +static void
> +rutabaga_cmd_create_resource_3d(VirtIOGPU *g,
> +                                struct virtio_gpu_ctrl_command *cmd)
> +{
> +    int32_t result;
> +    struct rutabaga_create_3d rc_3d = { 0 };
> +    struct virtio_gpu_simple_resource *res;
> +    struct virtio_gpu_resource_create_3d c3d;
> +
> +    VirtIOGPURutabaga *vr = VIRTIO_GPU_RUTABAGA(g);
> +
> +    VIRTIO_GPU_FILL_CMD(c3d);
> +
> +    trace_virtio_gpu_cmd_res_create_3d(c3d.resource_id, c3d.format,
> +                                       c3d.width, c3d.height, c3d.depth);
> +
> +    rc_3d.target = c3d.target;
> +    rc_3d.format = c3d.format;
> +    rc_3d.bind = c3d.bind;
> +    rc_3d.width = c3d.width;
> +    rc_3d.height = c3d.height;
> +    rc_3d.depth = c3d.depth;
> +    rc_3d.array_size = c3d.array_size;
> +    rc_3d.last_level = c3d.last_level;
> +    rc_3d.nr_samples = c3d.nr_samples;
> +    rc_3d.flags = c3d.flags;
> +
> +    result = rutabaga_resource_create_3d(vr->rutabaga, c3d.resource_id, &rc_3d);
> +    CHECK(!result, cmd);
> +
> +    res = g_new0(struct virtio_gpu_simple_resource, 1);
> +    res->width = c3d.width;
> +    res->height = c3d.height;
> +    res->format = c3d.format;
> +    res->resource_id = c3d.resource_id;
> +
> +    QTAILQ_INSERT_HEAD(&g->reslist, res, next);
> +}
> +
> +static void
> +rutabaga_cmd_resource_unref(VirtIOGPU *g,
> +                            struct virtio_gpu_ctrl_command *cmd)
> +{
> +    int32_t result;
> +    struct virtio_gpu_simple_resource *res;
> +    struct virtio_gpu_resource_unref unref;
> +
> +    VirtIOGPURutabaga *vr = VIRTIO_GPU_RUTABAGA(g);
> +
> +    VIRTIO_GPU_FILL_CMD(unref);
> +
> +    trace_virtio_gpu_cmd_res_unref(unref.resource_id);
> +
> +    res = virtio_gpu_find_resource(g, unref.resource_id);
> +    CHECK(res, cmd);
> +
> +    result = rutabaga_resource_unref(vr->rutabaga, unref.resource_id);
> +    CHECK(!result, cmd);
> +
> +    if (res->image) {
> +        pixman_image_unref(res->image);
> +    }
> +
> +    QTAILQ_REMOVE(&g->reslist, res, next);
> +    g_free(res);
> +}
> +
> +static void
> +rutabaga_cmd_context_create(VirtIOGPU *g,
> +                            struct virtio_gpu_ctrl_command *cmd)
> +{
> +    int32_t result;
> +    struct virtio_gpu_ctx_create cc;
> +
> +    VirtIOGPURutabaga *vr = VIRTIO_GPU_RUTABAGA(g);
> +
> +    VIRTIO_GPU_FILL_CMD(cc);
> +    trace_virtio_gpu_cmd_ctx_create(cc.hdr.ctx_id,
> +                                    cc.debug_name);
> +
> +    result = rutabaga_context_create(vr->rutabaga, cc.hdr.ctx_id,
> +                                     cc.context_init, cc.debug_name, cc.nlen);
> +    CHECK(!result, cmd);
> +}
> +
> +static void
> +rutabaga_cmd_context_destroy(VirtIOGPU *g,
> +                             struct virtio_gpu_ctrl_command *cmd)
> +{
> +    int32_t result;
> +    struct virtio_gpu_ctx_destroy cd;
> +
> +    VirtIOGPURutabaga *vr = VIRTIO_GPU_RUTABAGA(g);
> +
> +    VIRTIO_GPU_FILL_CMD(cd);
> +    trace_virtio_gpu_cmd_ctx_destroy(cd.hdr.ctx_id);
> +
> +    result = rutabaga_context_destroy(vr->rutabaga, cd.hdr.ctx_id);
> +    CHECK(!result, cmd);
> +}
> +
> +static void
> +rutabaga_cmd_resource_flush(VirtIOGPU *g, struct virtio_gpu_ctrl_command *cmd)
> +{
> +    int32_t result, i;
> +    struct virtio_gpu_scanout *scanout = NULL;
> +    struct virtio_gpu_simple_resource *res;
> +    struct rutabaga_transfer transfer = { 0 };
> +    struct iovec transfer_iovec;
> +    struct virtio_gpu_resource_flush rf;
> +    bool found = false;
> +
> +    VirtIOGPUBase *vb = VIRTIO_GPU_BASE(g);
> +    VirtIOGPURutabaga *vr = VIRTIO_GPU_RUTABAGA(g);
> +    if (vr->headless) {
> +        return;
> +    }
> +
> +    VIRTIO_GPU_FILL_CMD(rf);
> +    trace_virtio_gpu_cmd_res_flush(rf.resource_id,
> +                                   rf.r.width, rf.r.height, rf.r.x, rf.r.y);
> +
> +    res = virtio_gpu_find_resource(g, rf.resource_id);
> +    CHECK(res, cmd);
> +
> +    for (i = 0; i < vb->conf.max_outputs; i++) {
> +        scanout = &vb->scanout[i];
> +        if (i == res->scanout_bitmask) {
> +            found = true;
> +            break;
> +        }
> +    }
> +
> +    if (!found) {
> +        return;
> +    }
> +
> +    transfer.x = 0;
> +    transfer.y = 0;
> +    transfer.z = 0;
> +    transfer.w = res->width;
> +    transfer.h = res->height;
> +    transfer.d = 1;
> +
> +    transfer_iovec.iov_base = pixman_image_get_data(res->image);
> +    transfer_iovec.iov_len = res->width * res->height * 4;
> +
> +    result = rutabaga_resource_transfer_read(vr->rutabaga, 0,
> +                                             rf.resource_id, &transfer,
> +                                             &transfer_iovec);
> +    CHECK(!result, cmd);
> +    dpy_gfx_update_full(scanout->con);
> +}
> +
> +static void
> +rutabaga_cmd_set_scanout(VirtIOGPU *g, struct virtio_gpu_ctrl_command *cmd)
> +{
> +    struct virtio_gpu_simple_resource *res;
> +    struct virtio_gpu_scanout *scanout = NULL;
> +    struct virtio_gpu_set_scanout ss;
> +
> +    VirtIOGPUBase *vb = VIRTIO_GPU_BASE(g);
> +    VirtIOGPURutabaga *vr = VIRTIO_GPU_RUTABAGA(g);
> +    if (vr->headless) {
> +        return;
> +    }
> +
> +    VIRTIO_GPU_FILL_CMD(ss);
> +    trace_virtio_gpu_cmd_set_scanout(ss.scanout_id, ss.resource_id,
> +                                     ss.r.width, ss.r.height, ss.r.x, ss.r.y);
> +
> +    CHECK(ss.scanout_id < VIRTIO_GPU_MAX_SCANOUTS, cmd);
> +    scanout = &vb->scanout[ss.scanout_id];
> +
> +    if (ss.resource_id == 0) {
> +        dpy_gfx_replace_surface(scanout->con, NULL);
> +        dpy_gl_scanout_disable(scanout->con);
> +        return;
> +    }
> +
> +    res = virtio_gpu_find_resource(g, ss.resource_id);
> +    CHECK(res, cmd);
> +
> +    if (!res->image) {
> +        pixman_format_code_t pformat;
> +        pformat = virtio_gpu_get_pixman_format(res->format);
> +        CHECK(pformat, cmd);
> +
> +        res->image = pixman_image_create_bits(pformat,
> +                                              res->width,
> +                                              res->height,
> +                                              NULL, 0);
> +        CHECK(res->image, cmd);
> +        pixman_image_ref(res->image);
> +    }
> +
> +    vb->enable = 1;
> +
> +    /* realloc the surface ptr */
> +    scanout->ds = qemu_create_displaysurface_pixman(res->image);
> +    dpy_gfx_replace_surface(scanout->con, NULL);
> +    dpy_gfx_replace_surface(scanout->con, scanout->ds);
> +    res->scanout_bitmask = ss.scanout_id;
> +}
> +
> +static void
> +rutabaga_cmd_submit_3d(VirtIOGPU *g,
> +                       struct virtio_gpu_ctrl_command *cmd)
> +{
> +    int32_t result;
> +    struct virtio_gpu_cmd_submit cs;
> +    struct rutabaga_command rutabaga_cmd = { 0 };
> +    g_autofree uint8_t *buf = NULL;
> +    size_t s;
> +
> +    VirtIOGPURutabaga *vr = VIRTIO_GPU_RUTABAGA(g);
> +
> +    VIRTIO_GPU_FILL_CMD(cs);
> +    trace_virtio_gpu_cmd_ctx_submit(cs.hdr.ctx_id, cs.size);
> +
> +    buf = g_new0(uint8_t, cs.size);
> +    s = iov_to_buf(cmd->elem.out_sg, cmd->elem.out_num,
> +                   sizeof(cs), buf, cs.size);
> +    CHECK(s == cs.size, cmd);
> +
> +    rutabaga_cmd.ctx_id = cs.hdr.ctx_id;
> +    rutabaga_cmd.cmd = buf;
> +    rutabaga_cmd.cmd_size = cs.size;
> +
> +    result = rutabaga_submit_command(vr->rutabaga, &rutabaga_cmd);
> +    CHECK(!result, cmd);
> +}
> +
> +static void
> +rutabaga_cmd_transfer_to_host_2d(VirtIOGPU *g,
> +                                 struct virtio_gpu_ctrl_command *cmd)
> +{
> +    int32_t result;
> +    struct rutabaga_transfer transfer = { 0 };
> +    struct virtio_gpu_transfer_to_host_2d t2d;
> +
> +    VirtIOGPURutabaga *vr = VIRTIO_GPU_RUTABAGA(g);
> +
> +    VIRTIO_GPU_FILL_CMD(t2d);
> +    trace_virtio_gpu_cmd_res_xfer_toh_2d(t2d.resource_id);
> +
> +    transfer.x = t2d.r.x;
> +    transfer.y = t2d.r.y;
> +    transfer.z = 0;
> +    transfer.w = t2d.r.width;
> +    transfer.h = t2d.r.height;
> +    transfer.d = 1;
> +
> +    result = rutabaga_resource_transfer_write(vr->rutabaga, 0, t2d.resource_id,
> +                                              &transfer);
> +    CHECK(!result, cmd);
> +}
> +
> +static void
> +rutabaga_cmd_transfer_to_host_3d(VirtIOGPU *g,
> +                                 struct virtio_gpu_ctrl_command *cmd)
> +{
> +    int32_t result;
> +    struct rutabaga_transfer transfer = { 0 };
> +    struct virtio_gpu_transfer_host_3d t3d;
> +
> +    VirtIOGPURutabaga *vr = VIRTIO_GPU_RUTABAGA(g);
> +
> +    VIRTIO_GPU_FILL_CMD(t3d);
> +    trace_virtio_gpu_cmd_res_xfer_toh_3d(t3d.resource_id);
> +
> +    transfer.x = t3d.box.x;
> +    transfer.y = t3d.box.y;
> +    transfer.z = t3d.box.z;
> +    transfer.w = t3d.box.w;
> +    transfer.h = t3d.box.h;
> +    transfer.d = t3d.box.d;
> +    transfer.level = t3d.level;
> +    transfer.stride = t3d.stride;
> +    transfer.layer_stride = t3d.layer_stride;
> +    transfer.offset = t3d.offset;
> +
> +    result = rutabaga_resource_transfer_write(vr->rutabaga, t3d.hdr.ctx_id,
> +                                              t3d.resource_id, &transfer);
> +    CHECK(!result, cmd);
> +}
> +
> +static void
> +rutabaga_cmd_transfer_from_host_3d(VirtIOGPU *g,
> +                                   struct virtio_gpu_ctrl_command *cmd)
> +{
> +    int32_t result;
> +    struct rutabaga_transfer transfer = { 0 };
> +    struct virtio_gpu_transfer_host_3d t3d;
> +
> +    VirtIOGPURutabaga *vr = VIRTIO_GPU_RUTABAGA(g);
> +
> +    VIRTIO_GPU_FILL_CMD(t3d);
> +    trace_virtio_gpu_cmd_res_xfer_fromh_3d(t3d.resource_id);
> +
> +    transfer.x = t3d.box.x;
> +    transfer.y = t3d.box.y;
> +    transfer.z = t3d.box.z;
> +    transfer.w = t3d.box.w;
> +    transfer.h = t3d.box.h;
> +    transfer.d = t3d.box.d;
> +    transfer.level = t3d.level;
> +    transfer.stride = t3d.stride;
> +    transfer.layer_stride = t3d.layer_stride;
> +    transfer.offset = t3d.offset;
> +
> +    result = rutabaga_resource_transfer_read(vr->rutabaga, t3d.hdr.ctx_id,
> +                                             t3d.resource_id, &transfer, NULL);
> +    CHECK(!result, cmd);
> +}
> +
> +static void
> +rutabaga_cmd_attach_backing(VirtIOGPU *g, struct virtio_gpu_ctrl_command *cmd)
> +{
> +    struct rutabaga_iovecs vecs = { 0 };
> +    struct virtio_gpu_simple_resource *res;
> +    struct virtio_gpu_resource_attach_backing att_rb;
> +    int ret;
> +
> +    VirtIOGPURutabaga *vr = VIRTIO_GPU_RUTABAGA(g);
> +
> +    VIRTIO_GPU_FILL_CMD(att_rb);
> +    trace_virtio_gpu_cmd_res_back_attach(att_rb.resource_id);
> +
> +    res = virtio_gpu_find_resource(g, att_rb.resource_id);
> +    CHECK(res, cmd);
> +    CHECK(!res->iov, cmd);
> +
> +    ret = virtio_gpu_create_mapping_iov(g, att_rb.nr_entries, sizeof(att_rb),
> +                                        cmd, NULL, &res->iov, &res->iov_cnt);
> +    CHECK(!ret, cmd);
> +
> +    vecs.iovecs = res->iov;
> +    vecs.num_iovecs = res->iov_cnt;
> +
> +    ret = rutabaga_resource_attach_backing(vr->rutabaga, att_rb.resource_id,
> +                                           &vecs);
> +    if (ret != 0) {
> +        virtio_gpu_cleanup_mapping(g, res);
> +    }
> +
> +    CHECK(!ret, cmd);
> +}
> +
> +static void
> +rutabaga_cmd_detach_backing(VirtIOGPU *g, struct virtio_gpu_ctrl_command *cmd)
> +{
> +    struct virtio_gpu_simple_resource *res;
> +    struct virtio_gpu_resource_detach_backing detach_rb;
> +
> +    VirtIOGPURutabaga *vr = VIRTIO_GPU_RUTABAGA(g);
> +
> +    VIRTIO_GPU_FILL_CMD(detach_rb);
> +    trace_virtio_gpu_cmd_res_back_detach(detach_rb.resource_id);
> +
> +    res = virtio_gpu_find_resource(g, detach_rb.resource_id);
> +    CHECK(res, cmd);
> +
> +    rutabaga_resource_detach_backing(vr->rutabaga,
> +                                     detach_rb.resource_id);
> +
> +    virtio_gpu_cleanup_mapping(g, res);
> +}
> +
> +static void
> +rutabaga_cmd_ctx_attach_resource(VirtIOGPU *g,
> +                                 struct virtio_gpu_ctrl_command *cmd)
> +{
> +    int32_t result;
> +    struct virtio_gpu_ctx_resource att_res;
> +
> +    VirtIOGPURutabaga *vr = VIRTIO_GPU_RUTABAGA(g);
> +
> +    VIRTIO_GPU_FILL_CMD(att_res);
> +    trace_virtio_gpu_cmd_ctx_res_attach(att_res.hdr.ctx_id,
> +                                        att_res.resource_id);
> +
> +    result = rutabaga_context_attach_resource(vr->rutabaga, att_res.hdr.ctx_id,
> +                                              att_res.resource_id);
> +    CHECK(!result, cmd);
> +}
> +
> +static void
> +rutabaga_cmd_ctx_detach_resource(VirtIOGPU *g,
> +                                 struct virtio_gpu_ctrl_command *cmd)
> +{
> +    int32_t result;
> +    struct virtio_gpu_ctx_resource det_res;
> +
> +    VirtIOGPURutabaga *vr = VIRTIO_GPU_RUTABAGA(g);
> +
> +    VIRTIO_GPU_FILL_CMD(det_res);
> +    trace_virtio_gpu_cmd_ctx_res_detach(det_res.hdr.ctx_id,
> +                                        det_res.resource_id);
> +
> +    result = rutabaga_context_detach_resource(vr->rutabaga, det_res.hdr.ctx_id,
> +                                              det_res.resource_id);
> +    CHECK(!result, cmd);
> +}
> +
> +static void
> +rutabaga_cmd_get_capset_info(VirtIOGPU *g, struct virtio_gpu_ctrl_command *cmd)
> +{
> +    int32_t result;
> +    struct virtio_gpu_get_capset_info info;
> +    struct virtio_gpu_resp_capset_info resp;
> +
> +    VirtIOGPURutabaga *vr = VIRTIO_GPU_RUTABAGA(g);
> +
> +    VIRTIO_GPU_FILL_CMD(info);
> +
> +    result = rutabaga_get_capset_info(vr->rutabaga, info.capset_index,
> +                                      &resp.capset_id, &resp.capset_max_version,
> +                                      &resp.capset_max_size);
> +    CHECK(!result, cmd);
> +
> +    resp.hdr.type = VIRTIO_GPU_RESP_OK_CAPSET_INFO;
> +    virtio_gpu_ctrl_response(g, cmd, &resp.hdr, sizeof(resp));
> +}
> +
> +static void
> +rutabaga_cmd_get_capset(VirtIOGPU *g, struct virtio_gpu_ctrl_command *cmd)
> +{
> +    int32_t result;
> +    struct virtio_gpu_get_capset gc;
> +    struct virtio_gpu_resp_capset *resp;
> +    uint32_t capset_size, capset_version;
> +    uint32_t current_id, i;
> +
> +    VirtIOGPURutabaga *vr = VIRTIO_GPU_RUTABAGA(g);
> +
> +    VIRTIO_GPU_FILL_CMD(gc);
> +    for (i = 0; i < vr->num_capsets; i++) {
> +        result = rutabaga_get_capset_info(vr->rutabaga, i,
> +                                          &current_id, &capset_version,
> +                                          &capset_size);
> +        CHECK(!result, cmd);
> +
> +        if (current_id == gc.capset_id) {
> +            break;
> +        }
> +    }
> +
> +    CHECK(i < vr->num_capsets, cmd);
> +
> +    resp = g_malloc0(sizeof(*resp) + capset_size);
> +    resp->hdr.type = VIRTIO_GPU_RESP_OK_CAPSET;
> +    rutabaga_get_capset(vr->rutabaga, gc.capset_id, gc.capset_version,
> +                        resp->capset_data, capset_size);
> +
> +    virtio_gpu_ctrl_response(g, cmd, &resp->hdr, sizeof(*resp) + capset_size);
> +    g_free(resp);
> +}
> +
> +static void
> +rutabaga_cmd_resource_create_blob(VirtIOGPU *g,
> +                                  struct virtio_gpu_ctrl_command *cmd)
> +{
> +    int result;
> +    struct rutabaga_iovecs vecs = { 0 };
> +    g_autofree struct virtio_gpu_simple_resource *res = NULL;
> +    struct virtio_gpu_resource_create_blob cblob;
> +    struct rutabaga_create_blob rc_blob = { 0 };
> +
> +    VirtIOGPURutabaga *vr = VIRTIO_GPU_RUTABAGA(g);
> +
> +    VIRTIO_GPU_FILL_CMD(cblob);
> +    trace_virtio_gpu_cmd_res_create_blob(cblob.resource_id, cblob.size);
> +
> +    CHECK(cblob.resource_id != 0, cmd);
> +
> +    res = g_new0(struct virtio_gpu_simple_resource, 1);
> +
> +    res->resource_id = cblob.resource_id;
> +    res->blob_size = cblob.size;
> +
> +    if (cblob.blob_mem != VIRTIO_GPU_BLOB_MEM_HOST3D) {
> +        result = virtio_gpu_create_mapping_iov(g, cblob.nr_entries,
> +                                               sizeof(cblob), cmd, &res->addrs,
> +                                               &res->iov, &res->iov_cnt);
> +        CHECK(!result, cmd);
> +    }
> +
> +    rc_blob.blob_id = cblob.blob_id;
> +    rc_blob.blob_mem = cblob.blob_mem;
> +    rc_blob.blob_flags = cblob.blob_flags;
> +    rc_blob.size = cblob.size;
> +
> +    vecs.iovecs = res->iov;
> +    vecs.num_iovecs = res->iov_cnt;
> +
> +    result = rutabaga_resource_create_blob(vr->rutabaga, cblob.hdr.ctx_id,
> +                                           cblob.resource_id, &rc_blob, &vecs,
> +                                           NULL);
> +
> +    if (result && cblob.blob_mem != VIRTIO_GPU_BLOB_MEM_HOST3D) {
> +        virtio_gpu_cleanup_mapping(g, res);
> +    }
> +
> +    CHECK(!result, cmd);
> +
> +    QTAILQ_INSERT_HEAD(&g->reslist, res, next);
> +    res = NULL;
> +}
> +
> +static void
> +rutabaga_cmd_resource_map_blob(VirtIOGPU *g,
> +                               struct virtio_gpu_ctrl_command *cmd)
> +{
> +    int32_t result;
> +    uint32_t map_info = 0;
> +    uint32_t slot = 0;
> +    struct virtio_gpu_simple_resource *res;
> +    struct rutabaga_mapping mapping = { 0 };
> +    struct virtio_gpu_resource_map_blob mblob;
> +    struct virtio_gpu_resp_map_info resp = { 0 };
> +
> +    VirtIOGPUBase *vb = VIRTIO_GPU_BASE(g);
> +    VirtIOGPURutabaga *vr = VIRTIO_GPU_RUTABAGA(g);
> +
> +    VIRTIO_GPU_FILL_CMD(mblob);
> +
> +    CHECK(mblob.resource_id != 0, cmd);
> +
> +    res = virtio_gpu_find_resource(g, mblob.resource_id);
> +    CHECK(res, cmd);
> +
> +    result = rutabaga_resource_map_info(vr->rutabaga, mblob.resource_id,
> +                                        &map_info);
> +    CHECK(!result, cmd);
> +
> +    /*
> +     * RUTABAGA_MAP_ACCESS_* flags are not part of the virtio-gpu spec, but do
> +     * exist to potentially allow the hypervisor to restrict write access to
> +     * memory. QEMU does not need to use this functionality at the moment.
> +     */
> +    resp.map_info = map_info & RUTABAGA_MAP_CACHE_MASK;
> +
> +    result = rutabaga_resource_map(vr->rutabaga, mblob.resource_id, &mapping);
> +    CHECK(!result, cmd);
> +
> +    for (slot = 0; slot < MAX_SLOTS; slot++) {
> +        if (vr->memory_regions[slot].used) {
> +            continue;
> +        }
> +
> +        MemoryRegion *mr = &(vr->memory_regions[slot].mr);
> +        memory_region_init_ram_ptr(mr, OBJECT(vr), "blob", mapping.size,
> +                                   mapping.ptr);
> +        memory_region_add_subregion(&vb->hostmem, mblob.offset, mr);
> +        vr->memory_regions[slot].resource_id = mblob.resource_id;
> +        vr->memory_regions[slot].used = 1;
> +        break;
> +    }
> +
> +    if (slot >= MAX_SLOTS) {
> +        result = rutabaga_resource_unmap(vr->rutabaga, mblob.resource_id);
> +        CHECK(!result, cmd);
> +    }
> +
> +    CHECK(slot < MAX_SLOTS, cmd);
> +
> +    resp.hdr.type = VIRTIO_GPU_RESP_OK_MAP_INFO;
> +    virtio_gpu_ctrl_response(g, cmd, &resp.hdr, sizeof(resp));
> +}
> +
> +static void
> +rutabaga_cmd_resource_unmap_blob(VirtIOGPU *g,
> +                                 struct virtio_gpu_ctrl_command *cmd)
> +{
> +    int32_t result;
> +    uint32_t slot = 0;
> +    struct virtio_gpu_simple_resource *res;
> +    struct virtio_gpu_resource_unmap_blob ublob;
> +
> +    VirtIOGPUBase *vb = VIRTIO_GPU_BASE(g);
> +    VirtIOGPURutabaga *vr = VIRTIO_GPU_RUTABAGA(g);
> +
> +    VIRTIO_GPU_FILL_CMD(ublob);
> +
> +    CHECK(ublob.resource_id != 0, cmd);
> +
> +    res = virtio_gpu_find_resource(g, ublob.resource_id);
> +    CHECK(res, cmd);
> +
> +    for (slot = 0; slot < MAX_SLOTS; slot++) {
> +        if (vr->memory_regions[slot].resource_id != ublob.resource_id) {
> +            continue;
> +        }
> +
> +        MemoryRegion *mr = &(vr->memory_regions[slot].mr);
> +        memory_region_del_subregion(&vb->hostmem, mr);
> +
> +        vr->memory_regions[slot].resource_id = 0;
> +        vr->memory_regions[slot].used = 0;
> +        break;
> +    }
> +
> +    CHECK(slot < MAX_SLOTS, cmd);
> +    result = rutabaga_resource_unmap(vr->rutabaga, res->resource_id);

Hi,

After the discussion with Xenia Ragiadakou regarding their patch for 
Venus, I found a bug present in the Venus implementation also affects 
Rutabaga.

The problem is that the memory region may not immediately go away with 
memory_region_del_subregion(), but it may be kept a bit after that. The 
memory region has a pointer to the mapped memory so the unmapping call 
that immediately follows will make it dangling.

Xenia raised a question whether the dangling pointer can be actually 
dereferenced and result in use-after-free, but the answer is 
unfortunately yes. For example, consider the following call chain:
kvm_cpu_exec -> address_space_rw -> address_space_write -> 
flatview_write -> flatview_write_continue

address_space_write() holds a RCU read lock so that the flatview it 
refers to will not go away during the operation even if it becomes 
obsolete and will be used for writes. It is possible that the obsolete 
flatview contains the memory region for the memory that is concurrently 
unmapped by virtio-gpu-rutabaga/virgl.  Note that the function can be 
called without holding BQL, and KVM actually does so.

Another case is address_space_map(). It acquires the reference to the 
memory with memory_region_ref() and expects it will be available until 
memory_region_unref() gets called with address_space_unmap().

In conclusion, both of Rutabaga and Virgl need to ensure to wait until 
all refrences to memory region will be gone before unmapping the 
underlying memory. The patch "[QEMU PATCH v5 07/13] softmmu/memory: 
enable automatic deallocation of memory regions" in the venus patch 
series is useful to know when that happens.

Regards,
Akihiko Odaki


^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH v13 6/9] gfxstream + rutabaga: add initial support for gfxstream
  2023-09-20 11:42   ` Akihiko Odaki
@ 2023-09-20 12:04     ` Mark Cave-Ayland
  2023-09-22  0:03       ` Gurchetan Singh
  0 siblings, 1 reply; 27+ messages in thread
From: Mark Cave-Ayland @ 2023-09-20 12:04 UTC (permalink / raw)
  To: Akihiko Odaki, Gurchetan Singh, qemu-devel, Xenia Ragiadakou
  Cc: marcandre.lureau, ray.huang, alex.bennee, shentey, hi, ernunes,
	manos.pitsidianakis, philmd, Gerd Hoffmann, Michael S . Tsirkin,
	Stefano Stabellini, Anthony PERARD, Antonio Caggiano,
	Dr . David Alan Gilbert, Robert Beckett, Dmitry Osipenko,
	xen-devel, Albert Esteve, Roger Pau Monné,
	Alex Deucher, Christian König, Pierre-Eric Pelloux-Prayer,
	Honglei Huang, Julia Zhang, Chen Jiqian

On 20/09/2023 12:42, Akihiko Odaki wrote:

> On 2023/08/29 9:36, Gurchetan Singh wrote:
>> This adds initial support for gfxstream and cross-domain.  Both
>> features rely on virtio-gpu blob resources and context types, which
>> are also implemented in this patch.
>>
>> gfxstream has a long and illustrious history in Android graphics
>> paravirtualization.  It has been powering graphics in the Android
>> Studio Emulator for more than a decade, which is the main developer
>> platform.
>>
>> Originally conceived by Jesse Hall, it was first known as "EmuGL" [a].
>> The key design characteristic was a 1:1 threading model and
>> auto-generation, which fit nicely with the OpenGLES spec.  It also
>> allowed easy layering with ANGLE on the host, which provides the GLES
>> implementations on Windows or MacOS enviroments.
>>
>> gfxstream has traditionally been maintained by a single engineer, and
>> between 2015 to 2021, the goldfish throne passed to Frank Yang.
>> Historians often remark this glorious reign ("pax gfxstreama" is the
>> academic term) was comparable to that of Augustus and both Queen
>> Elizabeths.  Just to name a few accomplishments in a resplendent
>> panoply: higher versions of GLES, address space graphics, snapshot
>> support and CTS compliant Vulkan [b].
>>
>> One major drawback was the use of out-of-tree goldfish drivers.
>> Android engineers didn't know much about DRM/KMS and especially TTM so
>> a simple guest to host pipe was conceived.
>>
>> Luckily, virtio-gpu 3D started to emerge in 2016 due to the work of
>> the Mesa/virglrenderer communities.  In 2018, the initial virtio-gpu
>> port of gfxstream was done by Cuttlefish enthusiast Alistair Delva.
>> It was a symbol compatible replacement of virglrenderer [c] and named
>> "AVDVirglrenderer".  This implementation forms the basis of the
>> current gfxstream host implementation still in use today.
>>
>> cross-domain support follows a similar arc.  Originally conceived by
>> Wayland aficionado David Reveman and crosvm enjoyer Zach Reizner in
>> 2018, it initially relied on the downstream "virtio-wl" device.
>>
>> In 2020 and 2021, virtio-gpu was extended to include blob resources
>> and multiple timelines by yours truly, features gfxstream/cross-domain
>> both require to function correctly.
>>
>> Right now, we stand at the precipice of a truly fantastic possibility:
>> the Android Emulator powered by upstream QEMU and upstream Linux
>> kernel.  gfxstream will then be packaged properfully, and app
>> developers can even fix gfxstream bugs on their own if they encounter
>> them.
>>
>> It's been quite the ride, my friends.  Where will gfxstream head next,
>> nobody really knows.  I wouldn't be surprised if it's around for
>> another decade, maintained by a new generation of Android graphics
>> enthusiasts.
>>
>> Technical details:
>>    - Very simple initial display integration: just used Pixman
>>    - Largely, 1:1 mapping of virtio-gpu hypercalls to rutabaga function
>>      calls
>>
>> Next steps for Android VMs:
>>    - The next step would be improving display integration and UI interfaces
>>      with the goal of the QEMU upstream graphics being in an emulator
>>      release [d].
>>
>> Next steps for Linux VMs for display virtualization:
>>    - For widespread distribution, someone needs to package Sommelier or the
>>      wayland-proxy-virtwl [e] ideally into Debian main. In addition, newer
>>      versions of the Linux kernel come with DRM_VIRTIO_GPU_KMS option,
>>      which allows disabling KMS hypercalls.  If anyone cares enough, it'll
>>      probably be possible to build a custom VM variant that uses this display
>>      virtualization strategy.
>>
>> [a] https://android-review.googlesource.com/c/platform/development/+/34470
>> [b] https://android-review.googlesource.com/q/topic:%22vulkan-hostconnection-start%22
>> [c] https://android-review.googlesource.com/c/device/generic/goldfish-opengl/+/761927
>> [d] https://developer.android.com/studio/releases/emulator
>> [e] https://github.com/talex5/wayland-proxy-virtwl
>>
>> Signed-off-by: Gurchetan Singh <gurchetansingh@chromium.org>
>> Tested-by: Alyssa Ross <hi@alyssa.is>
>> Tested-by: Emmanouil Pitsidianakis <manos.pitsidianakis@linaro.org>
>> Tested-by: Akihiko Odaki <akihiko.odaki@daynix.com>
>> Reviewed-by: Emmanouil Pitsidianakis <manos.pitsidianakis@linaro.org>
>> Reviewed-by: Antonio Caggiano <quic_acaggian@quicinc.com>
>> Reviewed-by: Akihiko Odaki <akihiko.odaki@daynix.com>
>> ---
>>   hw/display/virtio-gpu-pci-rutabaga.c |   47 ++
>>   hw/display/virtio-gpu-rutabaga.c     | 1119 ++++++++++++++++++++++++++
>>   hw/display/virtio-vga-rutabaga.c     |   50 ++
>>   3 files changed, 1216 insertions(+)
>>   create mode 100644 hw/display/virtio-gpu-pci-rutabaga.c
>>   create mode 100644 hw/display/virtio-gpu-rutabaga.c
>>   create mode 100644 hw/display/virtio-vga-rutabaga.c
>>
>> diff --git a/hw/display/virtio-gpu-pci-rutabaga.c 
>> b/hw/display/virtio-gpu-pci-rutabaga.c
>> new file mode 100644
>> index 0000000000..c96729e198
>> --- /dev/null
>> +++ b/hw/display/virtio-gpu-pci-rutabaga.c
>> @@ -0,0 +1,47 @@
>> +/* SPDX-License-Identifier: GPL-2.0-or-later */
>> +
>> +#include "qemu/osdep.h"
>> +#include "qapi/error.h"
>> +#include "qemu/module.h"
>> +#include "hw/pci/pci.h"
>> +#include "hw/qdev-properties.h"
>> +#include "hw/virtio/virtio.h"
>> +#include "hw/virtio/virtio-bus.h"
>> +#include "hw/virtio/virtio-gpu-pci.h"
>> +#include "qom/object.h"
>> +
>> +#define TYPE_VIRTIO_GPU_RUTABAGA_PCI "virtio-gpu-rutabaga-pci"
>> +OBJECT_DECLARE_SIMPLE_TYPE(VirtIOGPURutabagaPCI, VIRTIO_GPU_RUTABAGA_PCI)
>> +
>> +struct VirtIOGPURutabagaPCI {
>> +    VirtIOGPUPCIBase parent_obj;
>> +
>> +    VirtIOGPURutabaga vdev;
>> +};
>> +
>> +static void virtio_gpu_rutabaga_initfn(Object *obj)
>> +{
>> +    VirtIOGPURutabagaPCI *dev = VIRTIO_GPU_RUTABAGA_PCI(obj);
>> +
>> +    virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
>> +                                TYPE_VIRTIO_GPU_RUTABAGA);
>> +    VIRTIO_GPU_PCI_BASE(obj)->vgpu = VIRTIO_GPU_BASE(&dev->vdev);
>> +}
>> +
>> +static const TypeInfo virtio_gpu_rutabaga_pci_info[] = {
>> +    {
>> +        .name = TYPE_VIRTIO_GPU_RUTABAGA_PCI,
>> +        .parent = TYPE_VIRTIO_GPU_PCI_BASE,
>> +        .instance_size = sizeof(VirtIOGPURutabagaPCI),
>> +        .instance_init = virtio_gpu_rutabaga_initfn,
>> +        .interfaces = (InterfaceInfo[]) {
>> +            { INTERFACE_CONVENTIONAL_PCI_DEVICE },
>> +        }
>> +    },
>> +};
>> +
>> +DEFINE_TYPES(virtio_gpu_rutabaga_pci_info)
>> +
>> +module_obj(TYPE_VIRTIO_GPU_RUTABAGA_PCI);
>> +module_kconfig(VIRTIO_PCI);
>> +module_dep("hw-display-virtio-gpu-pci");
>> diff --git a/hw/display/virtio-gpu-rutabaga.c b/hw/display/virtio-gpu-rutabaga.c
>> new file mode 100644
>> index 0000000000..a105e06214
>> --- /dev/null
>> +++ b/hw/display/virtio-gpu-rutabaga.c
>> @@ -0,0 +1,1119 @@
>> +/* SPDX-License-Identifier: GPL-2.0-or-later */
>> +
>> +#include "qemu/osdep.h"
>> +#include "qapi/error.h"
>> +#include "qemu/error-report.h"
>> +#include "qemu/iov.h"
>> +#include "trace.h"
>> +#include "hw/virtio/virtio.h"
>> +#include "hw/virtio/virtio-gpu.h"
>> +#include "hw/virtio/virtio-gpu-pixman.h"
>> +#include "hw/virtio/virtio-iommu.h"
>> +
>> +#include <glib/gmem.h>
>> +#include <rutabaga_gfx/rutabaga_gfx_ffi.h>
>> +
>> +#define CHECK(condition, cmd)                                                 \
>> +    do {                                                                      \
>> +        if (!(condition)) {                                                   \
>> +            error_report("CHECK failed in %s() %s:" "%d", __func__,           \
>> +                         __FILE__, __LINE__);                                 \
>> +            (cmd)->error = VIRTIO_GPU_RESP_ERR_UNSPEC;                        \
>> +            return;                                                           \
>> +       }                                                                      \
>> +    } while (0)
>> +
>> +/*
>> + * This is the size of the char array in struct sock_addr_un. No Wayland socket
>> + * can be created with a path longer than this, including the null terminator.
>> + */
>> +#define UNIX_PATH_MAX sizeof((struct sockaddr_un) {} .sun_path)
>> +
>> +struct rutabaga_aio_data {
>> +    struct VirtIOGPURutabaga *vr;
>> +    struct rutabaga_fence fence;
>> +};
>> +
>> +static void
>> +virtio_gpu_rutabaga_update_cursor(VirtIOGPU *g, struct virtio_gpu_scanout *s,
>> +                                  uint32_t resource_id)
>> +{
>> +    struct virtio_gpu_simple_resource *res;
>> +    struct rutabaga_transfer transfer = { 0 };
>> +    struct iovec transfer_iovec;
>> +
>> +    VirtIOGPURutabaga *vr = VIRTIO_GPU_RUTABAGA(g);
>> +
>> +    res = virtio_gpu_find_resource(g, resource_id);
>> +    if (!res) {
>> +        return;
>> +    }
>> +
>> +    if (res->width != s->current_cursor->width ||
>> +        res->height != s->current_cursor->height) {
>> +        return;
>> +    }
>> +
>> +    transfer.x = 0;
>> +    transfer.y = 0;
>> +    transfer.z = 0;
>> +    transfer.w = res->width;
>> +    transfer.h = res->height;
>> +    transfer.d = 1;
>> +
>> +    transfer_iovec.iov_base = s->current_cursor->data;
>> +    transfer_iovec.iov_len = res->width * res->height * 4;
>> +
>> +    rutabaga_resource_transfer_read(vr->rutabaga, 0,
>> +                                    resource_id, &transfer,
>> +                                    &transfer_iovec);
>> +}
>> +
>> +static void
>> +virtio_gpu_rutabaga_gl_flushed(VirtIOGPUBase *b)
>> +{
>> +    VirtIOGPU *g = VIRTIO_GPU(b);
>> +    virtio_gpu_process_cmdq(g);
>> +}
>> +
>> +static void
>> +rutabaga_cmd_create_resource_2d(VirtIOGPU *g,
>> +                                struct virtio_gpu_ctrl_command *cmd)
>> +{
>> +    int32_t result;
>> +    struct rutabaga_create_3d rc_3d = { 0 };
>> +    struct virtio_gpu_simple_resource *res;
>> +    struct virtio_gpu_resource_create_2d c2d;
>> +
>> +    VirtIOGPURutabaga *vr = VIRTIO_GPU_RUTABAGA(g);
>> +
>> +    VIRTIO_GPU_FILL_CMD(c2d);
>> +    trace_virtio_gpu_cmd_res_create_2d(c2d.resource_id, c2d.format,
>> +                                       c2d.width, c2d.height);
>> +
>> +    rc_3d.target = 2;
>> +    rc_3d.format = c2d.format;
>> +    rc_3d.bind = (1 << 1);
>> +    rc_3d.width = c2d.width;
>> +    rc_3d.height = c2d.height;
>> +    rc_3d.depth = 1;
>> +    rc_3d.array_size = 1;
>> +    rc_3d.last_level = 0;
>> +    rc_3d.nr_samples = 0;
>> +    rc_3d.flags = VIRTIO_GPU_RESOURCE_FLAG_Y_0_TOP;
>> +
>> +    result = rutabaga_resource_create_3d(vr->rutabaga, c2d.resource_id, &rc_3d);
>> +    CHECK(!result, cmd);
>> +
>> +    res = g_new0(struct virtio_gpu_simple_resource, 1);
>> +    res->width = c2d.width;
>> +    res->height = c2d.height;
>> +    res->format = c2d.format;
>> +    res->resource_id = c2d.resource_id;
>> +
>> +    QTAILQ_INSERT_HEAD(&g->reslist, res, next);
>> +}
>> +
>> +static void
>> +rutabaga_cmd_create_resource_3d(VirtIOGPU *g,
>> +                                struct virtio_gpu_ctrl_command *cmd)
>> +{
>> +    int32_t result;
>> +    struct rutabaga_create_3d rc_3d = { 0 };
>> +    struct virtio_gpu_simple_resource *res;
>> +    struct virtio_gpu_resource_create_3d c3d;
>> +
>> +    VirtIOGPURutabaga *vr = VIRTIO_GPU_RUTABAGA(g);
>> +
>> +    VIRTIO_GPU_FILL_CMD(c3d);
>> +
>> +    trace_virtio_gpu_cmd_res_create_3d(c3d.resource_id, c3d.format,
>> +                                       c3d.width, c3d.height, c3d.depth);
>> +
>> +    rc_3d.target = c3d.target;
>> +    rc_3d.format = c3d.format;
>> +    rc_3d.bind = c3d.bind;
>> +    rc_3d.width = c3d.width;
>> +    rc_3d.height = c3d.height;
>> +    rc_3d.depth = c3d.depth;
>> +    rc_3d.array_size = c3d.array_size;
>> +    rc_3d.last_level = c3d.last_level;
>> +    rc_3d.nr_samples = c3d.nr_samples;
>> +    rc_3d.flags = c3d.flags;
>> +
>> +    result = rutabaga_resource_create_3d(vr->rutabaga, c3d.resource_id, &rc_3d);
>> +    CHECK(!result, cmd);
>> +
>> +    res = g_new0(struct virtio_gpu_simple_resource, 1);
>> +    res->width = c3d.width;
>> +    res->height = c3d.height;
>> +    res->format = c3d.format;
>> +    res->resource_id = c3d.resource_id;
>> +
>> +    QTAILQ_INSERT_HEAD(&g->reslist, res, next);
>> +}
>> +
>> +static void
>> +rutabaga_cmd_resource_unref(VirtIOGPU *g,
>> +                            struct virtio_gpu_ctrl_command *cmd)
>> +{
>> +    int32_t result;
>> +    struct virtio_gpu_simple_resource *res;
>> +    struct virtio_gpu_resource_unref unref;
>> +
>> +    VirtIOGPURutabaga *vr = VIRTIO_GPU_RUTABAGA(g);
>> +
>> +    VIRTIO_GPU_FILL_CMD(unref);
>> +
>> +    trace_virtio_gpu_cmd_res_unref(unref.resource_id);
>> +
>> +    res = virtio_gpu_find_resource(g, unref.resource_id);
>> +    CHECK(res, cmd);
>> +
>> +    result = rutabaga_resource_unref(vr->rutabaga, unref.resource_id);
>> +    CHECK(!result, cmd);
>> +
>> +    if (res->image) {
>> +        pixman_image_unref(res->image);
>> +    }
>> +
>> +    QTAILQ_REMOVE(&g->reslist, res, next);
>> +    g_free(res);
>> +}
>> +
>> +static void
>> +rutabaga_cmd_context_create(VirtIOGPU *g,
>> +                            struct virtio_gpu_ctrl_command *cmd)
>> +{
>> +    int32_t result;
>> +    struct virtio_gpu_ctx_create cc;
>> +
>> +    VirtIOGPURutabaga *vr = VIRTIO_GPU_RUTABAGA(g);
>> +
>> +    VIRTIO_GPU_FILL_CMD(cc);
>> +    trace_virtio_gpu_cmd_ctx_create(cc.hdr.ctx_id,
>> +                                    cc.debug_name);
>> +
>> +    result = rutabaga_context_create(vr->rutabaga, cc.hdr.ctx_id,
>> +                                     cc.context_init, cc.debug_name, cc.nlen);
>> +    CHECK(!result, cmd);
>> +}
>> +
>> +static void
>> +rutabaga_cmd_context_destroy(VirtIOGPU *g,
>> +                             struct virtio_gpu_ctrl_command *cmd)
>> +{
>> +    int32_t result;
>> +    struct virtio_gpu_ctx_destroy cd;
>> +
>> +    VirtIOGPURutabaga *vr = VIRTIO_GPU_RUTABAGA(g);
>> +
>> +    VIRTIO_GPU_FILL_CMD(cd);
>> +    trace_virtio_gpu_cmd_ctx_destroy(cd.hdr.ctx_id);
>> +
>> +    result = rutabaga_context_destroy(vr->rutabaga, cd.hdr.ctx_id);
>> +    CHECK(!result, cmd);
>> +}
>> +
>> +static void
>> +rutabaga_cmd_resource_flush(VirtIOGPU *g, struct virtio_gpu_ctrl_command *cmd)
>> +{
>> +    int32_t result, i;
>> +    struct virtio_gpu_scanout *scanout = NULL;
>> +    struct virtio_gpu_simple_resource *res;
>> +    struct rutabaga_transfer transfer = { 0 };
>> +    struct iovec transfer_iovec;
>> +    struct virtio_gpu_resource_flush rf;
>> +    bool found = false;
>> +
>> +    VirtIOGPUBase *vb = VIRTIO_GPU_BASE(g);
>> +    VirtIOGPURutabaga *vr = VIRTIO_GPU_RUTABAGA(g);
>> +    if (vr->headless) {
>> +        return;
>> +    }
>> +
>> +    VIRTIO_GPU_FILL_CMD(rf);
>> +    trace_virtio_gpu_cmd_res_flush(rf.resource_id,
>> +                                   rf.r.width, rf.r.height, rf.r.x, rf.r.y);
>> +
>> +    res = virtio_gpu_find_resource(g, rf.resource_id);
>> +    CHECK(res, cmd);
>> +
>> +    for (i = 0; i < vb->conf.max_outputs; i++) {
>> +        scanout = &vb->scanout[i];
>> +        if (i == res->scanout_bitmask) {
>> +            found = true;
>> +            break;
>> +        }
>> +    }
>> +
>> +    if (!found) {
>> +        return;
>> +    }
>> +
>> +    transfer.x = 0;
>> +    transfer.y = 0;
>> +    transfer.z = 0;
>> +    transfer.w = res->width;
>> +    transfer.h = res->height;
>> +    transfer.d = 1;
>> +
>> +    transfer_iovec.iov_base = pixman_image_get_data(res->image);
>> +    transfer_iovec.iov_len = res->width * res->height * 4;
>> +
>> +    result = rutabaga_resource_transfer_read(vr->rutabaga, 0,
>> +                                             rf.resource_id, &transfer,
>> +                                             &transfer_iovec);
>> +    CHECK(!result, cmd);
>> +    dpy_gfx_update_full(scanout->con);
>> +}
>> +
>> +static void
>> +rutabaga_cmd_set_scanout(VirtIOGPU *g, struct virtio_gpu_ctrl_command *cmd)
>> +{
>> +    struct virtio_gpu_simple_resource *res;
>> +    struct virtio_gpu_scanout *scanout = NULL;
>> +    struct virtio_gpu_set_scanout ss;
>> +
>> +    VirtIOGPUBase *vb = VIRTIO_GPU_BASE(g);
>> +    VirtIOGPURutabaga *vr = VIRTIO_GPU_RUTABAGA(g);
>> +    if (vr->headless) {
>> +        return;
>> +    }
>> +
>> +    VIRTIO_GPU_FILL_CMD(ss);
>> +    trace_virtio_gpu_cmd_set_scanout(ss.scanout_id, ss.resource_id,
>> +                                     ss.r.width, ss.r.height, ss.r.x, ss.r.y);
>> +
>> +    CHECK(ss.scanout_id < VIRTIO_GPU_MAX_SCANOUTS, cmd);
>> +    scanout = &vb->scanout[ss.scanout_id];
>> +
>> +    if (ss.resource_id == 0) {
>> +        dpy_gfx_replace_surface(scanout->con, NULL);
>> +        dpy_gl_scanout_disable(scanout->con);
>> +        return;
>> +    }
>> +
>> +    res = virtio_gpu_find_resource(g, ss.resource_id);
>> +    CHECK(res, cmd);
>> +
>> +    if (!res->image) {
>> +        pixman_format_code_t pformat;
>> +        pformat = virtio_gpu_get_pixman_format(res->format);
>> +        CHECK(pformat, cmd);
>> +
>> +        res->image = pixman_image_create_bits(pformat,
>> +                                              res->width,
>> +                                              res->height,
>> +                                              NULL, 0);
>> +        CHECK(res->image, cmd);
>> +        pixman_image_ref(res->image);
>> +    }
>> +
>> +    vb->enable = 1;
>> +
>> +    /* realloc the surface ptr */
>> +    scanout->ds = qemu_create_displaysurface_pixman(res->image);
>> +    dpy_gfx_replace_surface(scanout->con, NULL);
>> +    dpy_gfx_replace_surface(scanout->con, scanout->ds);
>> +    res->scanout_bitmask = ss.scanout_id;
>> +}
>> +
>> +static void
>> +rutabaga_cmd_submit_3d(VirtIOGPU *g,
>> +                       struct virtio_gpu_ctrl_command *cmd)
>> +{
>> +    int32_t result;
>> +    struct virtio_gpu_cmd_submit cs;
>> +    struct rutabaga_command rutabaga_cmd = { 0 };
>> +    g_autofree uint8_t *buf = NULL;
>> +    size_t s;
>> +
>> +    VirtIOGPURutabaga *vr = VIRTIO_GPU_RUTABAGA(g);
>> +
>> +    VIRTIO_GPU_FILL_CMD(cs);
>> +    trace_virtio_gpu_cmd_ctx_submit(cs.hdr.ctx_id, cs.size);
>> +
>> +    buf = g_new0(uint8_t, cs.size);
>> +    s = iov_to_buf(cmd->elem.out_sg, cmd->elem.out_num,
>> +                   sizeof(cs), buf, cs.size);
>> +    CHECK(s == cs.size, cmd);
>> +
>> +    rutabaga_cmd.ctx_id = cs.hdr.ctx_id;
>> +    rutabaga_cmd.cmd = buf;
>> +    rutabaga_cmd.cmd_size = cs.size;
>> +
>> +    result = rutabaga_submit_command(vr->rutabaga, &rutabaga_cmd);
>> +    CHECK(!result, cmd);
>> +}
>> +
>> +static void
>> +rutabaga_cmd_transfer_to_host_2d(VirtIOGPU *g,
>> +                                 struct virtio_gpu_ctrl_command *cmd)
>> +{
>> +    int32_t result;
>> +    struct rutabaga_transfer transfer = { 0 };
>> +    struct virtio_gpu_transfer_to_host_2d t2d;
>> +
>> +    VirtIOGPURutabaga *vr = VIRTIO_GPU_RUTABAGA(g);
>> +
>> +    VIRTIO_GPU_FILL_CMD(t2d);
>> +    trace_virtio_gpu_cmd_res_xfer_toh_2d(t2d.resource_id);
>> +
>> +    transfer.x = t2d.r.x;
>> +    transfer.y = t2d.r.y;
>> +    transfer.z = 0;
>> +    transfer.w = t2d.r.width;
>> +    transfer.h = t2d.r.height;
>> +    transfer.d = 1;
>> +
>> +    result = rutabaga_resource_transfer_write(vr->rutabaga, 0, t2d.resource_id,
>> +                                              &transfer);
>> +    CHECK(!result, cmd);
>> +}
>> +
>> +static void
>> +rutabaga_cmd_transfer_to_host_3d(VirtIOGPU *g,
>> +                                 struct virtio_gpu_ctrl_command *cmd)
>> +{
>> +    int32_t result;
>> +    struct rutabaga_transfer transfer = { 0 };
>> +    struct virtio_gpu_transfer_host_3d t3d;
>> +
>> +    VirtIOGPURutabaga *vr = VIRTIO_GPU_RUTABAGA(g);
>> +
>> +    VIRTIO_GPU_FILL_CMD(t3d);
>> +    trace_virtio_gpu_cmd_res_xfer_toh_3d(t3d.resource_id);
>> +
>> +    transfer.x = t3d.box.x;
>> +    transfer.y = t3d.box.y;
>> +    transfer.z = t3d.box.z;
>> +    transfer.w = t3d.box.w;
>> +    transfer.h = t3d.box.h;
>> +    transfer.d = t3d.box.d;
>> +    transfer.level = t3d.level;
>> +    transfer.stride = t3d.stride;
>> +    transfer.layer_stride = t3d.layer_stride;
>> +    transfer.offset = t3d.offset;
>> +
>> +    result = rutabaga_resource_transfer_write(vr->rutabaga, t3d.hdr.ctx_id,
>> +                                              t3d.resource_id, &transfer);
>> +    CHECK(!result, cmd);
>> +}
>> +
>> +static void
>> +rutabaga_cmd_transfer_from_host_3d(VirtIOGPU *g,
>> +                                   struct virtio_gpu_ctrl_command *cmd)
>> +{
>> +    int32_t result;
>> +    struct rutabaga_transfer transfer = { 0 };
>> +    struct virtio_gpu_transfer_host_3d t3d;
>> +
>> +    VirtIOGPURutabaga *vr = VIRTIO_GPU_RUTABAGA(g);
>> +
>> +    VIRTIO_GPU_FILL_CMD(t3d);
>> +    trace_virtio_gpu_cmd_res_xfer_fromh_3d(t3d.resource_id);
>> +
>> +    transfer.x = t3d.box.x;
>> +    transfer.y = t3d.box.y;
>> +    transfer.z = t3d.box.z;
>> +    transfer.w = t3d.box.w;
>> +    transfer.h = t3d.box.h;
>> +    transfer.d = t3d.box.d;
>> +    transfer.level = t3d.level;
>> +    transfer.stride = t3d.stride;
>> +    transfer.layer_stride = t3d.layer_stride;
>> +    transfer.offset = t3d.offset;
>> +
>> +    result = rutabaga_resource_transfer_read(vr->rutabaga, t3d.hdr.ctx_id,
>> +                                             t3d.resource_id, &transfer, NULL);
>> +    CHECK(!result, cmd);
>> +}
>> +
>> +static void
>> +rutabaga_cmd_attach_backing(VirtIOGPU *g, struct virtio_gpu_ctrl_command *cmd)
>> +{
>> +    struct rutabaga_iovecs vecs = { 0 };
>> +    struct virtio_gpu_simple_resource *res;
>> +    struct virtio_gpu_resource_attach_backing att_rb;
>> +    int ret;
>> +
>> +    VirtIOGPURutabaga *vr = VIRTIO_GPU_RUTABAGA(g);
>> +
>> +    VIRTIO_GPU_FILL_CMD(att_rb);
>> +    trace_virtio_gpu_cmd_res_back_attach(att_rb.resource_id);
>> +
>> +    res = virtio_gpu_find_resource(g, att_rb.resource_id);
>> +    CHECK(res, cmd);
>> +    CHECK(!res->iov, cmd);
>> +
>> +    ret = virtio_gpu_create_mapping_iov(g, att_rb.nr_entries, sizeof(att_rb),
>> +                                        cmd, NULL, &res->iov, &res->iov_cnt);
>> +    CHECK(!ret, cmd);
>> +
>> +    vecs.iovecs = res->iov;
>> +    vecs.num_iovecs = res->iov_cnt;
>> +
>> +    ret = rutabaga_resource_attach_backing(vr->rutabaga, att_rb.resource_id,
>> +                                           &vecs);
>> +    if (ret != 0) {
>> +        virtio_gpu_cleanup_mapping(g, res);
>> +    }
>> +
>> +    CHECK(!ret, cmd);
>> +}
>> +
>> +static void
>> +rutabaga_cmd_detach_backing(VirtIOGPU *g, struct virtio_gpu_ctrl_command *cmd)
>> +{
>> +    struct virtio_gpu_simple_resource *res;
>> +    struct virtio_gpu_resource_detach_backing detach_rb;
>> +
>> +    VirtIOGPURutabaga *vr = VIRTIO_GPU_RUTABAGA(g);
>> +
>> +    VIRTIO_GPU_FILL_CMD(detach_rb);
>> +    trace_virtio_gpu_cmd_res_back_detach(detach_rb.resource_id);
>> +
>> +    res = virtio_gpu_find_resource(g, detach_rb.resource_id);
>> +    CHECK(res, cmd);
>> +
>> +    rutabaga_resource_detach_backing(vr->rutabaga,
>> +                                     detach_rb.resource_id);
>> +
>> +    virtio_gpu_cleanup_mapping(g, res);
>> +}
>> +
>> +static void
>> +rutabaga_cmd_ctx_attach_resource(VirtIOGPU *g,
>> +                                 struct virtio_gpu_ctrl_command *cmd)
>> +{
>> +    int32_t result;
>> +    struct virtio_gpu_ctx_resource att_res;
>> +
>> +    VirtIOGPURutabaga *vr = VIRTIO_GPU_RUTABAGA(g);
>> +
>> +    VIRTIO_GPU_FILL_CMD(att_res);
>> +    trace_virtio_gpu_cmd_ctx_res_attach(att_res.hdr.ctx_id,
>> +                                        att_res.resource_id);
>> +
>> +    result = rutabaga_context_attach_resource(vr->rutabaga, att_res.hdr.ctx_id,
>> +                                              att_res.resource_id);
>> +    CHECK(!result, cmd);
>> +}
>> +
>> +static void
>> +rutabaga_cmd_ctx_detach_resource(VirtIOGPU *g,
>> +                                 struct virtio_gpu_ctrl_command *cmd)
>> +{
>> +    int32_t result;
>> +    struct virtio_gpu_ctx_resource det_res;
>> +
>> +    VirtIOGPURutabaga *vr = VIRTIO_GPU_RUTABAGA(g);
>> +
>> +    VIRTIO_GPU_FILL_CMD(det_res);
>> +    trace_virtio_gpu_cmd_ctx_res_detach(det_res.hdr.ctx_id,
>> +                                        det_res.resource_id);
>> +
>> +    result = rutabaga_context_detach_resource(vr->rutabaga, det_res.hdr.ctx_id,
>> +                                              det_res.resource_id);
>> +    CHECK(!result, cmd);
>> +}
>> +
>> +static void
>> +rutabaga_cmd_get_capset_info(VirtIOGPU *g, struct virtio_gpu_ctrl_command *cmd)
>> +{
>> +    int32_t result;
>> +    struct virtio_gpu_get_capset_info info;
>> +    struct virtio_gpu_resp_capset_info resp;
>> +
>> +    VirtIOGPURutabaga *vr = VIRTIO_GPU_RUTABAGA(g);
>> +
>> +    VIRTIO_GPU_FILL_CMD(info);
>> +
>> +    result = rutabaga_get_capset_info(vr->rutabaga, info.capset_index,
>> +                                      &resp.capset_id, &resp.capset_max_version,
>> +                                      &resp.capset_max_size);
>> +    CHECK(!result, cmd);
>> +
>> +    resp.hdr.type = VIRTIO_GPU_RESP_OK_CAPSET_INFO;
>> +    virtio_gpu_ctrl_response(g, cmd, &resp.hdr, sizeof(resp));
>> +}
>> +
>> +static void
>> +rutabaga_cmd_get_capset(VirtIOGPU *g, struct virtio_gpu_ctrl_command *cmd)
>> +{
>> +    int32_t result;
>> +    struct virtio_gpu_get_capset gc;
>> +    struct virtio_gpu_resp_capset *resp;
>> +    uint32_t capset_size, capset_version;
>> +    uint32_t current_id, i;
>> +
>> +    VirtIOGPURutabaga *vr = VIRTIO_GPU_RUTABAGA(g);
>> +
>> +    VIRTIO_GPU_FILL_CMD(gc);
>> +    for (i = 0; i < vr->num_capsets; i++) {
>> +        result = rutabaga_get_capset_info(vr->rutabaga, i,
>> +                                          &current_id, &capset_version,
>> +                                          &capset_size);
>> +        CHECK(!result, cmd);
>> +
>> +        if (current_id == gc.capset_id) {
>> +            break;
>> +        }
>> +    }
>> +
>> +    CHECK(i < vr->num_capsets, cmd);
>> +
>> +    resp = g_malloc0(sizeof(*resp) + capset_size);
>> +    resp->hdr.type = VIRTIO_GPU_RESP_OK_CAPSET;
>> +    rutabaga_get_capset(vr->rutabaga, gc.capset_id, gc.capset_version,
>> +                        resp->capset_data, capset_size);
>> +
>> +    virtio_gpu_ctrl_response(g, cmd, &resp->hdr, sizeof(*resp) + capset_size);
>> +    g_free(resp);
>> +}
>> +
>> +static void
>> +rutabaga_cmd_resource_create_blob(VirtIOGPU *g,
>> +                                  struct virtio_gpu_ctrl_command *cmd)
>> +{
>> +    int result;
>> +    struct rutabaga_iovecs vecs = { 0 };
>> +    g_autofree struct virtio_gpu_simple_resource *res = NULL;
>> +    struct virtio_gpu_resource_create_blob cblob;
>> +    struct rutabaga_create_blob rc_blob = { 0 };
>> +
>> +    VirtIOGPURutabaga *vr = VIRTIO_GPU_RUTABAGA(g);
>> +
>> +    VIRTIO_GPU_FILL_CMD(cblob);
>> +    trace_virtio_gpu_cmd_res_create_blob(cblob.resource_id, cblob.size);
>> +
>> +    CHECK(cblob.resource_id != 0, cmd);
>> +
>> +    res = g_new0(struct virtio_gpu_simple_resource, 1);
>> +
>> +    res->resource_id = cblob.resource_id;
>> +    res->blob_size = cblob.size;
>> +
>> +    if (cblob.blob_mem != VIRTIO_GPU_BLOB_MEM_HOST3D) {
>> +        result = virtio_gpu_create_mapping_iov(g, cblob.nr_entries,
>> +                                               sizeof(cblob), cmd, &res->addrs,
>> +                                               &res->iov, &res->iov_cnt);
>> +        CHECK(!result, cmd);
>> +    }
>> +
>> +    rc_blob.blob_id = cblob.blob_id;
>> +    rc_blob.blob_mem = cblob.blob_mem;
>> +    rc_blob.blob_flags = cblob.blob_flags;
>> +    rc_blob.size = cblob.size;
>> +
>> +    vecs.iovecs = res->iov;
>> +    vecs.num_iovecs = res->iov_cnt;
>> +
>> +    result = rutabaga_resource_create_blob(vr->rutabaga, cblob.hdr.ctx_id,
>> +                                           cblob.resource_id, &rc_blob, &vecs,
>> +                                           NULL);
>> +
>> +    if (result && cblob.blob_mem != VIRTIO_GPU_BLOB_MEM_HOST3D) {
>> +        virtio_gpu_cleanup_mapping(g, res);
>> +    }
>> +
>> +    CHECK(!result, cmd);
>> +
>> +    QTAILQ_INSERT_HEAD(&g->reslist, res, next);
>> +    res = NULL;
>> +}
>> +
>> +static void
>> +rutabaga_cmd_resource_map_blob(VirtIOGPU *g,
>> +                               struct virtio_gpu_ctrl_command *cmd)
>> +{
>> +    int32_t result;
>> +    uint32_t map_info = 0;
>> +    uint32_t slot = 0;
>> +    struct virtio_gpu_simple_resource *res;
>> +    struct rutabaga_mapping mapping = { 0 };
>> +    struct virtio_gpu_resource_map_blob mblob;
>> +    struct virtio_gpu_resp_map_info resp = { 0 };
>> +
>> +    VirtIOGPUBase *vb = VIRTIO_GPU_BASE(g);
>> +    VirtIOGPURutabaga *vr = VIRTIO_GPU_RUTABAGA(g);
>> +
>> +    VIRTIO_GPU_FILL_CMD(mblob);
>> +
>> +    CHECK(mblob.resource_id != 0, cmd);
>> +
>> +    res = virtio_gpu_find_resource(g, mblob.resource_id);
>> +    CHECK(res, cmd);
>> +
>> +    result = rutabaga_resource_map_info(vr->rutabaga, mblob.resource_id,
>> +                                        &map_info);
>> +    CHECK(!result, cmd);
>> +
>> +    /*
>> +     * RUTABAGA_MAP_ACCESS_* flags are not part of the virtio-gpu spec, but do
>> +     * exist to potentially allow the hypervisor to restrict write access to
>> +     * memory. QEMU does not need to use this functionality at the moment.
>> +     */
>> +    resp.map_info = map_info & RUTABAGA_MAP_CACHE_MASK;
>> +
>> +    result = rutabaga_resource_map(vr->rutabaga, mblob.resource_id, &mapping);
>> +    CHECK(!result, cmd);
>> +
>> +    for (slot = 0; slot < MAX_SLOTS; slot++) {
>> +        if (vr->memory_regions[slot].used) {
>> +            continue;
>> +        }
>> +
>> +        MemoryRegion *mr = &(vr->memory_regions[slot].mr);
>> +        memory_region_init_ram_ptr(mr, OBJECT(vr), "blob", mapping.size,
>> +                                   mapping.ptr);
>> +        memory_region_add_subregion(&vb->hostmem, mblob.offset, mr);
>> +        vr->memory_regions[slot].resource_id = mblob.resource_id;
>> +        vr->memory_regions[slot].used = 1;
>> +        break;
>> +    }
>> +
>> +    if (slot >= MAX_SLOTS) {
>> +        result = rutabaga_resource_unmap(vr->rutabaga, mblob.resource_id);
>> +        CHECK(!result, cmd);
>> +    }
>> +
>> +    CHECK(slot < MAX_SLOTS, cmd);
>> +
>> +    resp.hdr.type = VIRTIO_GPU_RESP_OK_MAP_INFO;
>> +    virtio_gpu_ctrl_response(g, cmd, &resp.hdr, sizeof(resp));
>> +}
>> +
>> +static void
>> +rutabaga_cmd_resource_unmap_blob(VirtIOGPU *g,
>> +                                 struct virtio_gpu_ctrl_command *cmd)
>> +{
>> +    int32_t result;
>> +    uint32_t slot = 0;
>> +    struct virtio_gpu_simple_resource *res;
>> +    struct virtio_gpu_resource_unmap_blob ublob;
>> +
>> +    VirtIOGPUBase *vb = VIRTIO_GPU_BASE(g);
>> +    VirtIOGPURutabaga *vr = VIRTIO_GPU_RUTABAGA(g);
>> +
>> +    VIRTIO_GPU_FILL_CMD(ublob);
>> +
>> +    CHECK(ublob.resource_id != 0, cmd);
>> +
>> +    res = virtio_gpu_find_resource(g, ublob.resource_id);
>> +    CHECK(res, cmd);
>> +
>> +    for (slot = 0; slot < MAX_SLOTS; slot++) {
>> +        if (vr->memory_regions[slot].resource_id != ublob.resource_id) {
>> +            continue;
>> +        }
>> +
>> +        MemoryRegion *mr = &(vr->memory_regions[slot].mr);
>> +        memory_region_del_subregion(&vb->hostmem, mr);
>> +
>> +        vr->memory_regions[slot].resource_id = 0;
>> +        vr->memory_regions[slot].used = 0;
>> +        break;
>> +    }
>> +
>> +    CHECK(slot < MAX_SLOTS, cmd);
>> +    result = rutabaga_resource_unmap(vr->rutabaga, res->resource_id);
> 
> Hi,
> 
> After the discussion with Xenia Ragiadakou regarding their patch for Venus, I found a 
> bug present in the Venus implementation also affects Rutabaga.
> 
> The problem is that the memory region may not immediately go away with 
> memory_region_del_subregion(), but it may be kept a bit after that. The memory region 
> has a pointer to the mapped memory so the unmapping call that immediately follows 
> will make it dangling.
> 
> Xenia raised a question whether the dangling pointer can be actually dereferenced and 
> result in use-after-free, but the answer is unfortunately yes. For example, consider 
> the following call chain:
> kvm_cpu_exec -> address_space_rw -> address_space_write -> flatview_write -> 
> flatview_write_continue
> 
> address_space_write() holds a RCU read lock so that the flatview it refers to will 
> not go away during the operation even if it becomes obsolete and will be used for 
> writes. It is possible that the obsolete flatview contains the memory region for the 
> memory that is concurrently unmapped by virtio-gpu-rutabaga/virgl.  Note that the 
> function can be called without holding BQL, and KVM actually does so.
> 
> Another case is address_space_map(). It acquires the reference to the memory with 
> memory_region_ref() and expects it will be available until memory_region_unref() gets 
> called with address_space_unmap().
> 
> In conclusion, both of Rutabaga and Virgl need to ensure to wait until all refrences 
> to memory region will be gone before unmapping the underlying memory. The patch 
> "[QEMU PATCH v5 07/13] softmmu/memory: enable automatic deallocation of memory 
> regions" in the venus patch series is useful to know when that happens.

FWIW this sounds exactly the same as the issue I had with unmapping ioports in commit 
690705ca0b ("softmmu/ioport.c: make MemoryRegionPortioList owner of portio_list 
MemoryRegions").

The solution in that commit is to assign the MemoryRegion reference to a new QOM 
object using memory_region_init(), but then re-parent the MR back onto its original 
device owner (so the QOM tree in "info qom-tree" remains unchanged). This means that 
the new QOM object receives the unref notification from the flatview instead of the 
MemoryRegion, which then manually unmaps the MemoryRegion from the device when it is 
safe.


ATB,

Mark.



^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH v13 6/9] gfxstream + rutabaga: add initial support for gfxstream
  2023-09-20 12:04     ` Mark Cave-Ayland
@ 2023-09-22  0:03       ` Gurchetan Singh
  2023-09-22  2:53         ` Akihiko Odaki
  0 siblings, 1 reply; 27+ messages in thread
From: Gurchetan Singh @ 2023-09-22  0:03 UTC (permalink / raw)
  To: Mark Cave-Ayland
  Cc: Akihiko Odaki, qemu-devel, Xenia Ragiadakou, marcandre.lureau,
	ray.huang, alex.bennee, shentey, hi, ernunes,
	manos.pitsidianakis, philmd, Gerd Hoffmann, Michael S . Tsirkin,
	Stefano Stabellini, Anthony PERARD, Antonio Caggiano,
	Dr . David Alan Gilbert, Robert Beckett, Dmitry Osipenko,
	xen-devel, Albert Esteve, Roger Pau Monné,
	Alex Deucher, Christian König, Pierre-Eric Pelloux-Prayer,
	Honglei Huang, Julia Zhang, Chen Jiqian

[-- Attachment #1: Type: text/plain, Size: 38162 bytes --]

On Wed, Sep 20, 2023 at 5:05 AM Mark Cave-Ayland <
mark.cave-ayland@ilande.co.uk> wrote:

> On 20/09/2023 12:42, Akihiko Odaki wrote:
>
> > On 2023/08/29 9:36, Gurchetan Singh wrote:
> >> This adds initial support for gfxstream and cross-domain.  Both
> >> features rely on virtio-gpu blob resources and context types, which
> >> are also implemented in this patch.
> >>
> >> gfxstream has a long and illustrious history in Android graphics
> >> paravirtualization.  It has been powering graphics in the Android
> >> Studio Emulator for more than a decade, which is the main developer
> >> platform.
> >>
> >> Originally conceived by Jesse Hall, it was first known as "EmuGL" [a].
> >> The key design characteristic was a 1:1 threading model and
> >> auto-generation, which fit nicely with the OpenGLES spec.  It also
> >> allowed easy layering with ANGLE on the host, which provides the GLES
> >> implementations on Windows or MacOS enviroments.
> >>
> >> gfxstream has traditionally been maintained by a single engineer, and
> >> between 2015 to 2021, the goldfish throne passed to Frank Yang.
> >> Historians often remark this glorious reign ("pax gfxstreama" is the
> >> academic term) was comparable to that of Augustus and both Queen
> >> Elizabeths.  Just to name a few accomplishments in a resplendent
> >> panoply: higher versions of GLES, address space graphics, snapshot
> >> support and CTS compliant Vulkan [b].
> >>
> >> One major drawback was the use of out-of-tree goldfish drivers.
> >> Android engineers didn't know much about DRM/KMS and especially TTM so
> >> a simple guest to host pipe was conceived.
> >>
> >> Luckily, virtio-gpu 3D started to emerge in 2016 due to the work of
> >> the Mesa/virglrenderer communities.  In 2018, the initial virtio-gpu
> >> port of gfxstream was done by Cuttlefish enthusiast Alistair Delva.
> >> It was a symbol compatible replacement of virglrenderer [c] and named
> >> "AVDVirglrenderer".  This implementation forms the basis of the
> >> current gfxstream host implementation still in use today.
> >>
> >> cross-domain support follows a similar arc.  Originally conceived by
> >> Wayland aficionado David Reveman and crosvm enjoyer Zach Reizner in
> >> 2018, it initially relied on the downstream "virtio-wl" device.
> >>
> >> In 2020 and 2021, virtio-gpu was extended to include blob resources
> >> and multiple timelines by yours truly, features gfxstream/cross-domain
> >> both require to function correctly.
> >>
> >> Right now, we stand at the precipice of a truly fantastic possibility:
> >> the Android Emulator powered by upstream QEMU and upstream Linux
> >> kernel.  gfxstream will then be packaged properfully, and app
> >> developers can even fix gfxstream bugs on their own if they encounter
> >> them.
> >>
> >> It's been quite the ride, my friends.  Where will gfxstream head next,
> >> nobody really knows.  I wouldn't be surprised if it's around for
> >> another decade, maintained by a new generation of Android graphics
> >> enthusiasts.
> >>
> >> Technical details:
> >>    - Very simple initial display integration: just used Pixman
> >>    - Largely, 1:1 mapping of virtio-gpu hypercalls to rutabaga function
> >>      calls
> >>
> >> Next steps for Android VMs:
> >>    - The next step would be improving display integration and UI
> interfaces
> >>      with the goal of the QEMU upstream graphics being in an emulator
> >>      release [d].
> >>
> >> Next steps for Linux VMs for display virtualization:
> >>    - For widespread distribution, someone needs to package Sommelier or
> the
> >>      wayland-proxy-virtwl [e] ideally into Debian main. In addition,
> newer
> >>      versions of the Linux kernel come with DRM_VIRTIO_GPU_KMS option,
> >>      which allows disabling KMS hypercalls.  If anyone cares enough,
> it'll
> >>      probably be possible to build a custom VM variant that uses this
> display
> >>      virtualization strategy.
> >>
> >> [a]
> https://android-review.googlesource.com/c/platform/development/+/34470
> >> [b]
> https://android-review.googlesource.com/q/topic:%22vulkan-hostconnection-start%22
> >> [c]
> https://android-review.googlesource.com/c/device/generic/goldfish-opengl/+/761927
> >> [d] https://developer.android.com/studio/releases/emulator
> >> [e] https://github.com/talex5/wayland-proxy-virtwl
> >>
> >> Signed-off-by: Gurchetan Singh <gurchetansingh@chromium.org>
> >> Tested-by: Alyssa Ross <hi@alyssa.is>
> >> Tested-by: Emmanouil Pitsidianakis <manos.pitsidianakis@linaro.org>
> >> Tested-by: Akihiko Odaki <akihiko.odaki@daynix.com>
> >> Reviewed-by: Emmanouil Pitsidianakis <manos.pitsidianakis@linaro.org>
> >> Reviewed-by: Antonio Caggiano <quic_acaggian@quicinc.com>
> >> Reviewed-by: Akihiko Odaki <akihiko.odaki@daynix.com>
> >> ---
> >>   hw/display/virtio-gpu-pci-rutabaga.c |   47 ++
> >>   hw/display/virtio-gpu-rutabaga.c     | 1119 ++++++++++++++++++++++++++
> >>   hw/display/virtio-vga-rutabaga.c     |   50 ++
> >>   3 files changed, 1216 insertions(+)
> >>   create mode 100644 hw/display/virtio-gpu-pci-rutabaga.c
> >>   create mode 100644 hw/display/virtio-gpu-rutabaga.c
> >>   create mode 100644 hw/display/virtio-vga-rutabaga.c
> >>
> >> diff --git a/hw/display/virtio-gpu-pci-rutabaga.c
> >> b/hw/display/virtio-gpu-pci-rutabaga.c
> >> new file mode 100644
> >> index 0000000000..c96729e198
> >> --- /dev/null
> >> +++ b/hw/display/virtio-gpu-pci-rutabaga.c
> >> @@ -0,0 +1,47 @@
> >> +/* SPDX-License-Identifier: GPL-2.0-or-later */
> >> +
> >> +#include "qemu/osdep.h"
> >> +#include "qapi/error.h"
> >> +#include "qemu/module.h"
> >> +#include "hw/pci/pci.h"
> >> +#include "hw/qdev-properties.h"
> >> +#include "hw/virtio/virtio.h"
> >> +#include "hw/virtio/virtio-bus.h"
> >> +#include "hw/virtio/virtio-gpu-pci.h"
> >> +#include "qom/object.h"
> >> +
> >> +#define TYPE_VIRTIO_GPU_RUTABAGA_PCI "virtio-gpu-rutabaga-pci"
> >> +OBJECT_DECLARE_SIMPLE_TYPE(VirtIOGPURutabagaPCI,
> VIRTIO_GPU_RUTABAGA_PCI)
> >> +
> >> +struct VirtIOGPURutabagaPCI {
> >> +    VirtIOGPUPCIBase parent_obj;
> >> +
> >> +    VirtIOGPURutabaga vdev;
> >> +};
> >> +
> >> +static void virtio_gpu_rutabaga_initfn(Object *obj)
> >> +{
> >> +    VirtIOGPURutabagaPCI *dev = VIRTIO_GPU_RUTABAGA_PCI(obj);
> >> +
> >> +    virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
> >> +                                TYPE_VIRTIO_GPU_RUTABAGA);
> >> +    VIRTIO_GPU_PCI_BASE(obj)->vgpu = VIRTIO_GPU_BASE(&dev->vdev);
> >> +}
> >> +
> >> +static const TypeInfo virtio_gpu_rutabaga_pci_info[] = {
> >> +    {
> >> +        .name = TYPE_VIRTIO_GPU_RUTABAGA_PCI,
> >> +        .parent = TYPE_VIRTIO_GPU_PCI_BASE,
> >> +        .instance_size = sizeof(VirtIOGPURutabagaPCI),
> >> +        .instance_init = virtio_gpu_rutabaga_initfn,
> >> +        .interfaces = (InterfaceInfo[]) {
> >> +            { INTERFACE_CONVENTIONAL_PCI_DEVICE },
> >> +        }
> >> +    },
> >> +};
> >> +
> >> +DEFINE_TYPES(virtio_gpu_rutabaga_pci_info)
> >> +
> >> +module_obj(TYPE_VIRTIO_GPU_RUTABAGA_PCI);
> >> +module_kconfig(VIRTIO_PCI);
> >> +module_dep("hw-display-virtio-gpu-pci");
> >> diff --git a/hw/display/virtio-gpu-rutabaga.c
> b/hw/display/virtio-gpu-rutabaga.c
> >> new file mode 100644
> >> index 0000000000..a105e06214
> >> --- /dev/null
> >> +++ b/hw/display/virtio-gpu-rutabaga.c
> >> @@ -0,0 +1,1119 @@
> >> +/* SPDX-License-Identifier: GPL-2.0-or-later */
> >> +
> >> +#include "qemu/osdep.h"
> >> +#include "qapi/error.h"
> >> +#include "qemu/error-report.h"
> >> +#include "qemu/iov.h"
> >> +#include "trace.h"
> >> +#include "hw/virtio/virtio.h"
> >> +#include "hw/virtio/virtio-gpu.h"
> >> +#include "hw/virtio/virtio-gpu-pixman.h"
> >> +#include "hw/virtio/virtio-iommu.h"
> >> +
> >> +#include <glib/gmem.h>
> >> +#include <rutabaga_gfx/rutabaga_gfx_ffi.h>
> >> +
> >> +#define CHECK(condition,
> cmd)                                                 \
> >> +    do
> {                                                                      \
> >> +        if (!(condition))
> {                                                   \
> >> +            error_report("CHECK failed in %s() %s:" "%d",
> __func__,           \
> >> +                         __FILE__,
> __LINE__);                                 \
> >> +            (cmd)->error =
> VIRTIO_GPU_RESP_ERR_UNSPEC;                        \
> >> +
> return;                                                           \
> >> +
> }                                                                      \
> >> +    } while (0)
> >> +
> >> +/*
> >> + * This is the size of the char array in struct sock_addr_un. No
> Wayland socket
> >> + * can be created with a path longer than this, including the null
> terminator.
> >> + */
> >> +#define UNIX_PATH_MAX sizeof((struct sockaddr_un) {} .sun_path)
> >> +
> >> +struct rutabaga_aio_data {
> >> +    struct VirtIOGPURutabaga *vr;
> >> +    struct rutabaga_fence fence;
> >> +};
> >> +
> >> +static void
> >> +virtio_gpu_rutabaga_update_cursor(VirtIOGPU *g, struct
> virtio_gpu_scanout *s,
> >> +                                  uint32_t resource_id)
> >> +{
> >> +    struct virtio_gpu_simple_resource *res;
> >> +    struct rutabaga_transfer transfer = { 0 };
> >> +    struct iovec transfer_iovec;
> >> +
> >> +    VirtIOGPURutabaga *vr = VIRTIO_GPU_RUTABAGA(g);
> >> +
> >> +    res = virtio_gpu_find_resource(g, resource_id);
> >> +    if (!res) {
> >> +        return;
> >> +    }
> >> +
> >> +    if (res->width != s->current_cursor->width ||
> >> +        res->height != s->current_cursor->height) {
> >> +        return;
> >> +    }
> >> +
> >> +    transfer.x = 0;
> >> +    transfer.y = 0;
> >> +    transfer.z = 0;
> >> +    transfer.w = res->width;
> >> +    transfer.h = res->height;
> >> +    transfer.d = 1;
> >> +
> >> +    transfer_iovec.iov_base = s->current_cursor->data;
> >> +    transfer_iovec.iov_len = res->width * res->height * 4;
> >> +
> >> +    rutabaga_resource_transfer_read(vr->rutabaga, 0,
> >> +                                    resource_id, &transfer,
> >> +                                    &transfer_iovec);
> >> +}
> >> +
> >> +static void
> >> +virtio_gpu_rutabaga_gl_flushed(VirtIOGPUBase *b)
> >> +{
> >> +    VirtIOGPU *g = VIRTIO_GPU(b);
> >> +    virtio_gpu_process_cmdq(g);
> >> +}
> >> +
> >> +static void
> >> +rutabaga_cmd_create_resource_2d(VirtIOGPU *g,
> >> +                                struct virtio_gpu_ctrl_command *cmd)
> >> +{
> >> +    int32_t result;
> >> +    struct rutabaga_create_3d rc_3d = { 0 };
> >> +    struct virtio_gpu_simple_resource *res;
> >> +    struct virtio_gpu_resource_create_2d c2d;
> >> +
> >> +    VirtIOGPURutabaga *vr = VIRTIO_GPU_RUTABAGA(g);
> >> +
> >> +    VIRTIO_GPU_FILL_CMD(c2d);
> >> +    trace_virtio_gpu_cmd_res_create_2d(c2d.resource_id, c2d.format,
> >> +                                       c2d.width, c2d.height);
> >> +
> >> +    rc_3d.target = 2;
> >> +    rc_3d.format = c2d.format;
> >> +    rc_3d.bind = (1 << 1);
> >> +    rc_3d.width = c2d.width;
> >> +    rc_3d.height = c2d.height;
> >> +    rc_3d.depth = 1;
> >> +    rc_3d.array_size = 1;
> >> +    rc_3d.last_level = 0;
> >> +    rc_3d.nr_samples = 0;
> >> +    rc_3d.flags = VIRTIO_GPU_RESOURCE_FLAG_Y_0_TOP;
> >> +
> >> +    result = rutabaga_resource_create_3d(vr->rutabaga,
> c2d.resource_id, &rc_3d);
> >> +    CHECK(!result, cmd);
> >> +
> >> +    res = g_new0(struct virtio_gpu_simple_resource, 1);
> >> +    res->width = c2d.width;
> >> +    res->height = c2d.height;
> >> +    res->format = c2d.format;
> >> +    res->resource_id = c2d.resource_id;
> >> +
> >> +    QTAILQ_INSERT_HEAD(&g->reslist, res, next);
> >> +}
> >> +
> >> +static void
> >> +rutabaga_cmd_create_resource_3d(VirtIOGPU *g,
> >> +                                struct virtio_gpu_ctrl_command *cmd)
> >> +{
> >> +    int32_t result;
> >> +    struct rutabaga_create_3d rc_3d = { 0 };
> >> +    struct virtio_gpu_simple_resource *res;
> >> +    struct virtio_gpu_resource_create_3d c3d;
> >> +
> >> +    VirtIOGPURutabaga *vr = VIRTIO_GPU_RUTABAGA(g);
> >> +
> >> +    VIRTIO_GPU_FILL_CMD(c3d);
> >> +
> >> +    trace_virtio_gpu_cmd_res_create_3d(c3d.resource_id, c3d.format,
> >> +                                       c3d.width, c3d.height,
> c3d.depth);
> >> +
> >> +    rc_3d.target = c3d.target;
> >> +    rc_3d.format = c3d.format;
> >> +    rc_3d.bind = c3d.bind;
> >> +    rc_3d.width = c3d.width;
> >> +    rc_3d.height = c3d.height;
> >> +    rc_3d.depth = c3d.depth;
> >> +    rc_3d.array_size = c3d.array_size;
> >> +    rc_3d.last_level = c3d.last_level;
> >> +    rc_3d.nr_samples = c3d.nr_samples;
> >> +    rc_3d.flags = c3d.flags;
> >> +
> >> +    result = rutabaga_resource_create_3d(vr->rutabaga,
> c3d.resource_id, &rc_3d);
> >> +    CHECK(!result, cmd);
> >> +
> >> +    res = g_new0(struct virtio_gpu_simple_resource, 1);
> >> +    res->width = c3d.width;
> >> +    res->height = c3d.height;
> >> +    res->format = c3d.format;
> >> +    res->resource_id = c3d.resource_id;
> >> +
> >> +    QTAILQ_INSERT_HEAD(&g->reslist, res, next);
> >> +}
> >> +
> >> +static void
> >> +rutabaga_cmd_resource_unref(VirtIOGPU *g,
> >> +                            struct virtio_gpu_ctrl_command *cmd)
> >> +{
> >> +    int32_t result;
> >> +    struct virtio_gpu_simple_resource *res;
> >> +    struct virtio_gpu_resource_unref unref;
> >> +
> >> +    VirtIOGPURutabaga *vr = VIRTIO_GPU_RUTABAGA(g);
> >> +
> >> +    VIRTIO_GPU_FILL_CMD(unref);
> >> +
> >> +    trace_virtio_gpu_cmd_res_unref(unref.resource_id);
> >> +
> >> +    res = virtio_gpu_find_resource(g, unref.resource_id);
> >> +    CHECK(res, cmd);
> >> +
> >> +    result = rutabaga_resource_unref(vr->rutabaga, unref.resource_id);
> >> +    CHECK(!result, cmd);
> >> +
> >> +    if (res->image) {
> >> +        pixman_image_unref(res->image);
> >> +    }
> >> +
> >> +    QTAILQ_REMOVE(&g->reslist, res, next);
> >> +    g_free(res);
> >> +}
> >> +
> >> +static void
> >> +rutabaga_cmd_context_create(VirtIOGPU *g,
> >> +                            struct virtio_gpu_ctrl_command *cmd)
> >> +{
> >> +    int32_t result;
> >> +    struct virtio_gpu_ctx_create cc;
> >> +
> >> +    VirtIOGPURutabaga *vr = VIRTIO_GPU_RUTABAGA(g);
> >> +
> >> +    VIRTIO_GPU_FILL_CMD(cc);
> >> +    trace_virtio_gpu_cmd_ctx_create(cc.hdr.ctx_id,
> >> +                                    cc.debug_name);
> >> +
> >> +    result = rutabaga_context_create(vr->rutabaga, cc.hdr.ctx_id,
> >> +                                     cc.context_init, cc.debug_name,
> cc.nlen);
> >> +    CHECK(!result, cmd);
> >> +}
> >> +
> >> +static void
> >> +rutabaga_cmd_context_destroy(VirtIOGPU *g,
> >> +                             struct virtio_gpu_ctrl_command *cmd)
> >> +{
> >> +    int32_t result;
> >> +    struct virtio_gpu_ctx_destroy cd;
> >> +
> >> +    VirtIOGPURutabaga *vr = VIRTIO_GPU_RUTABAGA(g);
> >> +
> >> +    VIRTIO_GPU_FILL_CMD(cd);
> >> +    trace_virtio_gpu_cmd_ctx_destroy(cd.hdr.ctx_id);
> >> +
> >> +    result = rutabaga_context_destroy(vr->rutabaga, cd.hdr.ctx_id);
> >> +    CHECK(!result, cmd);
> >> +}
> >> +
> >> +static void
> >> +rutabaga_cmd_resource_flush(VirtIOGPU *g, struct
> virtio_gpu_ctrl_command *cmd)
> >> +{
> >> +    int32_t result, i;
> >> +    struct virtio_gpu_scanout *scanout = NULL;
> >> +    struct virtio_gpu_simple_resource *res;
> >> +    struct rutabaga_transfer transfer = { 0 };
> >> +    struct iovec transfer_iovec;
> >> +    struct virtio_gpu_resource_flush rf;
> >> +    bool found = false;
> >> +
> >> +    VirtIOGPUBase *vb = VIRTIO_GPU_BASE(g);
> >> +    VirtIOGPURutabaga *vr = VIRTIO_GPU_RUTABAGA(g);
> >> +    if (vr->headless) {
> >> +        return;
> >> +    }
> >> +
> >> +    VIRTIO_GPU_FILL_CMD(rf);
> >> +    trace_virtio_gpu_cmd_res_flush(rf.resource_id,
> >> +                                   rf.r.width, rf.r.height, rf.r.x,
> rf.r.y);
> >> +
> >> +    res = virtio_gpu_find_resource(g, rf.resource_id);
> >> +    CHECK(res, cmd);
> >> +
> >> +    for (i = 0; i < vb->conf.max_outputs; i++) {
> >> +        scanout = &vb->scanout[i];
> >> +        if (i == res->scanout_bitmask) {
> >> +            found = true;
> >> +            break;
> >> +        }
> >> +    }
> >> +
> >> +    if (!found) {
> >> +        return;
> >> +    }
> >> +
> >> +    transfer.x = 0;
> >> +    transfer.y = 0;
> >> +    transfer.z = 0;
> >> +    transfer.w = res->width;
> >> +    transfer.h = res->height;
> >> +    transfer.d = 1;
> >> +
> >> +    transfer_iovec.iov_base = pixman_image_get_data(res->image);
> >> +    transfer_iovec.iov_len = res->width * res->height * 4;
> >> +
> >> +    result = rutabaga_resource_transfer_read(vr->rutabaga, 0,
> >> +                                             rf.resource_id, &transfer,
> >> +                                             &transfer_iovec);
> >> +    CHECK(!result, cmd);
> >> +    dpy_gfx_update_full(scanout->con);
> >> +}
> >> +
> >> +static void
> >> +rutabaga_cmd_set_scanout(VirtIOGPU *g, struct virtio_gpu_ctrl_command
> *cmd)
> >> +{
> >> +    struct virtio_gpu_simple_resource *res;
> >> +    struct virtio_gpu_scanout *scanout = NULL;
> >> +    struct virtio_gpu_set_scanout ss;
> >> +
> >> +    VirtIOGPUBase *vb = VIRTIO_GPU_BASE(g);
> >> +    VirtIOGPURutabaga *vr = VIRTIO_GPU_RUTABAGA(g);
> >> +    if (vr->headless) {
> >> +        return;
> >> +    }
> >> +
> >> +    VIRTIO_GPU_FILL_CMD(ss);
> >> +    trace_virtio_gpu_cmd_set_scanout(ss.scanout_id, ss.resource_id,
> >> +                                     ss.r.width, ss.r.height, ss.r.x,
> ss.r.y);
> >> +
> >> +    CHECK(ss.scanout_id < VIRTIO_GPU_MAX_SCANOUTS, cmd);
> >> +    scanout = &vb->scanout[ss.scanout_id];
> >> +
> >> +    if (ss.resource_id == 0) {
> >> +        dpy_gfx_replace_surface(scanout->con, NULL);
> >> +        dpy_gl_scanout_disable(scanout->con);
> >> +        return;
> >> +    }
> >> +
> >> +    res = virtio_gpu_find_resource(g, ss.resource_id);
> >> +    CHECK(res, cmd);
> >> +
> >> +    if (!res->image) {
> >> +        pixman_format_code_t pformat;
> >> +        pformat = virtio_gpu_get_pixman_format(res->format);
> >> +        CHECK(pformat, cmd);
> >> +
> >> +        res->image = pixman_image_create_bits(pformat,
> >> +                                              res->width,
> >> +                                              res->height,
> >> +                                              NULL, 0);
> >> +        CHECK(res->image, cmd);
> >> +        pixman_image_ref(res->image);
> >> +    }
> >> +
> >> +    vb->enable = 1;
> >> +
> >> +    /* realloc the surface ptr */
> >> +    scanout->ds = qemu_create_displaysurface_pixman(res->image);
> >> +    dpy_gfx_replace_surface(scanout->con, NULL);
> >> +    dpy_gfx_replace_surface(scanout->con, scanout->ds);
> >> +    res->scanout_bitmask = ss.scanout_id;
> >> +}
> >> +
> >> +static void
> >> +rutabaga_cmd_submit_3d(VirtIOGPU *g,
> >> +                       struct virtio_gpu_ctrl_command *cmd)
> >> +{
> >> +    int32_t result;
> >> +    struct virtio_gpu_cmd_submit cs;
> >> +    struct rutabaga_command rutabaga_cmd = { 0 };
> >> +    g_autofree uint8_t *buf = NULL;
> >> +    size_t s;
> >> +
> >> +    VirtIOGPURutabaga *vr = VIRTIO_GPU_RUTABAGA(g);
> >> +
> >> +    VIRTIO_GPU_FILL_CMD(cs);
> >> +    trace_virtio_gpu_cmd_ctx_submit(cs.hdr.ctx_id, cs.size);
> >> +
> >> +    buf = g_new0(uint8_t, cs.size);
> >> +    s = iov_to_buf(cmd->elem.out_sg, cmd->elem.out_num,
> >> +                   sizeof(cs), buf, cs.size);
> >> +    CHECK(s == cs.size, cmd);
> >> +
> >> +    rutabaga_cmd.ctx_id = cs.hdr.ctx_id;
> >> +    rutabaga_cmd.cmd = buf;
> >> +    rutabaga_cmd.cmd_size = cs.size;
> >> +
> >> +    result = rutabaga_submit_command(vr->rutabaga, &rutabaga_cmd);
> >> +    CHECK(!result, cmd);
> >> +}
> >> +
> >> +static void
> >> +rutabaga_cmd_transfer_to_host_2d(VirtIOGPU *g,
> >> +                                 struct virtio_gpu_ctrl_command *cmd)
> >> +{
> >> +    int32_t result;
> >> +    struct rutabaga_transfer transfer = { 0 };
> >> +    struct virtio_gpu_transfer_to_host_2d t2d;
> >> +
> >> +    VirtIOGPURutabaga *vr = VIRTIO_GPU_RUTABAGA(g);
> >> +
> >> +    VIRTIO_GPU_FILL_CMD(t2d);
> >> +    trace_virtio_gpu_cmd_res_xfer_toh_2d(t2d.resource_id);
> >> +
> >> +    transfer.x = t2d.r.x;
> >> +    transfer.y = t2d.r.y;
> >> +    transfer.z = 0;
> >> +    transfer.w = t2d.r.width;
> >> +    transfer.h = t2d.r.height;
> >> +    transfer.d = 1;
> >> +
> >> +    result = rutabaga_resource_transfer_write(vr->rutabaga, 0,
> t2d.resource_id,
> >> +                                              &transfer);
> >> +    CHECK(!result, cmd);
> >> +}
> >> +
> >> +static void
> >> +rutabaga_cmd_transfer_to_host_3d(VirtIOGPU *g,
> >> +                                 struct virtio_gpu_ctrl_command *cmd)
> >> +{
> >> +    int32_t result;
> >> +    struct rutabaga_transfer transfer = { 0 };
> >> +    struct virtio_gpu_transfer_host_3d t3d;
> >> +
> >> +    VirtIOGPURutabaga *vr = VIRTIO_GPU_RUTABAGA(g);
> >> +
> >> +    VIRTIO_GPU_FILL_CMD(t3d);
> >> +    trace_virtio_gpu_cmd_res_xfer_toh_3d(t3d.resource_id);
> >> +
> >> +    transfer.x = t3d.box.x;
> >> +    transfer.y = t3d.box.y;
> >> +    transfer.z = t3d.box.z;
> >> +    transfer.w = t3d.box.w;
> >> +    transfer.h = t3d.box.h;
> >> +    transfer.d = t3d.box.d;
> >> +    transfer.level = t3d.level;
> >> +    transfer.stride = t3d.stride;
> >> +    transfer.layer_stride = t3d.layer_stride;
> >> +    transfer.offset = t3d.offset;
> >> +
> >> +    result = rutabaga_resource_transfer_write(vr->rutabaga,
> t3d.hdr.ctx_id,
> >> +                                              t3d.resource_id,
> &transfer);
> >> +    CHECK(!result, cmd);
> >> +}
> >> +
> >> +static void
> >> +rutabaga_cmd_transfer_from_host_3d(VirtIOGPU *g,
> >> +                                   struct virtio_gpu_ctrl_command *cmd)
> >> +{
> >> +    int32_t result;
> >> +    struct rutabaga_transfer transfer = { 0 };
> >> +    struct virtio_gpu_transfer_host_3d t3d;
> >> +
> >> +    VirtIOGPURutabaga *vr = VIRTIO_GPU_RUTABAGA(g);
> >> +
> >> +    VIRTIO_GPU_FILL_CMD(t3d);
> >> +    trace_virtio_gpu_cmd_res_xfer_fromh_3d(t3d.resource_id);
> >> +
> >> +    transfer.x = t3d.box.x;
> >> +    transfer.y = t3d.box.y;
> >> +    transfer.z = t3d.box.z;
> >> +    transfer.w = t3d.box.w;
> >> +    transfer.h = t3d.box.h;
> >> +    transfer.d = t3d.box.d;
> >> +    transfer.level = t3d.level;
> >> +    transfer.stride = t3d.stride;
> >> +    transfer.layer_stride = t3d.layer_stride;
> >> +    transfer.offset = t3d.offset;
> >> +
> >> +    result = rutabaga_resource_transfer_read(vr->rutabaga,
> t3d.hdr.ctx_id,
> >> +                                             t3d.resource_id,
> &transfer, NULL);
> >> +    CHECK(!result, cmd);
> >> +}
> >> +
> >> +static void
> >> +rutabaga_cmd_attach_backing(VirtIOGPU *g, struct
> virtio_gpu_ctrl_command *cmd)
> >> +{
> >> +    struct rutabaga_iovecs vecs = { 0 };
> >> +    struct virtio_gpu_simple_resource *res;
> >> +    struct virtio_gpu_resource_attach_backing att_rb;
> >> +    int ret;
> >> +
> >> +    VirtIOGPURutabaga *vr = VIRTIO_GPU_RUTABAGA(g);
> >> +
> >> +    VIRTIO_GPU_FILL_CMD(att_rb);
> >> +    trace_virtio_gpu_cmd_res_back_attach(att_rb.resource_id);
> >> +
> >> +    res = virtio_gpu_find_resource(g, att_rb.resource_id);
> >> +    CHECK(res, cmd);
> >> +    CHECK(!res->iov, cmd);
> >> +
> >> +    ret = virtio_gpu_create_mapping_iov(g, att_rb.nr_entries,
> sizeof(att_rb),
> >> +                                        cmd, NULL, &res->iov,
> &res->iov_cnt);
> >> +    CHECK(!ret, cmd);
> >> +
> >> +    vecs.iovecs = res->iov;
> >> +    vecs.num_iovecs = res->iov_cnt;
> >> +
> >> +    ret = rutabaga_resource_attach_backing(vr->rutabaga,
> att_rb.resource_id,
> >> +                                           &vecs);
> >> +    if (ret != 0) {
> >> +        virtio_gpu_cleanup_mapping(g, res);
> >> +    }
> >> +
> >> +    CHECK(!ret, cmd);
> >> +}
> >> +
> >> +static void
> >> +rutabaga_cmd_detach_backing(VirtIOGPU *g, struct
> virtio_gpu_ctrl_command *cmd)
> >> +{
> >> +    struct virtio_gpu_simple_resource *res;
> >> +    struct virtio_gpu_resource_detach_backing detach_rb;
> >> +
> >> +    VirtIOGPURutabaga *vr = VIRTIO_GPU_RUTABAGA(g);
> >> +
> >> +    VIRTIO_GPU_FILL_CMD(detach_rb);
> >> +    trace_virtio_gpu_cmd_res_back_detach(detach_rb.resource_id);
> >> +
> >> +    res = virtio_gpu_find_resource(g, detach_rb.resource_id);
> >> +    CHECK(res, cmd);
> >> +
> >> +    rutabaga_resource_detach_backing(vr->rutabaga,
> >> +                                     detach_rb.resource_id);
> >> +
> >> +    virtio_gpu_cleanup_mapping(g, res);
> >> +}
> >> +
> >> +static void
> >> +rutabaga_cmd_ctx_attach_resource(VirtIOGPU *g,
> >> +                                 struct virtio_gpu_ctrl_command *cmd)
> >> +{
> >> +    int32_t result;
> >> +    struct virtio_gpu_ctx_resource att_res;
> >> +
> >> +    VirtIOGPURutabaga *vr = VIRTIO_GPU_RUTABAGA(g);
> >> +
> >> +    VIRTIO_GPU_FILL_CMD(att_res);
> >> +    trace_virtio_gpu_cmd_ctx_res_attach(att_res.hdr.ctx_id,
> >> +                                        att_res.resource_id);
> >> +
> >> +    result = rutabaga_context_attach_resource(vr->rutabaga,
> att_res.hdr.ctx_id,
> >> +                                              att_res.resource_id);
> >> +    CHECK(!result, cmd);
> >> +}
> >> +
> >> +static void
> >> +rutabaga_cmd_ctx_detach_resource(VirtIOGPU *g,
> >> +                                 struct virtio_gpu_ctrl_command *cmd)
> >> +{
> >> +    int32_t result;
> >> +    struct virtio_gpu_ctx_resource det_res;
> >> +
> >> +    VirtIOGPURutabaga *vr = VIRTIO_GPU_RUTABAGA(g);
> >> +
> >> +    VIRTIO_GPU_FILL_CMD(det_res);
> >> +    trace_virtio_gpu_cmd_ctx_res_detach(det_res.hdr.ctx_id,
> >> +                                        det_res.resource_id);
> >> +
> >> +    result = rutabaga_context_detach_resource(vr->rutabaga,
> det_res.hdr.ctx_id,
> >> +                                              det_res.resource_id);
> >> +    CHECK(!result, cmd);
> >> +}
> >> +
> >> +static void
> >> +rutabaga_cmd_get_capset_info(VirtIOGPU *g, struct
> virtio_gpu_ctrl_command *cmd)
> >> +{
> >> +    int32_t result;
> >> +    struct virtio_gpu_get_capset_info info;
> >> +    struct virtio_gpu_resp_capset_info resp;
> >> +
> >> +    VirtIOGPURutabaga *vr = VIRTIO_GPU_RUTABAGA(g);
> >> +
> >> +    VIRTIO_GPU_FILL_CMD(info);
> >> +
> >> +    result = rutabaga_get_capset_info(vr->rutabaga, info.capset_index,
> >> +                                      &resp.capset_id,
> &resp.capset_max_version,
> >> +                                      &resp.capset_max_size);
> >> +    CHECK(!result, cmd);
> >> +
> >> +    resp.hdr.type = VIRTIO_GPU_RESP_OK_CAPSET_INFO;
> >> +    virtio_gpu_ctrl_response(g, cmd, &resp.hdr, sizeof(resp));
> >> +}
> >> +
> >> +static void
> >> +rutabaga_cmd_get_capset(VirtIOGPU *g, struct virtio_gpu_ctrl_command
> *cmd)
> >> +{
> >> +    int32_t result;
> >> +    struct virtio_gpu_get_capset gc;
> >> +    struct virtio_gpu_resp_capset *resp;
> >> +    uint32_t capset_size, capset_version;
> >> +    uint32_t current_id, i;
> >> +
> >> +    VirtIOGPURutabaga *vr = VIRTIO_GPU_RUTABAGA(g);
> >> +
> >> +    VIRTIO_GPU_FILL_CMD(gc);
> >> +    for (i = 0; i < vr->num_capsets; i++) {
> >> +        result = rutabaga_get_capset_info(vr->rutabaga, i,
> >> +                                          &current_id, &capset_version,
> >> +                                          &capset_size);
> >> +        CHECK(!result, cmd);
> >> +
> >> +        if (current_id == gc.capset_id) {
> >> +            break;
> >> +        }
> >> +    }
> >> +
> >> +    CHECK(i < vr->num_capsets, cmd);
> >> +
> >> +    resp = g_malloc0(sizeof(*resp) + capset_size);
> >> +    resp->hdr.type = VIRTIO_GPU_RESP_OK_CAPSET;
> >> +    rutabaga_get_capset(vr->rutabaga, gc.capset_id, gc.capset_version,
> >> +                        resp->capset_data, capset_size);
> >> +
> >> +    virtio_gpu_ctrl_response(g, cmd, &resp->hdr, sizeof(*resp) +
> capset_size);
> >> +    g_free(resp);
> >> +}
> >> +
> >> +static void
> >> +rutabaga_cmd_resource_create_blob(VirtIOGPU *g,
> >> +                                  struct virtio_gpu_ctrl_command *cmd)
> >> +{
> >> +    int result;
> >> +    struct rutabaga_iovecs vecs = { 0 };
> >> +    g_autofree struct virtio_gpu_simple_resource *res = NULL;
> >> +    struct virtio_gpu_resource_create_blob cblob;
> >> +    struct rutabaga_create_blob rc_blob = { 0 };
> >> +
> >> +    VirtIOGPURutabaga *vr = VIRTIO_GPU_RUTABAGA(g);
> >> +
> >> +    VIRTIO_GPU_FILL_CMD(cblob);
> >> +    trace_virtio_gpu_cmd_res_create_blob(cblob.resource_id,
> cblob.size);
> >> +
> >> +    CHECK(cblob.resource_id != 0, cmd);
> >> +
> >> +    res = g_new0(struct virtio_gpu_simple_resource, 1);
> >> +
> >> +    res->resource_id = cblob.resource_id;
> >> +    res->blob_size = cblob.size;
> >> +
> >> +    if (cblob.blob_mem != VIRTIO_GPU_BLOB_MEM_HOST3D) {
> >> +        result = virtio_gpu_create_mapping_iov(g, cblob.nr_entries,
> >> +                                               sizeof(cblob), cmd,
> &res->addrs,
> >> +                                               &res->iov,
> &res->iov_cnt);
> >> +        CHECK(!result, cmd);
> >> +    }
> >> +
> >> +    rc_blob.blob_id = cblob.blob_id;
> >> +    rc_blob.blob_mem = cblob.blob_mem;
> >> +    rc_blob.blob_flags = cblob.blob_flags;
> >> +    rc_blob.size = cblob.size;
> >> +
> >> +    vecs.iovecs = res->iov;
> >> +    vecs.num_iovecs = res->iov_cnt;
> >> +
> >> +    result = rutabaga_resource_create_blob(vr->rutabaga,
> cblob.hdr.ctx_id,
> >> +                                           cblob.resource_id,
> &rc_blob, &vecs,
> >> +                                           NULL);
> >> +
> >> +    if (result && cblob.blob_mem != VIRTIO_GPU_BLOB_MEM_HOST3D) {
> >> +        virtio_gpu_cleanup_mapping(g, res);
> >> +    }
> >> +
> >> +    CHECK(!result, cmd);
> >> +
> >> +    QTAILQ_INSERT_HEAD(&g->reslist, res, next);
> >> +    res = NULL;
> >> +}
> >> +
> >> +static void
> >> +rutabaga_cmd_resource_map_blob(VirtIOGPU *g,
> >> +                               struct virtio_gpu_ctrl_command *cmd)
> >> +{
> >> +    int32_t result;
> >> +    uint32_t map_info = 0;
> >> +    uint32_t slot = 0;
> >> +    struct virtio_gpu_simple_resource *res;
> >> +    struct rutabaga_mapping mapping = { 0 };
> >> +    struct virtio_gpu_resource_map_blob mblob;
> >> +    struct virtio_gpu_resp_map_info resp = { 0 };
> >> +
> >> +    VirtIOGPUBase *vb = VIRTIO_GPU_BASE(g);
> >> +    VirtIOGPURutabaga *vr = VIRTIO_GPU_RUTABAGA(g);
> >> +
> >> +    VIRTIO_GPU_FILL_CMD(mblob);
> >> +
> >> +    CHECK(mblob.resource_id != 0, cmd);
> >> +
> >> +    res = virtio_gpu_find_resource(g, mblob.resource_id);
> >> +    CHECK(res, cmd);
> >> +
> >> +    result = rutabaga_resource_map_info(vr->rutabaga,
> mblob.resource_id,
> >> +                                        &map_info);
> >> +    CHECK(!result, cmd);
> >> +
> >> +    /*
> >> +     * RUTABAGA_MAP_ACCESS_* flags are not part of the virtio-gpu
> spec, but do
> >> +     * exist to potentially allow the hypervisor to restrict write
> access to
> >> +     * memory. QEMU does not need to use this functionality at the
> moment.
> >> +     */
> >> +    resp.map_info = map_info & RUTABAGA_MAP_CACHE_MASK;
> >> +
> >> +    result = rutabaga_resource_map(vr->rutabaga, mblob.resource_id,
> &mapping);
> >> +    CHECK(!result, cmd);
> >> +
> >> +    for (slot = 0; slot < MAX_SLOTS; slot++) {
> >> +        if (vr->memory_regions[slot].used) {
> >> +            continue;
> >> +        }
> >> +
> >> +        MemoryRegion *mr = &(vr->memory_regions[slot].mr);
> >> +        memory_region_init_ram_ptr(mr, OBJECT(vr), "blob",
> mapping.size,
> >> +                                   mapping.ptr);
> >> +        memory_region_add_subregion(&vb->hostmem, mblob.offset, mr);
> >> +        vr->memory_regions[slot].resource_id = mblob.resource_id;
> >> +        vr->memory_regions[slot].used = 1;
> >> +        break;
> >> +    }
> >> +
> >> +    if (slot >= MAX_SLOTS) {
> >> +        result = rutabaga_resource_unmap(vr->rutabaga,
> mblob.resource_id);
> >> +        CHECK(!result, cmd);
> >> +    }
> >> +
> >> +    CHECK(slot < MAX_SLOTS, cmd);
> >> +
> >> +    resp.hdr.type = VIRTIO_GPU_RESP_OK_MAP_INFO;
> >> +    virtio_gpu_ctrl_response(g, cmd, &resp.hdr, sizeof(resp));
> >> +}
> >> +
> >> +static void
> >> +rutabaga_cmd_resource_unmap_blob(VirtIOGPU *g,
> >> +                                 struct virtio_gpu_ctrl_command *cmd)
> >> +{
> >> +    int32_t result;
> >> +    uint32_t slot = 0;
> >> +    struct virtio_gpu_simple_resource *res;
> >> +    struct virtio_gpu_resource_unmap_blob ublob;
> >> +
> >> +    VirtIOGPUBase *vb = VIRTIO_GPU_BASE(g);
> >> +    VirtIOGPURutabaga *vr = VIRTIO_GPU_RUTABAGA(g);
> >> +
> >> +    VIRTIO_GPU_FILL_CMD(ublob);
> >> +
> >> +    CHECK(ublob.resource_id != 0, cmd);
> >> +
> >> +    res = virtio_gpu_find_resource(g, ublob.resource_id);
> >> +    CHECK(res, cmd);
> >> +
> >> +    for (slot = 0; slot < MAX_SLOTS; slot++) {
> >> +        if (vr->memory_regions[slot].resource_id != ublob.resource_id)
> {
> >> +            continue;
> >> +        }
> >> +
> >> +        MemoryRegion *mr = &(vr->memory_regions[slot].mr);
> >> +        memory_region_del_subregion(&vb->hostmem, mr);
> >> +
> >> +        vr->memory_regions[slot].resource_id = 0;
> >> +        vr->memory_regions[slot].used = 0;
> >> +        break;
> >> +    }
> >> +
> >> +    CHECK(slot < MAX_SLOTS, cmd);
> >> +    result = rutabaga_resource_unmap(vr->rutabaga, res->resource_id);
> >
> > Hi,
> >
> > After the discussion with Xenia Ragiadakou regarding their patch for
> Venus, I found a
> > bug present in the Venus implementation also affects Rutabaga.
> >
> > The problem is that the memory region may not immediately go away with
> > memory_region_del_subregion(), but it may be kept a bit after that. The
> memory region
> > has a pointer to the mapped memory so the unmapping call that
> immediately follows
> > will make it dangling.
> >
> > Xenia raised a question whether the dangling pointer can be actually
> dereferenced and
> > result in use-after-free, but the answer is unfortunately yes. For
> example, consider
> > the following call chain:
> > kvm_cpu_exec -> address_space_rw -> address_space_write ->
> flatview_write ->
> > flatview_write_continue
> >
> > address_space_write() holds a RCU read lock so that the flatview it
> refers to will
> > not go away during the operation even if it becomes obsolete and will be
> used for
> > writes. It is possible that the obsolete flatview contains the memory
> region for the
> > memory that is concurrently unmapped by virtio-gpu-rutabaga/virgl.  Note
> that the
> > function can be called without holding BQL, and KVM actually does so.
> >
> > Another case is address_space_map(). It acquires the reference to the
> memory with
> > memory_region_ref() and expects it will be available until
> memory_region_unref() gets
> > called with address_space_unmap().
>

Yeah, I did notice weird behavior around map/unmap when initially testing
the series:

https://lists.gnu.org/archive/html/qemu-devel/2023-04/msg03378.html

The solution I did was just do what the Android Emulator (which uses
QEMU2.12) has been doing for years.  Not call "obj_unparent(g)" and keep a
table of memory regions for initialization.  It does pass all ./deqp-vk
memory tests and is sufficient to run Android on a Vulkan-only stack.  I
think the way blob resources are handled in the guest some of the cases
you've cited may not be hit practice.  The biggest bug on Linux we do hit
is a KVM bug but hopefully that should be fixed soon:

https://lore.kernel.org/kvmarm/20230911021637.1941096-1-stevensd@google.com/T/#m7c23c97b56378e3e865057140be54fa3dd87154e

We hit interesting issues on MacOS on the gitlab issue and I do think a
follow-up memory-only series may be warranted in the future.

https://gitlab.com/qemu-project/qemu/-/issues/1611

Since the Android Emulator has been running the solution in the
rutabaga/gfxstream series for years, it should be good for our purposes on
Linux for now.  WDYT?


> >
> > In conclusion, both of Rutabaga and Virgl need to ensure to wait until
> all refrences
> > to memory region will be gone before unmapping the underlying memory.
> The patch
> > "[QEMU PATCH v5 07/13] softmmu/memory: enable automatic deallocation of
> memory
> > regions" in the venus patch series is useful to know when that happens.
>
> FWIW this sounds exactly the same as the issue I had with unmapping
> ioports in commit
> 690705ca0b ("softmmu/ioport.c: make MemoryRegionPortioList owner of
> portio_list
> MemoryRegions").
>
> The solution in that commit is to assign the MemoryRegion reference to a
> new QOM
> object using memory_region_init(), but then re-parent the MR back onto its
> original
> device owner (so the QOM tree in "info qom-tree" remains unchanged). This
> means that
> the new QOM object receives the unref notification from the flatview
> instead of the
> MemoryRegion, which then manually unmaps the MemoryRegion from the device
> when it is
> safe.
>
>
> ATB,
>
> Mark.
>
>

[-- Attachment #2: Type: text/html, Size: 51889 bytes --]

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH v13 6/9] gfxstream + rutabaga: add initial support for gfxstream
  2023-09-22  0:03       ` Gurchetan Singh
@ 2023-09-22  2:53         ` Akihiko Odaki
  2023-09-22  7:42           ` Alyssa Ross
  0 siblings, 1 reply; 27+ messages in thread
From: Akihiko Odaki @ 2023-09-22  2:53 UTC (permalink / raw)
  To: Gurchetan Singh, Mark Cave-Ayland
  Cc: qemu-devel, Xenia Ragiadakou, marcandre.lureau, ray.huang,
	alex.bennee, shentey, hi, ernunes, manos.pitsidianakis, philmd,
	Gerd Hoffmann, Michael S . Tsirkin, Stefano Stabellini,
	Anthony PERARD, Antonio Caggiano, Dr . David Alan Gilbert,
	Robert Beckett, Dmitry Osipenko, xen-devel, Albert Esteve,
	Roger Pau Monné,
	Alex Deucher, Christian König, Pierre-Eric Pelloux-Prayer,
	Honglei Huang, Julia Zhang, Chen Jiqian

On 2023/09/22 9:03, Gurchetan Singh wrote:
> 
> 
> On Wed, Sep 20, 2023 at 5:05 AM Mark Cave-Ayland 
> <mark.cave-ayland@ilande.co.uk <mailto:mark.cave-ayland@ilande.co.uk>> 
> wrote:
> 
>     On 20/09/2023 12:42, Akihiko Odaki wrote:
> 
>      > On 2023/08/29 9:36, Gurchetan Singh wrote:
>      >> This adds initial support for gfxstream and cross-domain.  Both
>      >> features rely on virtio-gpu blob resources and context types, which
>      >> are also implemented in this patch.
>      >>
>      >> gfxstream has a long and illustrious history in Android graphics
>      >> paravirtualization.  It has been powering graphics in the Android
>      >> Studio Emulator for more than a decade, which is the main developer
>      >> platform.
>      >>
>      >> Originally conceived by Jesse Hall, it was first known as
>     "EmuGL" [a].
>      >> The key design characteristic was a 1:1 threading model and
>      >> auto-generation, which fit nicely with the OpenGLES spec.  It also
>      >> allowed easy layering with ANGLE on the host, which provides the
>     GLES
>      >> implementations on Windows or MacOS enviroments.
>      >>
>      >> gfxstream has traditionally been maintained by a single
>     engineer, and
>      >> between 2015 to 2021, the goldfish throne passed to Frank Yang.
>      >> Historians often remark this glorious reign ("pax gfxstreama" is the
>      >> academic term) was comparable to that of Augustus and both Queen
>      >> Elizabeths.  Just to name a few accomplishments in a resplendent
>      >> panoply: higher versions of GLES, address space graphics, snapshot
>      >> support and CTS compliant Vulkan [b].
>      >>
>      >> One major drawback was the use of out-of-tree goldfish drivers.
>      >> Android engineers didn't know much about DRM/KMS and especially
>     TTM so
>      >> a simple guest to host pipe was conceived.
>      >>
>      >> Luckily, virtio-gpu 3D started to emerge in 2016 due to the work of
>      >> the Mesa/virglrenderer communities.  In 2018, the initial virtio-gpu
>      >> port of gfxstream was done by Cuttlefish enthusiast Alistair Delva.
>      >> It was a symbol compatible replacement of virglrenderer [c] and
>     named
>      >> "AVDVirglrenderer".  This implementation forms the basis of the
>      >> current gfxstream host implementation still in use today.
>      >>
>      >> cross-domain support follows a similar arc.  Originally conceived by
>      >> Wayland aficionado David Reveman and crosvm enjoyer Zach Reizner in
>      >> 2018, it initially relied on the downstream "virtio-wl" device.
>      >>
>      >> In 2020 and 2021, virtio-gpu was extended to include blob resources
>      >> and multiple timelines by yours truly, features
>     gfxstream/cross-domain
>      >> both require to function correctly.
>      >>
>      >> Right now, we stand at the precipice of a truly fantastic
>     possibility:
>      >> the Android Emulator powered by upstream QEMU and upstream Linux
>      >> kernel.  gfxstream will then be packaged properfully, and app
>      >> developers can even fix gfxstream bugs on their own if they
>     encounter
>      >> them.
>      >>
>      >> It's been quite the ride, my friends.  Where will gfxstream head
>     next,
>      >> nobody really knows.  I wouldn't be surprised if it's around for
>      >> another decade, maintained by a new generation of Android graphics
>      >> enthusiasts.
>      >>
>      >> Technical details:
>      >>    - Very simple initial display integration: just used Pixman
>      >>    - Largely, 1:1 mapping of virtio-gpu hypercalls to rutabaga
>     function
>      >>      calls
>      >>
>      >> Next steps for Android VMs:
>      >>    - The next step would be improving display integration and UI
>     interfaces
>      >>      with the goal of the QEMU upstream graphics being in an
>     emulator
>      >>      release [d].
>      >>
>      >> Next steps for Linux VMs for display virtualization:
>      >>    - For widespread distribution, someone needs to package
>     Sommelier or the
>      >>      wayland-proxy-virtwl [e] ideally into Debian main. In
>     addition, newer
>      >>      versions of the Linux kernel come with DRM_VIRTIO_GPU_KMS
>     option,
>      >>      which allows disabling KMS hypercalls.  If anyone cares
>     enough, it'll
>      >>      probably be possible to build a custom VM variant that uses
>     this display
>      >>      virtualization strategy.
>      >>
>      >> [a]
>     https://android-review.googlesource.com/c/platform/development/+/34470 <https://android-review.googlesource.com/c/platform/development/+/34470>
>      >> [b]
>     https://android-review.googlesource.com/q/topic:%22vulkan-hostconnection-start%22 <https://android-review.googlesource.com/q/topic:%22vulkan-hostconnection-start%22>
>      >> [c]
>     https://android-review.googlesource.com/c/device/generic/goldfish-opengl/+/761927 <https://android-review.googlesource.com/c/device/generic/goldfish-opengl/+/761927>
>      >> [d] https://developer.android.com/studio/releases/emulator
>     <https://developer.android.com/studio/releases/emulator>
>      >> [e] https://github.com/talex5/wayland-proxy-virtwl
>     <https://github.com/talex5/wayland-proxy-virtwl>
>      >>
>      >> Signed-off-by: Gurchetan Singh <gurchetansingh@chromium.org
>     <mailto:gurchetansingh@chromium.org>>
>      >> Tested-by: Alyssa Ross <hi@alyssa.is <mailto:hi@alyssa.is>>
>      >> Tested-by: Emmanouil Pitsidianakis
>     <manos.pitsidianakis@linaro.org <mailto:manos.pitsidianakis@linaro.org>>
>      >> Tested-by: Akihiko Odaki <akihiko.odaki@daynix.com
>     <mailto:akihiko.odaki@daynix.com>>
>      >> Reviewed-by: Emmanouil Pitsidianakis
>     <manos.pitsidianakis@linaro.org <mailto:manos.pitsidianakis@linaro.org>>
>      >> Reviewed-by: Antonio Caggiano <quic_acaggian@quicinc.com
>     <mailto:quic_acaggian@quicinc.com>>
>      >> Reviewed-by: Akihiko Odaki <akihiko.odaki@daynix.com
>     <mailto:akihiko.odaki@daynix.com>>
>      >> ---
>      >>   hw/display/virtio-gpu-pci-rutabaga.c |   47 ++
>      >>   hw/display/virtio-gpu-rutabaga.c     | 1119
>     ++++++++++++++++++++++++++
>      >>   hw/display/virtio-vga-rutabaga.c     |   50 ++
>      >>   3 files changed, 1216 insertions(+)
>      >>   create mode 100644 hw/display/virtio-gpu-pci-rutabaga.c
>      >>   create mode 100644 hw/display/virtio-gpu-rutabaga.c
>      >>   create mode 100644 hw/display/virtio-vga-rutabaga.c
>      >>
>      >> diff --git a/hw/display/virtio-gpu-pci-rutabaga.c
>      >> b/hw/display/virtio-gpu-pci-rutabaga.c
>      >> new file mode 100644
>      >> index 0000000000..c96729e198
>      >> --- /dev/null
>      >> +++ b/hw/display/virtio-gpu-pci-rutabaga.c
>      >> @@ -0,0 +1,47 @@
>      >> +/* SPDX-License-Identifier: GPL-2.0-or-later */
>      >> +
>      >> +#include "qemu/osdep.h"
>      >> +#include "qapi/error.h"
>      >> +#include "qemu/module.h"
>      >> +#include "hw/pci/pci.h"
>      >> +#include "hw/qdev-properties.h"
>      >> +#include "hw/virtio/virtio.h"
>      >> +#include "hw/virtio/virtio-bus.h"
>      >> +#include "hw/virtio/virtio-gpu-pci.h"
>      >> +#include "qom/object.h"
>      >> +
>      >> +#define TYPE_VIRTIO_GPU_RUTABAGA_PCI "virtio-gpu-rutabaga-pci"
>      >> +OBJECT_DECLARE_SIMPLE_TYPE(VirtIOGPURutabagaPCI,
>     VIRTIO_GPU_RUTABAGA_PCI)
>      >> +
>      >> +struct VirtIOGPURutabagaPCI {
>      >> +    VirtIOGPUPCIBase parent_obj;
>      >> +
>      >> +    VirtIOGPURutabaga vdev;
>      >> +};
>      >> +
>      >> +static void virtio_gpu_rutabaga_initfn(Object *obj)
>      >> +{
>      >> +    VirtIOGPURutabagaPCI *dev = VIRTIO_GPU_RUTABAGA_PCI(obj);
>      >> +
>      >> +    virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
>      >> +                                TYPE_VIRTIO_GPU_RUTABAGA);
>      >> +    VIRTIO_GPU_PCI_BASE(obj)->vgpu = VIRTIO_GPU_BASE(&dev->vdev);
>      >> +}
>      >> +
>      >> +static const TypeInfo virtio_gpu_rutabaga_pci_info[] = {
>      >> +    {
>      >> +        .name = TYPE_VIRTIO_GPU_RUTABAGA_PCI,
>      >> +        .parent = TYPE_VIRTIO_GPU_PCI_BASE,
>      >> +        .instance_size = sizeof(VirtIOGPURutabagaPCI),
>      >> +        .instance_init = virtio_gpu_rutabaga_initfn,
>      >> +        .interfaces = (InterfaceInfo[]) {
>      >> +            { INTERFACE_CONVENTIONAL_PCI_DEVICE },
>      >> +        }
>      >> +    },
>      >> +};
>      >> +
>      >> +DEFINE_TYPES(virtio_gpu_rutabaga_pci_info)
>      >> +
>      >> +module_obj(TYPE_VIRTIO_GPU_RUTABAGA_PCI);
>      >> +module_kconfig(VIRTIO_PCI);
>      >> +module_dep("hw-display-virtio-gpu-pci");
>      >> diff --git a/hw/display/virtio-gpu-rutabaga.c
>     b/hw/display/virtio-gpu-rutabaga.c
>      >> new file mode 100644
>      >> index 0000000000..a105e06214
>      >> --- /dev/null
>      >> +++ b/hw/display/virtio-gpu-rutabaga.c
>      >> @@ -0,0 +1,1119 @@
>      >> +/* SPDX-License-Identifier: GPL-2.0-or-later */
>      >> +
>      >> +#include "qemu/osdep.h"
>      >> +#include "qapi/error.h"
>      >> +#include "qemu/error-report.h"
>      >> +#include "qemu/iov.h"
>      >> +#include "trace.h"
>      >> +#include "hw/virtio/virtio.h"
>      >> +#include "hw/virtio/virtio-gpu.h"
>      >> +#include "hw/virtio/virtio-gpu-pixman.h"
>      >> +#include "hw/virtio/virtio-iommu.h"
>      >> +
>      >> +#include <glib/gmem.h>
>      >> +#include <rutabaga_gfx/rutabaga_gfx_ffi.h>
>      >> +
>      >> +#define CHECK(condition,
>     cmd)                                                 \
>      >> +    do
>     {                                                                      \
>      >> +        if (!(condition))
>     {                                                   \
>      >> +            error_report("CHECK failed in %s() %s:" "%d",
>     __func__,           \
>      >> +                         __FILE__,
>     __LINE__);                                 \
>      >> +            (cmd)->error =
>     VIRTIO_GPU_RESP_ERR_UNSPEC;                        \
>      >> +           
>     return;                                                           \
>      >> +      
>     }                                                                      \
>      >> +    } while (0)
>      >> +
>      >> +/*
>      >> + * This is the size of the char array in struct sock_addr_un.
>     No Wayland socket
>      >> + * can be created with a path longer than this, including the
>     null terminator.
>      >> + */
>      >> +#define UNIX_PATH_MAX sizeof((struct sockaddr_un) {} .sun_path)
>      >> +
>      >> +struct rutabaga_aio_data {
>      >> +    struct VirtIOGPURutabaga *vr;
>      >> +    struct rutabaga_fence fence;
>      >> +};
>      >> +
>      >> +static void
>      >> +virtio_gpu_rutabaga_update_cursor(VirtIOGPU *g, struct
>     virtio_gpu_scanout *s,
>      >> +                                  uint32_t resource_id)
>      >> +{
>      >> +    struct virtio_gpu_simple_resource *res;
>      >> +    struct rutabaga_transfer transfer = { 0 };
>      >> +    struct iovec transfer_iovec;
>      >> +
>      >> +    VirtIOGPURutabaga *vr = VIRTIO_GPU_RUTABAGA(g);
>      >> +
>      >> +    res = virtio_gpu_find_resource(g, resource_id);
>      >> +    if (!res) {
>      >> +        return;
>      >> +    }
>      >> +
>      >> +    if (res->width != s->current_cursor->width ||
>      >> +        res->height != s->current_cursor->height) {
>      >> +        return;
>      >> +    }
>      >> +
>      >> +    transfer.x = 0;
>      >> +    transfer.y = 0;
>      >> +    transfer.z = 0;
>      >> +    transfer.w = res->width;
>      >> +    transfer.h = res->height;
>      >> +    transfer.d = 1;
>      >> +
>      >> +    transfer_iovec.iov_base = s->current_cursor->data;
>      >> +    transfer_iovec.iov_len = res->width * res->height * 4;
>      >> +
>      >> +    rutabaga_resource_transfer_read(vr->rutabaga, 0,
>      >> +                                    resource_id, &transfer,
>      >> +                                    &transfer_iovec);
>      >> +}
>      >> +
>      >> +static void
>      >> +virtio_gpu_rutabaga_gl_flushed(VirtIOGPUBase *b)
>      >> +{
>      >> +    VirtIOGPU *g = VIRTIO_GPU(b);
>      >> +    virtio_gpu_process_cmdq(g);
>      >> +}
>      >> +
>      >> +static void
>      >> +rutabaga_cmd_create_resource_2d(VirtIOGPU *g,
>      >> +                                struct virtio_gpu_ctrl_command
>     *cmd)
>      >> +{
>      >> +    int32_t result;
>      >> +    struct rutabaga_create_3d rc_3d = { 0 };
>      >> +    struct virtio_gpu_simple_resource *res;
>      >> +    struct virtio_gpu_resource_create_2d c2d;
>      >> +
>      >> +    VirtIOGPURutabaga *vr = VIRTIO_GPU_RUTABAGA(g);
>      >> +
>      >> +    VIRTIO_GPU_FILL_CMD(c2d);
>      >> +    trace_virtio_gpu_cmd_res_create_2d(c2d.resource_id, c2d.format,
>      >> +                                       c2d.width, c2d.height);
>      >> +
>      >> +    rc_3d.target = 2;
>      >> +    rc_3d.format = c2d.format;
>      >> +    rc_3d.bind = (1 << 1);
>      >> +    rc_3d.width = c2d.width;
>      >> +    rc_3d.height = c2d.height;
>      >> +    rc_3d.depth = 1;
>      >> +    rc_3d.array_size = 1;
>      >> +    rc_3d.last_level = 0;
>      >> +    rc_3d.nr_samples = 0;
>      >> +    rc_3d.flags = VIRTIO_GPU_RESOURCE_FLAG_Y_0_TOP;
>      >> +
>      >> +    result = rutabaga_resource_create_3d(vr->rutabaga,
>     c2d.resource_id, &rc_3d);
>      >> +    CHECK(!result, cmd);
>      >> +
>      >> +    res = g_new0(struct virtio_gpu_simple_resource, 1);
>      >> +    res->width = c2d.width;
>      >> +    res->height = c2d.height;
>      >> +    res->format = c2d.format;
>      >> +    res->resource_id = c2d.resource_id;
>      >> +
>      >> +    QTAILQ_INSERT_HEAD(&g->reslist, res, next);
>      >> +}
>      >> +
>      >> +static void
>      >> +rutabaga_cmd_create_resource_3d(VirtIOGPU *g,
>      >> +                                struct virtio_gpu_ctrl_command
>     *cmd)
>      >> +{
>      >> +    int32_t result;
>      >> +    struct rutabaga_create_3d rc_3d = { 0 };
>      >> +    struct virtio_gpu_simple_resource *res;
>      >> +    struct virtio_gpu_resource_create_3d c3d;
>      >> +
>      >> +    VirtIOGPURutabaga *vr = VIRTIO_GPU_RUTABAGA(g);
>      >> +
>      >> +    VIRTIO_GPU_FILL_CMD(c3d);
>      >> +
>      >> +    trace_virtio_gpu_cmd_res_create_3d(c3d.resource_id, c3d.format,
>      >> +                                       c3d.width, c3d.height,
>     c3d.depth);
>      >> +
>      >> +    rc_3d.target = c3d.target;
>      >> +    rc_3d.format = c3d.format;
>      >> +    rc_3d.bind = c3d.bind;
>      >> +    rc_3d.width = c3d.width;
>      >> +    rc_3d.height = c3d.height;
>      >> +    rc_3d.depth = c3d.depth;
>      >> +    rc_3d.array_size = c3d.array_size;
>      >> +    rc_3d.last_level = c3d.last_level;
>      >> +    rc_3d.nr_samples = c3d.nr_samples;
>      >> +    rc_3d.flags = c3d.flags;
>      >> +
>      >> +    result = rutabaga_resource_create_3d(vr->rutabaga,
>     c3d.resource_id, &rc_3d);
>      >> +    CHECK(!result, cmd);
>      >> +
>      >> +    res = g_new0(struct virtio_gpu_simple_resource, 1);
>      >> +    res->width = c3d.width;
>      >> +    res->height = c3d.height;
>      >> +    res->format = c3d.format;
>      >> +    res->resource_id = c3d.resource_id;
>      >> +
>      >> +    QTAILQ_INSERT_HEAD(&g->reslist, res, next);
>      >> +}
>      >> +
>      >> +static void
>      >> +rutabaga_cmd_resource_unref(VirtIOGPU *g,
>      >> +                            struct virtio_gpu_ctrl_command *cmd)
>      >> +{
>      >> +    int32_t result;
>      >> +    struct virtio_gpu_simple_resource *res;
>      >> +    struct virtio_gpu_resource_unref unref;
>      >> +
>      >> +    VirtIOGPURutabaga *vr = VIRTIO_GPU_RUTABAGA(g);
>      >> +
>      >> +    VIRTIO_GPU_FILL_CMD(unref);
>      >> +
>      >> +    trace_virtio_gpu_cmd_res_unref(unref.resource_id);
>      >> +
>      >> +    res = virtio_gpu_find_resource(g, unref.resource_id);
>      >> +    CHECK(res, cmd);
>      >> +
>      >> +    result = rutabaga_resource_unref(vr->rutabaga,
>     unref.resource_id);
>      >> +    CHECK(!result, cmd);
>      >> +
>      >> +    if (res->image) {
>      >> +        pixman_image_unref(res->image);
>      >> +    }
>      >> +
>      >> +    QTAILQ_REMOVE(&g->reslist, res, next);
>      >> +    g_free(res);
>      >> +}
>      >> +
>      >> +static void
>      >> +rutabaga_cmd_context_create(VirtIOGPU *g,
>      >> +                            struct virtio_gpu_ctrl_command *cmd)
>      >> +{
>      >> +    int32_t result;
>      >> +    struct virtio_gpu_ctx_create cc;
>      >> +
>      >> +    VirtIOGPURutabaga *vr = VIRTIO_GPU_RUTABAGA(g);
>      >> +
>      >> +    VIRTIO_GPU_FILL_CMD(cc);
>      >> +    trace_virtio_gpu_cmd_ctx_create(cc.hdr.ctx_id,
>      >> +                                    cc.debug_name);
>      >> +
>      >> +    result = rutabaga_context_create(vr->rutabaga, cc.hdr.ctx_id,
>      >> +                                     cc.context_init,
>     cc.debug_name, cc.nlen);
>      >> +    CHECK(!result, cmd);
>      >> +}
>      >> +
>      >> +static void
>      >> +rutabaga_cmd_context_destroy(VirtIOGPU *g,
>      >> +                             struct virtio_gpu_ctrl_command *cmd)
>      >> +{
>      >> +    int32_t result;
>      >> +    struct virtio_gpu_ctx_destroy cd;
>      >> +
>      >> +    VirtIOGPURutabaga *vr = VIRTIO_GPU_RUTABAGA(g);
>      >> +
>      >> +    VIRTIO_GPU_FILL_CMD(cd);
>      >> +    trace_virtio_gpu_cmd_ctx_destroy(cd.hdr.ctx_id);
>      >> +
>      >> +    result = rutabaga_context_destroy(vr->rutabaga, cd.hdr.ctx_id);
>      >> +    CHECK(!result, cmd);
>      >> +}
>      >> +
>      >> +static void
>      >> +rutabaga_cmd_resource_flush(VirtIOGPU *g, struct
>     virtio_gpu_ctrl_command *cmd)
>      >> +{
>      >> +    int32_t result, i;
>      >> +    struct virtio_gpu_scanout *scanout = NULL;
>      >> +    struct virtio_gpu_simple_resource *res;
>      >> +    struct rutabaga_transfer transfer = { 0 };
>      >> +    struct iovec transfer_iovec;
>      >> +    struct virtio_gpu_resource_flush rf;
>      >> +    bool found = false;
>      >> +
>      >> +    VirtIOGPUBase *vb = VIRTIO_GPU_BASE(g);
>      >> +    VirtIOGPURutabaga *vr = VIRTIO_GPU_RUTABAGA(g);
>      >> +    if (vr->headless) {
>      >> +        return;
>      >> +    }
>      >> +
>      >> +    VIRTIO_GPU_FILL_CMD(rf);
>      >> +    trace_virtio_gpu_cmd_res_flush(rf.resource_id,
>      >> +                                   rf.r.width, rf.r.height,
>     rf.r.x, rf.r.y);
>      >> +
>      >> +    res = virtio_gpu_find_resource(g, rf.resource_id);
>      >> +    CHECK(res, cmd);
>      >> +
>      >> +    for (i = 0; i < vb->conf.max_outputs; i++) {
>      >> +        scanout = &vb->scanout[i];
>      >> +        if (i == res->scanout_bitmask) {
>      >> +            found = true;
>      >> +            break;
>      >> +        }
>      >> +    }
>      >> +
>      >> +    if (!found) {
>      >> +        return;
>      >> +    }
>      >> +
>      >> +    transfer.x = 0;
>      >> +    transfer.y = 0;
>      >> +    transfer.z = 0;
>      >> +    transfer.w = res->width;
>      >> +    transfer.h = res->height;
>      >> +    transfer.d = 1;
>      >> +
>      >> +    transfer_iovec.iov_base = pixman_image_get_data(res->image);
>      >> +    transfer_iovec.iov_len = res->width * res->height * 4;
>      >> +
>      >> +    result = rutabaga_resource_transfer_read(vr->rutabaga, 0,
>      >> +                                             rf.resource_id,
>     &transfer,
>      >> +                                             &transfer_iovec);
>      >> +    CHECK(!result, cmd);
>      >> +    dpy_gfx_update_full(scanout->con);
>      >> +}
>      >> +
>      >> +static void
>      >> +rutabaga_cmd_set_scanout(VirtIOGPU *g, struct
>     virtio_gpu_ctrl_command *cmd)
>      >> +{
>      >> +    struct virtio_gpu_simple_resource *res;
>      >> +    struct virtio_gpu_scanout *scanout = NULL;
>      >> +    struct virtio_gpu_set_scanout ss;
>      >> +
>      >> +    VirtIOGPUBase *vb = VIRTIO_GPU_BASE(g);
>      >> +    VirtIOGPURutabaga *vr = VIRTIO_GPU_RUTABAGA(g);
>      >> +    if (vr->headless) {
>      >> +        return;
>      >> +    }
>      >> +
>      >> +    VIRTIO_GPU_FILL_CMD(ss);
>      >> +    trace_virtio_gpu_cmd_set_scanout(ss.scanout_id, ss.resource_id,
>      >> +                                     ss.r.width, ss.r.height,
>     ss.r.x, ss.r.y);
>      >> +
>      >> +    CHECK(ss.scanout_id < VIRTIO_GPU_MAX_SCANOUTS, cmd);
>      >> +    scanout = &vb->scanout[ss.scanout_id];
>      >> +
>      >> +    if (ss.resource_id == 0) {
>      >> +        dpy_gfx_replace_surface(scanout->con, NULL);
>      >> +        dpy_gl_scanout_disable(scanout->con);
>      >> +        return;
>      >> +    }
>      >> +
>      >> +    res = virtio_gpu_find_resource(g, ss.resource_id);
>      >> +    CHECK(res, cmd);
>      >> +
>      >> +    if (!res->image) {
>      >> +        pixman_format_code_t pformat;
>      >> +        pformat = virtio_gpu_get_pixman_format(res->format);
>      >> +        CHECK(pformat, cmd);
>      >> +
>      >> +        res->image = pixman_image_create_bits(pformat,
>      >> +                                              res->width,
>      >> +                                              res->height,
>      >> +                                              NULL, 0);
>      >> +        CHECK(res->image, cmd);
>      >> +        pixman_image_ref(res->image);
>      >> +    }
>      >> +
>      >> +    vb->enable = 1;
>      >> +
>      >> +    /* realloc the surface ptr */
>      >> +    scanout->ds = qemu_create_displaysurface_pixman(res->image);
>      >> +    dpy_gfx_replace_surface(scanout->con, NULL);
>      >> +    dpy_gfx_replace_surface(scanout->con, scanout->ds);
>      >> +    res->scanout_bitmask = ss.scanout_id;
>      >> +}
>      >> +
>      >> +static void
>      >> +rutabaga_cmd_submit_3d(VirtIOGPU *g,
>      >> +                       struct virtio_gpu_ctrl_command *cmd)
>      >> +{
>      >> +    int32_t result;
>      >> +    struct virtio_gpu_cmd_submit cs;
>      >> +    struct rutabaga_command rutabaga_cmd = { 0 };
>      >> +    g_autofree uint8_t *buf = NULL;
>      >> +    size_t s;
>      >> +
>      >> +    VirtIOGPURutabaga *vr = VIRTIO_GPU_RUTABAGA(g);
>      >> +
>      >> +    VIRTIO_GPU_FILL_CMD(cs);
>      >> +    trace_virtio_gpu_cmd_ctx_submit(cs.hdr.ctx_id, cs.size);
>      >> +
>      >> +    buf = g_new0(uint8_t, cs.size);
>      >> +    s = iov_to_buf(cmd->elem.out_sg, cmd->elem.out_num,
>      >> +                   sizeof(cs), buf, cs.size);
>      >> +    CHECK(s == cs.size, cmd);
>      >> +
>      >> +    rutabaga_cmd.ctx_id = cs.hdr.ctx_id;
>      >> +    rutabaga_cmd.cmd = buf;
>      >> +    rutabaga_cmd.cmd_size = cs.size;
>      >> +
>      >> +    result = rutabaga_submit_command(vr->rutabaga, &rutabaga_cmd);
>      >> +    CHECK(!result, cmd);
>      >> +}
>      >> +
>      >> +static void
>      >> +rutabaga_cmd_transfer_to_host_2d(VirtIOGPU *g,
>      >> +                                 struct virtio_gpu_ctrl_command
>     *cmd)
>      >> +{
>      >> +    int32_t result;
>      >> +    struct rutabaga_transfer transfer = { 0 };
>      >> +    struct virtio_gpu_transfer_to_host_2d t2d;
>      >> +
>      >> +    VirtIOGPURutabaga *vr = VIRTIO_GPU_RUTABAGA(g);
>      >> +
>      >> +    VIRTIO_GPU_FILL_CMD(t2d);
>      >> +    trace_virtio_gpu_cmd_res_xfer_toh_2d(t2d.resource_id);
>      >> +
>      >> +    transfer.x = t2d.r.x;
>      >> +    transfer.y = t2d.r.y;
>      >> +    transfer.z = 0;
>      >> +    transfer.w = t2d.r.width;
>      >> +    transfer.h = t2d.r.height;
>      >> +    transfer.d = 1;
>      >> +
>      >> +    result = rutabaga_resource_transfer_write(vr->rutabaga, 0,
>     t2d.resource_id,
>      >> +                                              &transfer);
>      >> +    CHECK(!result, cmd);
>      >> +}
>      >> +
>      >> +static void
>      >> +rutabaga_cmd_transfer_to_host_3d(VirtIOGPU *g,
>      >> +                                 struct virtio_gpu_ctrl_command
>     *cmd)
>      >> +{
>      >> +    int32_t result;
>      >> +    struct rutabaga_transfer transfer = { 0 };
>      >> +    struct virtio_gpu_transfer_host_3d t3d;
>      >> +
>      >> +    VirtIOGPURutabaga *vr = VIRTIO_GPU_RUTABAGA(g);
>      >> +
>      >> +    VIRTIO_GPU_FILL_CMD(t3d);
>      >> +    trace_virtio_gpu_cmd_res_xfer_toh_3d(t3d.resource_id);
>      >> +
>      >> +    transfer.x = t3d.box.x;
>      >> +    transfer.y = t3d.box.y;
>      >> +    transfer.z = t3d.box.z;
>      >> +    transfer.w = t3d.box.w;
>      >> +    transfer.h = t3d.box.h;
>      >> +    transfer.d = t3d.box.d;
>      >> +    transfer.level = t3d.level;
>      >> +    transfer.stride = t3d.stride;
>      >> +    transfer.layer_stride = t3d.layer_stride;
>      >> +    transfer.offset = t3d.offset;
>      >> +
>      >> +    result = rutabaga_resource_transfer_write(vr->rutabaga,
>     t3d.hdr.ctx_id,
>      >> +                                              t3d.resource_id,
>     &transfer);
>      >> +    CHECK(!result, cmd);
>      >> +}
>      >> +
>      >> +static void
>      >> +rutabaga_cmd_transfer_from_host_3d(VirtIOGPU *g,
>      >> +                                   struct
>     virtio_gpu_ctrl_command *cmd)
>      >> +{
>      >> +    int32_t result;
>      >> +    struct rutabaga_transfer transfer = { 0 };
>      >> +    struct virtio_gpu_transfer_host_3d t3d;
>      >> +
>      >> +    VirtIOGPURutabaga *vr = VIRTIO_GPU_RUTABAGA(g);
>      >> +
>      >> +    VIRTIO_GPU_FILL_CMD(t3d);
>      >> +    trace_virtio_gpu_cmd_res_xfer_fromh_3d(t3d.resource_id);
>      >> +
>      >> +    transfer.x = t3d.box.x;
>      >> +    transfer.y = t3d.box.y;
>      >> +    transfer.z = t3d.box.z;
>      >> +    transfer.w = t3d.box.w;
>      >> +    transfer.h = t3d.box.h;
>      >> +    transfer.d = t3d.box.d;
>      >> +    transfer.level = t3d.level;
>      >> +    transfer.stride = t3d.stride;
>      >> +    transfer.layer_stride = t3d.layer_stride;
>      >> +    transfer.offset = t3d.offset;
>      >> +
>      >> +    result = rutabaga_resource_transfer_read(vr->rutabaga,
>     t3d.hdr.ctx_id,
>      >> +                                             t3d.resource_id,
>     &transfer, NULL);
>      >> +    CHECK(!result, cmd);
>      >> +}
>      >> +
>      >> +static void
>      >> +rutabaga_cmd_attach_backing(VirtIOGPU *g, struct
>     virtio_gpu_ctrl_command *cmd)
>      >> +{
>      >> +    struct rutabaga_iovecs vecs = { 0 };
>      >> +    struct virtio_gpu_simple_resource *res;
>      >> +    struct virtio_gpu_resource_attach_backing att_rb;
>      >> +    int ret;
>      >> +
>      >> +    VirtIOGPURutabaga *vr = VIRTIO_GPU_RUTABAGA(g);
>      >> +
>      >> +    VIRTIO_GPU_FILL_CMD(att_rb);
>      >> +    trace_virtio_gpu_cmd_res_back_attach(att_rb.resource_id);
>      >> +
>      >> +    res = virtio_gpu_find_resource(g, att_rb.resource_id);
>      >> +    CHECK(res, cmd);
>      >> +    CHECK(!res->iov, cmd);
>      >> +
>      >> +    ret = virtio_gpu_create_mapping_iov(g, att_rb.nr_entries,
>     sizeof(att_rb),
>      >> +                                        cmd, NULL, &res->iov,
>     &res->iov_cnt);
>      >> +    CHECK(!ret, cmd);
>      >> +
>      >> +    vecs.iovecs = res->iov;
>      >> +    vecs.num_iovecs = res->iov_cnt;
>      >> +
>      >> +    ret = rutabaga_resource_attach_backing(vr->rutabaga,
>     att_rb.resource_id,
>      >> +                                           &vecs);
>      >> +    if (ret != 0) {
>      >> +        virtio_gpu_cleanup_mapping(g, res);
>      >> +    }
>      >> +
>      >> +    CHECK(!ret, cmd);
>      >> +}
>      >> +
>      >> +static void
>      >> +rutabaga_cmd_detach_backing(VirtIOGPU *g, struct
>     virtio_gpu_ctrl_command *cmd)
>      >> +{
>      >> +    struct virtio_gpu_simple_resource *res;
>      >> +    struct virtio_gpu_resource_detach_backing detach_rb;
>      >> +
>      >> +    VirtIOGPURutabaga *vr = VIRTIO_GPU_RUTABAGA(g);
>      >> +
>      >> +    VIRTIO_GPU_FILL_CMD(detach_rb);
>      >> +    trace_virtio_gpu_cmd_res_back_detach(detach_rb.resource_id);
>      >> +
>      >> +    res = virtio_gpu_find_resource(g, detach_rb.resource_id);
>      >> +    CHECK(res, cmd);
>      >> +
>      >> +    rutabaga_resource_detach_backing(vr->rutabaga,
>      >> +                                     detach_rb.resource_id);
>      >> +
>      >> +    virtio_gpu_cleanup_mapping(g, res);
>      >> +}
>      >> +
>      >> +static void
>      >> +rutabaga_cmd_ctx_attach_resource(VirtIOGPU *g,
>      >> +                                 struct virtio_gpu_ctrl_command
>     *cmd)
>      >> +{
>      >> +    int32_t result;
>      >> +    struct virtio_gpu_ctx_resource att_res;
>      >> +
>      >> +    VirtIOGPURutabaga *vr = VIRTIO_GPU_RUTABAGA(g);
>      >> +
>      >> +    VIRTIO_GPU_FILL_CMD(att_res);
>      >> +    trace_virtio_gpu_cmd_ctx_res_attach(att_res.hdr.ctx_id,
>      >> +                                        att_res.resource_id);
>      >> +
>      >> +    result = rutabaga_context_attach_resource(vr->rutabaga,
>     att_res.hdr.ctx_id,
>      >> +                                              att_res.resource_id);
>      >> +    CHECK(!result, cmd);
>      >> +}
>      >> +
>      >> +static void
>      >> +rutabaga_cmd_ctx_detach_resource(VirtIOGPU *g,
>      >> +                                 struct virtio_gpu_ctrl_command
>     *cmd)
>      >> +{
>      >> +    int32_t result;
>      >> +    struct virtio_gpu_ctx_resource det_res;
>      >> +
>      >> +    VirtIOGPURutabaga *vr = VIRTIO_GPU_RUTABAGA(g);
>      >> +
>      >> +    VIRTIO_GPU_FILL_CMD(det_res);
>      >> +    trace_virtio_gpu_cmd_ctx_res_detach(det_res.hdr.ctx_id,
>      >> +                                        det_res.resource_id);
>      >> +
>      >> +    result = rutabaga_context_detach_resource(vr->rutabaga,
>     det_res.hdr.ctx_id,
>      >> +                                              det_res.resource_id);
>      >> +    CHECK(!result, cmd);
>      >> +}
>      >> +
>      >> +static void
>      >> +rutabaga_cmd_get_capset_info(VirtIOGPU *g, struct
>     virtio_gpu_ctrl_command *cmd)
>      >> +{
>      >> +    int32_t result;
>      >> +    struct virtio_gpu_get_capset_info info;
>      >> +    struct virtio_gpu_resp_capset_info resp;
>      >> +
>      >> +    VirtIOGPURutabaga *vr = VIRTIO_GPU_RUTABAGA(g);
>      >> +
>      >> +    VIRTIO_GPU_FILL_CMD(info);
>      >> +
>      >> +    result = rutabaga_get_capset_info(vr->rutabaga,
>     info.capset_index,
>      >> +                                      &resp.capset_id,
>     &resp.capset_max_version,
>      >> +                                      &resp.capset_max_size);
>      >> +    CHECK(!result, cmd);
>      >> +
>      >> +    resp.hdr.type = VIRTIO_GPU_RESP_OK_CAPSET_INFO;
>      >> +    virtio_gpu_ctrl_response(g, cmd, &resp.hdr, sizeof(resp));
>      >> +}
>      >> +
>      >> +static void
>      >> +rutabaga_cmd_get_capset(VirtIOGPU *g, struct
>     virtio_gpu_ctrl_command *cmd)
>      >> +{
>      >> +    int32_t result;
>      >> +    struct virtio_gpu_get_capset gc;
>      >> +    struct virtio_gpu_resp_capset *resp;
>      >> +    uint32_t capset_size, capset_version;
>      >> +    uint32_t current_id, i;
>      >> +
>      >> +    VirtIOGPURutabaga *vr = VIRTIO_GPU_RUTABAGA(g);
>      >> +
>      >> +    VIRTIO_GPU_FILL_CMD(gc);
>      >> +    for (i = 0; i < vr->num_capsets; i++) {
>      >> +        result = rutabaga_get_capset_info(vr->rutabaga, i,
>      >> +                                          &current_id,
>     &capset_version,
>      >> +                                          &capset_size);
>      >> +        CHECK(!result, cmd);
>      >> +
>      >> +        if (current_id == gc.capset_id) {
>      >> +            break;
>      >> +        }
>      >> +    }
>      >> +
>      >> +    CHECK(i < vr->num_capsets, cmd);
>      >> +
>      >> +    resp = g_malloc0(sizeof(*resp) + capset_size);
>      >> +    resp->hdr.type = VIRTIO_GPU_RESP_OK_CAPSET;
>      >> +    rutabaga_get_capset(vr->rutabaga, gc.capset_id,
>     gc.capset_version,
>      >> +                        resp->capset_data, capset_size);
>      >> +
>      >> +    virtio_gpu_ctrl_response(g, cmd, &resp->hdr, sizeof(*resp)
>     + capset_size);
>      >> +    g_free(resp);
>      >> +}
>      >> +
>      >> +static void
>      >> +rutabaga_cmd_resource_create_blob(VirtIOGPU *g,
>      >> +                                  struct
>     virtio_gpu_ctrl_command *cmd)
>      >> +{
>      >> +    int result;
>      >> +    struct rutabaga_iovecs vecs = { 0 };
>      >> +    g_autofree struct virtio_gpu_simple_resource *res = NULL;
>      >> +    struct virtio_gpu_resource_create_blob cblob;
>      >> +    struct rutabaga_create_blob rc_blob = { 0 };
>      >> +
>      >> +    VirtIOGPURutabaga *vr = VIRTIO_GPU_RUTABAGA(g);
>      >> +
>      >> +    VIRTIO_GPU_FILL_CMD(cblob);
>      >> +    trace_virtio_gpu_cmd_res_create_blob(cblob.resource_id,
>     cblob.size);
>      >> +
>      >> +    CHECK(cblob.resource_id != 0, cmd);
>      >> +
>      >> +    res = g_new0(struct virtio_gpu_simple_resource, 1);
>      >> +
>      >> +    res->resource_id = cblob.resource_id;
>      >> +    res->blob_size = cblob.size;
>      >> +
>      >> +    if (cblob.blob_mem != VIRTIO_GPU_BLOB_MEM_HOST3D) {
>      >> +        result = virtio_gpu_create_mapping_iov(g, cblob.nr_entries,
>      >> +                                               sizeof(cblob),
>     cmd, &res->addrs,
>      >> +                                               &res->iov,
>     &res->iov_cnt);
>      >> +        CHECK(!result, cmd);
>      >> +    }
>      >> +
>      >> +    rc_blob.blob_id = cblob.blob_id;
>      >> +    rc_blob.blob_mem = cblob.blob_mem;
>      >> +    rc_blob.blob_flags = cblob.blob_flags;
>      >> +    rc_blob.size = cblob.size;
>      >> +
>      >> +    vecs.iovecs = res->iov;
>      >> +    vecs.num_iovecs = res->iov_cnt;
>      >> +
>      >> +    result = rutabaga_resource_create_blob(vr->rutabaga,
>     cblob.hdr.ctx_id,
>      >> +                                           cblob.resource_id,
>     &rc_blob, &vecs,
>      >> +                                           NULL);
>      >> +
>      >> +    if (result && cblob.blob_mem != VIRTIO_GPU_BLOB_MEM_HOST3D) {
>      >> +        virtio_gpu_cleanup_mapping(g, res);
>      >> +    }
>      >> +
>      >> +    CHECK(!result, cmd);
>      >> +
>      >> +    QTAILQ_INSERT_HEAD(&g->reslist, res, next);
>      >> +    res = NULL;
>      >> +}
>      >> +
>      >> +static void
>      >> +rutabaga_cmd_resource_map_blob(VirtIOGPU *g,
>      >> +                               struct virtio_gpu_ctrl_command *cmd)
>      >> +{
>      >> +    int32_t result;
>      >> +    uint32_t map_info = 0;
>      >> +    uint32_t slot = 0;
>      >> +    struct virtio_gpu_simple_resource *res;
>      >> +    struct rutabaga_mapping mapping = { 0 };
>      >> +    struct virtio_gpu_resource_map_blob mblob;
>      >> +    struct virtio_gpu_resp_map_info resp = { 0 };
>      >> +
>      >> +    VirtIOGPUBase *vb = VIRTIO_GPU_BASE(g);
>      >> +    VirtIOGPURutabaga *vr = VIRTIO_GPU_RUTABAGA(g);
>      >> +
>      >> +    VIRTIO_GPU_FILL_CMD(mblob);
>      >> +
>      >> +    CHECK(mblob.resource_id != 0, cmd);
>      >> +
>      >> +    res = virtio_gpu_find_resource(g, mblob.resource_id);
>      >> +    CHECK(res, cmd);
>      >> +
>      >> +    result = rutabaga_resource_map_info(vr->rutabaga,
>     mblob.resource_id,
>      >> +                                        &map_info);
>      >> +    CHECK(!result, cmd);
>      >> +
>      >> +    /*
>      >> +     * RUTABAGA_MAP_ACCESS_* flags are not part of the
>     virtio-gpu spec, but do
>      >> +     * exist to potentially allow the hypervisor to restrict
>     write access to
>      >> +     * memory. QEMU does not need to use this functionality at
>     the moment.
>      >> +     */
>      >> +    resp.map_info = map_info & RUTABAGA_MAP_CACHE_MASK;
>      >> +
>      >> +    result = rutabaga_resource_map(vr->rutabaga,
>     mblob.resource_id, &mapping);
>      >> +    CHECK(!result, cmd);
>      >> +
>      >> +    for (slot = 0; slot < MAX_SLOTS; slot++) {
>      >> +        if (vr->memory_regions[slot].used) {
>      >> +            continue;
>      >> +        }
>      >> +
>      >> +        MemoryRegion *mr = &(vr->memory_regions[slot].mr);
>      >> +        memory_region_init_ram_ptr(mr, OBJECT(vr), "blob",
>     mapping.size,
>      >> +                                   mapping.ptr);
>      >> +        memory_region_add_subregion(&vb->hostmem, mblob.offset,
>     mr);
>      >> +        vr->memory_regions[slot].resource_id = mblob.resource_id;
>      >> +        vr->memory_regions[slot].used = 1;
>      >> +        break;
>      >> +    }
>      >> +
>      >> +    if (slot >= MAX_SLOTS) {
>      >> +        result = rutabaga_resource_unmap(vr->rutabaga,
>     mblob.resource_id);
>      >> +        CHECK(!result, cmd);
>      >> +    }
>      >> +
>      >> +    CHECK(slot < MAX_SLOTS, cmd);
>      >> +
>      >> +    resp.hdr.type = VIRTIO_GPU_RESP_OK_MAP_INFO;
>      >> +    virtio_gpu_ctrl_response(g, cmd, &resp.hdr, sizeof(resp));
>      >> +}
>      >> +
>      >> +static void
>      >> +rutabaga_cmd_resource_unmap_blob(VirtIOGPU *g,
>      >> +                                 struct virtio_gpu_ctrl_command
>     *cmd)
>      >> +{
>      >> +    int32_t result;
>      >> +    uint32_t slot = 0;
>      >> +    struct virtio_gpu_simple_resource *res;
>      >> +    struct virtio_gpu_resource_unmap_blob ublob;
>      >> +
>      >> +    VirtIOGPUBase *vb = VIRTIO_GPU_BASE(g);
>      >> +    VirtIOGPURutabaga *vr = VIRTIO_GPU_RUTABAGA(g);
>      >> +
>      >> +    VIRTIO_GPU_FILL_CMD(ublob);
>      >> +
>      >> +    CHECK(ublob.resource_id != 0, cmd);
>      >> +
>      >> +    res = virtio_gpu_find_resource(g, ublob.resource_id);
>      >> +    CHECK(res, cmd);
>      >> +
>      >> +    for (slot = 0; slot < MAX_SLOTS; slot++) {
>      >> +        if (vr->memory_regions[slot].resource_id !=
>     ublob.resource_id) {
>      >> +            continue;
>      >> +        }
>      >> +
>      >> +        MemoryRegion *mr = &(vr->memory_regions[slot].mr);
>      >> +        memory_region_del_subregion(&vb->hostmem, mr);
>      >> +
>      >> +        vr->memory_regions[slot].resource_id = 0;
>      >> +        vr->memory_regions[slot].used = 0;
>      >> +        break;
>      >> +    }
>      >> +
>      >> +    CHECK(slot < MAX_SLOTS, cmd);
>      >> +    result = rutabaga_resource_unmap(vr->rutabaga,
>     res->resource_id);
>      >
>      > Hi,
>      >
>      > After the discussion with Xenia Ragiadakou regarding their patch
>     for Venus, I found a
>      > bug present in the Venus implementation also affects Rutabaga.
>      >
>      > The problem is that the memory region may not immediately go away
>     with
>      > memory_region_del_subregion(), but it may be kept a bit after
>     that. The memory region
>      > has a pointer to the mapped memory so the unmapping call that
>     immediately follows
>      > will make it dangling.
>      >
>      > Xenia raised a question whether the dangling pointer can be
>     actually dereferenced and
>      > result in use-after-free, but the answer is unfortunately yes.
>     For example, consider
>      > the following call chain:
>      > kvm_cpu_exec -> address_space_rw -> address_space_write ->
>     flatview_write ->
>      > flatview_write_continue
>      >
>      > address_space_write() holds a RCU read lock so that the flatview
>     it refers to will
>      > not go away during the operation even if it becomes obsolete and
>     will be used for
>      > writes. It is possible that the obsolete flatview contains the
>     memory region for the
>      > memory that is concurrently unmapped by
>     virtio-gpu-rutabaga/virgl.  Note that the
>      > function can be called without holding BQL, and KVM actually does so.
>      >
>      > Another case is address_space_map(). It acquires the reference to
>     the memory with
>      > memory_region_ref() and expects it will be available until
>     memory_region_unref() gets
>      > called with address_space_unmap().
> 
> 
> Yeah, I did notice weird behavior around map/unmap when initially 
> testing the series:
> 
> https://lists.gnu.org/archive/html/qemu-devel/2023-04/msg03378.html 
> <https://lists.gnu.org/archive/html/qemu-devel/2023-04/msg03378.html>
> 
> The solution I did was just do what the Android Emulator (which uses 
> QEMU2.12) has been doing for years.  Not call "obj_unparent(g)" and keep 
> a table of memory regions for initialization.  It does pass all 
> ./deqp-vk memory tests and is sufficient to run Android on a Vulkan-only 
> stack.  I think the way blob resources are handled in the guest some of 
> the cases you've cited may not be hit practice.  The biggest bug on 
> Linux we do hit is a KVM bug but hopefully that should be fixed soon:
> 
> https://lore.kernel.org/kvmarm/20230911021637.1941096-1-stevensd@google.com/T/#m7c23c97b56378e3e865057140be54fa3dd87154e <https://lore.kernel.org/kvmarm/20230911021637.1941096-1-stevensd@google.com/T/#m7c23c97b56378e3e865057140be54fa3dd87154e>
> 
> We hit interesting issues on MacOS on the gitlab issue and I do think a 
> follow-up memory-only series may be warranted in the future.
> 
> https://gitlab.com/qemu-project/qemu/-/issues/1611 
> <https://gitlab.com/qemu-project/qemu/-/issues/1611>
> 
> Since the Android Emulator has been running the solution in the 
> rutabaga/gfxstream series for years, it should be good for our purposes 
> on Linux for now.  WDYT?

Practically there is very low chance to hit the bug. I think only 
fuzzers and malicious actors will trigger it, and probably no one will 
dare using virtio-gpu-rutabaga or virtio-gpu-gl in a security-sensitive 
context.

That said, we know there is a bug so why don't you fix it? Otherwise you 
may document the bug, but getting it fixed is better.

Regards,
Akihiko Odaki


^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH v13 6/9] gfxstream + rutabaga: add initial support for gfxstream
  2023-09-22  2:53         ` Akihiko Odaki
@ 2023-09-22  7:42           ` Alyssa Ross
  2023-09-22  7:54             ` Akihiko Odaki
  0 siblings, 1 reply; 27+ messages in thread
From: Alyssa Ross @ 2023-09-22  7:42 UTC (permalink / raw)
  To: Akihiko Odaki, Gurchetan Singh, Mark Cave-Ayland
  Cc: qemu-devel, Xenia Ragiadakou, marcandre.lureau, ray.huang,
	alex.bennee, shentey, ernunes, manos.pitsidianakis, philmd,
	Gerd Hoffmann, Michael S . Tsirkin, Stefano Stabellini,
	Anthony PERARD, Antonio Caggiano, Dr . David Alan Gilbert,
	Robert Beckett, Dmitry Osipenko, xen-devel, Albert Esteve,
	Roger Pau Monné,
	Alex Deucher, Christian König, Pierre-Eric Pelloux-Prayer,
	Honglei Huang, Julia Zhang, Chen Jiqian

[-- Attachment #1: Type: text/plain, Size: 375 bytes --]

Akihiko Odaki <akihiko.odaki@gmail.com> writes:

> Practically there is very low chance to hit the bug. I think only 
> fuzzers and malicious actors will trigger it, and probably no one will 
> dare using virtio-gpu-rutabaga or virtio-gpu-gl in a security-sensitive 
> context.

Well, this is exactly what Chrome OS does, albiet with crosvm rather
than QEMU, right?

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 832 bytes --]

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH v13 6/9] gfxstream + rutabaga: add initial support for gfxstream
  2023-09-22  7:42           ` Alyssa Ross
@ 2023-09-22  7:54             ` Akihiko Odaki
  0 siblings, 0 replies; 27+ messages in thread
From: Akihiko Odaki @ 2023-09-22  7:54 UTC (permalink / raw)
  To: Alyssa Ross, Gurchetan Singh, Mark Cave-Ayland
  Cc: qemu-devel, Xenia Ragiadakou, marcandre.lureau, ray.huang,
	alex.bennee, shentey, ernunes, manos.pitsidianakis, philmd,
	Gerd Hoffmann, Michael S . Tsirkin, Stefano Stabellini,
	Anthony PERARD, Antonio Caggiano, Dr . David Alan Gilbert,
	Robert Beckett, Dmitry Osipenko, xen-devel, Albert Esteve,
	Roger Pau Monné,
	Alex Deucher, Christian König, Pierre-Eric Pelloux-Prayer,
	Honglei Huang, Julia Zhang, Chen Jiqian

On 2023/09/22 16:42, Alyssa Ross wrote:
> Akihiko Odaki <akihiko.odaki@gmail.com> writes:
> 
>> Practically there is very low chance to hit the bug. I think only
>> fuzzers and malicious actors will trigger it, and probably no one will
>> dare using virtio-gpu-rutabaga or virtio-gpu-gl in a security-sensitive
>> context.
> 
> Well, this is exactly what Chrome OS does, albiet with crosvm rather
> than QEMU, right?

I think so, but QEMU's virtio-gpu-rutabaga and virtio-gpu-gl should be 
very different from crosvm in terms that it does not isolate the 
graphics stack into a separate process while I believe crosvm does so. 
Having the entire graphics stack in a VMM is a security nightmare; it 
means giving a complex shader compiler the highest privilege. We need to 
use vhost-user-gpu instead for process isolation.

Since we already have such a serious security hazard, I don't think we 
have to care much about security. But security approximately equals to 
reliability, which matters for virtio-gpu-rutabaga and virtio-gpu-gl 
too, so it's still nice to get the bug fixed.


^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH v13 6/9] gfxstream + rutabaga: add initial support for gfxstream
  2023-08-29  0:36 ` [PATCH v13 6/9] gfxstream + rutabaga: add initial support for gfxstream Gurchetan Singh
  2023-09-20 11:42   ` Akihiko Odaki
@ 2023-09-27 11:45   ` Thomas Huth
  2023-09-27 12:24     ` Markus Armbruster
  2023-09-27 12:26     ` Mark Cave-Ayland
  1 sibling, 2 replies; 27+ messages in thread
From: Thomas Huth @ 2023-09-27 11:45 UTC (permalink / raw)
  To: Gurchetan Singh, qemu-devel, Markus Armbruster
  Cc: marcandre.lureau, akihiko.odaki, ray.huang, alex.bennee, shentey,
	hi, ernunes, manos.pitsidianakis, philmd, mark.cave-ayland

On 29/08/2023 02.36, Gurchetan Singh wrote:
> This adds initial support for gfxstream and cross-domain.  Both
> features rely on virtio-gpu blob resources and context types, which
> are also implemented in this patch.
> 
> gfxstream has a long and illustrious history in Android graphics
> paravirtualization.  It has been powering graphics in the Android
> Studio Emulator for more than a decade, which is the main developer
> platform.
> 
> Originally conceived by Jesse Hall, it was first known as "EmuGL" [a].
> The key design characteristic was a 1:1 threading model and
> auto-generation, which fit nicely with the OpenGLES spec.  It also
> allowed easy layering with ANGLE on the host, which provides the GLES
> implementations on Windows or MacOS enviroments.
> 
> gfxstream has traditionally been maintained by a single engineer, and
> between 2015 to 2021, the goldfish throne passed to Frank Yang.
> Historians often remark this glorious reign ("pax gfxstreama" is the
> academic term) was comparable to that of Augustus and both Queen
> Elizabeths.  Just to name a few accomplishments in a resplendent
> panoply: higher versions of GLES, address space graphics, snapshot
> support and CTS compliant Vulkan [b].
> 
> One major drawback was the use of out-of-tree goldfish drivers.
> Android engineers didn't know much about DRM/KMS and especially TTM so
> a simple guest to host pipe was conceived.
> 
> Luckily, virtio-gpu 3D started to emerge in 2016 due to the work of
> the Mesa/virglrenderer communities.  In 2018, the initial virtio-gpu
> port of gfxstream was done by Cuttlefish enthusiast Alistair Delva.
> It was a symbol compatible replacement of virglrenderer [c] and named
> "AVDVirglrenderer".  This implementation forms the basis of the
> current gfxstream host implementation still in use today.
> 
> cross-domain support follows a similar arc.  Originally conceived by
> Wayland aficionado David Reveman and crosvm enjoyer Zach Reizner in
> 2018, it initially relied on the downstream "virtio-wl" device.
> 
> In 2020 and 2021, virtio-gpu was extended to include blob resources
> and multiple timelines by yours truly, features gfxstream/cross-domain
> both require to function correctly.
> 
> Right now, we stand at the precipice of a truly fantastic possibility:
> the Android Emulator powered by upstream QEMU and upstream Linux
> kernel.  gfxstream will then be packaged properfully, and app
> developers can even fix gfxstream bugs on their own if they encounter
> them.
> 
> It's been quite the ride, my friends.  Where will gfxstream head next,
> nobody really knows.  I wouldn't be surprised if it's around for
> another decade, maintained by a new generation of Android graphics
> enthusiasts.
> 
> Technical details:
>    - Very simple initial display integration: just used Pixman
>    - Largely, 1:1 mapping of virtio-gpu hypercalls to rutabaga function
>      calls
> 
> Next steps for Android VMs:
>    - The next step would be improving display integration and UI interfaces
>      with the goal of the QEMU upstream graphics being in an emulator
>      release [d].
> 
> Next steps for Linux VMs for display virtualization:
>    - For widespread distribution, someone needs to package Sommelier or the
>      wayland-proxy-virtwl [e] ideally into Debian main. In addition, newer
>      versions of the Linux kernel come with DRM_VIRTIO_GPU_KMS option,
>      which allows disabling KMS hypercalls.  If anyone cares enough, it'll
>      probably be possible to build a custom VM variant that uses this display
>      virtualization strategy.
> 
> [a] https://android-review.googlesource.com/c/platform/development/+/34470
> [b] https://android-review.googlesource.com/q/topic:%22vulkan-hostconnection-start%22
> [c] https://android-review.googlesource.com/c/device/generic/goldfish-opengl/+/761927
> [d] https://developer.android.com/studio/releases/emulator
> [e] https://github.com/talex5/wayland-proxy-virtwl
> 
> Signed-off-by: Gurchetan Singh <gurchetansingh@chromium.org>
> Tested-by: Alyssa Ross <hi@alyssa.is>
> Tested-by: Emmanouil Pitsidianakis <manos.pitsidianakis@linaro.org>
> Tested-by: Akihiko Odaki <akihiko.odaki@daynix.com>
> Reviewed-by: Emmanouil Pitsidianakis <manos.pitsidianakis@linaro.org>
> Reviewed-by: Antonio Caggiano <quic_acaggian@quicinc.com>
> Reviewed-by: Akihiko Odaki <akihiko.odaki@daynix.com>
> ---
...
> +static Property virtio_gpu_rutabaga_properties[] = {
> +    DEFINE_PROP_STRING("capset_names", VirtIOGPURutabaga, capset_names),
> +    DEFINE_PROP_STRING("wayland_socket_path", VirtIOGPURutabaga,
> +                       wayland_socket_path),

FWIW, it seems to be more common to use "-" instead of "_" to separate words 
in properties ... so I'd like to suggest to replace the underscores in the 
strings here.

  Thomas



^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH v13 6/9] gfxstream + rutabaga: add initial support for gfxstream
  2023-09-27 11:45   ` Thomas Huth
@ 2023-09-27 12:24     ` Markus Armbruster
  2023-09-27 12:26     ` Mark Cave-Ayland
  1 sibling, 0 replies; 27+ messages in thread
From: Markus Armbruster @ 2023-09-27 12:24 UTC (permalink / raw)
  To: Thomas Huth
  Cc: Gurchetan Singh, qemu-devel, Markus Armbruster, marcandre.lureau,
	akihiko.odaki, ray.huang, alex.bennee, shentey, hi, ernunes,
	manos.pitsidianakis, philmd, mark.cave-ayland

Thomas Huth <thuth@redhat.com> writes:

[...]

>> +static Property virtio_gpu_rutabaga_properties[] = {
>> +    DEFINE_PROP_STRING("capset_names", VirtIOGPURutabaga, capset_names),
>> +    DEFINE_PROP_STRING("wayland_socket_path", VirtIOGPURutabaga,
>> +                       wayland_socket_path),
>
> FWIW, it seems to be more common to use "-" instead of "_" to separate words in properties ... so I'd like to suggest to replace the underscores in the strings here.

Please separate words with '-', not '_', except where existing
properties all use '_'.



^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH v13 6/9] gfxstream + rutabaga: add initial support for gfxstream
  2023-09-27 11:45   ` Thomas Huth
  2023-09-27 12:24     ` Markus Armbruster
@ 2023-09-27 12:26     ` Mark Cave-Ayland
  1 sibling, 0 replies; 27+ messages in thread
From: Mark Cave-Ayland @ 2023-09-27 12:26 UTC (permalink / raw)
  To: Thomas Huth, Gurchetan Singh, qemu-devel, Markus Armbruster
  Cc: marcandre.lureau, akihiko.odaki, ray.huang, alex.bennee, shentey,
	hi, ernunes, manos.pitsidianakis, philmd

On 27/09/2023 12:45, Thomas Huth wrote:

> On 29/08/2023 02.36, Gurchetan Singh wrote:
>> This adds initial support for gfxstream and cross-domain.  Both
>> features rely on virtio-gpu blob resources and context types, which
>> are also implemented in this patch.
>>
>> gfxstream has a long and illustrious history in Android graphics
>> paravirtualization.  It has been powering graphics in the Android
>> Studio Emulator for more than a decade, which is the main developer
>> platform.
>>
>> Originally conceived by Jesse Hall, it was first known as "EmuGL" [a].
>> The key design characteristic was a 1:1 threading model and
>> auto-generation, which fit nicely with the OpenGLES spec.  It also
>> allowed easy layering with ANGLE on the host, which provides the GLES
>> implementations on Windows or MacOS enviroments.
>>
>> gfxstream has traditionally been maintained by a single engineer, and
>> between 2015 to 2021, the goldfish throne passed to Frank Yang.
>> Historians often remark this glorious reign ("pax gfxstreama" is the
>> academic term) was comparable to that of Augustus and both Queen
>> Elizabeths.  Just to name a few accomplishments in a resplendent
>> panoply: higher versions of GLES, address space graphics, snapshot
>> support and CTS compliant Vulkan [b].
>>
>> One major drawback was the use of out-of-tree goldfish drivers.
>> Android engineers didn't know much about DRM/KMS and especially TTM so
>> a simple guest to host pipe was conceived.
>>
>> Luckily, virtio-gpu 3D started to emerge in 2016 due to the work of
>> the Mesa/virglrenderer communities.  In 2018, the initial virtio-gpu
>> port of gfxstream was done by Cuttlefish enthusiast Alistair Delva.
>> It was a symbol compatible replacement of virglrenderer [c] and named
>> "AVDVirglrenderer".  This implementation forms the basis of the
>> current gfxstream host implementation still in use today.
>>
>> cross-domain support follows a similar arc.  Originally conceived by
>> Wayland aficionado David Reveman and crosvm enjoyer Zach Reizner in
>> 2018, it initially relied on the downstream "virtio-wl" device.
>>
>> In 2020 and 2021, virtio-gpu was extended to include blob resources
>> and multiple timelines by yours truly, features gfxstream/cross-domain
>> both require to function correctly.
>>
>> Right now, we stand at the precipice of a truly fantastic possibility:
>> the Android Emulator powered by upstream QEMU and upstream Linux
>> kernel.  gfxstream will then be packaged properfully, and app
>> developers can even fix gfxstream bugs on their own if they encounter
>> them.
>>
>> It's been quite the ride, my friends.  Where will gfxstream head next,
>> nobody really knows.  I wouldn't be surprised if it's around for
>> another decade, maintained by a new generation of Android graphics
>> enthusiasts.
>>
>> Technical details:
>>    - Very simple initial display integration: just used Pixman
>>    - Largely, 1:1 mapping of virtio-gpu hypercalls to rutabaga function
>>      calls
>>
>> Next steps for Android VMs:
>>    - The next step would be improving display integration and UI interfaces
>>      with the goal of the QEMU upstream graphics being in an emulator
>>      release [d].
>>
>> Next steps for Linux VMs for display virtualization:
>>    - For widespread distribution, someone needs to package Sommelier or the
>>      wayland-proxy-virtwl [e] ideally into Debian main. In addition, newer
>>      versions of the Linux kernel come with DRM_VIRTIO_GPU_KMS option,
>>      which allows disabling KMS hypercalls.  If anyone cares enough, it'll
>>      probably be possible to build a custom VM variant that uses this display
>>      virtualization strategy.
>>
>> [a] https://android-review.googlesource.com/c/platform/development/+/34470
>> [b] https://android-review.googlesource.com/q/topic:%22vulkan-hostconnection-start%22
>> [c] https://android-review.googlesource.com/c/device/generic/goldfish-opengl/+/761927
>> [d] https://developer.android.com/studio/releases/emulator
>> [e] https://github.com/talex5/wayland-proxy-virtwl
>>
>> Signed-off-by: Gurchetan Singh <gurchetansingh@chromium.org>
>> Tested-by: Alyssa Ross <hi@alyssa.is>
>> Tested-by: Emmanouil Pitsidianakis <manos.pitsidianakis@linaro.org>
>> Tested-by: Akihiko Odaki <akihiko.odaki@daynix.com>
>> Reviewed-by: Emmanouil Pitsidianakis <manos.pitsidianakis@linaro.org>
>> Reviewed-by: Antonio Caggiano <quic_acaggian@quicinc.com>
>> Reviewed-by: Akihiko Odaki <akihiko.odaki@daynix.com>
>> ---
> ...
>> +static Property virtio_gpu_rutabaga_properties[] = {
>> +    DEFINE_PROP_STRING("capset_names", VirtIOGPURutabaga, capset_names),
>> +    DEFINE_PROP_STRING("wayland_socket_path", VirtIOGPURutabaga,
>> +                       wayland_socket_path),
> 
> FWIW, it seems to be more common to use "-" instead of "_" to separate words in 
> properties ... so I'd like to suggest to replace the underscores in the strings here.

It is actually part of the QOM documentation that object properties should use 
hyphens instead of underscores (see 
https://gitlab.com/qemu-project/qemu/-/blob/master/include/qom/object.h?ref_type=heads#L1013) 
but I agree it's buried so deep in the header file, it's almost impossible to find :( 
  Certainly it should be placed somewhere more prominent in the QOM and/or style 
documentation.


ATB,

Mark.



^ permalink raw reply	[flat|nested] 27+ messages in thread

end of thread, other threads:[~2023-09-27 12:27 UTC | newest]

Thread overview: 27+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-08-29  0:36 [PATCH v13 0/9] rutabaga_gfx + gfxstream Gurchetan Singh
2023-08-29  0:36 ` [PATCH v13 1/9] virtio: Add shared memory capability Gurchetan Singh
2023-08-29  0:36 ` [PATCH v13 2/9] virtio-gpu: CONTEXT_INIT feature Gurchetan Singh
2023-08-29  0:36 ` [PATCH v13 3/9] virtio-gpu: hostmem Gurchetan Singh
2023-08-29  0:36 ` [PATCH v13 4/9] virtio-gpu: blob prep Gurchetan Singh
2023-08-29  0:36 ` [PATCH v13 5/9] gfxstream + rutabaga prep: added need defintions, fields, and options Gurchetan Singh
2023-08-29  0:36 ` [PATCH v13 6/9] gfxstream + rutabaga: add initial support for gfxstream Gurchetan Singh
2023-09-20 11:42   ` Akihiko Odaki
2023-09-20 12:04     ` Mark Cave-Ayland
2023-09-22  0:03       ` Gurchetan Singh
2023-09-22  2:53         ` Akihiko Odaki
2023-09-22  7:42           ` Alyssa Ross
2023-09-22  7:54             ` Akihiko Odaki
2023-09-27 11:45   ` Thomas Huth
2023-09-27 12:24     ` Markus Armbruster
2023-09-27 12:26     ` Mark Cave-Ayland
2023-08-29  0:36 ` [PATCH v13 7/9] gfxstream + rutabaga: meson support Gurchetan Singh
2023-08-29  0:36 ` [PATCH v13 8/9] gfxstream + rutabaga: enable rutabaga Gurchetan Singh
2023-08-29  0:36 ` [PATCH v13 9/9] docs/system: add basic virtio-gpu documentation Gurchetan Singh
2023-08-31  2:25 ` [PATCH v13 0/9] rutabaga_gfx + gfxstream Huang Rui
2023-09-06  1:20   ` Gurchetan Singh
2023-09-06  6:25     ` Marc-André Lureau
2023-09-13 21:03       ` Bernhard Beschow
2023-09-12 13:59     ` Marc-André Lureau
2023-09-13  1:08       ` Gurchetan Singh
2023-09-13 13:49         ` Marc-André Lureau
2023-09-14  4:10           ` Gurchetan Singh

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).