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@xxxxxxxxxx> --- 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 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list