Lucas Amaral <[email protected]> writes:

> Venus (virtio-gpu Vulkan context) currently requires an OpenGL
> display backend due to build-time and runtime coupling.  On macOS,
> no OpenGL display backend exists.
>
> Remove the opengl.found() build requirement for the virtio-gpu-gl
> module; virglrenderer provides Venus independently of OpenGL.
>
> Gate GL-specific code paths behind CONFIG_OPENGL and display_opengl:
> - Only advertise VIRGL/VIRGL2 capsets when display_opengl is set
> - Only pass VIRGL_RENDERER_NO_VIRGL when !display_opengl with Venus
> - Null out GL context callbacks when no GL display is available
> - Route 2D display commands to the software renderer (pixman) when
>   Venus runs without GL (venus no-GL mode)
> - Allow Venus to bypass the OpenGL display check at device realize
>
> Signed-off-by: Lucas Amaral <[email protected]>
<snip>
> @@ -157,7 +158,18 @@ virtio_gpu_get_flags(void *opaque)
>      VirtIOGPUBase *g = opaque;
>      int flags = GRAPHIC_FLAGS_NONE;
>  
> -    if (virtio_gpu_virgl_enabled(g->conf)) {
> +    if (virtio_gpu_venus_enabled(g->conf)) {
> +        /* TODO: set GRAPHIC_FLAGS_VK for direct Vulkan scanout */
> +    }
> +
> +    /*
> +     * TODO: virtio_gpu_virgl_enabled() checks VIRTIO_GPU_FLAG_VIRGL_ENABLED
> +     * which is set for both OpenGL (VIRGL) and Vulkan (Venus) backends.
> +     * This condition should ideally use a dedicated OpenGL-only
> flag.

Isn't this entirely in QEMU's control? The Venus flag is checked when
needed and set by:

    DEFINE_PROP_BIT("venus", VirtIOGPU, parent_obj.conf.flags,
                    VIRTIO_GPU_FLAG_VENUS_ENABLED, false),

So do we just need to define:

    DEFINE_PROP_BIT("virgl", VirtIOGPU, parent_obj.conf.flags,
                    VIRTIO_GPU_FLAG_VIRGL_ENABLED, true),

and allow the user to squash it and drop the:

    g->parent_obj.conf.flags |= (1 << VIRTIO_GPU_FLAG_VIRGL_ENABLED);

I guess we need to drop the prop bit definition on platforms that can't
support OpenGL?

> For
> +     * now, display_opengl correctly gates GL scanout since Venus leaves it
> +     * at 0.
> +     */
> +    if (virtio_gpu_virgl_enabled(g->conf) && display_opengl) {
>          flags |= GRAPHIC_FLAGS_GL;
>      }
>  
> @@ -273,6 +285,7 @@ virtio_gpu_base_get_features(VirtIODevice *vdev, uint64_t 
> features,
>      }
>      if (virtio_gpu_blob_enabled(g->conf)) {
>          features |= (1 << VIRTIO_GPU_F_RESOURCE_BLOB);
> +        features |= (1 << VIRTIO_GPU_F_BLOB_ALIGNMENT);
>      }
>      if (virtio_gpu_context_init_enabled(g->conf)) {
>          features |= (1 << VIRTIO_GPU_F_CONTEXT_INIT);
> diff --git a/hw/display/virtio-gpu-gl.c b/hw/display/virtio-gpu-gl.c
> index 2b7a41c4..1a95e6a7 100644
> --- a/hw/display/virtio-gpu-gl.c
> +++ b/hw/display/virtio-gpu-gl.c
> @@ -124,7 +124,9 @@ static void virtio_gpu_gl_device_realize(DeviceState 
> *qdev, Error **errp)
>          return;
>      }
>  
> -    if (!display_opengl) {
> +    if (virtio_gpu_venus_enabled(g->parent_obj.conf)) {
> +        /* Venus uses Vulkan in the render server, no GL needed */
> +    } else if (!display_opengl) {
>          error_setg(errp,
>                     "The display backend does not have OpenGL support 
> enabled");
>          error_append_hint(errp,
> @@ -245,4 +247,6 @@ static void virtio_register_types(void)
>  type_init(virtio_register_types)
>  
>  module_dep("hw-display-virtio-gpu");
> +#ifdef CONFIG_OPENGL
>  module_dep("ui-opengl");
> +#endif
> diff --git a/hw/display/virtio-gpu-virgl.c b/hw/display/virtio-gpu-virgl.c
> index b7a2d160..2f9700e0 100644
> --- a/hw/display/virtio-gpu-virgl.c
> +++ b/hw/display/virtio-gpu-virgl.c
> @@ -19,8 +19,10 @@
>  #include "hw/virtio/virtio-gpu.h"
>  #include "hw/virtio/virtio-gpu-bswap.h"
>  #include "hw/virtio/virtio-gpu-pixman.h"
> -
> +#include "system/system.h"
> +#ifdef CONFIG_OPENGL
>  #include "ui/egl-helpers.h"
> +#endif
>  
>  #include <virglrenderer.h>
>  
> @@ -50,6 +52,16 @@ struct virtio_gpu_virgl_resource {
>      void *map_fixed;
>  };
>  
> +/*
> + * Venus no-GL mode: Venus is enabled but no OpenGL display is available.
> + * Display commands use software (pixman) rendering; Venus/3D commands
> + * go through the virglrenderer render server.
> + */
> +static bool virtio_gpu_venus_nogl(VirtIOGPU *g)
> +{
> +    return virtio_gpu_venus_enabled(g->parent_obj.conf) && !display_opengl;
> +}
> +
>  static struct virtio_gpu_virgl_resource *
>  virtio_gpu_virgl_find_resource(VirtIOGPU *g, uint32_t resource_id)
>  {
> @@ -63,7 +75,7 @@ virtio_gpu_virgl_find_resource(VirtIOGPU *g, uint32_t 
> resource_id)
>      return container_of(res, struct virtio_gpu_virgl_resource, base);
>  }
>  
> -#if VIRGL_RENDERER_CALLBACKS_VERSION >= 4
> +#if VIRGL_RENDERER_CALLBACKS_VERSION >= 4 && defined(CONFIG_OPENGL)
>  static void *
>  virgl_get_egl_display(G_GNUC_UNUSED void *cookie)
>  {
> @@ -1032,6 +1044,45 @@ void virtio_gpu_virgl_process_cmd(VirtIOGPU *g,
>  
>      VIRTIO_GPU_FILL_CMD(cmd->cmd_hdr);
>  
> +    /*
> +     * Venus no-GL mode: route 2D display commands to the base software
> +     * renderer (pixman). The guest kernel always uses 2D commands for
> +     * display framebuffers even with VIRGL enabled; Venus/3D commands
> +     * go through the virglrenderer render server as usual.
> +     */
> +    if (virtio_gpu_venus_nogl(g)) {
> +        switch (cmd->cmd_hdr.type) {
> +        case VIRTIO_GPU_CMD_RESOURCE_CREATE_2D:
> +        case VIRTIO_GPU_CMD_SET_SCANOUT:
> +        case VIRTIO_GPU_CMD_RESOURCE_FLUSH:
> +        case VIRTIO_GPU_CMD_TRANSFER_TO_HOST_2D:
> +        case VIRTIO_GPU_CMD_GET_DISPLAY_INFO:
> +        case VIRTIO_GPU_CMD_GET_EDID:
> +            virtio_gpu_simple_process_cmd(g, cmd);
> +            return;
> +        case VIRTIO_GPU_CMD_RESOURCE_UNREF:
> +        case VIRTIO_GPU_CMD_RESOURCE_ATTACH_BACKING:
> +        case VIRTIO_GPU_CMD_RESOURCE_DETACH_BACKING: {
> +            /*
> +             * Both 2D (simple) and blob (virgl) resources share g->reslist.
> +             * Check if virglrenderer owns the resource to pick
> +             * the right handler.
> +             */
> +            struct virtio_gpu_resource_unref hdr;
> +            struct virgl_renderer_resource_info info;
> +            VIRTIO_GPU_FILL_CMD(hdr);
> +            if (virgl_renderer_resource_get_info(hdr.resource_id, &info)) {
> +                /* Not in virglrenderer — it's a 2D software resource */
> +                virtio_gpu_simple_process_cmd(g, cmd);
> +                return;
> +            }
> +            break; /* virglrenderer owns it — fall through */
> +        }
> +        default:
> +            break;
> +        }
> +    }
> +
>      virgl_renderer_force_ctx_0();
>      switch (cmd->cmd_hdr.type) {
>      case VIRTIO_GPU_CMD_CTX_CREATE:
> @@ -1433,6 +1484,7 @@ static int virtio_gpu_virgl_init(VirtIOGPU *g)
>      uint32_t flags = 0;
>      VirtIOGPUGL *gl = VIRTIO_GPU_GL(g);
>  
> +#ifdef CONFIG_OPENGL
>  #if VIRGL_RENDERER_CALLBACKS_VERSION >= 4
>      if (qemu_egl_display) {
>          virtio_gpu_3d_cbs.version = 4;
> @@ -1450,9 +1502,14 @@ static int virtio_gpu_virgl_init(VirtIOGPU *g)
>          flags |= VIRGL_RENDERER_D3D11_SHARE_TEXTURE;
>      }
>  #endif
> +#endif /* CONFIG_OPENGL */
>  #if VIRGL_VERSION_MAJOR >= 1
>      if (virtio_gpu_venus_enabled(g->parent_obj.conf)) {
> -        flags |= VIRGL_RENDERER_VENUS | VIRGL_RENDERER_RENDER_SERVER;
> +        flags |= VIRGL_RENDERER_VENUS
> +               | VIRGL_RENDERER_RENDER_SERVER;
> +        if (!display_opengl) {
> +            flags |= VIRGL_RENDERER_NO_VIRGL;
> +        }
>      }
>      if (virtio_gpu_drm_enabled(g->parent_obj.conf)) {
>          flags |= VIRGL_RENDERER_DRM;
> @@ -1475,6 +1532,12 @@ static int virtio_gpu_virgl_init(VirtIOGPU *g)
>      }
>  #endif
>  
> +    if (!display_opengl) {
> +        virtio_gpu_3d_cbs.create_gl_context = NULL;
> +        virtio_gpu_3d_cbs.destroy_gl_context = NULL;
> +        virtio_gpu_3d_cbs.make_current = NULL;
> +    }
> +
>      ret = virgl_renderer_init(g, flags, &virtio_gpu_3d_cbs);
>      if (ret != 0) {
>          error_report("virgl could not be initialized: %d", ret);
> @@ -1546,14 +1609,16 @@ GArray *virtio_gpu_virgl_get_capsets(VirtIOGPU *g)
>  
>      capset_ids = g_array_new(false, false, sizeof(uint32_t));
>  
> -    /* VIRGL is always supported. */
> -    virtio_gpu_virgl_add_capset(capset_ids, VIRTIO_GPU_CAPSET_VIRGL);
> +    /* OpenGL: VIRGL/VIRGL2 require a GL display backend */
> +    if (display_opengl) {
> +        virtio_gpu_virgl_add_capset(capset_ids, VIRTIO_GPU_CAPSET_VIRGL);
>  
> -    virgl_renderer_get_cap_set(VIRTIO_GPU_CAPSET_VIRGL2,
> -                               &capset_max_ver,
> -                               &capset_max_size);
> -    if (capset_max_ver) {
> -        virtio_gpu_virgl_add_capset(capset_ids, VIRTIO_GPU_CAPSET_VIRGL2);
> +        virgl_renderer_get_cap_set(VIRTIO_GPU_CAPSET_VIRGL2,
> +                                   &capset_max_ver,
> +                                   &capset_max_size);
> +        if (capset_max_ver) {
> +            virtio_gpu_virgl_add_capset(capset_ids, 
> VIRTIO_GPU_CAPSET_VIRGL2);
> +        }
>      }
>  
>      if (virtio_gpu_venus_enabled(g->parent_obj.conf)) {

-- 
Alex Bennée
Virtualisation Tech Lead @ Linaro

Reply via email to