Since QEMU 2.10, there's a new cmdline option '-display egl-headless'
which enables OpenGL support for cases where we can't render on a local
display (i.e. <listen> is set to either 'address' or 'network').
This is to work around the current restriction on the local node with
native OpenGL SPICE support. However, compared to native support,
egl-headless has overhead, because the rendered framebuffer has to be
copied back to QEMU's display area which is then accessed by either
SPICE or VNC and sent to the remote side.
This patch enables this configuration feature by introducing a new
SPICE-only attribute 'native' which helps libvirt to determine whether
to use '-spice gl=on' or '-display egl-headless' on the cmdline. If the
attribute wasn't specified but OpenGL is to be enabled, then given the
nature of the <listen> element, libvirt will determine the default
value.
Signed-off-by: Erik Skultety <eskultet(a)redhat.com>
---
docs/formatdomain.html.in | 8 ++++
docs/schemas/domaincommon.rng | 16 +++++--
src/conf/domain_conf.c | 49 ++++++++++++++++++++--
src/conf/domain_conf.h | 1 +
src/qemu/qemu_command.c | 43 ++++++++++++-------
.../qemuxml2argvdata/graphics-spice-gl-native.args | 26 ++++++++++++
.../qemuxml2argvdata/graphics-spice-gl-native.xml | 25 +++++++++++
.../graphics-spice-gl-non-native.args | 27 ++++++++++++
.../graphics-spice-gl-non-native.xml | 24 +++++++++++
tests/qemuxml2argvtest.c | 8 ++++
.../video-virtio-gpu-spice-gl.xml | 2 +-
11 files changed, 206 insertions(+), 23 deletions(-)
create mode 100644 tests/qemuxml2argvdata/graphics-spice-gl-native.args
create mode 100644 tests/qemuxml2argvdata/graphics-spice-gl-native.xml
create mode 100644 tests/qemuxml2argvdata/graphics-spice-gl-non-native.args
create mode 100644 tests/qemuxml2argvdata/graphics-spice-gl-non-native.xml
diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in
index aa0d6b26df..c6ebd39bd9 100644
--- a/docs/formatdomain.html.in
+++ b/docs/formatdomain.html.in
@@ -6461,6 +6461,14 @@ qemu-kvm -net nic,model=? /dev/null
You can enable or disable OpenGL support explicitly with
the <code>gl</code> element, by setting the
<code>enable</code>
property. (QEMU only, <span class="since">since
1.3.3</span>).
+ Additionally, attribute <code>native</code>
+ (<span class="since">Since 4.6.0</span>) can be used
to specify
+ whether native OpenGL support should be used with SPICE or
+ egl-headless should be used instead. Note that the native OpenGL
+ support is only limited to the local setup (<code>listen</code>
is
+ either 'none' or 'socket') and for remote access
egl-headless
+ needs to be used. The supported values for this attribute are 'on'
+ and 'off'.
</p>
<p>
By default, QEMU will pick the first available GPU DRM render node.
diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng
index 20649c5f6f..4ad53d976b 100644
--- a/docs/schemas/domaincommon.rng
+++ b/docs/schemas/domaincommon.rng
@@ -3066,6 +3066,11 @@
<attribute name="enable">
<ref name="virYesNo"/>
</attribute>
+ <optional>
+ <attribute name="native">
+ <ref name="virYesNo"/>
+ </attribute>
+ </optional>
<empty/>
</element>
</optional>
@@ -3322,9 +3327,14 @@
<ref name="absFilePath"/>
</attribute>
</optional>
- <empty/>
- </element>
- </optional>
+ <optional>
+ <attribute name="native">
+ <ref name="virYesNo"/>
+ </attribute>
+ </optional>
+ <empty/>
+ </element>
+ </optional>
</interleave>
</group>
<group>
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
index 2ccd9e124f..6d399a198e 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -4280,6 +4280,7 @@ virDomainDefPostParseGraphics(virDomainDef *def)
* same. */
if (graphics->type == VIR_DOMAIN_GRAPHICS_TYPE_SPICE) {
virDomainGraphicsListenDefPtr glisten = &graphics->listens[0];
+ virDomainGraphicsGLDefPtr gl = graphics->gl;
if (glisten->type == VIR_DOMAIN_GRAPHICS_LISTEN_TYPE_ADDRESS &&
graphics->data.spice.port == 0 &&
@@ -4288,6 +4289,28 @@ virDomainDefPostParseGraphics(virDomainDef *def)
VIR_FREE(glisten->address);
glisten->type = VIR_DOMAIN_GRAPHICS_LISTEN_TYPE_NONE;
}
+
+ /* Next we need to figure out how to properly configure the OpenGL
+ * if that is enabled and the 'native' attribute is missing.
+ * The cases are:
+ * 1) Listen type is either 'socket' or 'none' - SPICE
native
+ * OpenGL support (,gl=on) should be used because we're
+ * rendering on a local display.
+ *
+ * 2) Listen is either network or address - SPICE can't use
+ * the native OpenGL support remotely yet, so we use
+ * native='no' and format '-display egl-headless' onto
the
+ * cmdline.
+ */
+ if (graphics->gl &&
+ graphics->gl->enable == VIR_TRISTATE_BOOL_YES &&
+ graphics->gl->native == VIR_TRISTATE_BOOL_ABSENT) {
+ gl->native = VIR_TRISTATE_BOOL_NO;
+
+ if (glisten->type == VIR_DOMAIN_GRAPHICS_LISTEN_TYPE_NONE ||
+ glisten->type == VIR_DOMAIN_GRAPHICS_LISTEN_TYPE_SOCKET)
+ gl->native = VIR_TRISTATE_BOOL_YES;
+ }
}
}
}
@@ -13573,6 +13596,7 @@ virDomainGraphicsGLDefParseXML(virDomainGraphicsDefPtr def,
{
virDomainGraphicsGLDefPtr gl = NULL;
char *enable = NULL;
+ char *native = NULL;
int ret = -1;
if (!node)
@@ -13596,14 +13620,26 @@ virDomainGraphicsGLDefParseXML(virDomainGraphicsDefPtr def,
goto cleanup;
}
- if (def->type == VIR_DOMAIN_GRAPHICS_TYPE_SPICE)
- gl->rendernode = virXMLPropString(node, "rendernode");
+ /* SPICE recognizes a few more attributes */
+ if (def->type == VIR_DOMAIN_GRAPHICS_TYPE_SPICE) {
+ gl->rendernode = virXMLPropString(node, "rendernode");
+
+ native = virXMLPropString(node, "native");
+ if (native &&
+ (gl->native = virTristateBoolTypeFromString(native)) <= 0) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("unknown value for attribute enable
'%s'"),
+ enable);
+ goto cleanup;
+ }
+ }
VIR_STEAL_PTR(def->gl, gl);
ret = 0;
cleanup:
VIR_FREE(enable);
+ VIR_FREE(native);
virDomainGraphicsGLDefFree(gl);
return ret;
}
@@ -26184,8 +26220,13 @@ virDomainGraphicsGLDefFormat(virBufferPtr buf,
virDomainGraphicsDefPtr def)
virBufferAsprintf(buf, "<gl enable='%s'",
virTristateBoolTypeToString(gl->enable));
- if (def->type == VIR_DOMAIN_GRAPHICS_TYPE_SPICE)
- virBufferEscapeString(buf, " rendernode='%s'",
gl->rendernode);
+ if (gl->enable == VIR_TRISTATE_BOOL_YES) {
+ if (def->type == VIR_DOMAIN_GRAPHICS_TYPE_SPICE) {
+ virBufferAsprintf(buf, " native='%s'",
+ virTristateBoolTypeToString(gl->native));
+ virBufferEscapeString(buf, " rendernode='%s'",
gl->rendernode);
+ }
+ }
virBufferAddLit(buf, "/>\n");
}
diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
index 20dc1334c4..99b5896391 100644
--- a/src/conf/domain_conf.h
+++ b/src/conf/domain_conf.h
@@ -1602,6 +1602,7 @@ typedef struct _virDomainGraphicsGLDef virDomainGraphicsGLDef;
typedef virDomainGraphicsGLDef *virDomainGraphicsGLDefPtr;
struct _virDomainGraphicsGLDef {
virTristateBool enable;
+ virTristateBool native; /* -spice gl=on vs -display egl-headless for QEMU */
char *rendernode; /* SPICE only */
};
diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c
index 89a8408df6..fc80a6c3a6 100644
--- a/src/qemu/qemu_command.c
+++ b/src/qemu/qemu_command.c
@@ -7896,27 +7896,39 @@ qemuBuildGraphicsVNCCommandLine(virQEMUDriverConfigPtr cfg,
static int
qemuBuildGraphicsSPICEGLCommandLine(virDomainGraphicsGLDefPtr gl,
+ virCommandPtr cmd,
virBufferPtr opt,
virQEMUCapsPtr qemuCaps)
{
- if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_SPICE_GL)) {
- virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
- _("This QEMU doesn't support spice OpenGL"));
- return -1;
- }
-
- virBufferAddLit(opt, "gl=on,");
-
- if (gl->rendernode) {
- if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_SPICE_RENDERNODE)) {
+ if (gl->native == VIR_TRISTATE_BOOL_NO) {
+ /* For non-native OpenGL, we need to add egl-headless to the cmdline.
+ *
+ * NB: QEMU defaults to '-spice gl=off', so we don't have to add
that
+ * explicitly, especially since we're not testing for GL capability
+ * presence.
+ */
+ virCommandAddArg(cmd, "-display");
+ virCommandAddArg(cmd, "egl-headless");
+ } else {
+ if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_SPICE_GL)) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
- _("This QEMU doesn't support spice OpenGL
rendernode"));
+ _("This QEMU doesn't support spice OpenGL"));
return -1;
}
- virBufferAddLit(opt, "rendernode=");
- virQEMUBuildBufferEscapeComma(opt, gl->rendernode);
- virBufferAddLit(opt, ",");
+ virBufferAddLit(opt, "gl=on,");
+
+ if (gl->rendernode) {
+ if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_SPICE_RENDERNODE)) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+ _("This QEMU doesn't support spice OpenGL
rendernode"));
+ return -1;
+ }
+
+ virBufferAddLit(opt, "rendernode=");
+ virQEMUBuildBufferEscapeComma(opt, gl->rendernode);
+ virBufferAddLit(opt, ",");
+ }
}
return 0;
@@ -8137,7 +8149,8 @@ qemuBuildGraphicsSPICECommandLine(virQEMUDriverConfigPtr cfg,
/* OpenGL magic */
if (graphics->gl &&
graphics->gl->enable == VIR_TRISTATE_BOOL_YES &&
- qemuBuildGraphicsSPICEGLCommandLine(graphics->gl, &opt, qemuCaps) < 0)
+ qemuBuildGraphicsSPICEGLCommandLine(graphics->gl, cmd,
+ &opt, qemuCaps) < 0)
goto error;
virBufferTrim(&opt, ",", -1);
diff --git a/tests/qemuxml2argvdata/graphics-spice-gl-native.args
b/tests/qemuxml2argvdata/graphics-spice-gl-native.args
new file mode 100644
index 0000000000..70d6694022
--- /dev/null
+++ b/tests/qemuxml2argvdata/graphics-spice-gl-native.args
@@ -0,0 +1,26 @@
+LC_ALL=C \
+PATH=/bin \
+HOME=/home/test \
+USER=test \
+LOGNAME=test \
+QEMU_AUDIO_DRV=spice \
+/usr/bin/qemu-system-i686 \
+-name QEMUGuest1 \
+-S \
+-machine pc,accel=tcg,usb=off,dump-guest-core=off \
+-m 214 \
+-smp 1,sockets=1,cores=1,threads=1 \
+-uuid c7a5fdbd-edaf-9455-926a-d65c16db1809 \
+-no-user-config \
+-nodefaults \
+-chardev socket,id=charmonitor,path=/tmp/lib/domain--1-QEMUGuest1/monitor.sock,\
+server,nowait \
+-mon chardev=charmonitor,id=monitor,mode=control \
+-rtc base=utc \
+-no-shutdown \
+-no-acpi \
+-boot c \
+-usb \
+-spice port=0,gl=on,rendernode=/dev/dri/foo \
+-vga cirrus \
+-device virtio-balloon-pci,id=balloon0,bus=pci.0,addr=0x3
diff --git a/tests/qemuxml2argvdata/graphics-spice-gl-native.xml
b/tests/qemuxml2argvdata/graphics-spice-gl-native.xml
new file mode 100644
index 0000000000..abfe628a9c
--- /dev/null
+++ b/tests/qemuxml2argvdata/graphics-spice-gl-native.xml
@@ -0,0 +1,25 @@
+<domain type='qemu'>
+ <name>QEMUGuest1</name>
+ <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid>
+ <memory unit='KiB'>219136</memory>
+ <currentMemory unit='KiB'>219136</currentMemory>
+ <vcpu placement='static'>1</vcpu>
+ <os>
+ <type arch='i686' machine='pc'>hvm</type>
+ <boot dev='hd'/>
+ </os>
+ <clock offset='utc'/>
+ <on_poweroff>destroy</on_poweroff>
+ <on_reboot>restart</on_reboot>
+ <on_crash>destroy</on_crash>
+ <devices>
+ <emulator>/usr/bin/qemu-system-i686</emulator>
+ <input type='mouse' bus='ps2'/>
+ <input type='keyboard' bus='ps2'/>
+ <graphics type='spice' autoport='no'>
+ <listen type='none'/>
+ <gl enable='yes' native='yes'
rendernode='/dev/dri/foo'/>
+ </graphics>
+ <memballoon model='virtio'/>
+ </devices>
+</domain>
diff --git a/tests/qemuxml2argvdata/graphics-spice-gl-non-native.args
b/tests/qemuxml2argvdata/graphics-spice-gl-non-native.args
new file mode 100644
index 0000000000..9833cd6c0f
--- /dev/null
+++ b/tests/qemuxml2argvdata/graphics-spice-gl-non-native.args
@@ -0,0 +1,27 @@
+LC_ALL=C \
+PATH=/bin \
+HOME=/home/test \
+USER=test \
+LOGNAME=test \
+QEMU_AUDIO_DRV=spice \
+/usr/bin/qemu-system-i686 \
+-name QEMUGuest1 \
+-S \
+-machine pc,accel=tcg,usb=off,dump-guest-core=off \
+-m 214 \
+-smp 1,sockets=1,cores=1,threads=1 \
+-uuid c7a5fdbd-edaf-9455-926a-d65c16db1809 \
+-no-user-config \
+-nodefaults \
+-chardev socket,id=charmonitor,path=/tmp/lib/domain--1-QEMUGuest1/monitor.sock,\
+server,nowait \
+-mon chardev=charmonitor,id=monitor,mode=control \
+-rtc base=utc \
+-no-shutdown \
+-no-acpi \
+-boot c \
+-usb \
+-display egl-headless \
+-spice port=0 \
+-vga cirrus \
+-device virtio-balloon-pci,id=balloon0,bus=pci.0,addr=0x3
diff --git a/tests/qemuxml2argvdata/graphics-spice-gl-non-native.xml
b/tests/qemuxml2argvdata/graphics-spice-gl-non-native.xml
new file mode 100644
index 0000000000..003f2406ac
--- /dev/null
+++ b/tests/qemuxml2argvdata/graphics-spice-gl-non-native.xml
@@ -0,0 +1,24 @@
+<domain type='qemu'>
+ <name>QEMUGuest1</name>
+ <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid>
+ <memory unit='KiB'>219136</memory>
+ <currentMemory unit='KiB'>219136</currentMemory>
+ <vcpu placement='static'>1</vcpu>
+ <os>
+ <type arch='i686' machine='pc'>hvm</type>
+ <boot dev='hd'/>
+ </os>
+ <clock offset='utc'/>
+ <on_poweroff>destroy</on_poweroff>
+ <on_reboot>restart</on_reboot>
+ <on_crash>destroy</on_crash>
+ <devices>
+ <emulator>/usr/bin/qemu-system-i686</emulator>
+ <input type='mouse' bus='ps2'/>
+ <input type='keyboard' bus='ps2'/>
+ <graphics type='spice' autoport='no'>
+ <gl enable='yes' native='no'/>
+ </graphics>
+ <memballoon model='virtio'/>
+ </devices>
+</domain>
diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c
index c310349b57..e82496d403 100644
--- a/tests/qemuxml2argvtest.c
+++ b/tests/qemuxml2argvtest.c
@@ -1256,6 +1256,14 @@ mymain(void)
QEMU_CAPS_SPICE_UNIX,
QEMU_CAPS_DEVICE_CIRRUS_VGA);
driver.config->spiceAutoUnixSocket = false;
+ DO_TEST("graphics-spice-gl-native",
+ QEMU_CAPS_SPICE,
+ QEMU_CAPS_SPICE_GL,
+ QEMU_CAPS_SPICE_RENDERNODE,
+ QEMU_CAPS_DEVICE_CIRRUS_VGA);
+ DO_TEST("graphics-spice-gl-non-native",
+ QEMU_CAPS_SPICE,
+ QEMU_CAPS_DEVICE_CIRRUS_VGA);
DO_TEST("input-usbmouse", NONE);
DO_TEST("input-usbtablet", NONE);
diff --git a/tests/qemuxml2xmloutdata/video-virtio-gpu-spice-gl.xml
b/tests/qemuxml2xmloutdata/video-virtio-gpu-spice-gl.xml
index 720d362230..578341e09b 100644
--- a/tests/qemuxml2xmloutdata/video-virtio-gpu-spice-gl.xml
+++ b/tests/qemuxml2xmloutdata/video-virtio-gpu-spice-gl.xml
@@ -31,7 +31,7 @@
<input type='keyboard' bus='ps2'/>
<graphics type='spice'>
<listen type='none'/>
- <gl enable='yes' rendernode='/dev/dri/foo'/>
+ <gl enable='yes' native='yes'
rendernode='/dev/dri/foo'/>
</graphics>
<video>
<model type='virtio' heads='1' primary='yes'>
--
2.14.4