All of lore.kernel.org
 help / color / mirror / Atom feed
From: Huang Rui via <qemu-devel@nongnu.org>
To: Pierre-Eric Pelloux-Prayer <pierre-eric@damsy.net>
Cc: "Akihiko Odaki" <akihiko.odaki@daynix.com>,
	"Marc-André Lureau" <marcandre.lureau@gmail.com>,
	"Philippe Mathieu-Daudé" <philmd@linaro.org>,
	"Gerd Hoffmann" <kraxel@redhat.com>,
	"Michael S . Tsirkin" <mst@redhat.com>,
	"Stefano Stabellini" <sstabellini@kernel.org>,
	"Anthony PERARD" <anthony.perard@citrix.com>,
	"Antonio Caggiano" <quic_acaggian@quicinc.com>,
	"Dr . David Alan Gilbert" <dgilbert@redhat.com>,
	"Robert Beckett" <bob.beckett@collabora.com>,
	"Dmitry Osipenko" <dmitry.osipenko@collabora.com>,
	"Gert Wollny" <gert.wollny@collabora.com>,
	"Alex Bennée" <alex.bennee@linaro.org>,
	"qemu-devel@nongnu.org" <qemu-devel@nongnu.org>,
	"xen-devel@lists.xenproject.org" <xen-devel@lists.xenproject.org>,
	"Gurchetan Singh" <gurchetansingh@chromium.org>,
	"ernunes@redhat.com" <ernunes@redhat.com>,
	"Alyssa Ross" <hi@alyssa.is>,
	"Roger Pau Monné" <roger.pau@citrix.com>,
	"Deucher, Alexander" <Alexander.Deucher@amd.com>,
	"Stabellini, Stefano" <stefano.stabellini@amd.com>,
	"Koenig, Christian" <Christian.Koenig@amd.com>,
	"Ragiadakou, Xenia" <Xenia.Ragiadakou@amd.com>,
	"Pelloux-Prayer,
	Pierre-Eric" <Pierre-eric.Pelloux-prayer@amd.com>,
	"Huang, Honglei1" <Honglei1.Huang@amd.com>,
	"Zhang, Julia" <Julia.Zhang@amd.com>,
	"Chen, Jiqian" <Jiqian.Chen@amd.com>,
	"Antonio Caggiano" <antonio.caggiano@collabora.com>
Subject: Re: [PATCH v6 07/11] virtio-gpu: Handle resource blob commands
Date: Fri, 23 Feb 2024 14:34:53 +0800	[thread overview]
Message-ID: <Zdg8jYYI1e3+xyJi@amd.com> (raw)
In-Reply-To: <c986f552-60b8-471a-a439-a8714936fa47@damsy.net>

