On 10/31/24 10:44, Akihiko Odaki wrote:
> On 2024/10/25 8:33, Dmitry Osipenko wrote:
>> Support asynchronous fencing feature of virglrenderer. It allows Qemu to
>> handle fence as soon as it's signalled instead of periodically polling
>> the fence status. This feature is required for enabling DRM context
>> support in Qemu because legacy fencing mode isn't supported for DRM
>> contexts in virglrenderer.
>>
>> Signed-off-by: Dmitry Osipenko <dmitry.osipe...@collabora.com>
>> ---
>>   hw/display/virtio-gpu-gl.c     |   3 +
>>   hw/display/virtio-gpu-virgl.c  | 138 +++++++++++++++++++++++++++------
>>   include/hw/virtio/virtio-gpu.h |  13 ++++
>>   3 files changed, 132 insertions(+), 22 deletions(-)
>>
>> diff --git a/hw/display/virtio-gpu-gl.c b/hw/display/virtio-gpu-gl.c
>> index 7c0e448b4661..53d938f23f20 100644
>> --- a/hw/display/virtio-gpu-gl.c
>> +++ b/hw/display/virtio-gpu-gl.c
>> @@ -170,6 +170,9 @@ static void
>> virtio_gpu_gl_device_unrealize(DeviceState *qdev)
>>       if (gl->renderer_state >= RS_INITED) {
>>   #if VIRGL_VERSION_MAJOR >= 1
>>           qemu_bh_delete(gl->cmdq_resume_bh);
>> +
>> +        virtio_gpu_virgl_reset_async_fences(g);
>> +        qemu_bh_delete(gl->async_fence_bh);
>>   #endif
>>           if (virtio_gpu_stats_enabled(g->parent_obj.conf)) {
>>               timer_free(gl->print_stats);
>> diff --git a/hw/display/virtio-gpu-virgl.c b/hw/display/virtio-gpu-
>> virgl.c
>> index 3c564683820b..37b40e258398 100644
>> --- a/hw/display/virtio-gpu-virgl.c
>> +++ b/hw/display/virtio-gpu-virgl.c
>> @@ -891,6 +891,7 @@ static void virgl_cmd_set_scanout_blob(VirtIOGPU *g,
>>   void virtio_gpu_virgl_process_cmd(VirtIOGPU *g,
>>                                         struct virtio_gpu_ctrl_command
>> *cmd)
>>   {
>> +    VirtIOGPUGL *gl = VIRTIO_GPU_GL(g);
>>       bool cmd_suspended = false;
>>       int ret;
>>   @@ -992,34 +993,71 @@ void virtio_gpu_virgl_process_cmd(VirtIOGPU *g,
>>         trace_virtio_gpu_fence_ctrl(cmd->cmd_hdr.fence_id, cmd-
>> >cmd_hdr.type);
>>   -    /*
>> -     * Unlike other virglrenderer functions, this one returns a positive
>> -     * error code.
>> -     */
>> -    ret = virgl_renderer_create_fence(cmd->cmd_hdr.fence_id, 0);
>> -    if (ret)
>> -        qemu_log_mask(LOG_GUEST_ERROR,
>> -                      "%s: virgl_renderer_create_fence error: %s",
>> -                      __func__, strerror(ret));
>> +    if (gl->context_fence_enabled &&
>> +        (cmd->cmd_hdr.flags & VIRTIO_GPU_FLAG_INFO_RING_IDX)) {
>> +        uint32_t flags = 0;
>> +
>> +        ret = virgl_renderer_context_create_fence(cmd-
>> >cmd_hdr.ctx_id, flags,
>> +                                                  cmd->cmd_hdr.ring_idx,
>> +                                                  cmd-
>> >cmd_hdr.fence_id);
>> +        if (ret)
>> +            qemu_log_mask(LOG_GUEST_ERROR,
>> +                          "%s: virgl_renderer_context_create_fence
>> error: %s",
>> +                          __func__, strerror(-ret));
>> +    } else {
>> +        /*
>> +         * Unlike other virglrenderer functions, this one returns a
>> positive
>> +         * error code.
>> +         */
>> +        ret = virgl_renderer_create_fence(cmd->cmd_hdr.fence_id, 0);
>> +        if (ret)
>> +            qemu_log_mask(LOG_GUEST_ERROR,
>> +                          "%s: virgl_renderer_create_fence error: %s",
>> +                          __func__, strerror(ret));
>> +    }
>>   }
>>   -static void virgl_write_fence(void *opaque, uint32_t fence)
>> +static void virtio_gpu_virgl_async_fence_bh(void *opaque)
>>   {
>> -    VirtIOGPU *g = opaque;
>> +    QSLIST_HEAD(, virtio_gpu_virgl_context_fence) async_fenceq;
>>       struct virtio_gpu_ctrl_command *cmd, *tmp;
>> +    struct virtio_gpu_virgl_context_fence *f;
>> +    VirtIOGPU *g = opaque;
>> +    VirtIOGPUGL *gl = VIRTIO_GPU_GL(g);
>>   -    QTAILQ_FOREACH_SAFE(cmd, &g->fenceq, next, tmp) {
>> -        /*
>> -         * the guest can end up emitting fences out of order
>> -         * so we should check all fenced cmds not just the first one.
>> -         */
>> -        if (cmd->cmd_hdr.fence_id > fence) {
>> -            continue;
>> +    QSLIST_MOVE_ATOMIC(&async_fenceq, &gl->async_fenceq);
>> +
>> +    while (!QSLIST_EMPTY(&async_fenceq)) {
>> +        f = QSLIST_FIRST(&async_fenceq);
>> +
>> +        QSLIST_REMOVE_HEAD(&async_fenceq, next);
>> +
>> +        QTAILQ_FOREACH_SAFE(cmd, &g->fenceq, next, tmp) {
>> +            /*
>> +             * the guest can end up emitting fences out of order
>> +             * so we should check all fenced cmds not just the first
>> one.
>> +             */
>> +            if (cmd->cmd_hdr.fence_id > f->fence_id) {
>> +                continue;
>> +            }
>> +            if (cmd->cmd_hdr.flags & VIRTIO_GPU_FLAG_INFO_RING_IDX) {
>> +                if (cmd->cmd_hdr.ring_idx != f->ring_idx) {
>> +                    continue;
>> +                }
>> +                if (cmd->cmd_hdr.ctx_id != f->ctx_id) {
>> +                    continue;
>> +                }
>> +            } else if (f->ring_idx >= 0) {
>> +                /* ctx0 GL-query fences don't have ring info */
>> +                continue;
>> +            }
>> +            virtio_gpu_ctrl_response_nodata(g, cmd,
>> VIRTIO_GPU_RESP_OK_NODATA);
>> +            QTAILQ_REMOVE(&g->fenceq, cmd, next);
>> +            g_free(cmd);
>>           }
>> -        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);
>> +
>> +        trace_virtio_gpu_fence_resp(f->fence_id);
>> +        g_free(f);
>>           g->inflight--;
>>           if (virtio_gpu_stats_enabled(g->parent_obj.conf)) {
>>               trace_virtio_gpu_dec_inflight_fences(g->inflight);
>> @@ -1027,6 +1065,50 @@ static void virgl_write_fence(void *opaque,
>> uint32_t fence)
>>       }
>>   }
>>   +void virtio_gpu_virgl_reset_async_fences(VirtIOGPU *g)
>> +{
>> +    struct virtio_gpu_virgl_context_fence *f, *f_tmp;
>> +    VirtIOGPUGL *gl = VIRTIO_GPU_GL(g);
>> +
>> +    QSLIST_FOREACH_SAFE(f, &gl->async_fenceq, next, f_tmp) {
>> +        QSLIST_REMOVE(&gl->async_fenceq, f,
>> virtio_gpu_virgl_context_fence,
>> +                      next);
> 
> Replace QSLIST_FOREACH_SAFE() and QSLIST_REMOVE() with QSLIST_EMPTY(),
> QSLIST_FIRST() and QSLIST_REMOVE_HEAD() as you have done for
> virtio_gpu_virgl_async_fence_bh().

Ack

-- 
Best regards,
Dmitry

Reply via email to