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
Introduce GRAPHIC_FLAGS_VK (bit 2) in the console flags for future
Vulkan scanout support alongside the existing GL and DMABUF paths.
Gate Venus at device realize when the HVF map granule exceeds the
guest page size; this ensures blob mappings succeed at runtime.
Signed-off-by: Lucas Amaral <lucaaamaral@gmail.com>
---
hw/display/meson.build | 8 ++--
hw/display/virtio-gpu-base.c | 8 +++-
hw/display/virtio-gpu-gl.c | 17 ++++++-
hw/display/virtio-gpu-virgl.c | 89 ++++++++++++++++++++++++++++++-----
include/ui/console.h | 2 +
ui/console.c | 7 +++
6 files changed, 114 insertions(+), 17 deletions(-)
diff --git a/hw/display/meson.build b/hw/display/meson.build
index 90e6c04..509479e 100644
--- a/hw/display/meson.build
+++ b/hw/display/meson.build
@@ -76,9 +76,9 @@ if config_all_devices.has_key('CONFIG_VIRTIO_GPU')
virtio_gpu_ss.add(when: 'CONFIG_VHOST_USER_GPU', if_true: files('vhost-user-gpu.c'))
hw_display_modules += {'virtio-gpu': virtio_gpu_ss}
- if virgl.found() and opengl.found()
+ if virgl.found()
virtio_gpu_gl_ss = ss.source_set()
- virtio_gpu_gl_ss.add(when: ['CONFIG_VIRTIO_GPU', virgl, opengl],
+ virtio_gpu_gl_ss.add(when: ['CONFIG_VIRTIO_GPU', virgl],
if_true: [files('virtio-gpu-gl.c', 'virtio-gpu-virgl.c'), pixman, virgl])
hw_display_modules += {'virtio-gpu-gl': virtio_gpu_gl_ss}
endif
@@ -99,9 +99,9 @@ if config_all_devices.has_key('CONFIG_VIRTIO_PCI')
if_true: files('vhost-user-gpu-pci.c'))
hw_display_modules += {'virtio-gpu-pci': virtio_gpu_pci_ss}
- if virgl.found() and opengl.found()
+ if virgl.found()
virtio_gpu_pci_gl_ss = ss.source_set()
- virtio_gpu_pci_gl_ss.add(when: ['CONFIG_VIRTIO_GPU', 'CONFIG_VIRTIO_PCI', virgl, opengl],
+ virtio_gpu_pci_gl_ss.add(when: ['CONFIG_VIRTIO_GPU', 'CONFIG_VIRTIO_PCI', virgl],
if_true: [files('virtio-gpu-pci-gl.c'), pixman])
hw_display_modules += {'virtio-gpu-pci-gl': virtio_gpu_pci_gl_ss}
endif
diff --git a/hw/display/virtio-gpu-base.c b/hw/display/virtio-gpu-base.c
index 7269477..faee6dc 100644
--- a/hw/display/virtio-gpu-base.c
+++ b/hw/display/virtio-gpu-base.c
@@ -18,6 +18,7 @@
#include "qapi/error.h"
#include "qemu/error-report.h"
#include "hw/display/edid.h"
+#include "system/system.h"
#include "trace.h"
#include "qapi/qapi-types-virtio.h"
@@ -157,7 +158,11 @@ 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 */
+ }
+
+ if (virtio_gpu_virgl_enabled(g->conf) && display_opengl) {
flags |= GRAPHIC_FLAGS_GL;
}
@@ -257,6 +262,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 b98ef2e..e55fe87 100644
--- a/hw/display/virtio-gpu-gl.c
+++ b/hw/display/virtio-gpu-gl.c
@@ -17,6 +17,8 @@
#include "qemu/error-report.h"
#include "qapi/error.h"
#include "system/system.h"
+#include "system/hvf.h"
+#include "exec/target_page.h"
#include "hw/virtio/virtio.h"
#include "hw/virtio/virtio-gpu.h"
#include "hw/virtio/virtio-gpu-bswap.h"
@@ -133,7 +135,18 @@ 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 renders via Vulkan -- no GL display needed */
+ uint64_t map_gran = hvf_get_map_granule();
+ if (map_gran > qemu_target_page_size()) {
+ error_report("Venus disabled: host map granule (%zu) > guest "
+ "page size (%zu). Requires macOS 26+ or guest "
+ "F_BLOB_ALIGNMENT support.",
+ (size_t)map_gran, qemu_target_page_size());
+ g->parent_obj.conf.flags &=
+ ~(1 << VIRTIO_GPU_FLAG_VENUS_ENABLED);
+ }
+ } else if (!display_opengl) {
error_setg(errp,
"The display backend does not have OpenGL support enabled");
error_append_hint(errp,
@@ -217,4 +230,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 0f75482..826d6d7 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>
@@ -29,6 +31,16 @@ struct virtio_gpu_virgl_resource {
MemoryRegion *mr;
};
+/*
+ * 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)
{
@@ -42,7 +54,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)
{
@@ -903,6 +915,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:
@@ -1169,6 +1220,7 @@ 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;
@@ -1180,12 +1232,23 @@ 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;
+ }
}
#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);
@@ -1223,22 +1286,26 @@ 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);
+ }
}
+ /* Vulkan: Venus capset (gated at device realize if needed) */
if (virtio_gpu_venus_enabled(g->parent_obj.conf)) {
virgl_renderer_get_cap_set(VIRTIO_GPU_CAPSET_VENUS,
&capset_max_ver,
&capset_max_size);
if (capset_max_size) {
- virtio_gpu_virgl_add_capset(capset_ids, VIRTIO_GPU_CAPSET_VENUS);
+ virtio_gpu_virgl_add_capset(capset_ids,
+ VIRTIO_GPU_CAPSET_VENUS);
}
}
diff --git a/include/ui/console.h b/include/ui/console.h
index 98feaa5..fa7fdec 100644
--- a/include/ui/console.h
+++ b/include/ui/console.h
@@ -361,6 +361,8 @@ enum {
GRAPHIC_FLAGS_GL = 1 << 0,
/* require a console/display with DMABUF import */
GRAPHIC_FLAGS_DMABUF = 1 << 1,
+ /* require a console/display with Vulkan scanout */
+ GRAPHIC_FLAGS_VK = 1 << 2,
};
typedef struct GraphicHwOps {
diff --git a/ui/console.c b/ui/console.c
index f445db1..d53dc10 100644
--- a/ui/console.c
+++ b/ui/console.c
@@ -594,6 +594,13 @@ static bool console_compatible_with(QemuConsole *con,
return false;
}
+ if (flags & GRAPHIC_FLAGS_VK) {
+ error_setg(errp,
+ "The console requires Vulkan scanout "
+ "(not yet implemented).");
+ return false;
+ }
+
return true;
}
--
2.52.0
© 2016 - 2026 Red Hat, Inc.