Re: [PATCH v6 10/11] virtio-gpu: Initialize Venus

2024-03-26 Thread Pierre-Eric Pelloux-Prayer




Le 23/02/2024 à 10:15, Huang Rui a écrit :

On Tue, Jan 02, 2024 at 09:33:11PM +0800, Marc-André Lureau wrote:

Hi

On Tue, Dec 19, 2023 at 11:55 AM Huang Rui  wrote:


From: Antonio Caggiano 

Request Venus when initializing VirGL.

Signed-off-by: Antonio Caggiano 
Signed-off-by: Huang Rui 
---

Changes in v6:
- Remove the unstable API flags check because virglrenderer is already 1.0.
- Squash the render server flag support into "Initialize Venus".

  hw/display/virtio-gpu-virgl.c | 4 
  1 file changed, 4 insertions(+)

diff --git a/hw/display/virtio-gpu-virgl.c b/hw/display/virtio-gpu-virgl.c
index f35a751824..c523a6717a 100644
--- a/hw/display/virtio-gpu-virgl.c
+++ b/hw/display/virtio-gpu-virgl.c
@@ -964,6 +964,10 @@ int virtio_gpu_virgl_init(VirtIOGPU *g)
  }
  #endif

+#ifdef VIRGL_RENDERER_VENUS
+flags |= VIRGL_RENDERER_VENUS | VIRGL_RENDERER_RENDER_SERVER;
+#endif
+


I wonder if it's a good idea to initialize venus by default. It
doesn't seem to require vulkan during initialization, but this may
evolve. Make it optional?



I am fine. In fact, vulkan is widely used for graphic area such as gaming,
compute, VR/AR, etc.


Actually, making it optional is useful because Venus support is optional in
virglrenderer (= having VIRGL_RENDERER_VENUS defined doesn't mean that
Venus is supported).

Thanks,
Pierre-Eric




