All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v7 0/9] gfxstream + rutabaga_gfx
@ 2023-08-17  2:23 Gurchetan Singh
  2023-08-17  2:23 ` [PATCH v7 1/9] virtio: Add shared memory capability Gurchetan Singh
                   ` (8 more replies)
  0 siblings, 9 replies; 24+ messages in thread
From: Gurchetan Singh @ 2023-08-17  2:23 UTC (permalink / raw)
  To: qemu-devel
  Cc: marcandre.lureau, kraxel, akihiko.odaki, ray.huang, alex.bennee,
	shentey, hi, ernunes, manos.pitsidianakis

Prior versions:

v6:
https://lists.gnu.org/archive/html/qemu-devel/2023-08/msg02520.html

v5:
https://lists.gnu.org/archive/html/qemu-devel/2023-08/msg02339.html

v4:
https://lists.gnu.org/archive/html/qemu-devel/2023-08/msg01566.html

v3:
https://lists.gnu.org/archive/html/qemu-devel/2023-08/msg00565.html

v2:
https://lists.gnu.org/archive/html/qemu-devel/2023-07/msg05801.html

v1:
https://lists.gnu.org/archive/html/qemu-devel/2023-07/msg02341.html

RFC:
https://patchew.org/QEMU/20230421011223.718-1-gurchetansingh@chromium.org/

Changes since v6:
- Incorporated review feedback

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.freedesktop.org/gurchetansingh/qemu-gfxstream/-/commits/qemu-gfxstream-v7

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   |  113 +++
 hw/display/meson.build               |   22 +
 hw/display/virtio-gpu-base.c         |    6 +-
 hw/display/virtio-gpu-pci-rutabaga.c |   48 ++
 hw/display/virtio-gpu-pci.c          |   14 +
 hw/display/virtio-gpu-rutabaga.c     | 1115 ++++++++++++++++++++++++++
 hw/display/virtio-gpu.c              |   16 +-
 hw/display/virtio-vga-rutabaga.c     |   51 ++
 hw/display/virtio-vga.c              |   33 +-
 hw/virtio/virtio-pci.c               |   18 +
 include/hw/virtio/virtio-gpu-bswap.h |   18 +
 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, 1497 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.rc1.204.g551eb34607-goog



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

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

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>
Reviewed-by: Gurchetan Singh <gurchetansingh@chromium.org>
Signed-off-by: Gurchetan Singh <gurchetansingh@chromium.org>
Tested-by: Alyssa Ross <hi@alyssa.is>
Acked-by: Huang Rui <ray.huang@amd.com>
Tested-by: Huang Rui <ray.huang@amd.com>
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.rc1.204.g551eb34607-goog



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

* [PATCH v7 2/9] virtio-gpu: CONTEXT_INIT feature
  2023-08-17  2:23 [PATCH v7 0/9] gfxstream + rutabaga_gfx Gurchetan Singh
  2023-08-17  2:23 ` [PATCH v7 1/9] virtio: Add shared memory capability Gurchetan Singh
@ 2023-08-17  2:23 ` Gurchetan Singh
  2023-08-17  2:23 ` [PATCH v7 3/9] virtio-gpu: hostmem Gurchetan Singh
                   ` (6 subsequent siblings)
  8 siblings, 0 replies; 24+ messages in thread
From: Gurchetan Singh @ 2023-08-17  2:23 UTC (permalink / raw)
  To: qemu-devel
  Cc: marcandre.lureau, kraxel, akihiko.odaki, ray.huang, alex.bennee,
	shentey, hi, ernunes, manos.pitsidianakis

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>
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Signed-off-by: Gurchetan Singh <gurchetansingh@chromium.org>
Tested-by: Alyssa Ross <hi@alyssa.is>
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.rc1.204.g551eb34607-goog



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

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

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>
Acked-by: Michael S. Tsirkin <mst@redhat.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.rc1.204.g551eb34607-goog



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

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

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>
Reviewed-by: Emmanouil Pitsidianakis <manos.pitsidianakis@linaro.org>
---
 hw/display/virtio-gpu.c              | 10 +++-------
 include/hw/virtio/virtio-gpu-bswap.h | 18 ++++++++++++++++++
 include/hw/virtio/virtio-gpu.h       |  5 +++++
 3 files changed, 26 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 9124108485..dd1975e2d4 100644