On Wed, Jan 10, 2024 at 04:51:31PM +0800, Pierre-Eric Pelloux-Prayer wrote:
> 
> 
> 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 <antonio.caggiano@collabora.com>
> >>
> >> 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 <antonio.caggiano@collabora.com>
> >> Signed-off-by: Dmitry Osipenko <dmitry.osipenko@collabora.com>
> >> Signed-off-by: Xenia Ragiadakou <xenia.ragiadakou@amd.com>
> >> Signed-off-by: Huang Rui <ray.huang@amd.com>
> >> ---
> >>
> >> 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(&vres->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 = &vres->res;
> >> +    QTAILQ_REMOVE(&g->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 = &vres->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(&vres->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(&b->hostmem, mr);
> >> +        object_unparent(OBJECT(mr));
> >> +    }
> >> +#endif /* HAVE_VIRGL_RESOURCE_BLOB */
> >> -    QTAILQ_REMOVE(&g->reslist, &vres->res, next);
> >> -    virtio_gpu_cleanup_mapping(g, &vres->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 virtio_gpu_ctrl_command *cmd)
> >> +{
> >> +    struct virgl_gpu_resource *vres;
> >> +    struct virtio_gpu_resource_create_blob cblob;
> >> +    struct virgl_renderer_resource_create_blob_args virgl_args = { 0 };
> >> +    int ret;
> >> +
> >> +    VIRTIO_GPU_FILL_CMD(cblob);
> >> +    virtio_gpu_create_blob_bswap(&cblob);
> >> +    trace_virtio_gpu_cmd_res_create_blob(cblob.resource_id, cblob.size);
> >> +
> >> +    if (cblob.resource_id == 0) {
> >> +        qemu_log_mask(LOG_GUEST_ERROR, "%s: resource id 0 is not allowed\n",
> >> +                      __func__);
> >> +        cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID;
> >> +        return;
> >> +    }
> >> +
> >> +    vres = virgl_gpu_find_resource(g, cblob.resource_id);
> >> +    if (vres) {
> >> +        qemu_log_mask(LOG_GUEST_ERROR, "%s: resource already exists %d\n",
> >> +                      __func__, cblob.resource_id);
> >> +        cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID;
> >> +        return;
> >> +    }
> >> +
> >> +    vres = g_new0(struct virgl_gpu_resource, 1);
> >> +    vres_get_ref(vres);
> >> +    vres->g = g;
> >> +    vres->res.resource_id = cblob.resource_id;
> >> +    vres->res.blob_size = cblob.size;
> >> +
> >> +    if (cblob.blob_mem != VIRTIO_GPU_BLOB_MEM_HOST3D) {
> >> +        ret = virtio_gpu_create_mapping_iov(g, cblob.nr_entries, sizeof(cblob),
> >> +                                            cmd, &vres->res.addrs,
> >> +                                            &vres->res.iov, &vres->res.iov_cnt);
> >> +        if (!ret) {
> >> +            g_free(vres);
> >> +            cmd->error = VIRTIO_GPU_RESP_ERR_UNSPEC;
> >> +            return;
> >> +        }
> >> +    }
> >> +
> >> +    QTAILQ_INSERT_HEAD(&g->reslist, &vres->res, next);
> >> +
> >> +    virgl_args.res_handle = cblob.resource_id;
> >> +    virgl_args.ctx_id = cblob.hdr.ctx_id;
> >> +    virgl_args.blob_mem = cblob.blob_mem;
> >> +    virgl_args.blob_id = cblob.blob_id;
> >> +    virgl_args.blob_flags = cblob.blob_flags;
> >> +    virgl_args.size = cblob.size;
> >> +    virgl_args.iovecs = vres->res.iov;
> >> +    virgl_args.num_iovs = vres->res.iov_cnt;
> >> +
> >> +    ret = virgl_renderer_resource_create_blob(&virgl_args);
> >> +    if (ret) {
> >> +        qemu_log_mask(LOG_GUEST_ERROR, "%s: virgl blob create error: %s\n",
> >> +                      __func__, strerror(-ret));
> >> +        cmd->error = VIRTIO_GPU_RESP_ERR_UNSPEC;
> >> +    }
> >> +}
> >> +
> >> +static void virgl_cmd_resource_map_blob(VirtIOGPU *g,
> >> +                                        struct virtio_gpu_ctrl_command *cmd)
> >> +{
> >> +    struct virgl_gpu_resource *vres;
> >> +    struct virtio_gpu_resource_map_blob mblob;
> >> +    int ret;
> >> +    void *data;
> >> +    uint64_t size;
> >> +    struct virtio_gpu_resp_map_info resp;
> >> +    VirtIOGPUBase *b = VIRTIO_GPU_BASE(g);
> >> +
> >> +    VIRTIO_GPU_FILL_CMD(mblob);
> >> +    virtio_gpu_map_blob_bswap(&mblob);
> >> +
> >> +    if (mblob.resource_id == 0) {
> >> +        qemu_log_mask(LOG_GUEST_ERROR, "%s: resource id 0 is not allowed\n",
> >> +                      __func__);
> >> +        cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID;
> >> +        return;
> >> +    }
> >> +
> >> +    vres = virgl_gpu_find_resource(g, mblob.resource_id);
> >> +    if (!vres) {
> >> +        qemu_log_mask(LOG_GUEST_ERROR, "%s: resource does not exist %d\n",
> >> +                      __func__, mblob.resource_id);
> >> +        cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID;
> >> +        return;
> >> +    }
> >> +    if (vres->region) {
> >> +        qemu_log_mask(LOG_GUEST_ERROR, "%s: resource already mapped %d\n",
> >> +                      __func__, mblob.resource_id);
> >> +        cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID;
> >> +        return;
> >> +    }
> >> +
> >> +    ret = virgl_renderer_resource_map(vres->res.resource_id, &data, &size);
> >> +    if (ret) {
> >> +        qemu_log_mask(LOG_GUEST_ERROR, "%s: resource map error: %s\n",
> >> +                      __func__, strerror(-ret));
> >> +        cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID;
> >> +        return;
> >> +    }
> >> +
> >> +    vres_get_ref(vres);
> > 
> > Why is this needed? And if it is, shouldn't virgl_cmd_resource_unmap_blob
> > call "vres_put_ref(vres)" ?
> > 
> >> +    vres->region = g_new0(MemoryRegion, 1);
> >> +    memory_region_init_ram_ptr(vres->region, OBJECT(g), NULL, size, data);
> >> +    vres->region->opaque = vres;
> >> +    OBJECT(vres->region)->free = virgl_resource_blob_async_unmap;
> >> +    memory_region_add_subregion(&b->hostmem, mblob.offset, vres->region);
> >> +    memory_region_set_enabled(vres->region, true);
> >> +
> >> +    memset(&resp, 0, sizeof(resp));
> >> +    resp.hdr.type = VIRTIO_GPU_RESP_OK_MAP_INFO;
> >> +    virgl_renderer_resource_get_map_info(mblob.resource_id, &resp.map_info);
> >> +    virtio_gpu_ctrl_response(g, cmd, &resp.hdr, sizeof(resp));
> >> +}
> >> +
> >> +static void virgl_cmd_resource_unmap_blob(VirtIOGPU *g,
> >> +                                          struct virtio_gpu_ctrl_command *cmd)
> >> +{
> >> +    struct virgl_gpu_resource *vres;
> >> +    struct virtio_gpu_resource_unmap_blob ublob;
> >> +    VirtIOGPUBase *b = VIRTIO_GPU_BASE(g);
> >> +    MemoryRegion *mr;
> >> +
> >> +    VIRTIO_GPU_FILL_CMD(ublob);
> >> +    virtio_gpu_unmap_blob_bswap(&ublob);
> >> +
> >> +    if (ublob.resource_id == 0) {
> >> +        qemu_log_mask(LOG_GUEST_ERROR, "%s: resource id 0 is not allowed\n",
> >> +                      __func__);
> >> +        cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID;
> >> +        return;
> >> +    }
> >> +
> >> +    vres = virgl_gpu_find_resource(g, ublob.resource_id);
> >> +    if (!vres) {
> >> +        qemu_log_mask(LOG_GUEST_ERROR, "%s: resource does not exist %d\n",
> >> +                      __func__, ublob.resource_id);
> >> +        cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID;
> >> +        return;
> >> +    }
> >> +
> >> +    if (!vres->region) {
> >> +        qemu_log_mask(LOG_GUEST_ERROR, "%s: resource already unmapped %d\n",
> >> +                      __func__, ublob.resource_id);
> >> +        cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID;
> >> +        return;
> >> +    }
> >> +
> >> +    mr = vres->region;
> >> +    vres->region = NULL;
> > 
> > memory_region_unref(mr)?
> > 
> > Note that AFAICT without the added memory_region_unref() calls virgl_resource_unmap()
> > was never called.
> 
> 
> Xenia and I figured out the refcounting issue: this code is written based on the
> assumption that:
>   
>     object_unparent(OBJECT(mr));
> 
> 
> Will decrement the refcount. But this assumption is only true if mr->parent_obj.parent
> is non-NULL.
> 
> The map_blob function uses the following arguments:
> 
>     memory_region_init_ram_ptr(vres->region, OBJECT(g), NULL, size, data);
> 
> Since name is NULL, mr won't be added as a child of 'g' and thus object_unparent()
> does nothing.
> 
> I'd suggest 2 changes:
>     * use a name ("blob_memory"?) to so mr can be a child of g
>     * increment mr's refcount when setting vres->region and decrement it when clearing it.
>       This change is not needed technically but when a variable is refcounted it seems
>       clearer to increment/decrement the refcount in these situations.
> 

Yes, issue is caused by NULL in name field, I will update according to your
suggestions in V7.

Thanks,
Ray

> 
> Pierre-Eric
> 
> 
> > 
> >> +    memory_region_set_enabled(mr, false);
> >> +    memory_region_del_subregion(&b->hostmem, mr);
> >> +    object_unparent(OBJECT(mr));
> >> +}
> >> +
> >> +#endif /* HAVE_VIRGL_RESOURCE_BLOB */
> >> +
> >>   void virtio_gpu_virgl_process_cmd(VirtIOGPU *g,
> >>                                         struct virtio_gpu_ctrl_command *cmd)
> >>   {
> >> @@ -536,6 +789,17 @@ void virtio_gpu_virgl_process_cmd(VirtIOGPU *g,
> >>       case VIRTIO_GPU_CMD_GET_EDID:
> >>           virtio_gpu_get_edid(g, cmd);
> >>           break;
> >> +#ifdef HAVE_VIRGL_RESOURCE_BLOB
> >> +    case VIRTIO_GPU_CMD_RESOURCE_CREATE_BLOB:
> >> +        virgl_cmd_resource_create_blob(g, cmd);
> >> +        break;
> >> +    case VIRTIO_GPU_CMD_RESOURCE_MAP_BLOB:
> >> +        virgl_cmd_resource_map_blob(g, cmd);
> >> +        break;
> >> +    case VIRTIO_GPU_CMD_RESOURCE_UNMAP_BLOB:
> >> +        virgl_cmd_resource_unmap_blob(g, cmd);
> >> +        break;
> >> +#endif /* HAVE_VIRGL_RESOURCE_BLOB */
> >>       default:
> >>           cmd->error = VIRTIO_GPU_RESP_ERR_UNSPEC;
> >>           break;
> >> diff --git a/hw/display/virtio-gpu.c b/hw/display/virtio-gpu.c
> >> index 4c3ec9d0ea..8189c392dc 100644
> >> --- a/hw/display/virtio-gpu.c
> >> +++ b/hw/display/virtio-gpu.c
> >> @@ -1449,10 +1449,12 @@ void virtio_gpu_device_realize(DeviceState *qdev, Error **errp)
> >>               return;
> >>           }
> >> +#ifndef HAVE_VIRGL_RESOURCE_BLOB
> >>           if (virtio_gpu_virgl_enabled(g->parent_obj.conf)) {
> >> -            error_setg(errp, "blobs and virgl are not compatible (yet)");
> >> +            error_setg(errp, "Linked virglrenderer does not support blob resources");
> >>               return;
> >>           }
> >> +#endif
> >>       }
> >>       if (!virtio_gpu_base_device_realize(qdev,
> >> diff --git a/meson.build b/meson.build
> >> index ea52ef1b9c..629407128e 100644
> >> --- a/meson.build
> >> +++ b/meson.build
> >> @@ -1054,6 +1054,10 @@ if not get_option('virglrenderer').auto() or have_system or have_vhost_user_gpu
> >>                            cc.has_function('virgl_renderer_context_create_with_flags',
> >>                                            prefix: '#include <virglrenderer.h>',
> >>                                            dependencies: virgl))
> >> +    config_host_data.set('HAVE_VIRGL_RESOURCE_BLOB',
> >> +                         cc.has_function('virgl_renderer_resource_create_blob',
> >> +                                         prefix: '#include <virglrenderer.h>',
> >> +                                         dependencies: virgl))
> >>     endif
> >>   endif
> >>   rutabaga = not_found
> > 


WARNING: multiple messages have this Message-ID (diff)
From: Huang Rui <ray.huang@amd.com>
To: Pierre-Eric Pelloux-Prayer <pierre-eric@damsy.net>
Cc: "Akihiko Odaki" <akihiko.odaki@daynix.com>,
	"Marc-André Lureau" <marcandre.lureau@gmail.com>,
	"Philippe Mathieu-Daudé" <philmd@linaro.org>,
	"Gerd Hoffmann" <kraxel@redhat.com>,
	"Michael S . Tsirkin" <mst@redhat.com>,
	"Stefano Stabellini" <sstabellini@kernel.org>,
	"Anthony PERARD" <anthony.perard@citrix.com>,
	"Antonio Caggiano" <quic_acaggian@quicinc.com>,
	"Dr . David Alan Gilbert" <dgilbert@redhat.com>,
	"Robert Beckett" <bob.beckett@collabora.com>,
	"Dmitry Osipenko" <dmitry.osipenko@collabora.com>,
	"Gert Wollny" <gert.wollny@collabora.com>,
	"Alex Bennée" <alex.bennee@linaro.org>,
	"qemu-devel@nongnu.org" <qemu-devel@nongnu.org>,
	"xen-devel@lists.xenproject.org" <xen-devel@lists.xenproject.org>,
	"Gurchetan Singh" <gurchetansingh@chromium.org>,
	"ernunes@redhat.com" <ernunes@redhat.com>,
	"Alyssa Ross" <hi@alyssa.is>,
	"Roger Pau Monné" <roger.pau@citrix.com>,
	"Deucher, Alexander" <Alexander.Deucher@amd.com>,
	"Stabellini, Stefano" <stefano.stabellini@amd.com>,
	"Koenig, Christian" <Christian.Koenig@amd.com>,
	"Ragiadakou, Xenia" <Xenia.Ragiadakou@amd.com>,
	"Pelloux-Prayer,
	Pierre-Eric" <Pierre-eric.Pelloux-prayer@amd.com>,
	"Huang, Honglei1" <Honglei1.Huang@amd.com>,
	"Zhang, Julia" <Julia.Zhang@amd.com>,
	"Chen, Jiqian" <Jiqian.Chen@amd.com>,
	"Antonio Caggiano" <antonio.caggiano@collabora.com>
Subject: Re: [PATCH v6 07/11] virtio-gpu: Handle resource blob commands
Date: Fri, 23 Feb 2024 14:34:53 +0800	[thread overview]
Message-ID: <Zdg8jYYI1e3+xyJi@amd.com> (raw)
In-Reply-To: <c986f552-60b8-471a-a439-a8714936fa47@damsy.net>

On Wed, Jan 10, 2024 at 04:51:31PM +0800, Pierre-Eric Pelloux-Prayer wrote:
> 
> 
> 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 <antonio.caggiano@collabora.com>
> >>
> >> 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 <antonio.caggiano@collabora.com>
> >> Signed-off-by: Dmitry Osipenko <dmitry.osipenko@collabora.com>
> >> Signed-off-by: Xenia Ragiadakou <xenia.ragiadakou@amd.com>
> >> Signed-off-by: Huang Rui <ray.huang@amd.com>
> >> ---
> >>
> >> 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(&vres->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 = &vres->res;
> >> +    QTAILQ_REMOVE(&g->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 = &vres->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(&vres->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(&b->hostmem, mr);
> >> +        object_unparent(OBJECT(mr));
> >> +    }
> >> +#endif /* HAVE_VIRGL_RESOURCE_BLOB */
> >> -    QTAILQ_REMOVE(&g->reslist, &vres->res, next);
> >> -    virtio_gpu_cleanup_mapping(g, &vres->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 virtio_gpu_ctrl_command *cmd)
> >> +{
> >> +    struct virgl_gpu_resource *vres;
> >> +    struct virtio_gpu_resource_create_blob cblob;
> >> +    struct virgl_renderer_resource_create_blob_args virgl_args = { 0 };
> >> +    int ret;
> >> +
> >> +    VIRTIO_GPU_FILL_CMD(cblob);
> >> +    virtio_gpu_create_blob_bswap(&cblob);
> >> +    trace_virtio_gpu_cmd_res_create_blob(cblob.resource_id, cblob.size);
> >> +
> >> +    if (cblob.resource_id == 0) {
> >> +        qemu_log_mask(LOG_GUEST_ERROR, "%s: resource id 0 is not allowed\n",
> >> +                      __func__);
> >> +        cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID;
> >> +        return;
> >> +    }
> >> +
> >> +    vres = virgl_gpu_find_resource(g, cblob.resource_id);
> >> +    if (vres) {
> >> +        qemu_log_mask(LOG_GUEST_ERROR, "%s: resource already exists %d\n",
> >> +                      __func__, cblob.resource_id);
> >> +        cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID;
> >> +        return;
> >> +    }
> >> +
> >> +    vres = g_new0(struct virgl_gpu_resource, 1);
> >> +    vres_get_ref(vres);
> >> +    vres->g = g;
> >> +    vres->res.resource_id = cblob.resource_id;
> >> +    vres->res.blob_size = cblob.size;
> >> +
> >> +    if (cblob.blob_mem != VIRTIO_GPU_BLOB_MEM_HOST3D) {
> >> +        ret = virtio_gpu_create_mapping_iov(g, cblob.nr_entries, sizeof(cblob),
> >> +                                            cmd, &vres->res.addrs,
> >> +                                            &vres->res.iov, &vres->res.iov_cnt);
> >> +        if (!ret) {
> >> +            g_free(vres);
> >> +            cmd->error = VIRTIO_GPU_RESP_ERR_UNSPEC;
> >> +            return;
> >> +        }
> >> +    }
> >> +
> >> +    QTAILQ_INSERT_HEAD(&g->reslist, &vres->res, next);
> >> +
> >> +    virgl_args.res_handle = cblob.resource_id;
> >> +    virgl_args.ctx_id = cblob.hdr.ctx_id;
> >> +    virgl_args.blob_mem = cblob.blob_mem;
> >> +    virgl_args.blob_id = cblob.blob_id;
> >> +    virgl_args.blob_flags = cblob.blob_flags;
> >> +    virgl_args.size = cblob.size;
> >> +    virgl_args.iovecs = vres->res.iov;
> >> +    virgl_args.num_iovs = vres->res.iov_cnt;
> >> +
> >> +    ret = virgl_renderer_resource_create_blob(&virgl_args);
> >> +    if (ret) {
> >> +        qemu_log_mask(LOG_GUEST_ERROR, "%s: virgl blob create error: %s\n",
> >> +                      __func__, strerror(-ret));
> >> +        cmd->error = VIRTIO_GPU_RESP_ERR_UNSPEC;
> >> +    }
> >> +}
> >> +
> >> +static void virgl_cmd_resource_map_blob(VirtIOGPU *g,
> >> +                                        struct virtio_gpu_ctrl_command *cmd)
> >> +{
> >> +    struct virgl_gpu_resource *vres;
> >> +    struct virtio_gpu_resource_map_blob mblob;
> >> +    int ret;
> >> +    void *data;
> >> +    uint64_t size;
> >> +    struct virtio_gpu_resp_map_info resp;
> >> +    VirtIOGPUBase *b = VIRTIO_GPU_BASE(g);
> >> +
> >> +    VIRTIO_GPU_FILL_CMD(mblob);
> >> +    virtio_gpu_map_blob_bswap(&mblob);
> >> +
> >> +    if (mblob.resource_id == 0) {
> >> +        qemu_log_mask(LOG_GUEST_ERROR, "%s: resource id 0 is not allowed\n",
> >> +                      __func__);
> >> +        cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID;
> >> +        return;
> >> +    }
> >> +
> >> +    vres = virgl_gpu_find_resource(g, mblob.resource_id);
> >> +    if (!vres) {
> >> +        qemu_log_mask(LOG_GUEST_ERROR, "%s: resource does not exist %d\n",
> >> +                      __func__, mblob.resource_id);
> >> +        cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID;
> >> +        return;
> >> +    }
> >> +    if (vres->region) {
> >> +        qemu_log_mask(LOG_GUEST_ERROR, "%s: resource already mapped %d\n",
> >> +                      __func__, mblob.resource_id);
> >> +        cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID;
> >> +        return;
> >> +    }
> >> +
> >> +    ret = virgl_renderer_resource_map(vres->res.resource_id, &data, &size);
> >> +    if (ret) {
> >> +        qemu_log_mask(LOG_GUEST_ERROR, "%s: resource map error: %s\n",
> >> +                      __func__, strerror(-ret));
> >> +        cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID;
> >> +        return;
> >> +    }
> >> +
> >> +    vres_get_ref(vres);
> > 
> > Why is this needed? And if it is, shouldn't virgl_cmd_resource_unmap_blob
> > call "vres_put_ref(vres)" ?
> > 
> >> +    vres->region = g_new0(MemoryRegion, 1);
> >> +    memory_region_init_ram_ptr(vres->region, OBJECT(g), NULL, size, data);
> >> +    vres->region->opaque = vres;
> >> +    OBJECT(vres->region)->free = virgl_resource_blob_async_unmap;
> >> +    memory_region_add_subregion(&b->hostmem, mblob.offset, vres->region);
> >> +    memory_region_set_enabled(vres->region, true);
> >> +
> >> +    memset(&resp, 0, sizeof(resp));
> >> +    resp.hdr.type = VIRTIO_GPU_RESP_OK_MAP_INFO;
> >> +    virgl_renderer_resource_get_map_info(mblob.resource_id, &resp.map_info);
> >> +    virtio_gpu_ctrl_response(g, cmd, &resp.hdr, sizeof(resp));
> >> +}
> >> +
> >> +static void virgl_cmd_resource_unmap_blob(VirtIOGPU *g,
> >> +                                          struct virtio_gpu_ctrl_command *cmd)
> >> +{
> >> +    struct virgl_gpu_resource *vres;
> >> +    struct virtio_gpu_resource_unmap_blob ublob;
> >> +    VirtIOGPUBase *b = VIRTIO_GPU_BASE(g);
> >> +    MemoryRegion *mr;
> >> +
> >> +    VIRTIO_GPU_FILL_CMD(ublob);
> >> +    virtio_gpu_unmap_blob_bswap(&ublob);
> >> +
> >> +    if (ublob.resource_id == 0) {
> >> +        qemu_log_mask(LOG_GUEST_ERROR, "%s: resource id 0 is not allowed\n",
> >> +                      __func__);
> >> +        cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID;
> >> +        return;
> >> +    }
> >> +
> >> +    vres = virgl_gpu_find_resource(g, ublob.resource_id);
> >> +    if (!vres) {
> >> +        qemu_log_mask(LOG_GUEST_ERROR, "%s: resource does not exist %d\n",
> >> +                      __func__, ublob.resource_id);
> >> +        cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID;
> >> +        return;
> >> +    }
> >> +
> >> +    if (!vres->region) {
> >> +        qemu_log_mask(LOG_GUEST_ERROR, "%s: resource already unmapped %d\n",
> >> +                      __func__, ublob.resource_id);
> >> +        cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID;
> >> +        return;
> >> +    }
> >> +
> >> +    mr = vres->region;
> >> +    vres->region = NULL;
> > 
> > memory_region_unref(mr)?
> > 
> > Note that AFAICT without the added memory_region_unref() calls virgl_resource_unmap()
> > was never called.
> 
> 
> Xenia and I figured out the refcounting issue: this code is written based on the
> assumption that:
>   
>     object_unparent(OBJECT(mr));
> 
> 
> Will decrement the refcount. But this assumption is only true if mr->parent_obj.parent
> is non-NULL.
> 
> The map_blob function uses the following arguments:
> 
>     memory_region_init_ram_ptr(vres->region, OBJECT(g), NULL, size, data);
> 
> Since name is NULL, mr won't be added as a child of 'g' and thus object_unparent()
> does nothing.
> 
> I'd suggest 2 changes:
>     * use a name ("blob_memory"?) to so mr can be a child of g
>     * increment mr's refcount when setting vres->region and decrement it when clearing it.
>       This change is not needed technically but when a variable is refcounted it seems
>       clearer to increment/decrement the refcount in these situations.
> 

Yes, issue is caused by NULL in name field, I will update according to your
suggestions in V7.

Thanks,
Ray

> 
> Pierre-Eric
> 
> 
> > 
> >> +    memory_region_set_enabled(mr, false);
> >> +    memory_region_del_subregion(&b->hostmem, mr);
> >> +    object_unparent(OBJECT(mr));
> >> +}
> >> +
> >> +#endif /* HAVE_VIRGL_RESOURCE_BLOB */
> >> +
> >>   void virtio_gpu_virgl_process_cmd(VirtIOGPU *g,
> >>                                         struct virtio_gpu_ctrl_command *cmd)
> >>   {
> >> @@ -536,6 +789,17 @@ void virtio_gpu_virgl_process_cmd(VirtIOGPU *g,
> >>       case VIRTIO_GPU_CMD_GET_EDID:
> >>           virtio_gpu_get_edid(g, cmd);
> >>           break;
> >> +#ifdef HAVE_VIRGL_RESOURCE_BLOB
> >> +    case VIRTIO_GPU_CMD_RESOURCE_CREATE_BLOB:
> >> +        virgl_cmd_resource_create_blob(g, cmd);
> >> +        break;
> >> +    case VIRTIO_GPU_CMD_RESOURCE_MAP_BLOB:
> >> +        virgl_cmd_resource_map_blob(g, cmd);
> >> +        break;
> >> +    case VIRTIO_GPU_CMD_RESOURCE_UNMAP_BLOB:
> >> +        virgl_cmd_resource_unmap_blob(g, cmd);
> >> +        break;
> >> +#endif /* HAVE_VIRGL_RESOURCE_BLOB */
> >>       default:
> >>           cmd->error = VIRTIO_GPU_RESP_ERR_UNSPEC;
> >>           break;
> >> diff --git a/hw/display/virtio-gpu.c b/hw/display/virtio-gpu.c
> >> index 4c3ec9d0ea..8189c392dc 100644
> >> --- a/hw/display/virtio-gpu.c
> >> +++ b/hw/display/virtio-gpu.c
> >> @@ -1449,10 +1449,12 @@ void virtio_gpu_device_realize(DeviceState *qdev, Error **errp)
> >>               return;
> >>           }
> >> +#ifndef HAVE_VIRGL_RESOURCE_BLOB
> >>           if (virtio_gpu_virgl_enabled(g->parent_obj.conf)) {
> >> -            error_setg(errp, "blobs and virgl are not compatible (yet)");
> >> +            error_setg(errp, "Linked virglrenderer does not support blob resources");
> >>               return;
> >>           }
> >> +#endif
> >>       }
> >>       if (!virtio_gpu_base_device_realize(qdev,
> >> diff --git a/meson.build b/meson.build
> >> index ea52ef1b9c..629407128e 100644
> >> --- a/meson.build
> >> +++ b/meson.build
> >> @@ -1054,6 +1054,10 @@ if not get_option('virglrenderer').auto() or have_system or have_vhost_user_gpu
> >>                            cc.has_function('virgl_renderer_context_create_with_flags',
> >>                                            prefix: '#include <virglrenderer.h>',
> >>                                            dependencies: virgl))
> >> +    config_host_data.set('HAVE_VIRGL_RESOURCE_BLOB',
> >> +                         cc.has_function('virgl_renderer_resource_create_blob',
> >> +                                         prefix: '#include <virglrenderer.h>',
> >> +                                         dependencies: virgl))
> >>     endif
> >>   endif
> >>   rutabaga = not_found
> > 


  reply	other threads:[~2024-02-23  6:41 UTC|newest]

Thread overview: 57+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-12-19  7:53 [PATCH v6 00/11] Support blob memory and venus on qemu Huang Rui
2023-12-19  7:53 ` [PATCH v6 01/11] linux-headers: Update to kernel headers to add venus capset Huang Rui
2023-12-19 12:20   ` Akihiko Odaki
2023-12-19 13:47     ` Huang Rui
2023-12-19 14:14       ` Peter Maydell
2023-12-21  6:55         ` Akihiko Odaki
2024-01-02 10:42           ` Marc-André Lureau
2024-01-03  6:35             ` Huang Rui
2024-01-03  6:03         ` Huang Rui
2024-01-03  5:58     ` Huang Rui
2023-12-19  7:53 ` [PATCH v6 02/11] virtio-gpu: Configure new feature flag context_create_with_flags for virglrenderer Huang Rui
2023-12-19  9:09   ` Antonio Caggiano
2023-12-19 11:41     ` Huang Rui
2024-01-05 16:18   ` Alex Bennée
2023-12-19  7:53 ` [PATCH v6 03/11] virtio-gpu: Support context init feature with virglrenderer Huang Rui
2024-01-02 11:43   ` Marc-André Lureau
2024-01-03  8:46     ` Huang Rui
2024-01-04 12:16   ` Akihiko Odaki
2023-12-19  7:53 ` [PATCH v6 04/11] virtio-gpu: Don't require udmabuf when blobs and virgl are enabled Huang Rui
2024-01-02 11:50   ` Marc-André Lureau
2023-12-19  7:53 ` [PATCH v6 05/11] virtio-gpu: Introduce virgl_gpu_resource structure Huang Rui
2023-12-19 12:35   ` Akihiko Odaki
2023-12-19 13:27     ` Huang Rui
2023-12-21  5:43       ` Akihiko Odaki
2024-01-03  8:48         ` Huang Rui
2024-01-02 11:52   ` Marc-André Lureau
2024-01-04  7:27     ` Huang Rui
2023-12-19  7:53 ` [PATCH v6 06/11] softmmu/memory: enable automatic deallocation of memory regions Huang Rui
2023-12-21  5:45   ` Akihiko Odaki
2023-12-21  7:35     ` Xenia Ragiadakou
2023-12-21  7:50       ` Akihiko Odaki
2023-12-21  8:32         ` Xenia Ragiadakou
2023-12-19  7:53 ` [PATCH v6 07/11] virtio-gpu: Handle resource blob commands Huang Rui
2023-12-21  5:57   ` Akihiko Odaki
2023-12-21  7:39     ` Xenia Ragiadakou
2023-12-21  8:09   ` Akihiko Odaki
2024-01-10 12:59     ` Pierre-Eric Pelloux-Prayer
2024-01-02 12:38   ` Marc-André Lureau
2024-01-09 16:50   ` Pierre-Eric Pelloux-Prayer
2024-01-10  8:51     ` Pierre-Eric Pelloux-Prayer
2024-02-23  6:34       ` Huang Rui via [this message]
2024-02-23  6:34         ` Huang Rui
2023-12-19  7:53 ` [PATCH v6 08/11] virtio-gpu: Resource UUID Huang Rui
2023-12-21  6:03   ` Akihiko Odaki
2024-01-02 12:49   ` Marc-André Lureau
2024-02-23  9:04     ` Huang Rui
2023-12-19  7:53 ` [PATCH v6 09/11] virtio-gpu: Support Venus capset Huang Rui
2023-12-19 10:42   ` Pierre-Eric Pelloux-Prayer
2023-12-19  7:53 ` [PATCH v6 10/11] virtio-gpu: Initialize Venus Huang Rui
2024-01-02 13:33   ` Marc-André Lureau
2024-02-23  9:15     ` Huang Rui
2024-03-26  8:53       ` Pierre-Eric Pelloux-Prayer
2023-12-19  7:53 ` [PATCH v6 11/11] virtio-gpu: make blob scanout use dmabuf fd Huang Rui
2023-12-21  6:25   ` Akihiko Odaki
2024-01-04 11:19     ` Pierre-Eric Pelloux-Prayer
2024-01-05 13:28   ` Alex Bennée
2024-01-05 16:09     ` Alex Bennée

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=Zdg8jYYI1e3+xyJi@amd.com \
    --to=qemu-devel@nongnu.org \
    --cc=Alexander.Deucher@amd.com \
    --cc=Christian.Koenig@amd.com \
    --cc=Honglei1.Huang@amd.com \
    --cc=Jiqian.Chen@amd.com \
    --cc=Julia.Zhang@amd.com \
    --cc=Pierre-eric.Pelloux-prayer@amd.com \
    --cc=Xenia.Ragiadakou@amd.com \
    --cc=akihiko.odaki@daynix.com \
    --cc=alex.bennee@linaro.org \
    --cc=anthony.perard@citrix.com \
    --cc=antonio.caggiano@collabora.com \
    --cc=bob.beckett@collabora.com \
    --cc=dgilbert@redhat.com \
    --cc=dmitry.osipenko@collabora.com \
    --cc=ernunes@redhat.com \
    --cc=gert.wollny@collabora.com \
    --cc=gurchetansingh@chromium.org \
    --cc=hi@alyssa.is \
    --cc=kraxel@redhat.com \
    --cc=marcandre.lureau@gmail.com \
    --cc=mst@redhat.com \
    --cc=philmd@linaro.org \
    --cc=pierre-eric@damsy.net \
    --cc=quic_acaggian@quicinc.com \
    --cc=ray.huang@amd.com \
    --cc=roger.pau@citrix.com \
    --cc=sstabellini@kernel.org \
    --cc=stefano.stabellini@amd.com \
    --cc=xen-devel@lists.xenproject.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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.