Thanks,
Ray


  ret = virgl_renderer_init(g, flags, _gpu_3d_cbs);
  if (ret != 0) {
  error_report("virgl could not be initialized: %d", ret);
--
2.25.1




--
Marc-André Lureau






Re: [PATCH v6 07/11] virtio-gpu: Handle resource blob commands

2024-01-10 Thread Pierre-Eric Pelloux-Prayer




Le 21/12/2023 à 09:09, Akihiko Odaki a écrit :

On 2023/12/19 16:53, Huang Rui wrote:

From: Antonio Caggiano 

Support BLOB resources creation, mapping and unmapping by calling the
new stable virglrenderer 0.10 interface. Only enabled when available and
via the blob config. E.g. -device virtio-vga-gl,blob=true


I have another concern about delaying virgl_renderer_resource_unref() until the 
resource gets unmapped; the guest will expect the resource ID will be available 
for a new resource immediately after VIRTIO_GPU_CMD_RESOURCE_UNREF, but it will 
break the assumption and may corrupt things.



Yes this is a problem.

And another one is virglrenderer is not really thread-safe, so this callstack:

#0  virgl_resource_blob_async_unmap ()
#1  object_finalize ()
#2  object_unref ()
#3  memory_region_unref ()
#4  flatview_destroy ()
#5  call_rcu_thread ()
#6  qemu_thread_start ()

Will call into virgl_renderer_ctx_resource_unmap which in turn uses 
virgl_resource_lookup
without any multithreading considerations.


Regards,
Pierre-Eric



Re: [PATCH v6 07/11] virtio-gpu: Handle resource blob commands

2024-01-10 Thread Pierre-Eric Pelloux-Prayer




Le 09/01/2024 à 17:50, Pierre-Eric Pelloux-Prayer a écrit :



Le 19/12/2023 à 08:53, Huang Rui a écrit :

From: Antonio Caggiano 

Support BLOB resources creation, mapping and unmapping by calling the
new stable virglrenderer 0.10 interface. Only enabled when available and
via the blob config. E.g. -device virtio-vga-gl,blob=true

Signed-off-by: Antonio Caggiano 
Signed-off-by: Dmitry Osipenko 
Signed-off-by: Xenia Ragiadakou 
Signed-off-by: Huang Rui 
---

Changes in v6:
- Use new struct virgl_gpu_resource.
- Unmap, unref and destroy the resource only after the memory region
   has been completely removed.
- In unref check whether the resource is still mapped.
- In unmap_blob check whether the resource has been already unmapped.
- Fix coding style

  hw/display/virtio-gpu-virgl.c | 274 +-
  hw/display/virtio-gpu.c   |   4 +-
  meson.build   |   4 +
  3 files changed, 276 insertions(+), 6 deletions(-)

diff --git a/hw/display/virtio-gpu-virgl.c b/hw/display/virtio-gpu-virgl.c
index faab374336..5a3a292f79 100644
--- a/hw/display/virtio-gpu-virgl.c
+++ b/hw/display/virtio-gpu-virgl.c
@@ -17,6 +17,7 @@
  #include "trace.h"
  #include "hw/virtio/virtio.h"
  #include "hw/virtio/virtio-gpu.h"
+#include "hw/virtio/virtio-gpu-bswap.h"
  #include "ui/egl-helpers.h"
@@ -24,8 +25,62 @@
  struct virgl_gpu_resource {
  struct virtio_gpu_simple_resource res;
+    uint32_t ref;
+    VirtIOGPU *g;
+
+#ifdef HAVE_VIRGL_RESOURCE_BLOB
+    /* only blob resource needs this region to be mapped as guest mmio */
+    MemoryRegion *region;
+#endif
  };
+static void vres_get_ref(struct virgl_gpu_resource *vres)
+{
+    uint32_t ref;
+
+    ref = qatomic_fetch_inc(>ref);
+    g_assert(ref < INT_MAX);
+}
+
+static void virgl_resource_destroy(struct virgl_gpu_resource *vres)
+{
+    struct virtio_gpu_simple_resource *res;
+    VirtIOGPU *g;
+
+    if (!vres) {
+    return;
+    }
+
+    g = vres->g;
+    res = >res;
+    QTAILQ_REMOVE(>reslist, res, next);
+    virtio_gpu_cleanup_mapping(g, res);
+    g_free(vres);
+}
+
+static void virgl_resource_unref(struct virgl_gpu_resource *vres)
+{
+    struct virtio_gpu_simple_resource *res;
+
+    if (!vres) {
+    return;
+    }
+
+    res = >res;
+    virgl_renderer_resource_detach_iov(res->resource_id, NULL, NULL);
+    virgl_renderer_resource_unref(res->resource_id);
+}
+
+static void vres_put_ref(struct virgl_gpu_resource *vres)
+{
+    g_assert(vres->ref > 0);
+
+    if (qatomic_fetch_dec(>ref) == 1) {
+    virgl_resource_unref(vres);
+    virgl_resource_destroy(vres);
+    }
+}
+
  static struct virgl_gpu_resource *
  virgl_gpu_find_resource(VirtIOGPU *g, uint32_t resource_id)
  {
@@ -59,6 +114,8 @@ static void virgl_cmd_create_resource_2d(VirtIOGPU *g,
 c2d.width, c2d.height);
  vres = g_new0(struct virgl_gpu_resource, 1);
+    vres_get_ref(vres);
+    vres->g = g;
  vres->res.width = c2d.width;
  vres->res.height = c2d.height;
  vres->res.format = c2d.format;
@@ -91,6 +148,8 @@ static void virgl_cmd_create_resource_3d(VirtIOGPU *g,
 c3d.width, c3d.height, c3d.depth);
  vres = g_new0(struct virgl_gpu_resource, 1);
+    vres_get_ref(vres);
+    vres->g = g;
  vres->res.width = c3d.width;
  vres->res.height = c3d.height;
  vres->res.format = c3d.format;
@@ -126,12 +185,21 @@ static void virgl_cmd_resource_unref(VirtIOGPU *g,
  return;
  }
-    virgl_renderer_resource_detach_iov(unref.resource_id, NULL, NULL);
-    virgl_renderer_resource_unref(unref.resource_id);
+#ifdef HAVE_VIRGL_RESOURCE_BLOB
+    if (vres->region) {
+    VirtIOGPUBase *b = VIRTIO_GPU_BASE(g);
+    MemoryRegion *mr = vres->region;
+
+    warn_report("%s: blob resource %d not unmapped",
+    __func__, unref.resource_id);
+    vres->region = NULL;


Shouldn't there be a call to memory_region_unref(mr)?


+    memory_region_set_enabled(mr, false);
+    memory_region_del_subregion(>hostmem, mr);
+    object_unparent(OBJECT(mr));
+    }
+#endif /* HAVE_VIRGL_RESOURCE_BLOB */
-    QTAILQ_REMOVE(>reslist, >res, next);
-    virtio_gpu_cleanup_mapping(g, >res);
-    g_free(vres);
+    vres_put_ref(vres);
  }
  static void virgl_cmd_context_create(VirtIOGPU *g,
@@ -470,6 +538,191 @@ static void virgl_cmd_get_capset(VirtIOGPU *g,
  g_free(resp);
  }
+#ifdef HAVE_VIRGL_RESOURCE_BLOB
+
+static void virgl_resource_unmap(struct virgl_gpu_resource *vres)
+{
+    if (!vres) {
+    return;
+    }
+
+    virgl_renderer_resource_unmap(vres->res.resource_id);
+
+    vres_put_ref(vres);
+}
+
+static void virgl_resource_blob_async_unmap(void *obj)
+{
+    MemoryRegion *mr = MEMORY_REGION(obj);
+    struct virgl_gpu_reso

Re: [PATCH v6 07/11] virtio-gpu: Handle resource blob commands

2024-01-09 Thread Pierre-Eric Pelloux-Prayer




Le 19/12/2023 à 08:53, Huang Rui a écrit :

From: Antonio Caggiano 

Support BLOB resources creation, mapping and unmapping by calling the
new stable virglrenderer 0.10 interface. Only enabled when available and
via the blob config. E.g. -device virtio-vga-gl,blob=true

Signed-off-by: Antonio Caggiano 
Signed-off-by: Dmitry Osipenko 
Signed-off-by: Xenia Ragiadakou 
Signed-off-by: Huang Rui 
---

Changes in v6:
- Use new struct virgl_gpu_resource.
- Unmap, unref and destroy the resource only after the memory region
   has been completely removed.
- In unref check whether the resource is still mapped.
- In unmap_blob check whether the resource has been already unmapped.
- Fix coding style

  hw/display/virtio-gpu-virgl.c | 274 +-
  hw/display/virtio-gpu.c   |   4 +-
  meson.build   |   4 +
  3 files changed, 276 insertions(+), 6 deletions(-)

diff --git a/hw/display/virtio-gpu-virgl.c b/hw/display/virtio-gpu-virgl.c
index faab374336..5a3a292f79 100644
--- a/hw/display/virtio-gpu-virgl.c
+++ b/hw/display/virtio-gpu-virgl.c
@@ -17,6 +17,7 @@
  #include "trace.h"
  #include "hw/virtio/virtio.h"
  #include "hw/virtio/virtio-gpu.h"
+#include "hw/virtio/virtio-gpu-bswap.h"
  
  #include "ui/egl-helpers.h"
  
@@ -24,8 +25,62 @@
  
  struct virgl_gpu_resource {

  struct virtio_gpu_simple_resource res;
+uint32_t ref;
+VirtIOGPU *g;
+
+#ifdef HAVE_VIRGL_RESOURCE_BLOB
+/* only blob resource needs this region to be mapped as guest mmio */
+MemoryRegion *region;
+#endif
  };
  
+static void vres_get_ref(struct virgl_gpu_resource *vres)

+{
+uint32_t ref;
+
+ref = qatomic_fetch_inc(>ref);
+g_assert(ref < INT_MAX);
+}
+
+static void virgl_resource_destroy(struct virgl_gpu_resource *vres)
+{
+struct virtio_gpu_simple_resource *res;
+VirtIOGPU *g;
+
+if (!vres) {
+return;
+}
+
+g = vres->g;
+res = >res;
+QTAILQ_REMOVE(>reslist, res, next);
+virtio_gpu_cleanup_mapping(g, res);
+g_free(vres);
+}
+
+static void virgl_resource_unref(struct virgl_gpu_resource *vres)
+{
+struct virtio_gpu_simple_resource *res;
+
+if (!vres) {
+return;
+}
+
+res = >res;
+virgl_renderer_resource_detach_iov(res->resource_id, NULL, NULL);
+virgl_renderer_resource_unref(res->resource_id);
+}
+
+static void vres_put_ref(struct virgl_gpu_resource *vres)
+{
+g_assert(vres->ref > 0);
+
+if (qatomic_fetch_dec(>ref) == 1) {
+virgl_resource_unref(vres);
+virgl_resource_destroy(vres);
+}
+}
+
  static struct virgl_gpu_resource *
  virgl_gpu_find_resource(VirtIOGPU *g, uint32_t resource_id)
  {
@@ -59,6 +114,8 @@ static void virgl_cmd_create_resource_2d(VirtIOGPU *g,
 c2d.width, c2d.height);
  
  vres = g_new0(struct virgl_gpu_resource, 1);

+vres_get_ref(vres);
+vres->g = g;
  vres->res.width = c2d.width;
  vres->res.height = c2d.height;
  vres->res.format = c2d.format;
@@ -91,6 +148,8 @@ static void virgl_cmd_create_resource_3d(VirtIOGPU *g,
 c3d.width, c3d.height, c3d.depth);
  
  vres = g_new0(struct virgl_gpu_resource, 1);

+vres_get_ref(vres);
+vres->g = g;
  vres->res.width = c3d.width;
  vres->res.height = c3d.height;
  vres->res.format = c3d.format;
@@ -126,12 +185,21 @@ static void virgl_cmd_resource_unref(VirtIOGPU *g,
  return;
  }
  
-virgl_renderer_resource_detach_iov(unref.resource_id, NULL, NULL);

-virgl_renderer_resource_unref(unref.resource_id);
+#ifdef HAVE_VIRGL_RESOURCE_BLOB
+if (vres->region) {
+VirtIOGPUBase *b = VIRTIO_GPU_BASE(g);
+MemoryRegion *mr = vres->region;
+
+warn_report("%s: blob resource %d not unmapped",
+__func__, unref.resource_id);
+vres->region = NULL;


Shouldn't there be a call to memory_region_unref(mr)?


+memory_region_set_enabled(mr, false);
+memory_region_del_subregion(>hostmem, mr);
+object_unparent(OBJECT(mr));
+}
+#endif /* HAVE_VIRGL_RESOURCE_BLOB */
  
-QTAILQ_REMOVE(>reslist, >res, next);

-virtio_gpu_cleanup_mapping(g, >res);
-g_free(vres);
+vres_put_ref(vres);
  }
  
  static void virgl_cmd_context_create(VirtIOGPU *g,

@@ -470,6 +538,191 @@ static void virgl_cmd_get_capset(VirtIOGPU *g,
  g_free(resp);
  }
  
+#ifdef HAVE_VIRGL_RESOURCE_BLOB

+
+static void virgl_resource_unmap(struct virgl_gpu_resource *vres)
+{
+if (!vres) {
+return;
+}
+
+virgl_renderer_resource_unmap(vres->res.resource_id);
+
+vres_put_ref(vres);
+}
+
+static void virgl_resource_blob_async_unmap(void *obj)
+{
+MemoryRegion *mr = MEMORY_REGION(obj);
+struct virgl_gpu_resource *vres = mr->opaque;
+
+virgl_resource_unmap(vres);
+
+g_free(obj);
+}
+
+static void virgl_cmd_resource_create_blob(VirtIOGPU *g,
+   struct 

Re: [PATCH v6 11/11] virtio-gpu: make blob scanout use dmabuf fd

2024-01-04 Thread Pierre-Eric Pelloux-Prayer



Le 21/12/2023 à 07:25, Akihiko Odaki a écrit :

On 2023/12/19 16:53, Huang Rui wrote:

From: Robert Beckett 

This relies on a virglrenderer change to include the dmabuf fd when
returning resource info.

Signed-off-by: Robert Beckett 
Signed-off-by: Huang Rui 
---

Changes in v6:
- Add scanout_blob function for virtio-gpu-virgl.
- Update for new virgl_gpu_resource.

  hw/display/virtio-gpu-virgl.c  | 104 +
  hw/display/virtio-gpu.c    |   4 +-
  include/hw/virtio/virtio-gpu.h |   6 ++
  3 files changed, 112 insertions(+), 2 deletions(-)

diff --git a/hw/display/virtio-gpu-virgl.c b/hw/display/virtio-gpu-virgl.c
index c523a6717a..c384225a98 100644
--- a/hw/display/virtio-gpu-virgl.c
+++ b/hw/display/virtio-gpu-virgl.c
@@ -18,6 +18,7 @@
  #include "hw/virtio/virtio.h"
  #include "hw/virtio/virtio-gpu.h"
  #include "hw/virtio/virtio-gpu-bswap.h"
+#include "hw/virtio/virtio-gpu-pixman.h"
  #include "ui/egl-helpers.h"
@@ -726,6 +727,106 @@ static void virgl_cmd_resource_unmap_blob(VirtIOGPU *g,
  object_unparent(OBJECT(mr));
  }
+static void virgl_cmd_set_scanout_blob(VirtIOGPU *g,
+   struct virtio_gpu_ctrl_command *cmd)
+{
+    struct virgl_gpu_resource *vres;
+    struct virtio_gpu_framebuffer fb = { 0 };
+    struct virtio_gpu_set_scanout_blob ss;
+    struct virgl_renderer_resource_info info;
+    uint64_t fbend;
+
+    VIRTIO_GPU_FILL_CMD(ss);
+    virtio_gpu_scanout_blob_bswap();
+    trace_virtio_gpu_cmd_set_scanout_blob(ss.scanout_id, ss.resource_id,
+  ss.r.width, ss.r.height, ss.r.x,
+  ss.r.y);
+
+    if (ss.scanout_id >= g->parent_obj.conf.max_outputs) {
+    qemu_log_mask(LOG_GUEST_ERROR, "%s: illegal scanout id specified %d",
+  __func__, ss.scanout_id);
+    cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_SCANOUT_ID;
+    return;
+    }
+
+    if (ss.resource_id == 0) {
+    virtio_gpu_disable_scanout(g, ss.scanout_id);
+    return;
+    }
+
+    if (ss.width < 16 ||
+    ss.height < 16 ||
+    ss.r.x + ss.r.width > ss.width ||
+    ss.r.y + ss.r.height > ss.height) {
+    qemu_log_mask(LOG_GUEST_ERROR, "%s: illegal scanout %d bounds for"
+  " resource %d, rect (%d,%d)+%d,%d, fb %d %d\n",
+  __func__, ss.scanout_id, ss.resource_id,
+  ss.r.x, ss.r.y, ss.r.width, ss.r.height,
+  ss.width, ss.height);
+    cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_PARAMETER;
+    return;
+    }
+
+    if (!console_has_gl(g->parent_obj.scanout[ss.scanout_id].con)) {


Shouldn't OpenGL always be available for virgl?


+    qemu_log_mask(LOG_GUEST_ERROR, "%s: unable to scanout blot without 
GL!\n", __func__);
+    return;
+    }
+
+    vres = virgl_gpu_find_resource(g, ss.resource_id);
+    if (!vres) {
+    qemu_log_mask(LOG_GUEST_ERROR,
+  "%s: illegal resource specified %d\n",
+  __func__, ss.resource_id);
+    cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID;
+    return;
+    }
+    if (virgl_renderer_resource_get_info(ss.resource_id, )) {
+    qemu_log_mask(LOG_GUEST_ERROR,
+  "%s: illegal virgl resource specified %d\n",
+  __func__, ss.resource_id);
+    cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID;
+    return;
+    }
+    if (!vres->res.dmabuf_fd && info.fd)
+    vres->res.dmabuf_fd = info.fd;
+
+    fb.format = virtio_gpu_get_pixman_format(ss.format);
+    if (!fb.format) {
+    qemu_log_mask(LOG_GUEST_ERROR,
+  "%s: host couldn't handle guest format %d\n",
+  __func__, ss.format);
+    cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_PARAMETER;
+    return;
+    }
+
+    fb.bytes_pp = DIV_ROUND_UP(PIXMAN_FORMAT_BPP(fb.format), 8);
+    fb.width = ss.width;
+    fb.height = ss.height;
+    fb.stride = ss.strides[0];
+    fb.offset = ss.offsets[0] + ss.r.x * fb.bytes_pp + ss.r.y * fb.stride;
+
+    fbend = fb.offset;
+    fbend += fb.stride * (ss.r.height - 1);
+    fbend += fb.bytes_pp * ss.r.width;
+    if (fbend > vres->res.blob_size) {
+    qemu_log_mask(LOG_GUEST_ERROR,
+  "%s: fb end out of range\n",
+  __func__);
+    cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_PARAMETER;
+    return;
+    }
+
+    g->parent_obj.enable = 1;
+    if (virtio_gpu_update_dmabuf(g, ss.scanout_id, >res,
+ , )) {
+    qemu_log_mask(LOG_GUEST_ERROR,
+  "%s: failed to update dmabuf\n", __func__);
+    cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_PARAMETER;
+    return;
+    }
+    virtio_gpu_update_scanout(g, ss.scanout_id, >res, );
+}
+
  #endif /* HAVE_VIRGL_RESOURCE_BLOB */
  void virtio_gpu_virgl_process_cmd(VirtIOGPU *g,
@@ -807,6 +908,9 @@ void 

Re: [PATCH v6 09/11] virtio-gpu: Support Venus capset

2023-12-19 Thread Pierre-Eric Pelloux-Prayer

Hi Ray, Antonio,


Le 19/12/2023 à 08:53, Huang Rui a écrit :

From: Antonio Caggiano 

Add support for the Venus capset, which enables Vulkan support through
the Venus Vulkan driver for virtio-gpu.

Signed-off-by: Antonio Caggiano 
Signed-off-by: Huang Rui 
---

No change in v6.

  hw/display/virtio-gpu-virgl.c | 21 +
  1 file changed, 17 insertions(+), 4 deletions(-)

diff --git a/hw/display/virtio-gpu-virgl.c b/hw/display/virtio-gpu-virgl.c
index be9da6e780..f35a751824 100644
--- a/hw/display/virtio-gpu-virgl.c
+++ b/hw/display/virtio-gpu-virgl.c
@@ -506,6 +506,11 @@ static void virgl_cmd_get_capset_info(VirtIOGPU *g,
  virgl_renderer_get_cap_set(resp.capset_id,
 _max_version,
 _max_size);
+} else if (info.capset_index == 2) {
+resp.capset_id = VIRTIO_GPU_CAPSET_VENUS;
+virgl_renderer_get_cap_set(resp.capset_id,
+   _max_version,
+   _max_size);
  } else {
  resp.capset_max_version = 0;
  resp.capset_max_size = 0;
@@ -978,10 +983,18 @@ int virtio_gpu_virgl_init(VirtIOGPU *g)
  
  int virtio_gpu_virgl_get_num_capsets(VirtIOGPU *g)

  {
-uint32_t capset2_max_ver, capset2_max_size;
+uint32_t capset2_max_ver, capset2_max_size, num_capsets;
+num_capsets = 1;
+
  virgl_renderer_get_cap_set(VIRTIO_GPU_CAPSET_VIRGL2,
-  _max_ver,
-  _max_size);
+   _max_ver,
+   _max_size);
+num_capsets += capset2_max_ver ? 1 : 0;
+
+virgl_renderer_get_cap_set(VIRTIO_GPU_CAPSET_VENUS,
+   _max_ver,
+   _max_size);
+num_capsets += capset2_max_size ? 1 : 0;


IMHO the logic here doesn't work.

The kernel will use num_capset like this:

for (i = 0; i < num_capsets; i++) {
virtio_gpu_cmd_get_capset_info(vgdev, i);

So if num_capset = 2, it will query the capset info of index 0 and 1.
Capset 0 is alway VIRGL so it's fine. But since VIRL2 support is optional,
QEMU has no way to know if index 1 is VIRGL2 (if it's supported)
or VENUS (if VIRGL2 support is missing).
And it'll get worse when we will want to support CAPSET_DRM.

Ray: we have a patch internally for this (virtio-gpu: fix capset query), you
may want to add it to this series, before this patch.

Regards,
Pierre-Eric



  
-return capset2_max_ver ? 2 : 1;

+return num_capsets;
  }