--- a/include/hw/virtio/virtio-gpu-bswap.h
+++ b/include/hw/virtio/virtio-gpu-bswap.h
@@ -63,10 +63,28 @@ virtio_gpu_create_blob_bswap(struct virtio_gpu_resource_create_blob *cblob)
 {
     virtio_gpu_ctrl_hdr_bswap(&cblob->hdr);
     le32_to_cpus(&cblob->resource_id);
+    le32_to_cpus(&cblob->blob_mem);
     le32_to_cpus(&cblob->blob_flags);
+    le32_to_cpus(&cblob->nr_entries);
+    le64_to_cpus(&cblob->blob_id);
     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.rc1.204.g551eb34607-goog



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

* [PATCH v7 5/9] gfxstream + rutabaga prep: added need defintions, fields, and options
  2023-08-17  2:23 [PATCH v7 0/9] gfxstream + rutabaga_gfx Gurchetan Singh
                   ` (3 preceding siblings ...)
  2023-08-17  2:23 ` [PATCH v7 4/9] virtio-gpu: blob prep Gurchetan Singh
@ 2023-08-17  2:23 ` Gurchetan Singh
  2023-08-23 14:32   ` Mark Cave-Ayland
  2023-08-17  2:23 ` [PATCH v7 6/9] gfxstream + rutabaga: add initial support for gfxstream Gurchetan Singh
                   ` (3 subsequent siblings)
  8 siblings, 1 reply; 24+ messages in thread
From: Gurchetan Singh @ 2023-08-17  2:23 UTC (permalink / raw)
  To: qemu-devel
  Cc: marcandre.lureau, kraxel, akihiko.odaki, ray.huang, alex.bennee,
	shentey, hi, ernunes, manos.pitsidianakis

From: Gurchetan Singh <gurchetansingh@chromium.org>

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>
Reviewed-by: Emmanouil Pitsidianakis <manos.pitsidianakis@linaro.org>
---
v1: void *rutabaga --> struct rutabaga *rutabaga (Akihiko)
    have a separate rutabaga device instead of using GL device (Bernard)

v2: VirtioGpuRutabaga --> VirtIOGPURutabaga (Akihiko)
    move MemoryRegionInfo into VirtIOGPURutabaga (Akihiko)
    remove 'ctx' field (Akihiko)
    remove 'rutabaga_active'

v6: remove command from commit message, refer to docs instead (Manos)

 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..e2a07e68d9 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 {
+    struct 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.rc1.204.g551eb34607-goog



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

* [PATCH v7 6/9] gfxstream + rutabaga: add initial support for gfxstream
  2023-08-17  2:23 [PATCH v7 0/9] gfxstream + rutabaga_gfx Gurchetan Singh
                   ` (4 preceding siblings ...)
  2023-08-17  2:23 ` [PATCH v7 5/9] gfxstream + rutabaga prep: added need defintions, fields, and options Gurchetan Singh
@ 2023-08-17  2:23 ` Gurchetan Singh
  2023-08-18 11:58   ` Akihiko Odaki
  2023-08-23 15:03   ` Mark Cave-Ayland
  2023-08-17  2:23 ` [PATCH v7 7/9] gfxstream + rutabaga: meson support Gurchetan Singh
                   ` (2 subsequent siblings)
  8 siblings, 2 replies; 24+ messages in thread
From: Gurchetan Singh @ 2023-08-17  2:23 UTC (permalink / raw)
  To: qemu-devel
  Cc: marcandre.lureau, kraxel, akihiko.odaki, ray.huang, alex.bennee,
	shentey, hi, ernunes, manos.pitsidianakis

From: Gurchetan Singh <gurchetansingh@chromium.org>

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>
Reviewed-by: Emmanouil Pitsidianakis <manos.pitsidianakis@linaro.org>
---
v1: Incorported various suggestions by Akihiko Odaki and Bernard Berschow
    - Removed GET_VIRTIO_GPU_GL / GET_RUTABAGA macros
    - Used error_report(..)
    - Used g_autofree to fix leaks on error paths
    - Removed unnecessary casts
    - added virtio-gpu-pci-rutabaga.c + virtio-vga-rutabaga.c files

v2: Incorported various suggestions by Akihiko Odaki, Marc-André Lureau and
    Bernard Berschow:
    - Parenthesis in CHECK macro
    - CHECK_RESULT(result, ..) --> CHECK(!result, ..)
    - delay until g->parent_obj.enable = 1
    - Additional cast fixes
    - initialize directly in virtio_gpu_rutabaga_realize(..)
    - add debug callback to hook into QEMU error's APIs

v3: Incorporated feedback from Akihiko Odaki and Alyssa Ross:
    - Autodetect Wayland socket when not explicitly specified
    - Fix map_blob error paths
    - Add comment why we need both `res` and `resource` in create blob
    - Cast and whitespace fixes
    - Big endian check comes before virtio_gpu_rutabaga_init().
    - VirtIOVGARUTABAGA --> VirtIOVGARutabaga

v4: Incorporated feedback from Akihiko Odaki and Alyssa Ross:
    - Double checked all casts
    - Remove unnecessary parenthesis
    - Removed `resource` in create_blob
    - Added comment about failure case
    - Pass user-provided socket as-is
    - Use stack variable rather than heap allocation
    - Future-proofed map info API to give access flags as well

v5: Incorporated feedback from Akihiko Odaki:
    - Check (ss.scanout_id < VIRTIO_GPU_MAX_SCANOUTS)
    - Simplify num_capsets check
    - Call cleanup mapping on error paths
    - uint64_t --> void* for rutabaga_map(..)
    - Removed unnecessary parenthesis
    - Removed unnecessary cast
    - #define UNIX_PATH_MAX sizeof((struct sockaddr_un) {}.sun_path)
    - Reuse result variable

v6: Incorporated feedback from Akihiko Odaki:
    - Remove unnecessary #ifndef
    - Disable scanout when appropriate
    - CHECK capset index within range outside loop
    - Add capset_version

v7: Incorporated feedback from Akihiko Odaki:
    - aio_bh_schedule_oneshot_full --> aio_bh_schedule_oneshot

 hw/display/virtio-gpu-pci-rutabaga.c |   48 ++
 hw/display/virtio-gpu-rutabaga.c     | 1115 ++++++++++++++++++++++++++
 hw/display/virtio-vga-rutabaga.c     |   51 ++
 3 files changed, 1214 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..c71173d8ca
--- /dev/null
+++ b/hw/display/virtio-gpu-pci-rutabaga.c
@@ -0,0 +1,48 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#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"
+typedef struct VirtIOGPURutabagaPCI VirtIOGPURutabagaPCI;
+DECLARE_INSTANCE_CHECKER(VirtIOGPURutabagaPCI, VIRTIO_GPU_RUTABAGA_PCI,
+                         TYPE_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 VirtioPCIDeviceTypeInfo virtio_gpu_rutabaga_pci_info = {
+    .generic_name = TYPE_VIRTIO_GPU_RUTABAGA_PCI,
+    .parent = TYPE_VIRTIO_GPU_PCI_BASE,
+    .instance_size = sizeof(VirtIOGPURutabagaPCI),
+    .instance_init = virtio_gpu_rutabaga_initfn,
+};
+module_obj(TYPE_VIRTIO_GPU_RUTABAGA_PCI);
+module_kconfig(VIRTIO_PCI);
+
+static void virtio_gpu_rutabaga_pci_register_types(void)
+{
+    virtio_pci_types_register(&virtio_gpu_rutabaga_pci_info);
+}
+
+type_init(virtio_gpu_rutabaga_pci_register_types)
+
+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..24977d3993
--- /dev/null
+++ b/hw/display/virtio-gpu-rutabaga.c
@@ -0,0 +1,1115 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#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;
+
+    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 < g->parent_obj.conf.max_outputs; i++) {
+        scanout = &g->parent_obj.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;
+
+    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 = &g->parent_obj.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);
+    }
+
+    g->parent_obj.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 };
+
+    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, NULL, "blob", mapping.size,
+                                   mapping.ptr);
+        memory_region_add_subregion(&g->parent_obj.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;
+
+    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(&g->parent_obj.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 int 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 -EINVAL;
+    }
+
+    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 -EINVAL;
+        }
+    }
+
+    result = rutabaga_calculate_capset_mask(vr->capset_names, &capset_mask);
+    if (result) {
+        error_setg(errp, "invalid capset names: %s", vr->capset_names);
+        return result;
+    }
+
+    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);
+    return result;
+}
+
+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
+
+    int result = virtio_gpu_rutabaga_init(gpudev, errp);
+    if (result) {
+        error_setg(errp, "virtio_gpu_rutabaga_init failed");
+        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,
+};
+module_obj(TYPE_VIRTIO_GPU_RUTABAGA);
+module_kconfig(VIRTIO_GPU);
+
+static void virtio_register_types(void)
+{
+    type_register_static(&virtio_gpu_rutabaga_info);
+}
+
+type_init(virtio_register_types)
+
+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..2b2ffed8a6
--- /dev/null
+++ b/hw/display/virtio-vga-rutabaga.c
@@ -0,0 +1,51 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#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"
+
+typedef struct VirtIOVGARutabaga VirtIOVGARutabaga;
+DECLARE_INSTANCE_CHECKER(VirtIOVGARutabaga, VIRTIO_VGA_RUTABAGA,
+                         TYPE_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.rc1.204.g551eb34607-goog



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

* [PATCH v7 7/9] gfxstream + rutabaga: meson support
  2023-08-17  2:23 [PATCH v7 0/9] gfxstream + rutabaga_gfx Gurchetan Singh
                   ` (5 preceding siblings ...)
  2023-08-17  2:23 ` [PATCH v7 6/9] gfxstream + rutabaga: add initial support for gfxstream Gurchetan Singh
@ 2023-08-17  2:23 ` Gurchetan Singh
  2023-08-17  2:23 ` [PATCH v7 8/9] gfxstream + rutabaga: enable rutabaga Gurchetan Singh
  2023-08-17  2:23 ` [PATCH v7 9/9] docs/system: add basic virtio-gpu documentation Gurchetan Singh
  8 siblings, 0 replies; 24+ messages in thread
From: Gurchetan Singh @ 2023-08-17  2:23 UTC (permalink / raw)
  To: qemu-devel
  Cc: marcandre.lureau, kraxel, akihiko.odaki, ray.huang, alex.bennee,
	shentey, hi, ernunes, manos.pitsidianakis

From: Gurchetan Singh <gurchetansingh@chromium.org>

- 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>
Reviewed-by: Emmanouil Pitsidianakis <manos.pitsidianakis@linaro.org>
---
v3: Fix alignment issues (Akihiko)

 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.rc1.204.g551eb34607-goog



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

* [PATCH v7 8/9] gfxstream + rutabaga: enable rutabaga
  2023-08-17  2:23 [PATCH v7 0/9] gfxstream + rutabaga_gfx Gurchetan Singh
                   ` (6 preceding siblings ...)
  2023-08-17  2:23 ` [PATCH v7 7/9] gfxstream + rutabaga: meson support Gurchetan Singh
@ 2023-08-17  2:23 ` Gurchetan Singh
  2023-08-18 11:58   ` Akihiko Odaki
  2023-08-17  2:23 ` [PATCH v7 9/9] docs/system: add basic virtio-gpu documentation Gurchetan Singh
  8 siblings, 1 reply; 24+ messages in thread
From: Gurchetan Singh @ 2023-08-17  2:23 UTC (permalink / raw)
  To: qemu-devel
  Cc: marcandre.lureau, kraxel, akihiko.odaki, ray.huang, alex.bennee,
	shentey, hi, ernunes, manos.pitsidianakis

From: Gurchetan Singh <gurchetansingh@chromium.org>

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>
Reviewed-by: Emmanouil Pitsidianakis <manos.pitsidianakis@linaro.org>
---
v3: Whitespace fix (Akihiko)

 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..08e170e029 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_have_udmabuf() &&
+            !virtio_gpu_rutabaga_enabled(g->parent_obj.conf)) {
+            error_setg(errp, "need udmabuf or rutabaga 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.rc1.204.g551eb34607-goog



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

* [PATCH v7 9/9] docs/system: add basic virtio-gpu documentation
  2023-08-17  2:23 [PATCH v7 0/9] gfxstream + rutabaga_gfx Gurchetan Singh
                   ` (7 preceding siblings ...)
  2023-08-17  2:23 ` [PATCH v7 8/9] gfxstream + rutabaga: enable rutabaga Gurchetan Singh
@ 2023-08-17  2:23 ` Gurchetan Singh
  2023-08-17  5:28   ` Akihiko Odaki
  8 siblings, 1 reply; 24+ messages in thread
From: Gurchetan Singh @ 2023-08-17  2:23 UTC (permalink / raw)
  To: qemu-devel
  Cc: marcandre.lureau, kraxel, akihiko.odaki, ray.huang, alex.bennee,
	shentey, hi, ernunes, manos.pitsidianakis

From: Gurchetan Singh <gurchetansingh@chromium.org>

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>
Reviewed-by: Emmanouil Pitsidianakis <manos.pitsidianakis@linaro.org>
---
v2: - Incorporated suggestions by Akihiko Odaki
    - Listed the currently supported capset_names (Bernard)

v3: - Incorporated suggestions by Akihiko Odaki and Alyssa Ross

v4: - Incorporated suggestions by Akihiko Odaki

v5: - Removed pci suffix from examples
    - Verified that -device virtio-gpu-rutabaga works.  Strangely
      enough, I don't remember changing anything, and I remember
      it not working.  I did rebase to top of tree though.
    - Fixed meson examples in crosvm docs

 docs/system/device-emulation.rst   |   1 +
 docs/system/devices/virtio-gpu.rst | 113 +++++++++++++++++++++++++++++
 2 files changed, 114 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..8c5c708272
--- /dev/null
+++ b/docs/system/devices/virtio-gpu.rst
@@ -0,0 +1,113 @@
+..
+   SPDX-License-Identifier: GPL-2.0
+
+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
+
+.. _rutabaga_gfx: https://github.com/google/crosvm/blob/main/rutabaga_gfx/ffi/src/include/rutabaga_gfx_ffi.h
+.. _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.rc1.204.g551eb34607-goog



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

* Re: [PATCH v7 9/9] docs/system: add basic virtio-gpu documentation
  2023-08-17  2:23 ` [PATCH v7 9/9] docs/system: add basic virtio-gpu documentation Gurchetan Singh
@ 2023-08-17  5:28   ` Akihiko Odaki
  2023-08-17 23:43     ` [PATCH v8 " Gurchetan Singh
  2023-08-17 23:47     ` [PATCH v7 " Gurchetan Singh
  0 siblings, 2 replies; 24+ messages in thread
From: Akihiko Odaki @ 2023-08-17  5:28 UTC (permalink / raw)
  To: Gurchetan Singh, qemu-devel
  Cc: marcandre.lureau, kraxel, ray.huang, alex.bennee, shentey, hi,
	ernunes, manos.pitsidianakis

On 2023/08/17 11:23, Gurchetan Singh wrote:
> From: Gurchetan Singh <gurchetansingh@chromium.org>
> 
> 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>
> Reviewed-by: Emmanouil Pitsidianakis <manos.pitsidianakis@linaro.org>
> ---
> v2: - Incorporated suggestions by Akihiko Odaki
>      - Listed the currently supported capset_names (Bernard)
> 
> v3: - Incorporated suggestions by Akihiko Odaki and Alyssa Ross
> 
> v4: - Incorporated suggestions by Akihiko Odaki
> 
> v5: - Removed pci suffix from examples
>      - Verified that -device virtio-gpu-rutabaga works.  Strangely
>        enough, I don't remember changing anything, and I remember
>        it not working.  I did rebase to top of tree though.
>      - Fixed meson examples in crosvm docs
> 
>   docs/system/device-emulation.rst   |   1 +
>   docs/system/devices/virtio-gpu.rst | 113 +++++++++++++++++++++++++++++
>   2 files changed, 114 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..8c5c708272
> --- /dev/null
> +++ b/docs/system/devices/virtio-gpu.rst
> @@ -0,0 +1,113 @@
> +..
> +   SPDX-License-Identifier: GPL-2.0
> +
> +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
> +
> +.. _rutabaga_gfx: https://github.com/google/crosvm/blob/main/rutabaga_gfx/ffi/src/include/rutabaga_gfx_ffi.h
> +.. _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

You have different links for "rutabaga_gfx" and "gfxstream-enabled 
rutabaga", but I think you only need one.

> +.. _guest Wayland proxy: https://crosvm.dev/book/devices/wayland.html


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

* [PATCH v8 9/9] docs/system: add basic virtio-gpu documentation
  2023-08-17  5:28   ` Akihiko Odaki
@ 2023-08-17 23:43     ` Gurchetan Singh
  2023-08-17 23:47     ` [PATCH v7 " Gurchetan Singh
  1 sibling, 0 replies; 24+ messages in thread
From: Gurchetan Singh @ 2023-08-17 23:43 UTC (permalink / raw)
  To: qemu-devel

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>
Reviewed-by: Emmanouil Pitsidianakis <manos.pitsidianakis@linaro.org>

v2: - Incorporated suggestions by Akihiko Odaki
    - Listed the currently supported capset_names (Bernard)

v3: - Incorporated suggestions by Akihiko Odaki and Alyssa Ross

v4: - Incorporated suggestions by Akihiko Odaki

v5: - Removed pci suffix from examples
    - Verified that -device virtio-gpu-rutabaga works.  Strangely
      enough, I don't remember changing anything, and I remember
      it not working.  I did rebase to top of tree though.
    - Fixed meson examples in crosvm docs

v8: - Remove different links for "rutabaga_gfx" and
      "gfxstream-enabled rutabaga" (Akihiko)
---
 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..2b3eb536f9
--- /dev/null
+++ b/docs/system/devices/virtio-gpu.rst
@@ -0,0 +1,112 @@
+..
+   SPDX-License-Identifier: GPL-2.0
+
+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.rc1.204.g551eb34607-goog



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

* Re: [PATCH v7 9/9] docs/system: add basic virtio-gpu documentation
  2023-08-17  5:28   ` Akihiko Odaki
  2023-08-17 23:43     ` [PATCH v8 " Gurchetan Singh
@ 2023-08-17 23:47     ` Gurchetan Singh
  2023-08-18 12:08       ` Akihiko Odaki
  1 sibling, 1 reply; 24+ messages in thread
From: Gurchetan Singh @ 2023-08-17 23:47 UTC (permalink / raw)
  To: Akihiko Odaki
  Cc: qemu-devel, marcandre.lureau, kraxel, ray.huang, alex.bennee,
	shentey, hi, ernunes, manos.pitsidianakis

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

On Wed, Aug 16, 2023 at 10:28 PM Akihiko Odaki <akihiko.odaki@gmail.com>
wrote:

> On 2023/08/17 11:23, Gurchetan Singh wrote:
> > From: Gurchetan Singh <gurchetansingh@chromium.org>
> >
> > 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>
> > Reviewed-by: Emmanouil Pitsidianakis <manos.pitsidianakis@linaro.org>
> > ---
> > v2: - Incorporated suggestions by Akihiko Odaki
> >      - Listed the currently supported capset_names (Bernard)
> >
> > v3: - Incorporated suggestions by Akihiko Odaki and Alyssa Ross
> >
> > v4: - Incorporated suggestions by Akihiko Odaki
> >
> > v5: - Removed pci suffix from examples
> >      - Verified that -device virtio-gpu-rutabaga works.  Strangely
> >        enough, I don't remember changing anything, and I remember
> >        it not working.  I did rebase to top of tree though.
> >      - Fixed meson examples in crosvm docs
> >
> >   docs/system/device-emulation.rst   |   1 +
> >   docs/system/devices/virtio-gpu.rst | 113 +++++++++++++++++++++++++++++
> >   2 files changed, 114 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..8c5c708272
> > --- /dev/null
> > +++ b/docs/system/devices/virtio-gpu.rst
> > @@ -0,0 +1,113 @@
> > +..
> > +   SPDX-License-Identifier: GPL-2.0
> > +
> > +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
> > +
> > +.. _rutabaga_gfx:
> https://github.com/google/crosvm/blob/main/rutabaga_gfx/ffi/src/include/rutabaga_gfx_ffi.h
> > +.. _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
>
> You have different links for "rutabaga_gfx" and "gfxstream-enabled
> rutabaga", but I think you only need one.
>

Done.  Didn't resend the entire patch series (to avoid spamming list), just
did "in-reply-to".  The change is also available at:

https://gitlab.freedesktop.org/gurchetansingh/qemu-gfxstream/-/commits/qemu-gfxstream-v8


>
> > +.. _guest Wayland proxy: https://crosvm.dev/book/devices/wayland.html
>

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

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

* Re: [PATCH v7 6/9] gfxstream + rutabaga: add initial support for gfxstream
  2023-08-17  2:23 ` [PATCH v7 6/9] gfxstream + rutabaga: add initial support for gfxstream Gurchetan Singh
@ 2023-08-18 11:58   ` Akihiko Odaki
  2023-08-23 15:03   ` Mark Cave-Ayland
  1 sibling, 0 replies; 24+ messages in thread
From: Akihiko Odaki @ 2023-08-18 11:58 UTC (permalink / raw)
  To: Gurchetan Singh, qemu-devel
  Cc: marcandre.lureau, kraxel, ray.huang, alex.bennee, shentey, hi,
	ernunes, manos.pitsidianakis

On 2023/08/17 11:23, Gurchetan Singh wrote:
> From: Gurchetan Singh <gurchetansingh@chromium.org>
> 
> 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>
> Reviewed-by: Emmanouil Pitsidianakis <manos.pitsidianakis@linaro.org>
> ---
> v1: Incorported various suggestions by Akihiko Odaki and Bernard Berschow
>      - Removed GET_VIRTIO_GPU_GL / GET_RUTABAGA macros
>      - Used error_report(..)
>      - Used g_autofree to fix leaks on error paths
>      - Removed unnecessary casts
>      - added virtio-gpu-pci-rutabaga.c + virtio-vga-rutabaga.c files
> 
> v2: Incorported various suggestions by Akihiko Odaki, Marc-André Lureau and
>      Bernard Berschow:
>      - Parenthesis in CHECK macro
>      - CHECK_RESULT(result, ..) --> CHECK(!result, ..)
>      - delay until g->parent_obj.enable = 1
>      - Additional cast fixes
>      - initialize directly in virtio_gpu_rutabaga_realize(..)
>      - add debug callback to hook into QEMU error's APIs
> 
> v3: Incorporated feedback from Akihiko Odaki and Alyssa Ross:
>      - Autodetect Wayland socket when not explicitly specified
>      - Fix map_blob error paths
>      - Add comment why we need both `res` and `resource` in create blob
>      - Cast and whitespace fixes
>      - Big endian check comes before virtio_gpu_rutabaga_init().
>      - VirtIOVGARUTABAGA --> VirtIOVGARutabaga
> 
> v4: Incorporated feedback from Akihiko Odaki and Alyssa Ross:
>      - Double checked all casts
>      - Remove unnecessary parenthesis
>      - Removed `resource` in create_blob
>      - Added comment about failure case
>      - Pass user-provided socket as-is
>      - Use stack variable rather than heap allocation
>      - Future-proofed map info API to give access flags as well
> 
> v5: Incorporated feedback from Akihiko Odaki:
>      - Check (ss.scanout_id < VIRTIO_GPU_MAX_SCANOUTS)
>      - Simplify num_capsets check
>      - Call cleanup mapping on error paths
>      - uint64_t --> void* for rutabaga_map(..)
>      - Removed unnecessary parenthesis
>      - Removed unnecessary cast
>      - #define UNIX_PATH_MAX sizeof((struct sockaddr_un) {}.sun_path)
>      - Reuse result variable
> 
> v6: Incorporated feedback from Akihiko Odaki:
>      - Remove unnecessary #ifndef
>      - Disable scanout when appropriate
>      - CHECK capset index within range outside loop
>      - Add capset_version
> 
> v7: Incorporated feedback from Akihiko Odaki:
>      - aio_bh_schedule_oneshot_full --> aio_bh_schedule_oneshot
> 
>   hw/display/virtio-gpu-pci-rutabaga.c |   48 ++
>   hw/display/virtio-gpu-rutabaga.c     | 1115 ++++++++++++++++++++++++++
>   hw/display/virtio-vga-rutabaga.c     |   51 ++
>   3 files changed, 1214 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..c71173d8ca
> --- /dev/null
> +++ b/hw/display/virtio-gpu-pci-rutabaga.c
> @@ -0,0 +1,48 @@
> +// SPDX-License-Identifier: GPL-2.0
> +
> +#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"
> +typedef struct VirtIOGPURutabagaPCI VirtIOGPURutabagaPCI;
> +DECLARE_INSTANCE_CHECKER(VirtIOGPURutabagaPCI, VIRTIO_GPU_RUTABAGA_PCI,
> +                         TYPE_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 VirtioPCIDeviceTypeInfo virtio_gpu_rutabaga_pci_info = {
> +    .generic_name = TYPE_VIRTIO_GPU_RUTABAGA_PCI,
> +    .parent = TYPE_VIRTIO_GPU_PCI_BASE,
> +    .instance_size = sizeof(VirtIOGPURutabagaPCI),
> +    .instance_init = virtio_gpu_rutabaga_initfn,
> +};
> +module_obj(TYPE_VIRTIO_GPU_RUTABAGA_PCI);
> +module_kconfig(VIRTIO_PCI);
> +
> +static void virtio_gpu_rutabaga_pci_register_types(void)
> +{
> +    virtio_pci_types_register(&virtio_gpu_rutabaga_pci_info);
> +}
> +
> +type_init(virtio_gpu_rutabaga_pci_register_types)
> +
> +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..24977d3993
> --- /dev/null
> +++ b/hw/display/virtio-gpu-rutabaga.c
> @@ -0,0 +1,1115 @@
> +// SPDX-License-Identifier: GPL-2.0
> +
> +#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;
> +
> +    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 < g->parent_obj.conf.max_outputs; i++) {
> +        scanout = &g->parent_obj.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;
> +
> +    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 = &g->parent_obj.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);
> +    }
> +
> +    g->parent_obj.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 };
> +
> +    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, NULL, "blob", mapping.size,
> +                                   mapping.ptr);
> +        memory_region_add_subregion(&g->parent_obj.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;
> +
> +    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(&g->parent_obj.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 int 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 -EINVAL;
> +    }
> +
> +    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 -EINVAL;
> +        }
> +    }
> +
> +    result = rutabaga_calculate_capset_mask(vr->capset_names, &capset_mask);
> +    if (result) {
> +        error_setg(errp, "invalid capset names: %s", vr->capset_names);
> +        return result;
> +    }
> +
> +    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);
> +    return result;
> +}
> +
> +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
> +
> +    int result = virtio_gpu_rutabaga_init(gpudev, errp);
> +    if (result) {
> +        error_setg(errp, "virtio_gpu_rutabaga_init failed");

virtio_gpu_rutabaga_init() should already have set errp. It is wrong to 
set an error again and result in assertion failure.

Also, virtio_gpu_rutabaga_init() does not set an error when 
rutabaga_init() fails, which should be corrected too.


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

* Re: [PATCH v7 8/9] gfxstream + rutabaga: enable rutabaga
  2023-08-17  2:23 ` [PATCH v7 8/9] gfxstream + rutabaga: enable rutabaga Gurchetan Singh
@ 2023-08-18 11:58   ` Akihiko Odaki
  2023-08-19  1:14     ` Gurchetan Singh
  0 siblings, 1 reply; 24+ messages in thread
From: Akihiko Odaki @ 2023-08-18 11:58 UTC (permalink / raw)
  To: Gurchetan Singh, qemu-devel
  Cc: marcandre.lureau, kraxel, ray.huang, alex.bennee, shentey, hi,
	ernunes, manos.pitsidianakis

On 2023/08/17 11:23, Gurchetan Singh wrote:
> From: Gurchetan Singh <gurchetansingh@chromium.org>
> 
> 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>
> Reviewed-by: Emmanouil Pitsidianakis <manos.pitsidianakis@linaro.org>
> ---
> v3: Whitespace fix (Akihiko)
> 
>   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..08e170e029 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_have_udmabuf() &&

virtio_gpu_have_udmabuf() emits a warning if udmabuf is not available, 
which is spurious when using Rutabaga.

I think virtio_gpu_have_udmabuf() should be renamed to 
virtio_gpu_init_udmabuf() or something, let it set errp instead of 
emitting a warning, and call it only when Rutabaga is not in use. That 
clarifies the timing when an error message will be shown.


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

* Re: [PATCH v7 9/9] docs/system: add basic virtio-gpu documentation
  2023-08-17 23:47     ` [PATCH v7 " Gurchetan Singh
@ 2023-08-18 12:08       ` Akihiko Odaki
  2023-08-19  1:17         ` Gurchetan Singh
  0 siblings, 1 reply; 24+ messages in thread
From: Akihiko Odaki @ 2023-08-18 12:08 UTC (permalink / raw)
  To: Gurchetan Singh
  Cc: qemu-devel, marcandre.lureau, kraxel, ray.huang, alex.bennee,
	shentey, hi, ernunes, manos.pitsidianakis

On 2023/08/18 8:47, Gurchetan Singh wrote:
> 
> 
> On Wed, Aug 16, 2023 at 10:28 PM Akihiko Odaki <akihiko.odaki@gmail.com 
> <mailto:akihiko.odaki@gmail.com>> wrote:
> 
>     On 2023/08/17 11:23, Gurchetan Singh wrote:
>      > From: Gurchetan Singh <gurchetansingh@chromium.org
>     <mailto:gurchetansingh@chromium.org>>
>      >
>      > This adds basic documentation for virtio-gpu.
>      >
>      > Suggested-by: Akihiko Odaki <akihiko.odaki@daynix.com
>     <mailto:akihiko.odaki@daynix.com>>
>      > 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>>
>      > Reviewed-by: Emmanouil Pitsidianakis
>     <manos.pitsidianakis@linaro.org <mailto:manos.pitsidianakis@linaro.org>>
>      > ---
>      > v2: - Incorporated suggestions by Akihiko Odaki
>      >      - Listed the currently supported capset_names (Bernard)
>      >
>      > v3: - Incorporated suggestions by Akihiko Odaki and Alyssa Ross
>      >
>      > v4: - Incorporated suggestions by Akihiko Odaki
>      >
>      > v5: - Removed pci suffix from examples
>      >      - Verified that -device virtio-gpu-rutabaga works.  Strangely
>      >        enough, I don't remember changing anything, and I remember
>      >        it not working.  I did rebase to top of tree though.
>      >      - Fixed meson examples in crosvm docs
>      >
>      >   docs/system/device-emulation.rst   |   1 +
>      >   docs/system/devices/virtio-gpu.rst | 113
>     +++++++++++++++++++++++++++++
>      >   2 files changed, 114 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..8c5c708272
>      > --- /dev/null
>      > +++ b/docs/system/devices/virtio-gpu.rst
>      > @@ -0,0 +1,113 @@
>      > +..
>      > +   SPDX-License-Identifier: GPL-2.0
>      > +
>      > +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/ <https://www.mesa3d.org/>
>      > +.. _SwiftShader: https://github.com/google/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/
>     <https://www.freedesktop.org/wiki/Software/gallium/>
>      > +.. _virglrenderer:
>     https://gitlab.freedesktop.org/virgl/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
>      > +
>      > +.. _rutabaga_gfx:
>     https://github.com/google/crosvm/blob/main/rutabaga_gfx/ffi/src/include/rutabaga_gfx_ffi.h <https://github.com/google/crosvm/blob/main/rutabaga_gfx/ffi/src/include/rutabaga_gfx_ffi.h>
>      > +.. _gfxstream:
>     https://android.googlesource.com/platform/hardware/google/gfxstream/
>     <https://android.googlesource.com/platform/hardware/google/gfxstream/>
>      > +.. _Wayland display passthrough:
>     https://www.youtube.com/watch?v=OZJiHMtIQ2M
>     <https://www.youtube.com/watch?v=OZJiHMtIQ2M>
>      > +.. _gfxstream-enabled rutabaga:
>     https://crosvm.dev/book/appendix/rutabaga_gfx.html
>     <https://crosvm.dev/book/appendix/rutabaga_gfx.html>
> 
>     You have different links for "rutabaga_gfx" and "gfxstream-enabled
>     rutabaga", but I think you only need one.
> 
> 
> Done.  Didn't resend the entire patch series (to avoid spamming list), 
> just did "in-reply-to".  The change is also available at:
> 
> https://gitlab.freedesktop.org/gurchetansingh/qemu-gfxstream/-/commits/qemu-gfxstream-v8 <https://gitlab.freedesktop.org/gurchetansingh/qemu-gfxstream/-/commits/qemu-gfxstream-v8>

The patch series now looks good so I finally decided to try this patch 
series, but I couldn't get it work.

I noticed gfxstream has page size hardcoded as 4 KiB, which broke my 
setup on M2 MacBook Air (running Asahi Linux) that has 16 KiB page. You 
may add code to check host page size and to report an error if it's not 
4 KiB to virtio-gpu-rutabaga, but I think it's trivial to fix gfxstream 
to query page size at runtime as QEMU and Rutabaga does so I hope you to 
do so. For testing purpose, I have replaced it with 16 KiB on my setup.

I also found some bugs on QEMU side so I added comments to respective 
patches.

Below is the logs from my last attempt of running vkgears:

$ VK_LOADER_DEBUG=all demos/build/src/vulkan/vkgears
INFO:             Vulkan Loader Version 1.3.243
LAYER:            Searching for layer manifest files
LAYER:               In following locations:
LAYER:                  /var/home/person/.config/vulkan/implicit_layer.d
LAYER:                  /etc/xdg/vulkan/implicit_layer.d
LAYER:                  /etc/vulkan/implicit_layer.d
LAYER: 
/var/home/person/.local/share/vulkan/implicit_layer.d
LAYER: 
/var/home/person/.local/share/flatpak/exports/share/vulkan/implicit_layer.d
LAYER: 
/var/lib/flatpak/exports/share/vulkan/implicit_layer.d
LAYER:                  /usr/local/share/vulkan/implicit_layer.d
LAYER:                  /usr/share/vulkan/implicit_layer.d
LAYER:               Found the following files:
LAYER: 
/usr/share/vulkan/implicit_layer.d/VkLayer_MESA_device_select.json
INFO:             Found manifest file 
/usr/share/vulkan/implicit_layer.d/VkLayer_MESA_device_select.json (file 
version "1.0.0")
LAYER:            Searching for layer manifest files
LAYER:               In following locations:
LAYER:                  /var/home/person/.config/vulkan/explicit_layer.d
LAYER:                  /etc/xdg/vulkan/explicit_layer.d
LAYER:                  /etc/vulkan/explicit_layer.d
LAYER: 
/var/home/person/.local/share/vulkan/explicit_layer.d
LAYER: 
/var/home/person/.local/share/flatpak/exports/share/vulkan/explicit_layer.d
LAYER: 
/var/lib/flatpak/exports/share/vulkan/explicit_layer.d
LAYER:                  /usr/local/share/vulkan/explicit_layer.d
LAYER:                  /usr/share/vulkan/explicit_layer.d
LAYER:               Found no files
DRIVER:           Searching for driver manifest files
DRIVER:              In following locations:
DRIVER:                 /var/home/person/.config/vulkan/icd.d
DRIVER:                 /etc/xdg/vulkan/icd.d
DRIVER:                 /etc/vulkan/icd.d
DRIVER:                 /var/home/person/.local/share/vulkan/icd.d
DRIVER: 
/var/home/person/.local/share/flatpak/exports/share/vulkan/icd.d
DRIVER:                 /var/lib/flatpak/exports/share/vulkan/icd.d
DRIVER:                 /usr/local/share/vulkan/icd.d
DRIVER:                 /usr/share/vulkan/icd.d
DRIVER:              Found the following files:
DRIVER: 
/usr/local/share/vulkan/icd.d/cereal_icd.aarch64.json
DRIVER:                 /usr/share/vulkan/icd.d/broadcom_icd.aarch64.json
DRIVER:                 /usr/share/vulkan/icd.d/freedreno_icd.aarch64.json
DRIVER:                 /usr/share/vulkan/icd.d/lvp_icd.aarch64.json
DRIVER:                 /usr/share/vulkan/icd.d/panfrost_icd.aarch64.json
DRIVER:                 /usr/share/vulkan/icd.d/radeon_icd.aarch64.json
DRIVER:           Found ICD manifest file 
/usr/local/share/vulkan/icd.d/cereal_icd.aarch64.json, version "1.0.0"
DEBUG | DRIVER:   Searching for ICD drivers named 
/usr/local/lib64/libvulkan_cereal.so
[VirtGpuDevice.cpp(71)]
[prio 6] virtgpu backend not enabling 
VIRTGPU_PARAM_CREATE_GUEST_HANDLE[AndroidHealthMonitor.cpp(275)]
[prio 4] HealthMonitor disabled. Returning nullptrI0818 21:00:07.980257 
154451 IntelDrmDecoder.cpp:38] IntelDrmDecoder created for context 2
DRIVER:           Found ICD manifest file 
/usr/share/vulkan/icd.d/broadcom_icd.aarch64.json, version "1.0.0"
DEBUG | DRIVER:   Searching for ICD drivers named 
/usr/lib64/libvulkan_broadcom.so
DRIVER:           Found ICD manifest file 
/usr/share/vulkan/icd.d/freedreno_icd.aarch64.json, version "1.0.0"
DEBUG | DRIVER:   Searching for ICD drivers named 
/usr/lib64/libvulkan_freedreno.so
DRIVER:           Found ICD manifest file 
/usr/share/vulkan/icd.d/lvp_icd.aarch64.json, version "1.0.0"
DEBUG | DRIVER:   Searching for ICD drivers named 
/usr/lib64/libvulkan_lvp.so
DRIVER:           Found ICD manifest file 
/usr/share/vulkan/icd.d/panfrost_icd.aarch64.json, version "1.0.0"
DEBUG | DRIVER:   Searching for ICD drivers named 
/usr/lib64/libvulkan_panfrost.so
DRIVER:           Found ICD manifest file 
/usr/share/vulkan/icd.d/radeon_icd.aarch64.json, version "1.0.0"
DEBUG | DRIVER:   Searching for ICD drivers named 
/usr/lib64/libvulkan_radeon.so
DEBUG | LAYER:    Loading layer library libVkLayer_MESA_device_select.so
INFO | LAYER:     Insert instance layer "VK_LAYER_MESA_device_select" 
(libVkLayer_MESA_device_select.so)
LAYER:            vkCreateInstance layer callstack setup to:
LAYER:               <Application>
LAYER:                 ||
LAYER:               <Loader>
LAYER:                 ||
LAYER:               VK_LAYER_MESA_device_select
LAYER:                       Type: Implicit
LAYER:                           Disable Env Var:  NODEVICE_SELECT
LAYER:                       Manifest: 
/usr/share/vulkan/implicit_layer.d/VkLayer_MESA_device_select.json
LAYER:                       Library:  libVkLayer_MESA_device_select.so
LAYER:                 ||
LAYER:               <Drivers>
I0818 21:00:08.014896  154451 VkDecoderGlobalState.cpp:443] Creating 
Vulkan instance for app: vkgears
INFO | DRIVER:    linux_read_sorted_physical_devices:
INFO | DRIVER:         Original order:
INFO | DRIVER:               [0] llvmpipe (LLVM 16.0.6, 128 bits)
INFO | DRIVER:               [1] llvmpipe (LLVM 15.0.7, 128 bits)
INFO | DRIVER:         Sorted order:
INFO | DRIVER:               [0] llvmpipe (LLVM 15.0.7, 128 bits)
INFO | DRIVER:               [1] llvmpipe (LLVM 16.0.6, 128 bits)
INFO | DRIVER:    linux_read_sorted_physical_devices:
INFO | DRIVER:         Original order:
INFO | DRIVER:               [0] llvmpipe (LLVM 16.0.6, 128 bits)
INFO | DRIVER:               [1] llvmpipe (LLVM 15.0.7, 128 bits)
INFO | DRIVER:         Sorted order:
INFO | DRIVER:               [0] llvmpipe (LLVM 15.0.7, 128 bits)
INFO | DRIVER:               [1] llvmpipe (LLVM 16.0.6, 128 bits)
DEBUG | DRIVER:   Copying old device 0 into new device 0
DEBUG | DRIVER:   Copying old device 1 into new device 1
INFO | DRIVER:    linux_read_sorted_physical_devices:
INFO | DRIVER:         Original order:
INFO | DRIVER:               [0] llvmpipe (LLVM 16.0.6, 128 bits)
INFO | DRIVER:               [1] llvmpipe (LLVM 15.0.7, 128 bits)
INFO | DRIVER:         Sorted order:
INFO | DRIVER:               [0] llvmpipe (LLVM 15.0.7, 128 bits)
INFO | DRIVER:               [1] llvmpipe (LLVM 16.0.6, 128 bits)
DEBUG | DRIVER:   Copying old device 0 into new device 0
DEBUG | DRIVER:   Copying old device 1 into new device 1
INFO | DRIVER:    linux_read_sorted_physical_devices:
INFO | DRIVER:         Original order:
INFO | DRIVER:               [0] llvmpipe (LLVM 16.0.6, 128 bits)
INFO | DRIVER:               [1] llvmpipe (LLVM 15.0.7, 128 bits)
INFO | DRIVER:         Sorted order:
INFO | DRIVER:               [0] llvmpipe (LLVM 15.0.7, 128 bits)
INFO | DRIVER:               [1] llvmpipe (LLVM 16.0.6, 128 bits)
DEBUG | DRIVER:   Copying old device 0 into new device 0
DEBUG | DRIVER:   Copying old device 1 into new device 1
ERROR:            loader_validate_device_extensions: Device extension 
VK_KHR_swapchain not supported by selected physical device or enabled 
layers.
ERROR:            vkCreateDevice: Failed to validate extensions in list
ERROR:            vkGetDeviceQueue2: Invalid device 
[VUID-vkGetDeviceQueue2-device-parameter]
Aborted (core dumped)


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

* Re: [PATCH v7 8/9] gfxstream + rutabaga: enable rutabaga
  2023-08-18 11:58   ` Akihiko Odaki
@ 2023-08-19  1:14     ` Gurchetan Singh
  0 siblings, 0 replies; 24+ messages in thread
From: Gurchetan Singh @ 2023-08-19  1:14 UTC (permalink / raw)
  To: Akihiko Odaki
  Cc: qemu-devel, marcandre.lureau, kraxel, ray.huang, alex.bennee,
	shentey, hi, ernunes, manos.pitsidianakis

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

On Fri, Aug 18, 2023 at 4:58 AM Akihiko Odaki <akihiko.odaki@gmail.com>
wrote:

> On 2023/08/17 11:23, Gurchetan Singh wrote:
> > From: Gurchetan Singh <gurchetansingh@chromium.org>
> >
> > 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>
> > Reviewed-by: Emmanouil Pitsidianakis <manos.pitsidianakis@linaro.org>
> > ---
> > v3: Whitespace fix (Akihiko)
> >
> >   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..08e170e029 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_have_udmabuf() &&
>
> virtio_gpu_have_udmabuf() emits a warning if udmabuf is not available,
> which is spurious when using Rutabaga.
>
> I think virtio_gpu_have_udmabuf() should be renamed to
> virtio_gpu_init_udmabuf() or something, let it set errp instead of
> emitting a warning, and call it only when Rutabaga is not in use.


Not too familiar with udmabuf case, so just reordered the if rutabaga check
to avoid the spurious warning.  Probably an udmabuf cleanups should in an
additional patch series.


> That
> clarifies the timing when an error message will be shown.
>

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

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

* Re: [PATCH v7 9/9] docs/system: add basic virtio-gpu documentation
  2023-08-18 12:08       ` Akihiko Odaki
@ 2023-08-19  1:17         ` Gurchetan Singh
  2023-08-19  6:13           ` Akihiko Odaki
  0 siblings, 1 reply; 24+ messages in thread
From: Gurchetan Singh @ 2023-08-19  1:17 UTC (permalink / raw)
  To: Akihiko Odaki
  Cc: qemu-devel, marcandre.lureau, kraxel, ray.huang, alex.bennee,
	shentey, hi, ernunes, manos.pitsidianakis

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

On Fri, Aug 18, 2023 at 5:08 AM Akihiko Odaki <akihiko.odaki@gmail.com>
wrote:

> On 2023/08/18 8:47, Gurchetan Singh wrote:
> >
> >
> > On Wed, Aug 16, 2023 at 10:28 PM Akihiko Odaki <akihiko.odaki@gmail.com
> > <mailto:akihiko.odaki@gmail.com>> wrote:
> >
> >     On 2023/08/17 11:23, Gurchetan Singh wrote:
> >      > From: Gurchetan Singh <gurchetansingh@chromium.org
> >     <mailto:gurchetansingh@chromium.org>>
> >      >
> >      > This adds basic documentation for virtio-gpu.
> >      >
> >      > Suggested-by: Akihiko Odaki <akihiko.odaki@daynix.com
> >     <mailto:akihiko.odaki@daynix.com>>
> >      > 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>>
> >      > Reviewed-by: Emmanouil Pitsidianakis
> >     <manos.pitsidianakis@linaro.org <mailto:
> manos.pitsidianakis@linaro.org>>
> >      > ---
> >      > v2: - Incorporated suggestions by Akihiko Odaki
> >      >      - Listed the currently supported capset_names (Bernard)
> >      >
> >      > v3: - Incorporated suggestions by Akihiko Odaki and Alyssa Ross
> >      >
> >      > v4: - Incorporated suggestions by Akihiko Odaki
> >      >
> >      > v5: - Removed pci suffix from examples
> >      >      - Verified that -device virtio-gpu-rutabaga works.  Strangely
> >      >        enough, I don't remember changing anything, and I remember
> >      >        it not working.  I did rebase to top of tree though.
> >      >      - Fixed meson examples in crosvm docs
> >      >
> >      >   docs/system/device-emulation.rst   |   1 +
> >      >   docs/system/devices/virtio-gpu.rst | 113
> >     +++++++++++++++++++++++++++++
> >      >   2 files changed, 114 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..8c5c708272
> >      > --- /dev/null
> >      > +++ b/docs/system/devices/virtio-gpu.rst
> >      > @@ -0,0 +1,113 @@
> >      > +..
> >      > +   SPDX-License-Identifier: GPL-2.0
> >      > +
> >      > +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/ <https://www.mesa3d.org/>
> >      > +.. _SwiftShader: https://github.com/google/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/
> >     <https://www.freedesktop.org/wiki/Software/gallium/>
> >      > +.. _virglrenderer:
> >     https://gitlab.freedesktop.org/virgl/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
> >      > +
> >      > +.. _rutabaga_gfx:
> >
> https://github.com/google/crosvm/blob/main/rutabaga_gfx/ffi/src/include/rutabaga_gfx_ffi.h
> <
> https://github.com/google/crosvm/blob/main/rutabaga_gfx/ffi/src/include/rutabaga_gfx_ffi.h
> >
> >      > +.. _gfxstream:
> >     https://android.googlesource.com/platform/hardware/google/gfxstream/
> >     <
> https://android.googlesource.com/platform/hardware/google/gfxstream/>
> >      > +.. _Wayland display passthrough:
> >     https://www.youtube.com/watch?v=OZJiHMtIQ2M
> >     <https://www.youtube.com/watch?v=OZJiHMtIQ2M>
> >      > +.. _gfxstream-enabled rutabaga:
> >     https://crosvm.dev/book/appendix/rutabaga_gfx.html
> >     <https://crosvm.dev/book/appendix/rutabaga_gfx.html>
> >
> >     You have different links for "rutabaga_gfx" and "gfxstream-enabled
> >     rutabaga", but I think you only need one.
> >
> >
> > Done.  Didn't resend the entire patch series (to avoid spamming list),
> > just did "in-reply-to".  The change is also available at:
> >
> >
> https://gitlab.freedesktop.org/gurchetansingh/qemu-gfxstream/-/commits/qemu-gfxstream-v8
> <
> https://gitlab.freedesktop.org/gurchetansingh/qemu-gfxstream/-/commits/qemu-gfxstream-v8
> >
>
> The patch series now looks good so I finally decided to try this patch
> series, but I couldn't get it work.
>
> I noticed gfxstream has page size hardcoded as 4 KiB, which broke my
> setup on M2 MacBook Air (running Asahi Linux) that has 16 KiB page. You
> may add code to check host page size and to report an error if it's not
> 4 KiB to virtio-gpu-rutabaga, but I think it's trivial to fix gfxstream
> to query page size at runtime as QEMU and Rutabaga does so I hope you to
> do so. For testing purpose, I have replaced it with 16 KiB on my setup.
>

Good catch, the fix to the 16KiB was merged today and is in gfxstream ToT
right now.


>
> I also found some bugs on QEMU side so I added comments to respective
> patches.
>
> Below is the logs from my last attempt of running vkgears:
>
> $ VK_LOADER_DEBUG=all demos/build/src/vulkan/vkgears
> INFO:             Vulkan Loader Version 1.3.243
> LAYER:            Searching for layer manifest files
> LAYER:               In following locations:
> LAYER:                  /var/home/person/.config/vulkan/implicit_layer.d
> LAYER:                  /etc/xdg/vulkan/implicit_layer.d
> LAYER:                  /etc/vulkan/implicit_layer.d
> LAYER:
> /var/home/person/.local/share/vulkan/implicit_layer.d
> LAYER:
> /var/home/person/.local/share/flatpak/exports/share/vulkan/implicit_layer.d
> LAYER:
> /var/lib/flatpak/exports/share/vulkan/implicit_layer.d
> LAYER:                  /usr/local/share/vulkan/implicit_layer.d
> LAYER:                  /usr/share/vulkan/implicit_layer.d
> LAYER:               Found the following files:
> LAYER:
> /usr/share/vulkan/implicit_layer.d/VkLayer_MESA_device_select.json
> INFO:             Found manifest file
> /usr/share/vulkan/implicit_layer.d/VkLayer_MESA_device_select.json (file
> version "1.0.0")
> LAYER:            Searching for layer manifest files
> LAYER:               In following locations:
> LAYER:                  /var/home/person/.config/vulkan/explicit_layer.d
> LAYER:                  /etc/xdg/vulkan/explicit_layer.d
> LAYER:                  /etc/vulkan/explicit_layer.d
> LAYER:
> /var/home/person/.local/share/vulkan/explicit_layer.d
> LAYER:
> /var/home/person/.local/share/flatpak/exports/share/vulkan/explicit_layer.d
> LAYER:
> /var/lib/flatpak/exports/share/vulkan/explicit_layer.d
> LAYER:                  /usr/local/share/vulkan/explicit_layer.d
> LAYER:                  /usr/share/vulkan/explicit_layer.d
> LAYER:               Found no files
> DRIVER:           Searching for driver manifest files
> DRIVER:              In following locations:
> DRIVER:                 /var/home/person/.config/vulkan/icd.d
> DRIVER:                 /etc/xdg/vulkan/icd.d
> DRIVER:                 /etc/vulkan/icd.d
> DRIVER:                 /var/home/person/.local/share/vulkan/icd.d
> DRIVER:
> /var/home/person/.local/share/flatpak/exports/share/vulkan/icd.d
> DRIVER:                 /var/lib/flatpak/exports/share/vulkan/icd.d
> DRIVER:                 /usr/local/share/vulkan/icd.d
> DRIVER:                 /usr/share/vulkan/icd.d
> DRIVER:              Found the following files:
> DRIVER:
> /usr/local/share/vulkan/icd.d/cereal_icd.aarch64.json
> DRIVER:                 /usr/share/vulkan/icd.d/broadcom_icd.aarch64.json
> DRIVER:                 /usr/share/vulkan/icd.d/freedreno_icd.aarch64.json
> DRIVER:                 /usr/share/vulkan/icd.d/lvp_icd.aarch64.json
> DRIVER:                 /usr/share/vulkan/icd.d/panfrost_icd.aarch64.json
> DRIVER:                 /usr/share/vulkan/icd.d/radeon_icd.aarch64.json
> DRIVER:           Found ICD manifest file
> /usr/local/share/vulkan/icd.d/cereal_icd.aarch64.json, version "1.0.0"
> DEBUG | DRIVER:   Searching for ICD drivers named
> /usr/local/lib64/libvulkan_cereal.so
> [VirtGpuDevice.cpp(71)]
> [prio 6] virtgpu backend not enabling
> VIRTGPU_PARAM_CREATE_GUEST_HANDLE[AndroidHealthMonitor.cpp(275)]
> [prio 4] HealthMonitor disabled. Returning nullptrI0818 21:00:07.980257
> 154451 IntelDrmDecoder.cpp:38] IntelDrmDecoder created for context 2
> DRIVER:           Found ICD manifest file
> /usr/share/vulkan/icd.d/broadcom_icd.aarch64.json, version "1.0.0"
> DEBUG | DRIVER:   Searching for ICD drivers named
> /usr/lib64/libvulkan_broadcom.so
> DRIVER:           Found ICD manifest file
> /usr/share/vulkan/icd.d/freedreno_icd.aarch64.json, version "1.0.0"
> DEBUG | DRIVER:   Searching for ICD drivers named
> /usr/lib64/libvulkan_freedreno.so
> DRIVER:           Found ICD manifest file
> /usr/share/vulkan/icd.d/lvp_icd.aarch64.json, version "1.0.0"
> DEBUG | DRIVER:   Searching for ICD drivers named
> /usr/lib64/libvulkan_lvp.so
> DRIVER:           Found ICD manifest file
> /usr/share/vulkan/icd.d/panfrost_icd.aarch64.json, version "1.0.0"
> DEBUG | DRIVER:   Searching for ICD drivers named
> /usr/lib64/libvulkan_panfrost.so
> DRIVER:           Found ICD manifest file
> /usr/share/vulkan/icd.d/radeon_icd.aarch64.json, version "1.0.0"
> DEBUG | DRIVER:   Searching for ICD drivers named
> /usr/lib64/libvulkan_radeon.so
> DEBUG | LAYER:    Loading layer library libVkLayer_MESA_device_select.so
> INFO | LAYER:     Insert instance layer "VK_LAYER_MESA_device_select"
> (libVkLayer_MESA_device_select.so)
> LAYER:            vkCreateInstance layer callstack setup to:
> LAYER:               <Application>
> LAYER:                 ||
> LAYER:               <Loader>
> LAYER:                 ||
> LAYER:               VK_LAYER_MESA_device_select
> LAYER:                       Type: Implicit
> LAYER:                           Disable Env Var:  NODEVICE_SELECT
> LAYER:                       Manifest:
> /usr/share/vulkan/implicit_layer.d/VkLayer_MESA_device_select.json
> LAYER:                       Library:  libVkLayer_MESA_device_select.so
> LAYER:                 ||
> LAYER:               <Drivers>
> I0818 21:00:08.014896  154451 VkDecoderGlobalState.cpp:443] Creating
> Vulkan instance for app: vkgears
> INFO | DRIVER:    linux_read_sorted_physical_devices:
> INFO | DRIVER:         Original order:
> INFO | DRIVER:               [0] llvmpipe (LLVM 16.0.6, 128 bits)
> INFO | DRIVER:               [1] llvmpipe (LLVM 15.0.7, 128 bits)
> INFO | DRIVER:         Sorted order:
> INFO | DRIVER:               [0] llvmpipe (LLVM 15.0.7, 128 bits)
> INFO | DRIVER:               [1] llvmpipe (LLVM 16.0.6, 128 bits)
> INFO | DRIVER:    linux_read_sorted_physical_devices:
> INFO | DRIVER:         Original order:
> INFO | DRIVER:               [0] llvmpipe (LLVM 16.0.6, 128 bits)
> INFO | DRIVER:               [1] llvmpipe (LLVM 15.0.7, 128 bits)
> INFO | DRIVER:         Sorted order:
> INFO | DRIVER:               [0] llvmpipe (LLVM 15.0.7, 128 bits)
> INFO | DRIVER:               [1] llvmpipe (LLVM 16.0.6, 128 bits)
> DEBUG | DRIVER:   Copying old device 0 into new device 0
> DEBUG | DRIVER:   Copying old device 1 into new device 1
> INFO | DRIVER:    linux_read_sorted_physical_devices:
> INFO | DRIVER:         Original order:
> INFO | DRIVER:               [0] llvmpipe (LLVM 16.0.6, 128 bits)
> INFO | DRIVER:               [1] llvmpipe (LLVM 15.0.7, 128 bits)
> INFO | DRIVER:         Sorted order:
> INFO | DRIVER:               [0] llvmpipe (LLVM 15.0.7, 128 bits)
> INFO | DRIVER:               [1] llvmpipe (LLVM 16.0.6, 128 bits)
> DEBUG | DRIVER:   Copying old device 0 into new device 0
> DEBUG | DRIVER:   Copying old device 1 into new device 1
> INFO | DRIVER:    linux_read_sorted_physical_devices:
> INFO | DRIVER:         Original order:
> INFO | DRIVER:               [0] llvmpipe (LLVM 16.0.6, 128 bits)
> INFO | DRIVER:               [1] llvmpipe (LLVM 15.0.7, 128 bits)
> INFO | DRIVER:         Sorted order:
> INFO | DRIVER:               [0] llvmpipe (LLVM 15.0.7, 128 bits)
> INFO | DRIVER:               [1] llvmpipe (LLVM 16.0.6, 128 bits)
> DEBUG | DRIVER:   Copying old device 0 into new device 0
> DEBUG | DRIVER:   Copying old device 1 into new device 1
> ERROR:            loader_validate_device_extensions: Device extension
> VK_KHR_swapchain not supported by selected physical device or enabled


Yeah, any non-headless Linux tests are unlikely to work.  Maybe in a future
gfxstream release, since our focus is of course on Android and getting
Vulkan in QEMU in general.


>
> layers.
> ERROR:            vkCreateDevice: Failed to validate extensions in list
> ERROR:            vkGetDeviceQueue2: Invalid device
> [VUID-vkGetDeviceQueue2-device-parameter]
> Aborted (core dumped)
>

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

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

* Re: [PATCH v7 9/9] docs/system: add basic virtio-gpu documentation
  2023-08-19  1:17         ` Gurchetan Singh
@ 2023-08-19  6:13           ` Akihiko Odaki
  2023-08-22  0:20             ` Gurchetan Singh
  0 siblings, 1 reply; 24+ messages in thread
From: Akihiko Odaki @ 2023-08-19  6:13 UTC (permalink / raw)
  To: Gurchetan Singh
  Cc: qemu-devel, marcandre.lureau, kraxel, ray.huang, alex.bennee,
	shentey, hi, ernunes, manos.pitsidianakis

On 2023/08/19 10:17, Gurchetan Singh wrote:
> 
> 
> On Fri, Aug 18, 2023 at 5:08 AM Akihiko Odaki <akihiko.odaki@gmail.com 
> <mailto:akihiko.odaki@gmail.com>> wrote:
> 
>     On 2023/08/18 8:47, Gurchetan Singh wrote:
>      >
>      >
>      > On Wed, Aug 16, 2023 at 10:28 PM Akihiko Odaki
>     <akihiko.odaki@gmail.com <mailto:akihiko.odaki@gmail.com>
>      > <mailto:akihiko.odaki@gmail.com
>     <mailto:akihiko.odaki@gmail.com>>> wrote:
>      >
>      >     On 2023/08/17 11:23, Gurchetan Singh wrote:
>      >      > From: Gurchetan Singh <gurchetansingh@chromium.org
>     <mailto:gurchetansingh@chromium.org>
>      >     <mailto:gurchetansingh@chromium.org
>     <mailto:gurchetansingh@chromium.org>>>
>      >      >
>      >      > This adds basic documentation for virtio-gpu.
>      >      >
>      >      > Suggested-by: Akihiko Odaki <akihiko.odaki@daynix.com
>     <mailto:akihiko.odaki@daynix.com>
>      >     <mailto:akihiko.odaki@daynix.com
>     <mailto:akihiko.odaki@daynix.com>>>
>      >      > Signed-off-by: Gurchetan Singh
>     <gurchetansingh@chromium.org <mailto:gurchetansingh@chromium.org>
>      >     <mailto:gurchetansingh@chromium.org
>     <mailto:gurchetansingh@chromium.org>>>
>      >      > Tested-by: Alyssa Ross <hi@alyssa.is <mailto:hi@alyssa.is>
>     <mailto:hi@alyssa.is <mailto:hi@alyssa.is>>>
>      >      > Tested-by: Emmanouil Pitsidianakis
>      >     <manos.pitsidianakis@linaro.org
>     <mailto:manos.pitsidianakis@linaro.org>
>     <mailto:manos.pitsidianakis@linaro.org
>     <mailto:manos.pitsidianakis@linaro.org>>>
>      >      > Reviewed-by: Emmanouil Pitsidianakis
>      >     <manos.pitsidianakis@linaro.org
>     <mailto:manos.pitsidianakis@linaro.org>
>     <mailto:manos.pitsidianakis@linaro.org
>     <mailto:manos.pitsidianakis@linaro.org>>>
>      >      > ---
>      >      > v2: - Incorporated suggestions by Akihiko Odaki
>      >      >      - Listed the currently supported capset_names (Bernard)
>      >      >
>      >      > v3: - Incorporated suggestions by Akihiko Odaki and Alyssa
>     Ross
>      >      >
>      >      > v4: - Incorporated suggestions by Akihiko Odaki
>      >      >
>      >      > v5: - Removed pci suffix from examples
>      >      >      - Verified that -device virtio-gpu-rutabaga works. 
>     Strangely
>      >      >        enough, I don't remember changing anything, and I
>     remember
>      >      >        it not working.  I did rebase to top of tree though.
>      >      >      - Fixed meson examples in crosvm docs
>      >      >
>      >      >   docs/system/device-emulation.rst   |   1 +
>      >      >   docs/system/devices/virtio-gpu.rst | 113
>      >     +++++++++++++++++++++++++++++
>      >      >   2 files changed, 114 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..8c5c708272
>      >      > --- /dev/null
>      >      > +++ b/docs/system/devices/virtio-gpu.rst
>      >      > @@ -0,0 +1,113 @@
>      >      > +..
>      >      > +   SPDX-License-Identifier: GPL-2.0
>      >      > +
>      >      > +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/
>     <https://www.mesa3d.org/> <https://www.mesa3d.org/
>     <https://www.mesa3d.org/>>
>      >      > +.. _SwiftShader: https://github.com/google/swiftshader
>     <https://github.com/google/swiftshader>
>      >     <https://github.com/google/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/
>     <https://www.freedesktop.org/wiki/Software/gallium/>
>      >     <https://www.freedesktop.org/wiki/Software/gallium/
>     <https://www.freedesktop.org/wiki/Software/gallium/>>
>      >      > +.. _virglrenderer:
>      > https://gitlab.freedesktop.org/virgl/virglrenderer/
>     <https://gitlab.freedesktop.org/virgl/virglrenderer/>
>      >     <https://gitlab.freedesktop.org/virgl/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
>      >      > +
>      >      > +.. _rutabaga_gfx:
>      >
>     https://github.com/google/crosvm/blob/main/rutabaga_gfx/ffi/src/include/rutabaga_gfx_ffi.h <https://github.com/google/crosvm/blob/main/rutabaga_gfx/ffi/src/include/rutabaga_gfx_ffi.h> <https://github.com/google/crosvm/blob/main/rutabaga_gfx/ffi/src/include/rutabaga_gfx_ffi.h <https://github.com/google/crosvm/blob/main/rutabaga_gfx/ffi/src/include/rutabaga_gfx_ffi.h>>
>      >      > +.. _gfxstream:
>      >
>     https://android.googlesource.com/platform/hardware/google/gfxstream/
>     <https://android.googlesource.com/platform/hardware/google/gfxstream/>
>      >   
>       <https://android.googlesource.com/platform/hardware/google/gfxstream/ <https://android.googlesource.com/platform/hardware/google/gfxstream/>>
>      >      > +.. _Wayland display passthrough:
>      > https://www.youtube.com/watch?v=OZJiHMtIQ2M
>     <https://www.youtube.com/watch?v=OZJiHMtIQ2M>
>      >     <https://www.youtube.com/watch?v=OZJiHMtIQ2M
>     <https://www.youtube.com/watch?v=OZJiHMtIQ2M>>
>      >      > +.. _gfxstream-enabled rutabaga:
>      > https://crosvm.dev/book/appendix/rutabaga_gfx.html
>     <https://crosvm.dev/book/appendix/rutabaga_gfx.html>
>      >     <https://crosvm.dev/book/appendix/rutabaga_gfx.html
>     <https://crosvm.dev/book/appendix/rutabaga_gfx.html>>
>      >
>      >     You have different links for "rutabaga_gfx" and
>     "gfxstream-enabled
>      >     rutabaga", but I think you only need one.
>      >
>      >
>      > Done.  Didn't resend the entire patch series (to avoid spamming
>     list),
>      > just did "in-reply-to".  The change is also available at:
>      >
>      >
>     https://gitlab.freedesktop.org/gurchetansingh/qemu-gfxstream/-/commits/qemu-gfxstream-v8 <https://gitlab.freedesktop.org/gurchetansingh/qemu-gfxstream/-/commits/qemu-gfxstream-v8> <https://gitlab.freedesktop.org/gurchetansingh/qemu-gfxstream/-/commits/qemu-gfxstream-v8 <https://gitlab.freedesktop.org/gurchetansingh/qemu-gfxstream/-/commits/qemu-gfxstream-v8>>
> 
>     The patch series now looks good so I finally decided to try this patch
>     series, but I couldn't get it work.
> 
>     I noticed gfxstream has page size hardcoded as 4 KiB, which broke my
>     setup on M2 MacBook Air (running Asahi Linux) that has 16 KiB page. You
>     may add code to check host page size and to report an error if it's not
>     4 KiB to virtio-gpu-rutabaga, but I think it's trivial to fix gfxstream
>     to query page size at runtime as QEMU and Rutabaga does so I hope
>     you to
>     do so. For testing purpose, I have replaced it with 16 KiB on my setup.
> 
> 
> Good catch, the fix to the 16KiB was merged today and is in gfxstream 
> ToT right now.

The fix is incomplete. There are a few other places that hardcodes page 
size, namely ANDROID_EMU_ADDRESS_SPACE_DEFAULT_PAGE_SIZE and 
ADDRESS_SPACE_GRAPHICS_PAGE_SIZE.

ANDROID_EMU_ADDRESS_SPACE_DEFAULT_PAGE_SIZE is used by no one so you can 
just remove it. ADDRESS_SPACE_GRAPHICS_PAGE_SIZE is actually in use and 
needs to be fixed.

It's also better to remove PAGE_SIZE definition from guest/meson.build 
just in case.

> 
> 
>     I also found some bugs on QEMU side so I added comments to respective
>     patches.
> 
>     Below is the logs from my last attempt of running vkgears:
> 
>     $ VK_LOADER_DEBUG=all demos/build/src/vulkan/vkgears
>     INFO:             Vulkan Loader Version 1.3.243
>     LAYER:            Searching for layer manifest files
>     LAYER:               In following locations:
>     LAYER:                  /var/home/person/.config/vulkan/implicit_layer.d
>     LAYER:                  /etc/xdg/vulkan/implicit_layer.d
>     LAYER:                  /etc/vulkan/implicit_layer.d
>     LAYER:
>     /var/home/person/.local/share/vulkan/implicit_layer.d
>     LAYER:
>     /var/home/person/.local/share/flatpak/exports/share/vulkan/implicit_layer.d
>     LAYER:
>     /var/lib/flatpak/exports/share/vulkan/implicit_layer.d
>     LAYER:                  /usr/local/share/vulkan/implicit_layer.d
>     LAYER:                  /usr/share/vulkan/implicit_layer.d
>     LAYER:               Found the following files:
>     LAYER:
>     /usr/share/vulkan/implicit_layer.d/VkLayer_MESA_device_select.json
>     INFO:             Found manifest file
>     /usr/share/vulkan/implicit_layer.d/VkLayer_MESA_device_select.json
>     (file
>     version "1.0.0")
>     LAYER:            Searching for layer manifest files
>     LAYER:               In following locations:
>     LAYER:                  /var/home/person/.config/vulkan/explicit_layer.d
>     LAYER:                  /etc/xdg/vulkan/explicit_layer.d
>     LAYER:                  /etc/vulkan/explicit_layer.d
>     LAYER:
>     /var/home/person/.local/share/vulkan/explicit_layer.d
>     LAYER:
>     /var/home/person/.local/share/flatpak/exports/share/vulkan/explicit_layer.d
>     LAYER:
>     /var/lib/flatpak/exports/share/vulkan/explicit_layer.d
>     LAYER:                  /usr/local/share/vulkan/explicit_layer.d
>     LAYER:                  /usr/share/vulkan/explicit_layer.d
>     LAYER:               Found no files
>     DRIVER:           Searching for driver manifest files
>     DRIVER:              In following locations:
>     DRIVER:                 /var/home/person/.config/vulkan/icd.d
>     DRIVER:                 /etc/xdg/vulkan/icd.d
>     DRIVER:                 /etc/vulkan/icd.d
>     DRIVER:                 /var/home/person/.local/share/vulkan/icd.d
>     DRIVER:
>     /var/home/person/.local/share/flatpak/exports/share/vulkan/icd.d
>     DRIVER:                 /var/lib/flatpak/exports/share/vulkan/icd.d
>     DRIVER:                 /usr/local/share/vulkan/icd.d
>     DRIVER:                 /usr/share/vulkan/icd.d
>     DRIVER:              Found the following files:
>     DRIVER:
>     /usr/local/share/vulkan/icd.d/cereal_icd.aarch64.json
>     DRIVER:               
>       /usr/share/vulkan/icd.d/broadcom_icd.aarch64.json
>     DRIVER:               
>       /usr/share/vulkan/icd.d/freedreno_icd.aarch64.json
>     DRIVER:                 /usr/share/vulkan/icd.d/lvp_icd.aarch64.json
>     DRIVER:               
>       /usr/share/vulkan/icd.d/panfrost_icd.aarch64.json
>     DRIVER:                 /usr/share/vulkan/icd.d/radeon_icd.aarch64.json
>     DRIVER:           Found ICD manifest file
>     /usr/local/share/vulkan/icd.d/cereal_icd.aarch64.json, version "1.0.0"
>     DEBUG | DRIVER:   Searching for ICD drivers named
>     /usr/local/lib64/libvulkan_cereal.so
>     [VirtGpuDevice.cpp(71)]
>     [prio 6] virtgpu backend not enabling
>     VIRTGPU_PARAM_CREATE_GUEST_HANDLE[AndroidHealthMonitor.cpp(275)]
>     [prio 4] HealthMonitor disabled. Returning nullptrI0818 21:00:07.980257
>     154451 IntelDrmDecoder.cpp:38] IntelDrmDecoder created for context 2
>     DRIVER:           Found ICD manifest file
>     /usr/share/vulkan/icd.d/broadcom_icd.aarch64.json, version "1.0.0"
>     DEBUG | DRIVER:   Searching for ICD drivers named
>     /usr/lib64/libvulkan_broadcom.so
>     DRIVER:           Found ICD manifest file
>     /usr/share/vulkan/icd.d/freedreno_icd.aarch64.json, version "1.0.0"
>     DEBUG | DRIVER:   Searching for ICD drivers named
>     /usr/lib64/libvulkan_freedreno.so
>     DRIVER:           Found ICD manifest file
>     /usr/share/vulkan/icd.d/lvp_icd.aarch64.json, version "1.0.0"
>     DEBUG | DRIVER:   Searching for ICD drivers named
>     /usr/lib64/libvulkan_lvp.so
>     DRIVER:           Found ICD manifest file
>     /usr/share/vulkan/icd.d/panfrost_icd.aarch64.json, version "1.0.0"
>     DEBUG | DRIVER:   Searching for ICD drivers named
>     /usr/lib64/libvulkan_panfrost.so
>     DRIVER:           Found ICD manifest file
>     /usr/share/vulkan/icd.d/radeon_icd.aarch64.json, version "1.0.0"
>     DEBUG | DRIVER:   Searching for ICD drivers named
>     /usr/lib64/libvulkan_radeon.so
>     DEBUG | LAYER:    Loading layer library libVkLayer_MESA_device_select.so
>     INFO | LAYER:     Insert instance layer "VK_LAYER_MESA_device_select"
>     (libVkLayer_MESA_device_select.so)
>     LAYER:            vkCreateInstance layer callstack setup to:
>     LAYER:               <Application>
>     LAYER:                 ||
>     LAYER:               <Loader>
>     LAYER:                 ||
>     LAYER:               VK_LAYER_MESA_device_select
>     LAYER:                       Type: Implicit
>     LAYER:                           Disable Env Var:  NODEVICE_SELECT
>     LAYER:                       Manifest:
>     /usr/share/vulkan/implicit_layer.d/VkLayer_MESA_device_select.json
>     LAYER:                       Library:  libVkLayer_MESA_device_select.so
>     LAYER:                 ||
>     LAYER:               <Drivers>
>     I0818 21:00:08.014896  154451 VkDecoderGlobalState.cpp:443] Creating
>     Vulkan instance for app: vkgears
>     INFO | DRIVER:    linux_read_sorted_physical_devices:
>     INFO | DRIVER:         Original order:
>     INFO | DRIVER:               [0] llvmpipe (LLVM 16.0.6, 128 bits)
>     INFO | DRIVER:               [1] llvmpipe (LLVM 15.0.7, 128 bits)
>     INFO | DRIVER:         Sorted order:
>     INFO | DRIVER:               [0] llvmpipe (LLVM 15.0.7, 128 bits)
>     INFO | DRIVER:               [1] llvmpipe (LLVM 16.0.6, 128 bits)
>     INFO | DRIVER:    linux_read_sorted_physical_devices:
>     INFO | DRIVER:         Original order:
>     INFO | DRIVER:               [0] llvmpipe (LLVM 16.0.6, 128 bits)
>     INFO | DRIVER:               [1] llvmpipe (LLVM 15.0.7, 128 bits)
>     INFO | DRIVER:         Sorted order:
>     INFO | DRIVER:               [0] llvmpipe (LLVM 15.0.7, 128 bits)
>     INFO | DRIVER:               [1] llvmpipe (LLVM 16.0.6, 128 bits)
>     DEBUG | DRIVER:   Copying old device 0 into new device 0
>     DEBUG | DRIVER:   Copying old device 1 into new device 1
>     INFO | DRIVER:    linux_read_sorted_physical_devices:
>     INFO | DRIVER:         Original order:
>     INFO | DRIVER:               [0] llvmpipe (LLVM 16.0.6, 128 bits)
>     INFO | DRIVER:               [1] llvmpipe (LLVM 15.0.7, 128 bits)
>     INFO | DRIVER:         Sorted order:
>     INFO | DRIVER:               [0] llvmpipe (LLVM 15.0.7, 128 bits)
>     INFO | DRIVER:               [1] llvmpipe (LLVM 16.0.6, 128 bits)
>     DEBUG | DRIVER:   Copying old device 0 into new device 0
>     DEBUG | DRIVER:   Copying old device 1 into new device 1
>     INFO | DRIVER:    linux_read_sorted_physical_devices:
>     INFO | DRIVER:         Original order:
>     INFO | DRIVER:               [0] llvmpipe (LLVM 16.0.6, 128 bits)
>     INFO | DRIVER:               [1] llvmpipe (LLVM 15.0.7, 128 bits)
>     INFO | DRIVER:         Sorted order:
>     INFO | DRIVER:               [0] llvmpipe (LLVM 15.0.7, 128 bits)
>     INFO | DRIVER:               [1] llvmpipe (LLVM 16.0.6, 128 bits)
>     DEBUG | DRIVER:   Copying old device 0 into new device 0
>     DEBUG | DRIVER:   Copying old device 1 into new device 1
>     ERROR:            loader_validate_device_extensions: Device extension
>     VK_KHR_swapchain not supported by selected physical device or enabled
> 
> 
> Yeah, any non-headless Linux tests are unlikely to work.  Maybe in a 
> future gfxstream release, since our focus is of course on Android and 
> getting Vulkan in QEMU in general.

I have just tried "vulkan-samples sample hello_triangle --headless" but 
no luck. Below is the output of QEMU with -trace virtio_gpu_cmd_*

virtio_gpu_cmd_ctx_create ctx 0x2, name vulkan_samples
virtio_gpu_cmd_res_create_blob res 0x24, size 1064960
virtio_gpu_cmd_ctx_res_attach ctx 0x2, res 0x24
virtio_gpu_cmd_ctx_submit ctx 0x2, size 8
I0819 15:10:06.916033   21850 IntelDrmDecoder.cpp:38] IntelDrmDecoder 
created for context 2
virtio_gpu_cmd_ctx_submit ctx 0x2, size 8
virtio_gpu_cmd_ctx_submit ctx 0x2, size 8
W0819 15:10:06.916443   21850 VkDecoder.cpp:137] Bad packet length 0 
detected, decode may fail
virtio_gpu_cmd_ctx_submit ctx 0x2, size 8
W0819 15:10:06.916465   21850 VkDecoder.cpp:137] Bad packet length 0 
detected, decode may fail
W0819 15:10:06.916473   21850 VkDecoder.cpp:137] Bad packet length 0 
detected, decode may fail
W0819 15:10:06.916478   21850 VkDecoder.cpp:137] Bad packet length 0 
detected, decode may fail
W0819 15:10:06.916482   21850 VkDecoder.cpp:137] Bad packet length 0 
detected, decode may fail

And it endlessly outputs "Bad packet length" error messages.


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

* Re: [PATCH v7 9/9] docs/system: add basic virtio-gpu documentation
  2023-08-19  6:13           ` Akihiko Odaki
@ 2023-08-22  0:20             ` Gurchetan Singh
  0 siblings, 0 replies; 24+ messages in thread
From: Gurchetan Singh @ 2023-08-22  0:20 UTC (permalink / raw)
  To: Akihiko Odaki
  Cc: qemu-devel, marcandre.lureau, kraxel, ray.huang, alex.bennee,
	shentey, hi, ernunes, manos.pitsidianakis

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

On Fri, Aug 18, 2023 at 11:13 PM Akihiko Odaki <akihiko.odaki@gmail.com>
wrote:

> On 2023/08/19 10:17, Gurchetan Singh wrote:
> >
> >
> > On Fri, Aug 18, 2023 at 5:08 AM Akihiko Odaki <akihiko.odaki@gmail.com
> > <mailto:akihiko.odaki@gmail.com>> wrote:
> >
> >     On 2023/08/18 8:47, Gurchetan Singh wrote:
> >      >
> >      >
> >      > On Wed, Aug 16, 2023 at 10:28 PM Akihiko Odaki
> >     <akihiko.odaki@gmail.com <mailto:akihiko.odaki@gmail.com>
> >      > <mailto:akihiko.odaki@gmail.com
> >     <mailto:akihiko.odaki@gmail.com>>> wrote:
> >      >
> >      >     On 2023/08/17 11:23, Gurchetan Singh wrote:
> >      >      > From: Gurchetan Singh <gurchetansingh@chromium.org
> >     <mailto:gurchetansingh@chromium.org>
> >      >     <mailto:gurchetansingh@chromium.org
> >     <mailto:gurchetansingh@chromium.org>>>
> >      >      >
> >      >      > This adds basic documentation for virtio-gpu.
> >      >      >
> >      >      > Suggested-by: Akihiko Odaki <akihiko.odaki@daynix.com
> >     <mailto:akihiko.odaki@daynix.com>
> >      >     <mailto:akihiko.odaki@daynix.com
> >     <mailto:akihiko.odaki@daynix.com>>>
> >      >      > Signed-off-by: Gurchetan Singh
> >     <gurchetansingh@chromium.org <mailto:gurchetansingh@chromium.org>
> >      >     <mailto:gurchetansingh@chromium.org
> >     <mailto:gurchetansingh@chromium.org>>>
> >      >      > Tested-by: Alyssa Ross <hi@alyssa.is <mailto:hi@alyssa.is>
> >     <mailto:hi@alyssa.is <mailto:hi@alyssa.is>>>
> >      >      > Tested-by: Emmanouil Pitsidianakis
> >      >     <manos.pitsidianakis@linaro.org
> >     <mailto:manos.pitsidianakis@linaro.org>
> >     <mailto:manos.pitsidianakis@linaro.org
> >     <mailto:manos.pitsidianakis@linaro.org>>>
> >      >      > Reviewed-by: Emmanouil Pitsidianakis
> >      >     <manos.pitsidianakis@linaro.org
> >     <mailto:manos.pitsidianakis@linaro.org>
> >     <mailto:manos.pitsidianakis@linaro.org
> >     <mailto:manos.pitsidianakis@linaro.org>>>
> >      >      > ---
> >      >      > v2: - Incorporated suggestions by Akihiko Odaki
> >      >      >      - Listed the currently supported capset_names
> (Bernard)
> >      >      >
> >      >      > v3: - Incorporated suggestions by Akihiko Odaki and Alyssa
> >     Ross
> >      >      >
> >      >      > v4: - Incorporated suggestions by Akihiko Odaki
> >      >      >
> >      >      > v5: - Removed pci suffix from examples
> >      >      >      - Verified that -device virtio-gpu-rutabaga works.
> >     Strangely
> >      >      >        enough, I don't remember changing anything, and I
> >     remember
> >      >      >        it not working.  I did rebase to top of tree though.
> >      >      >      - Fixed meson examples in crosvm docs
> >      >      >
> >      >      >   docs/system/device-emulation.rst   |   1 +
> >      >      >   docs/system/devices/virtio-gpu.rst | 113
> >      >     +++++++++++++++++++++++++++++
> >      >      >   2 files changed, 114 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..8c5c708272
> >      >      > --- /dev/null
> >      >      > +++ b/docs/system/devices/virtio-gpu.rst
> >      >      > @@ -0,0 +1,113 @@
> >      >      > +..
> >      >      > +   SPDX-License-Identifier: GPL-2.0
> >      >      > +
> >      >      > +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/
> >     <https://www.mesa3d.org/> <https://www.mesa3d.org/
> >     <https://www.mesa3d.org/>>
> >      >      > +.. _SwiftShader: https://github.com/google/swiftshader
> >     <https://github.com/google/swiftshader>
> >      >     <https://github.com/google/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/
> >     <https://www.freedesktop.org/wiki/Software/gallium/>
> >      >     <https://www.freedesktop.org/wiki/Software/gallium/
> >     <https://www.freedesktop.org/wiki/Software/gallium/>>
> >      >      > +.. _virglrenderer:
> >      > https://gitlab.freedesktop.org/virgl/virglrenderer/
> >     <https://gitlab.freedesktop.org/virgl/virglrenderer/>
> >      >     <https://gitlab.freedesktop.org/virgl/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
> >      >      > +
> >      >      > +.. _rutabaga_gfx:
> >      >
> >
> https://github.com/google/crosvm/blob/main/rutabaga_gfx/ffi/src/include/rutabaga_gfx_ffi.h
> <
> https://github.com/google/crosvm/blob/main/rutabaga_gfx/ffi/src/include/rutabaga_gfx_ffi.h>
> <
> https://github.com/google/crosvm/blob/main/rutabaga_gfx/ffi/src/include/rutabaga_gfx_ffi.h
> <
> https://github.com/google/crosvm/blob/main/rutabaga_gfx/ffi/src/include/rutabaga_gfx_ffi.h
> >>
> >      >      > +.. _gfxstream:
> >      >
> >     https://android.googlesource.com/platform/hardware/google/gfxstream/
> >     <
> https://android.googlesource.com/platform/hardware/google/gfxstream/>
> >      >
> >       <
> https://android.googlesource.com/platform/hardware/google/gfxstream/ <
> https://android.googlesource.com/platform/hardware/google/gfxstream/>>
> >      >      > +.. _Wayland display passthrough:
> >      > https://www.youtube.com/watch?v=OZJiHMtIQ2M
> >     <https://www.youtube.com/watch?v=OZJiHMtIQ2M>
> >      >     <https://www.youtube.com/watch?v=OZJiHMtIQ2M
> >     <https://www.youtube.com/watch?v=OZJiHMtIQ2M>>
> >      >      > +.. _gfxstream-enabled rutabaga:
> >      > https://crosvm.dev/book/appendix/rutabaga_gfx.html
> >     <https://crosvm.dev/book/appendix/rutabaga_gfx.html>
> >      >     <https://crosvm.dev/book/appendix/rutabaga_gfx.html
> >     <https://crosvm.dev/book/appendix/rutabaga_gfx.html>>
> >      >
> >      >     You have different links for "rutabaga_gfx" and
> >     "gfxstream-enabled
> >      >     rutabaga", but I think you only need one.
> >      >
> >      >
> >      > Done.  Didn't resend the entire patch series (to avoid spamming
> >     list),
> >      > just did "in-reply-to".  The change is also available at:
> >      >
> >      >
> >
> https://gitlab.freedesktop.org/gurchetansingh/qemu-gfxstream/-/commits/qemu-gfxstream-v8
> <
> https://gitlab.freedesktop.org/gurchetansingh/qemu-gfxstream/-/commits/qemu-gfxstream-v8>
> <
> https://gitlab.freedesktop.org/gurchetansingh/qemu-gfxstream/-/commits/qemu-gfxstream-v8
> <
> https://gitlab.freedesktop.org/gurchetansingh/qemu-gfxstream/-/commits/qemu-gfxstream-v8
> >>
> >
> >     The patch series now looks good so I finally decided to try this
> patch
> >     series, but I couldn't get it work.
> >
> >     I noticed gfxstream has page size hardcoded as 4 KiB, which broke my
> >     setup on M2 MacBook Air (running Asahi Linux) that has 16 KiB page.
> You
> >     may add code to check host page size and to report an error if it's
> not
> >     4 KiB to virtio-gpu-rutabaga, but I think it's trivial to fix
> gfxstream
> >     to query page size at runtime as QEMU and Rutabaga does so I hope
> >     you to
> >     do so. For testing purpose, I have replaced it with 16 KiB on my
> setup.
> >
> >
> > Good catch, the fix to the 16KiB was merged today and is in gfxstream
> > ToT right now.
>
> The fix is incomplete. There are a few other places that hardcodes page
> size, namely ANDROID_EMU_ADDRESS_SPACE_DEFAULT_PAGE_SIZE and
> ADDRESS_SPACE_GRAPHICS_PAGE_SIZE.
>
> ANDROID_EMU_ADDRESS_SPACE_DEFAULT_PAGE_SIZE is used by no one so you can
> just remove it. ADDRESS_SPACE_GRAPHICS_PAGE_SIZE is actually in use and
> needs to be fixed.
>
> It's also better to remove PAGE_SIZE definition from guest/meson.build
> just in case.
>

ANDROID_EMU_ADDRESS_SPACE_DEFAULT_PAGE_SIZE and  PAGE_SIZE were removed
from gfxstream ToT.
The host alignment of the ring blob is also now based on getpagesize(..)
and not hardcoded.


> >
> >
> >     I also found some bugs on QEMU side so I added comments to respective
> >     patches.
> >
> >     Below is the logs from my last attempt of running vkgears:
> >
> >     $ VK_LOADER_DEBUG=all demos/build/src/vulkan/vkgears
> >     INFO:             Vulkan Loader Version 1.3.243
> >     LAYER:            Searching for layer manifest files
> >     LAYER:               In following locations:
> >     LAYER:
> /var/home/person/.config/vulkan/implicit_layer.d
> >     LAYER:                  /etc/xdg/vulkan/implicit_layer.d
> >     LAYER:                  /etc/vulkan/implicit_layer.d
> >     LAYER:
> >     /var/home/person/.local/share/vulkan/implicit_layer.d
> >     LAYER:
> >
>  /var/home/person/.local/share/flatpak/exports/share/vulkan/implicit_layer.d
> >     LAYER:
> >     /var/lib/flatpak/exports/share/vulkan/implicit_layer.d
> >     LAYER:                  /usr/local/share/vulkan/implicit_layer.d
> >     LAYER:                  /usr/share/vulkan/implicit_layer.d
> >     LAYER:               Found the following files:
> >     LAYER:
> >     /usr/share/vulkan/implicit_layer.d/VkLayer_MESA_device_select.json
> >     INFO:             Found manifest file
> >     /usr/share/vulkan/implicit_layer.d/VkLayer_MESA_device_select.json
> >     (file
> >     version "1.0.0")
> >     LAYER:            Searching for layer manifest files
> >     LAYER:               In following locations:
> >     LAYER:
> /var/home/person/.config/vulkan/explicit_layer.d
> >     LAYER:                  /etc/xdg/vulkan/explicit_layer.d
> >     LAYER:                  /etc/vulkan/explicit_layer.d
> >     LAYER:
> >     /var/home/person/.local/share/vulkan/explicit_layer.d
> >     LAYER:
> >
>  /var/home/person/.local/share/flatpak/exports/share/vulkan/explicit_layer.d
> >     LAYER:
> >     /var/lib/flatpak/exports/share/vulkan/explicit_layer.d
> >     LAYER:                  /usr/local/share/vulkan/explicit_layer.d
> >     LAYER:                  /usr/share/vulkan/explicit_layer.d
> >     LAYER:               Found no files
> >     DRIVER:           Searching for driver manifest files
> >     DRIVER:              In following locations:
> >     DRIVER:                 /var/home/person/.config/vulkan/icd.d
> >     DRIVER:                 /etc/xdg/vulkan/icd.d
> >     DRIVER:                 /etc/vulkan/icd.d
> >     DRIVER:                 /var/home/person/.local/share/vulkan/icd.d
> >     DRIVER:
> >     /var/home/person/.local/share/flatpak/exports/share/vulkan/icd.d
> >     DRIVER:                 /var/lib/flatpak/exports/share/vulkan/icd.d
> >     DRIVER:                 /usr/local/share/vulkan/icd.d
> >     DRIVER:                 /usr/share/vulkan/icd.d
> >     DRIVER:              Found the following files:
> >     DRIVER:
> >     /usr/local/share/vulkan/icd.d/cereal_icd.aarch64.json
> >     DRIVER:
> >       /usr/share/vulkan/icd.d/broadcom_icd.aarch64.json
> >     DRIVER:
> >       /usr/share/vulkan/icd.d/freedreno_icd.aarch64.json
> >     DRIVER:                 /usr/share/vulkan/icd.d/lvp_icd.aarch64.json
> >     DRIVER:
> >       /usr/share/vulkan/icd.d/panfrost_icd.aarch64.json
> >     DRIVER:
>  /usr/share/vulkan/icd.d/radeon_icd.aarch64.json
> >     DRIVER:           Found ICD manifest file
> >     /usr/local/share/vulkan/icd.d/cereal_icd.aarch64.json, version
> "1.0.0"
> >     DEBUG | DRIVER:   Searching for ICD drivers named
> >     /usr/local/lib64/libvulkan_cereal.so
> >     [VirtGpuDevice.cpp(71)]
> >     [prio 6] virtgpu backend not enabling
> >     VIRTGPU_PARAM_CREATE_GUEST_HANDLE[AndroidHealthMonitor.cpp(275)]
> >     [prio 4] HealthMonitor disabled. Returning nullptrI0818
> 21:00:07.980257
> >     154451 IntelDrmDecoder.cpp:38] IntelDrmDecoder created for context 2
> >     DRIVER:           Found ICD manifest file
> >     /usr/share/vulkan/icd.d/broadcom_icd.aarch64.json, version "1.0.0"
> >     DEBUG | DRIVER:   Searching for ICD drivers named
> >     /usr/lib64/libvulkan_broadcom.so
> >     DRIVER:           Found ICD manifest file
> >     /usr/share/vulkan/icd.d/freedreno_icd.aarch64.json, version "1.0.0"
> >     DEBUG | DRIVER:   Searching for ICD drivers named
> >     /usr/lib64/libvulkan_freedreno.so
> >     DRIVER:           Found ICD manifest file
> >     /usr/share/vulkan/icd.d/lvp_icd.aarch64.json, version "1.0.0"
> >     DEBUG | DRIVER:   Searching for ICD drivers named
> >     /usr/lib64/libvulkan_lvp.so
> >     DRIVER:           Found ICD manifest file
> >     /usr/share/vulkan/icd.d/panfrost_icd.aarch64.json, version "1.0.0"
> >     DEBUG | DRIVER:   Searching for ICD drivers named
> >     /usr/lib64/libvulkan_panfrost.so
> >     DRIVER:           Found ICD manifest file
> >     /usr/share/vulkan/icd.d/radeon_icd.aarch64.json, version "1.0.0"
> >     DEBUG | DRIVER:   Searching for ICD drivers named
> >     /usr/lib64/libvulkan_radeon.so
> >     DEBUG | LAYER:    Loading layer library
> libVkLayer_MESA_device_select.so
> >     INFO | LAYER:     Insert instance layer "VK_LAYER_MESA_device_select"
> >     (libVkLayer_MESA_device_select.so)
> >     LAYER:            vkCreateInstance layer callstack setup to:
> >     LAYER:               <Application>
> >     LAYER:                 ||
> >     LAYER:               <Loader>
> >     LAYER:                 ||
> >     LAYER:               VK_LAYER_MESA_device_select
> >     LAYER:                       Type: Implicit
> >     LAYER:                           Disable Env Var:  NODEVICE_SELECT
> >     LAYER:                       Manifest:
> >     /usr/share/vulkan/implicit_layer.d/VkLayer_MESA_device_select.json
> >     LAYER:                       Library:
> libVkLayer_MESA_device_select.so
> >     LAYER:                 ||
> >     LAYER:               <Drivers>
> >     I0818 21:00:08.014896  154451 VkDecoderGlobalState.cpp:443] Creating
> >     Vulkan instance for app: vkgears
> >     INFO | DRIVER:    linux_read_sorted_physical_devices:
> >     INFO | DRIVER:         Original order:
> >     INFO | DRIVER:               [0] llvmpipe (LLVM 16.0.6, 128 bits)
> >     INFO | DRIVER:               [1] llvmpipe (LLVM 15.0.7, 128 bits)
> >     INFO | DRIVER:         Sorted order:
> >     INFO | DRIVER:               [0] llvmpipe (LLVM 15.0.7, 128 bits)
> >     INFO | DRIVER:               [1] llvmpipe (LLVM 16.0.6, 128 bits)
> >     INFO | DRIVER:    linux_read_sorted_physical_devices:
> >     INFO | DRIVER:         Original order:
> >     INFO | DRIVER:               [0] llvmpipe (LLVM 16.0.6, 128 bits)
> >     INFO | DRIVER:               [1] llvmpipe (LLVM 15.0.7, 128 bits)
> >     INFO | DRIVER:         Sorted order:
> >     INFO | DRIVER:               [0] llvmpipe (LLVM 15.0.7, 128 bits)
> >     INFO | DRIVER:               [1] llvmpipe (LLVM 16.0.6, 128 bits)
> >     DEBUG | DRIVER:   Copying old device 0 into new device 0
> >     DEBUG | DRIVER:   Copying old device 1 into new device 1
> >     INFO | DRIVER:    linux_read_sorted_physical_devices:
> >     INFO | DRIVER:         Original order:
> >     INFO | DRIVER:               [0] llvmpipe (LLVM 16.0.6, 128 bits)
> >     INFO | DRIVER:               [1] llvmpipe (LLVM 15.0.7, 128 bits)
> >     INFO | DRIVER:         Sorted order:
> >     INFO | DRIVER:               [0] llvmpipe (LLVM 15.0.7, 128 bits)
> >     INFO | DRIVER:               [1] llvmpipe (LLVM 16.0.6, 128 bits)
> >     DEBUG | DRIVER:   Copying old device 0 into new device 0
> >     DEBUG | DRIVER:   Copying old device 1 into new device 1
> >     INFO | DRIVER:    linux_read_sorted_physical_devices:
> >     INFO | DRIVER:         Original order:
> >     INFO | DRIVER:               [0] llvmpipe (LLVM 16.0.6, 128 bits)
> >     INFO | DRIVER:               [1] llvmpipe (LLVM 15.0.7, 128 bits)
> >     INFO | DRIVER:         Sorted order:
> >     INFO | DRIVER:               [0] llvmpipe (LLVM 15.0.7, 128 bits)
> >     INFO | DRIVER:               [1] llvmpipe (LLVM 16.0.6, 128 bits)
> >     DEBUG | DRIVER:   Copying old device 0 into new device 0
> >     DEBUG | DRIVER:   Copying old device 1 into new device 1
> >     ERROR:            loader_validate_device_extensions: Device extension
> >     VK_KHR_swapchain not supported by selected physical device or enabled
> >
> >
> > Yeah, any non-headless Linux tests are unlikely to work.  Maybe in a
> > future gfxstream release, since our focus is of course on Android and
> > getting Vulkan in QEMU in general.
>
> I have just tried "vulkan-samples sample hello_triangle --headless" but
> no luck. Below is the output of QEMU with -trace virtio_gpu_cmd_*
>

I have slightly different behavior on my setup, the app fails to find the
proper surface extensions and exits.   In headless mode, the app relies
on VK_EXT_headless_surface, which gfxstream does not currently support
(see on_vkEnumerateInstanceExtensionProperties).  For some reason, perhaps
due the presence of other VK drivers on the system, vulkaninfo does report
several X11/Wayland surface extensions with gfxstream.  This may confuse
some headless apps.

Either way, the crosvm docs will be clarified to mention what's been tested
regarding gfxstream guest Linux (crrev.com/c/4800334).  I suggest you run
deqp-vk if your goal is to test this patch series.


>
> virtio_gpu_cmd_ctx_create ctx 0x2, name vulkan_samples
> virtio_gpu_cmd_res_create_blob res 0x24, size 1064960
> virtio_gpu_cmd_ctx_res_attach ctx 0x2, res 0x24
> virtio_gpu_cmd_ctx_submit ctx 0x2, size 8
> I0819 15:10:06.916033   21850 IntelDrmDecoder.cpp:38] IntelDrmDecoder
> created for context 2
> virtio_gpu_cmd_ctx_submit ctx 0x2, size 8
> virtio_gpu_cmd_ctx_submit ctx 0x2, size 8
> W0819 15:10:06.916443   21850 VkDecoder.cpp:137] Bad packet length 0
> detected, decode may fail
> virtio_gpu_cmd_ctx_submit ctx 0x2, size 8
> W0819 15:10:06.916465   21850 VkDecoder.cpp:137] Bad packet length 0
> detected, decode may fail
> W0819 15:10:06.916473   21850 VkDecoder.cpp:137] Bad packet length 0
> detected, decode may fail
> W0819 15:10:06.916478   21850 VkDecoder.cpp:137] Bad packet length 0
> detected, decode may fail
> W0819 15:10:06.916482   21850 VkDecoder.cpp:137] Bad packet length 0
> detected, decode may fail
>
> And it endlessly outputs "Bad packet length" error messages.
>

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

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

* Re: [PATCH v7 5/9] gfxstream + rutabaga prep: added need defintions,  fields, and options
  2023-08-17  2:23 ` [PATCH v7 5/9] gfxstream + rutabaga prep: added need defintions, fields, and options Gurchetan Singh
@ 2023-08-23 14:32   ` Mark Cave-Ayland
  2023-08-24 23:47     ` Gurchetan Singh
  0 siblings, 1 reply; 24+ messages in thread
From: Mark Cave-Ayland @ 2023-08-23 14:32 UTC (permalink / raw)
  To: Gurchetan Singh, qemu-devel
  Cc: marcandre.lureau, kraxel, akihiko.odaki, ray.huang, alex.bennee,
	shentey, hi, ernunes, manos.pitsidianakis

On 17/08/2023 03:23, Gurchetan Singh wrote:

> From: Gurchetan Singh <gurchetansingh@chromium.org>
> 
> 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>
> Reviewed-by: Emmanouil Pitsidianakis <manos.pitsidianakis@linaro.org>
> ---
> v1: void *rutabaga --> struct rutabaga *rutabaga (Akihiko)
>      have a separate rutabaga device instead of using GL device (Bernard)
> 
> v2: VirtioGpuRutabaga --> VirtIOGPURutabaga (Akihiko)
>      move MemoryRegionInfo into VirtIOGPURutabaga (Akihiko)
>      remove 'ctx' field (Akihiko)
>      remove 'rutabaga_active'
> 
> v6: remove command from commit message, refer to docs instead (Manos)
> 
>   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..e2a07e68d9 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 {
> +    struct VirtIOGPU parent_obj;

The QOM macro should define a typedef for you, so you can drop the "struct" here.

> +
> +    struct MemoryRegionInfo memory_regions[MAX_SLOTS];
> +    char *capset_names;
> +    char *wayland_socket_path;
> +    char *wsi;
> +    bool headless;
> +    uint32_t num_capsets;
> +    struct rutabaga *rutabaga;
> +};
> +

Shouldn't the VIRTIO_GPU_RUTABAGA QOM declaration and this structure be in a separate 
virtio-gpu-rutabaga header file which also includes the header defining struct 
rutabaga? The fact that you're having to pre-declare struct rutabaga in this header 
when rutabaga support is an optional dependency doesn't seem right.

>   #define VIRTIO_GPU_FILL_CMD(out) do {                                   \
>           size_t s;                                                       \
>           s = iov_to_buf(cmd->elem.out_sg, cmd->elem.out_num, 0,          \


ATB,

Mark.



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

* Re: [PATCH v7 6/9] gfxstream + rutabaga: add initial support for gfxstream
  2023-08-17  2:23 ` [PATCH v7 6/9] gfxstream + rutabaga: add initial support for gfxstream Gurchetan Singh
  2023-08-18 11:58   ` Akihiko Odaki
@ 2023-08-23 15:03   ` Mark Cave-Ayland
  2023-08-24 23:50     ` Gurchetan Singh
  1 sibling, 1 reply; 24+ messages in thread
From: Mark Cave-Ayland @ 2023-08-23 15:03 UTC (permalink / raw)
  To: Gurchetan Singh, qemu-devel
  Cc: marcandre.lureau, kraxel, akihiko.odaki, ray.huang, alex.bennee,
	shentey, hi, ernunes, manos.pitsidianakis

On 17/08/2023 03:23, Gurchetan Singh wrote:

> From: Gurchetan Singh <gurchetansingh@chromium.org>
> 
> 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>
> Reviewed-by: Emmanouil Pitsidianakis <manos.pitsidianakis@linaro.org>
> ---
> v1: Incorported various suggestions by Akihiko Odaki and Bernard Berschow
>      - Removed GET_VIRTIO_GPU_GL / GET_RUTABAGA macros
>      - Used error_report(..)
>      - Used g_autofree to fix leaks on error paths
>      - Removed unnecessary casts
>      - added virtio-gpu-pci-rutabaga.c + virtio-vga-rutabaga.c files
> 
> v2: Incorported various suggestions by Akihiko Odaki, Marc-André Lureau and
>      Bernard Berschow:
>      - Parenthesis in CHECK macro
>      - CHECK_RESULT(result, ..) --> CHECK(!result, ..)
>      - delay until g->parent_obj.enable = 1
>      - Additional cast fixes
>      - initialize directly in virtio_gpu_rutabaga_realize(..)
>      - add debug callback to hook into QEMU error's APIs
> 
> v3: Incorporated feedback from Akihiko Odaki and Alyssa Ross:
>      - Autodetect Wayland socket when not explicitly specified
>      - Fix map_blob error paths
>      - Add comment why we need both `res` and `resource` in create blob
>      - Cast and whitespace fixes
>      - Big endian check comes before virtio_gpu_rutabaga_init().
>      - VirtIOVGARUTABAGA --> VirtIOVGARutabaga
> 
> v4: Incorporated feedback from Akihiko Odaki and Alyssa Ross:
>      - Double checked all casts
>      - Remove unnecessary parenthesis
>      - Removed `resource` in create_blob
>      - Added comment about failure case
>      - Pass user-provided socket as-is
>      - Use stack variable rather than heap allocation
>      - Future-proofed map info API to give access flags as well
> 
> v5: Incorporated feedback from Akihiko Odaki:
>      - Check (ss.scanout_id < VIRTIO_GPU_MAX_SCANOUTS)
>      - Simplify num_capsets check
>      - Call cleanup mapping on error paths
>      - uint64_t --> void* for rutabaga_map(..)
>      - Removed unnecessary parenthesis
>      - Removed unnecessary cast
>      - #define UNIX_PATH_MAX sizeof((struct sockaddr_un) {}.sun_path)
>      - Reuse result variable
> 
> v6: Incorporated feedback from Akihiko Odaki:
>      - Remove unnecessary #ifndef
>      - Disable scanout when appropriate
>      - CHECK capset index within range outside loop
>      - Add capset_version
> 
> v7: Incorporated feedback from Akihiko Odaki:
>      - aio_bh_schedule_oneshot_full --> aio_bh_schedule_oneshot
> 
>   hw/display/virtio-gpu-pci-rutabaga.c |   48 ++
>   hw/display/virtio-gpu-rutabaga.c     | 1115 ++++++++++++++++++++++++++
>   hw/display/virtio-vga-rutabaga.c     |   51 ++
>   3 files changed, 1214 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..c71173d8ca
> --- /dev/null
> +++ b/hw/display/virtio-gpu-pci-rutabaga.c
> @@ -0,0 +1,48 @@
> +// SPDX-License-Identifier: GPL-2.0

QEMU uses C instead of C++ comments.

> +
> +#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"
> +typedef struct VirtIOGPURutabagaPCI VirtIOGPURutabagaPCI;
> +DECLARE_INSTANCE_CHECKER(VirtIOGPURutabagaPCI, VIRTIO_GPU_RUTABAGA_PCI,
> +                         TYPE_VIRTIO_GPU_RUTABAGA_PCI)

The typedef above shouldn't be required, and why are you using 
DECLARE_INSTANCE_CHECKER instead of OBJECT_DECLARE_SIMPLE_TYPE?

> +struct VirtIOGPURutabagaPCI {
> +    VirtIOGPUPCIBase parent_obj;

Missing blank line here.

> +    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 VirtioPCIDeviceTypeInfo virtio_gpu_rutabaga_pci_info = {
> +    .generic_name = TYPE_VIRTIO_GPU_RUTABAGA_PCI,
> +    .parent = TYPE_VIRTIO_GPU_PCI_BASE,
> +    .instance_size = sizeof(VirtIOGPURutabagaPCI),
> +    .instance_init = virtio_gpu_rutabaga_initfn,
> +};
> +module_obj(TYPE_VIRTIO_GPU_RUTABAGA_PCI);
> +module_kconfig(VIRTIO_PCI);
> +
> +static void virtio_gpu_rutabaga_pci_register_types(void)
> +{
> +    virtio_pci_types_register(&virtio_gpu_rutabaga_pci_info);
> +}
> +
> +type_init(virtio_gpu_rutabaga_pci_register_types)

The new way to declare QOM types is with the DEFINE_TYPES() macro.

> +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..24977d3993
> --- /dev/null
> +++ b/hw/display/virtio-gpu-rutabaga.c
> @@ -0,0 +1,1115 @@
> +// SPDX-License-Identifier: GPL-2.0

This should be a C and not a C++ comment.

> +
> +#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;
> +
> +    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 < g->parent_obj.conf.max_outputs; i++) {
> +        scanout = &g->parent_obj.scanout[i];

You shouldn't access .parent_obj directly, but instead use the appropriate QOM cast 
macro.

> +        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;
> +
> +    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 = &g->parent_obj.scanout[ss.scanout_id];

Same comment here re: parent_obj.

> +    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);
> +    }
> +
> +    g->parent_obj.enable = 1;

And here.

> +    /* 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 };
> +
> +    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, NULL, "blob", mapping.size,
> +                                   mapping.ptr);

Here you're declaring the MemoryRegion so that it doesn't have an owner, which should 
only be required for MemoryRegions that are never destroyed. I think the owner should 
be the VirtIOGPURutabaga object since that is the container for the memory slots?

> +        memory_region_add_subregion(&g->parent_obj.hostmem,
> +                                    mblob.offset, mr);

Same again re: parent_obj.

> +        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;
> +
> +    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(&g->parent_obj.hostmem, mr);

Same again re: parent_obj.

> +        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 int 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 -EINVAL;
> +    }
> +
> +    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 -EINVAL;
> +        }
> +    }
> +
> +    result = rutabaga_calculate_capset_mask(vr->capset_names, &capset_mask);
> +    if (result) {
> +        error_setg(errp, "invalid capset names: %s", vr->capset_names);
> +        return result;
> +    }
> +
> +    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);
> +    return result;
> +}
> +
> +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
> +
> +    int result = virtio_gpu_rutabaga_init(gpudev, errp);
> +    if (result) {
> +        error_setg(errp, "virtio_gpu_rutabaga_init failed");
> +        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,
> +};
> +module_obj(TYPE_VIRTIO_GPU_RUTABAGA);
> +module_kconfig(VIRTIO_GPU);
> +
> +static void virtio_register_types(void)
> +{
> +    type_register_static(&virtio_gpu_rutabaga_info);
> +}
> +
> +type_init(virtio_register_types)

Same comment again re: DEFINE_TYPES.

> +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..2b2ffed8a6
> --- /dev/null
> +++ b/hw/display/virtio-vga-rutabaga.c
> @@ -0,0 +1,51 @@
> +// SPDX-License-Identifier: GPL-2.0

This should be a C and not a C++ comment.

> +
> +#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"
> +
> +typedef struct VirtIOVGARutabaga VirtIOVGARutabaga;
> +DECLARE_INSTANCE_CHECKER(VirtIOVGARutabaga, VIRTIO_VGA_RUTABAGA,
> +                         TYPE_VIRTIO_VGA_RUTABAGA)

Same comment as earlier: you should be able top drop the typedef and use 
OBJECT_DECLARE_SIMPLE_TYPE instead of DECLARE_INSTANCE_CHECKER.

> +struct VirtIOVGARutabaga {
> +    VirtIOVGABase parent_obj;

Missing newline here.

> +    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");

Just out of curiosity has this series passed a run through QEMU's gitlab CI and also 
scripts/checkpatch.pl?

I don't see any changes to the MAINTAINERS file for the new files introduced for the 
virtio-gpu-rutabaga-device: you'll need to nominate someone to receive bug 
reports/respond to patches and update MAINTAINERS accordingly.

Similarly I think you'll want a patch to include coverage of this in gitlab CI 
somewhere as otherwise any build errors may not be noticed by developers who don't 
have rutabaga installed.


ATB,

Mark.



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

* Re: [PATCH v7 5/9] gfxstream + rutabaga prep: added need defintions,  fields, and options
  2023-08-23 14:32   ` Mark Cave-Ayland
@ 2023-08-24 23:47     ` Gurchetan Singh
  0 siblings, 0 replies; 24+ messages in thread
From: Gurchetan Singh @ 2023-08-24 23:47 UTC (permalink / raw)
  To: Mark Cave-Ayland
  Cc: qemu-devel, marcandre.lureau, kraxel, akihiko.odaki, ray.huang,
	alex.bennee, shentey, hi, ernunes, manos.pitsidianakis

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

On Wed, Aug 23, 2023 at 7:32 AM Mark Cave-Ayland <
mark.cave-ayland@ilande.co.uk> wrote:

> On 17/08/2023 03:23, Gurchetan Singh wrote:
>
> > From: Gurchetan Singh <gurchetansingh@chromium.org>
> >
> > 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>
> > Reviewed-by: Emmanouil Pitsidianakis <manos.pitsidianakis@linaro.org>
> > ---
> > v1: void *rutabaga --> struct rutabaga *rutabaga (Akihiko)
> >      have a separate rutabaga device instead of using GL device (Bernard)
> >
> > v2: VirtioGpuRutabaga --> VirtIOGPURutabaga (Akihiko)
> >      move MemoryRegionInfo into VirtIOGPURutabaga (Akihiko)
> >      remove 'ctx' field (Akihiko)
> >      remove 'rutabaga_active'
> >
> > v6: remove command from commit message, refer to docs instead (Manos)
> >
> >   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..e2a07e68d9 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 {
> > +    struct VirtIOGPU parent_obj;
>
> The QOM macro should define a typedef for you, so you can drop the
> "struct" here.
>
> > +
> > +    struct MemoryRegionInfo memory_regions[MAX_SLOTS];
> > +    char *capset_names;
> > +    char *wayland_socket_path;
> > +    char *wsi;
> > +    bool headless;
> > +    uint32_t num_capsets;
> > +    struct rutabaga *rutabaga;
> > +};
> > +
>
> Shouldn't the VIRTIO_GPU_RUTABAGA QOM declaration and this structure be in
> a separate
> virtio-gpu-rutabaga header file which also includes the header defining
> struct
> rutabaga? The fact that you're having to pre-declare struct rutabaga in
> this header
> when rutabaga support is an optional dependency doesn't seem right.
>

It is the prevailing style of the virtio-gpu code.  For example, we do have
"virtio_gpu_virgl_*" functions, vhost-user, and udmabuf stubs in the same
file.  So for now, I didn't add an extra header file in v12.  In the
future, separating out optional dependencies into constituent header files
could be future refactoring/cleanup.


>
> >   #define VIRTIO_GPU_FILL_CMD(out) do {
>  \
> >           size_t s;
>  \
> >           s = iov_to_buf(cmd->elem.out_sg, cmd->elem.out_num, 0,
>   \
>
>
> ATB,
>
> Mark.
>
>

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

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

* Re: [PATCH v7 6/9] gfxstream + rutabaga: add initial support for gfxstream
  2023-08-23 15:03   ` Mark Cave-Ayland
@ 2023-08-24 23:50     ` Gurchetan Singh
  0 siblings, 0 replies; 24+ messages in thread
From: Gurchetan Singh @ 2023-08-24 23:50 UTC (permalink / raw)
  To: Mark Cave-Ayland
  Cc: qemu-devel, marcandre.lureau, kraxel, akihiko.odaki, ray.huang,
	alex.bennee, shentey, hi, ernunes, manos.pitsidianakis

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

On Wed, Aug 23, 2023 at 8:03 AM Mark Cave-Ayland <
mark.cave-ayland@ilande.co.uk> wrote:

> On 17/08/2023 03:23, Gurchetan Singh wrote:
>
> > From: Gurchetan Singh <gurchetansingh@chromium.org>
> >
> > 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>
> > Reviewed-by: Emmanouil Pitsidianakis <manos.pitsidianakis@linaro.org>
> > ---
> > v1: Incorported various suggestions by Akihiko Odaki and Bernard Berschow
> >      - Removed GET_VIRTIO_GPU_GL / GET_RUTABAGA macros
> >      - Used error_report(..)
> >      - Used g_autofree to fix leaks on error paths
> >      - Removed unnecessary casts
> >      - added virtio-gpu-pci-rutabaga.c + virtio-vga-rutabaga.c files
> >
> > v2: Incorported various suggestions by Akihiko Odaki, Marc-André Lureau
> and
> >      Bernard Berschow:
> >      - Parenthesis in CHECK macro
> >      - CHECK_RESULT(result, ..) --> CHECK(!result, ..)
> >      - delay until g->parent_obj.enable = 1
> >      - Additional cast fixes
> >      - initialize directly in virtio_gpu_rutabaga_realize(..)
> >      - add debug callback to hook into QEMU error's APIs
> >
> > v3: Incorporated feedback from Akihiko Odaki and Alyssa Ross:
> >      - Autodetect Wayland socket when not explicitly specified
> >      - Fix map_blob error paths
> >      - Add comment why we need both `res` and `resource` in create blob
> >      - Cast and whitespace fixes
> >      - Big endian check comes before virtio_gpu_rutabaga_init().
> >      - VirtIOVGARUTABAGA --> VirtIOVGARutabaga
> >
> > v4: Incorporated feedback from Akihiko Odaki and Alyssa Ross:
> >      - Double checked all casts
> >      - Remove unnecessary parenthesis
> >      - Removed `resource` in create_blob
> >      - Added comment about failure case
> >      - Pass user-provided socket as-is
> >      - Use stack variable rather than heap allocation
> >      - Future-proofed map info API to give access flags as well
> >
> > v5: Incorporated feedback from Akihiko Odaki:
> >      - Check (ss.scanout_id < VIRTIO_GPU_MAX_SCANOUTS)
> >      - Simplify num_capsets check
> >      - Call cleanup mapping on error paths
> >      - uint64_t --> void* for rutabaga_map(..)
> >      - Removed unnecessary parenthesis
> >      - Removed unnecessary cast
> >      - #define UNIX_PATH_MAX sizeof((struct sockaddr_un) {}.sun_path)
> >      - Reuse result variable
> >
> > v6: Incorporated feedback from Akihiko Odaki:
> >      - Remove unnecessary #ifndef
> >      - Disable scanout when appropriate
> >      - CHECK capset index within range outside loop
> >      - Add capset_version
> >
> > v7: Incorporated feedback from Akihiko Odaki:
> >      - aio_bh_schedule_oneshot_full --> aio_bh_schedule_oneshot
> >
> >   hw/display/virtio-gpu-pci-rutabaga.c |   48 ++
> >   hw/display/virtio-gpu-rutabaga.c     | 1115 ++++++++++++++++++++++++++
> >   hw/display/virtio-vga-rutabaga.c     |   51 ++
> >   3 files changed, 1214 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..c71173d8ca
> > --- /dev/null
> > +++ b/hw/display/virtio-gpu-pci-rutabaga.c
> > @@ -0,0 +1,48 @@
> > +// SPDX-License-Identifier: GPL-2.0
>
> QEMU uses C instead of C++ comments.
>
> > +
> > +#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"
> > +typedef struct VirtIOGPURutabagaPCI VirtIOGPURutabagaPCI;
> > +DECLARE_INSTANCE_CHECKER(VirtIOGPURutabagaPCI, VIRTIO_GPU_RUTABAGA_PCI,
> > +                         TYPE_VIRTIO_GPU_RUTABAGA_PCI)
>
> The typedef above shouldn't be required, and why are you using
> DECLARE_INSTANCE_CHECKER instead of OBJECT_DECLARE_SIMPLE_TYPE?
>
> > +struct VirtIOGPURutabagaPCI {
> > +    VirtIOGPUPCIBase parent_obj;
>
> Missing blank line here.
>
> > +    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 VirtioPCIDeviceTypeInfo virtio_gpu_rutabaga_pci_info = {
> > +    .generic_name = TYPE_VIRTIO_GPU_RUTABAGA_PCI,
> > +    .parent = TYPE_VIRTIO_GPU_PCI_BASE,
> > +    .instance_size = sizeof(VirtIOGPURutabagaPCI),
> > +    .instance_init = virtio_gpu_rutabaga_initfn,
> > +};
> > +module_obj(TYPE_VIRTIO_GPU_RUTABAGA_PCI);
> > +module_kconfig(VIRTIO_PCI);
> > +
> > +static void virtio_gpu_rutabaga_pci_register_types(void)
> > +{
> > +    virtio_pci_types_register(&virtio_gpu_rutabaga_pci_info);
> > +}
> > +
> > +type_init(virtio_gpu_rutabaga_pci_register_types)
>
> The new way to declare QOM types is with the DEFINE_TYPES() macro.
>

Done for virtio-gpu-rutabaga.c and virtio-gpu-pci-rutabaga.c.  The vga file
has the "have_vga" variable that prevents the transition.  Incorporated
your other suggestions for this patch though in v12.


>
> > +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..24977d3993
> > --- /dev/null
> > +++ b/hw/display/virtio-gpu-rutabaga.c
> > @@ -0,0 +1,1115 @@
> > +// SPDX-License-Identifier: GPL-2.0
>
> This should be a C and not a C++ comment.
>
> > +
> > +#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;
> > +
> > +    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 < g->parent_obj.conf.max_outputs; i++) {
> > +        scanout = &g->parent_obj.scanout[i];
>
> You shouldn't access .parent_obj directly, but instead use the appropriate
> QOM cast
> macro.
>
> > +        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;
> > +
> > +    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 = &g->parent_obj.scanout[ss.scanout_id];
>
> Same comment here re: parent_obj.
>
> > +    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);
> > +    }
> > +
> > +    g->parent_obj.enable = 1;
>
> And here.
>
> > +    /* 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 };
> > +
> > +    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, NULL, "blob", mapping.size,
> > +                                   mapping.ptr);
>
> Here you're declaring the MemoryRegion so that it doesn't have an owner,
> which should
> only be required for MemoryRegions that are never destroyed. I think the
> owner should
> be the VirtIOGPURutabaga object since that is the container for the memory
> slots?
>
> > +        memory_region_add_subregion(&g->parent_obj.hostmem,
> > +                                    mblob.offset, mr);
>
> Same again re: parent_obj.
>
> > +        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;
> > +
> > +    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(&g->parent_obj.hostmem, mr);
>
> Same again re: parent_obj.
>
> > +        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 int 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 -EINVAL;
> > +    }
> > +
> > +    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 -EINVAL;
> > +        }
> > +    }
> > +
> > +    result = rutabaga_calculate_capset_mask(vr->capset_names,
> &capset_mask);
> > +    if (result) {
> > +        error_setg(errp, "invalid capset names: %s", vr->capset_names);
> > +        return result;
> > +    }
> > +
> > +    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);
> > +    return result;
> > +}
> > +
> > +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
> > +
> > +    int result = virtio_gpu_rutabaga_init(gpudev, errp);
> > +    if (result) {
> > +        error_setg(errp, "virtio_gpu_rutabaga_init failed");
> > +        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,
> > +};
> > +module_obj(TYPE_VIRTIO_GPU_RUTABAGA);
> > +module_kconfig(VIRTIO_GPU);
> > +
> > +static void virtio_register_types(void)
> > +{
> > +    type_register_static(&virtio_gpu_rutabaga_info);
> > +}
> > +
> > +type_init(virtio_register_types)
>
> Same comment again re: DEFINE_TYPES.
>
> > +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..2b2ffed8a6
> > --- /dev/null
> > +++ b/hw/display/virtio-vga-rutabaga.c
> > @@ -0,0 +1,51 @@
> > +// SPDX-License-Identifier: GPL-2.0
>
> This should be a C and not a C++ comment.
>
> > +
> > +#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"
> > +
> > +typedef struct VirtIOVGARutabaga VirtIOVGARutabaga;
> > +DECLARE_INSTANCE_CHECKER(VirtIOVGARutabaga, VIRTIO_VGA_RUTABAGA,
> > +                         TYPE_VIRTIO_VGA_RUTABAGA)
>
> Same comment as earlier: you should be able top drop the typedef and use
> OBJECT_DECLARE_SIMPLE_TYPE instead of DECLARE_INSTANCE_CHECKER.
>
> > +struct VirtIOVGARutabaga {
> > +    VirtIOVGABase parent_obj;
>
> Missing newline here.
>
> > +    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");
>
> Just out of curiosity has this series passed a run through QEMU's gitlab
> CI and also
> scripts/checkpatch.pl?
>

I tried to run the CI as per:

https://wiki.qemu.org/Testing/CI/Integrated

It only automatically created a pipeline during the first push, and failed
since I didn't have my account validated.  After I verified my account, it
never created a pipeline again.  In the pipeline editor, I keep getting
"Pipeline will not run for the selected trigger. The rules configuration
prevented any jobs from being added to the pipeline."  So I gave up.

For checkpatch.pl, I've run every version of the series through it.
Interestingly, it doesn't catch a few things:

- Licensing regarding GPL2.0 or greater
- Style of comments if it's related to the licensing.  Other comments, I
think it helped with.
- Casting style or unnecessary style
- The new blank line after declaration of a "parent_obj" in QOM



> I don't see any changes to the MAINTAINERS file for the new files
> introduced for the
> virtio-gpu-rutabaga-device: you'll need to nominate someone to receive bug
> reports/respond to patches and update MAINTAINERS accordingly.
>

virtio-gpu-rutabaga would fall into the purview of "virtio-gpu" in
the MAINTAINERS file.  I don't expect many QEMU bugs after the initial
merge, since most of the bugs will be inside rutabaga or in guest userspace.

There's no shortage of reviewers, since I've gotten a lot of review
comments with this series.  So personally I'm fine with the status quo of
"whoever has interest reviews, maintainers do a sanity check".


> Similarly I think you'll want a patch to include coverage of this in
> gitlab CI
> somewhere as otherwise any build errors may not be noticed by developers
> who don't
> have rutabaga installed.


We do have to build upstream QEMU in AOSP due to compliance reasons, so
downstream testing should catch any upstream build failures quickly.
Long-term, I do think it makes sense to add upstream QEMU testing,
especially for downstream products who have their own elaborate testing
infra (Android Emulator).  But the exact form that takes probably requires
some more thought, so holding off on any CI patches for now.


>
>
> ATB,
>
> Mark.
>
>

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

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

end of thread, other threads:[~2023-08-24 23:51 UTC | newest]

Thread overview: 24+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-08-17  2:23 [PATCH v7 0/9] gfxstream + rutabaga_gfx Gurchetan Singh
2023-08-17  2:23 ` [PATCH v7 1/9] virtio: Add shared memory capability Gurchetan Singh
2023-08-17  2:23 ` [PATCH v7 2/9] virtio-gpu: CONTEXT_INIT feature Gurchetan Singh
2023-08-17  2:23 ` [PATCH v7 3/9] virtio-gpu: hostmem Gurchetan Singh
2023-08-17  2:23 ` [PATCH v7 4/9] virtio-gpu: blob prep Gurchetan Singh
2023-08-17  2:23 ` [PATCH v7 5/9] gfxstream + rutabaga prep: added need defintions, fields, and options Gurchetan Singh
2023-08-23 14:32   ` Mark Cave-Ayland
2023-08-24 23:47     ` Gurchetan Singh
2023-08-17  2:23 ` [PATCH v7 6/9] gfxstream + rutabaga: add initial support for gfxstream Gurchetan Singh
2023-08-18 11:58   ` Akihiko Odaki
2023-08-23 15:03   ` Mark Cave-Ayland
2023-08-24 23:50     ` Gurchetan Singh
2023-08-17  2:23 ` [PATCH v7 7/9] gfxstream + rutabaga: meson support Gurchetan Singh
2023-08-17  2:23 ` [PATCH v7 8/9] gfxstream + rutabaga: enable rutabaga Gurchetan Singh
2023-08-18 11:58   ` Akihiko Odaki
2023-08-19  1:14     ` Gurchetan Singh
2023-08-17  2:23 ` [PATCH v7 9/9] docs/system: add basic virtio-gpu documentation Gurchetan Singh
2023-08-17  5:28   ` Akihiko Odaki
2023-08-17 23:43     ` [PATCH v8 " Gurchetan Singh
2023-08-17 23:47     ` [PATCH v7 " Gurchetan Singh
2023-08-18 12:08       ` Akihiko Odaki
2023-08-19  1:17         ` Gurchetan Singh
2023-08-19  6:13           ` Akihiko Odaki
2023-08-22  0:20             ` Gurchetan Singh

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.