From a1d485ae2307a22a1e24aa4c678aab73859cba5d Mon Sep 17 00:00:00 2001
From: DRC
Date: Fri, 8 Jul 2022 10:46:41 -0500
Subject: [PATCH] EGLBE: Allow specifying an EGL device without DRI
EGL doesn't actually require DRI, so it isn't necessary to use a DRI
device path to specify an EGL device. The EGL device can simply be
specified by an "EGL device ID" of the form egl{n}, where {n} is the
device's index in the array of valid EGL devices returned by
eglQueryDevicesEXT(). This facilitates using the EGL back end on
systems that, for whatever reason, have not loaded the nvidia_drm
module. This also allows the Mesa unaccelerated EGL device to be
specified, although the usefulness of that is doubtful.
Closes #207
---
ChangeLog.md | 5 ++++
demos/eglinfo.c | 65 +++++++++++++++++++++++++++++++-----------
doc/advancedconfig.txt | 11 ++++---
doc/index.html | 51 +++++++++++++++++----------------
doc/overview.txt | 16 +++++------
doc/prefix.txt | 2 +-
doc/unixconfig.txt | 17 ++++++-----
server/faker.cpp | 11 ++++++-
8 files changed, 114 insertions(+), 64 deletions(-)
diff --git a/ChangeLog.md b/ChangeLog.md
index 4b9cc36f..dd3db983 100644
--- a/ChangeLog.md
+++ b/ChangeLog.md
@@ -10,6 +10,11 @@ display manager was restarted.
2. Fixed compilation errors when building with libX11 1.8.x.
+3. When using the EGL back end, a GPU can now be specified by an EGL device ID
+of the form `egl{n}`, where `{n}` is a zero-based index, or by a DRI device
+path. A list of valid EGL device IDs and their associated DRI device paths can
+be obtained by running `/opt/VirtualGL/bin/eglinfo -e`.
+
3.0.1
=====
diff --git a/demos/eglinfo.c b/demos/eglinfo.c
index 087238cd..c4a7dedd 100644
--- a/demos/eglinfo.c
+++ b/demos/eglinfo.c
@@ -1,7 +1,7 @@
/*
* Copyright (C) 1999-2014 Brian Paul All Rights Reserved.
* Copyright (C) 2005-2007 Sun Microsystems, Inc. All Rights Reserved.
- * Copyright (C) 2011, 2013, 2015, 2019-2021 D. R. Commander
+ * Copyright (C) 2011, 2013, 2015, 2019-2022 D. R. Commander
* All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
@@ -242,7 +242,7 @@ create_context_with_config(EGLDisplay edpy, EGLConfig config,
static GLboolean
print_display_info(EGLDisplay edpy,
- const struct options *opts,
+ const struct options *opts, int eglDeviceID,
GLboolean coreProfile, GLboolean limits,
GLboolean coreWorked)
{
@@ -315,7 +315,12 @@ print_display_info(EGLDisplay edpy,
CheckError(__LINE__);
if (!coreWorked) {
- printf("device: %s\n", opts->displayName);
+ printf("EGL device ID: egl%d", eglDeviceID);
+ if (eglDeviceID == 0)
+ printf(" or egl");
+ printf("\n");
+ if (opts->displayName)
+ printf("DRI device path: %s\n", opts->displayName);
if (opts->mode != Brief) {
printf("EGL client APIs string: %s\n", eglAPIs);
printf("EGL vendor string: %s\n", eglVendor);
@@ -610,8 +615,9 @@ static void
usage(void)
{
printf("Usage: eglinfo [-v] [-h] [-l] [-s]\n");
- printf("\t: Print EGL configs for the specified DRI device.\n");
- printf("\t (\"egl\" = print EGL configs for the first DRI device)\n");
+ printf("\t: Print EGL configs for the specified EGL device. can\n");
+ printf("\t be a DRI device path or an EGL device ID (use -e for a list.)\n");
+ printf("\t-e: List all valid EGL devices\n");
printf("\t-B: brief output, print only the basics.\n");
printf("\t-v: Print config info in verbose form.\n");
printf("\t-h: This information.\n");
@@ -623,8 +629,8 @@ usage(void)
int
main(int argc, char *argv[])
{
- const char *exts;
- int numDevices, major, minor, i;
+ const char *exts, *devStr = NULL;
+ int numDevices, major, minor, i, list = 0, validDevices = 0;
EGLDeviceEXT *devices = NULL;
EGLDisplay edpy;
struct options opts;
@@ -660,11 +666,14 @@ main(int argc, char *argv[])
else if (strcmp(argv[i], "-s") == 0) {
opts.singleLine = GL_TRUE;
}
+ else if (strcmp(argv[i], "-e") == 0) {
+ list = 1;
+ }
else {
opts.displayName = argv[i];
}
}
- if (!opts.displayName) {
+ if (!opts.displayName && !list) {
usage();
exit(0);
}
@@ -712,18 +721,38 @@ main(int argc, char *argv[])
return -1;
}
for (i = 0; i < numDevices; i++) {
- const char *devStr;
-
edpy = _eglGetPlatformDisplayEXT(EGL_PLATFORM_DEVICE_EXT, devices[i],
NULL);
if (!edpy || !eglInitialize(edpy, &major, &minor))
continue;
eglTerminate(edpy);
- if (!strcasecmp(opts.displayName, "egl"))
- break;
devStr = _eglQueryDeviceStringEXT(devices[i], EGL_DRM_DEVICE_FILE_EXT);
- if (devStr && !strcmp(devStr, opts.displayName))
- break;
+ if (opts.displayName && !list) {
+ if (!strcasecmp(opts.displayName, "egl"))
+ break;
+ if (!strncasecmp(opts.displayName, "egl", 3)) {
+ char temps[80];
+
+ snprintf(temps, 80, "egl%d", validDevices);
+ if (!strcasecmp(opts.displayName, temps))
+ break;
+ }
+ if (devStr && !strcmp(devStr, opts.displayName))
+ break;
+ }
+ if (list) {
+ printf("EGL device ID: egl%d", validDevices);
+ if (validDevices == 0)
+ printf(" or egl");
+ if (devStr)
+ printf(", DRI device path: %s", devStr);
+ printf("\n");
+ }
+ validDevices++;
+ }
+ if (list) {
+ free(devices);
+ return 0;
}
if (i == numDevices) {
fprintf(stderr, "Error: invalid EGL device\n");
@@ -742,9 +771,11 @@ main(int argc, char *argv[])
return -1;
}
- coreWorked = print_display_info(edpy, &opts, GL_TRUE, opts.limits,
- GL_FALSE);
- print_display_info(edpy, &opts, GL_FALSE, opts.limits, coreWorked);
+ opts.displayName = (char *)devStr;
+ coreWorked = print_display_info(edpy, &opts, validDevices, GL_TRUE,
+ opts.limits, GL_FALSE);
+ print_display_info(edpy, &opts, validDevices, GL_FALSE, opts.limits,
+ coreWorked);
printf("\n");
diff --git a/doc/advancedconfig.txt b/doc/advancedconfig.txt
index 4eb09f24..38bd111f 100644
--- a/doc/advancedconfig.txt
+++ b/doc/advancedconfig.txt
@@ -113,9 +113,10 @@ previous method:
''VGL_COMPRESS'' to any numeric value >= 0 (Default value = ''0''.) The
plugin can choose to respond to this value as it sees fit.
+{anchor: VGL_DISPLAY}
| Environment Variable | {pcode: VGL_DISPLAY = __{d}__ } |
| ''vglrun'' argument | {pcode: -d __{d}__ } |
-| Summary | __''{d}''__ = the X display/screen or DRI device to use for 3D \
+| Summary | __''{d}''__ = the X display/screen or EGL device to use for 3D \
rendering |
| Image Transports | All |
| Default Value | '':0'' |
@@ -127,9 +128,11 @@ previous method:
'':0.1'' would cause VirtualGL to use the GLX back end and redirect all of
the OpenGL rendering from the 3D application to a GPU attached to Screen 1 on
X display :0. Setting ''VGL_DISPLAY'' to (or invoking ''vglrun -d'' with)
- ''/dev/dri/card0'' or ''egl'' would cause VirtualGL to use the EGL back end
- and redirect all of the OpenGL rendering from the 3D application to the first
- GPU in the system.
+ a DRI device path (such as ''/dev/dri/card0'') or an EGL device ID (such as
+ ''egl0'') would cause VirtualGL to use the EGL back end and redirect all of
+ the OpenGL rendering from the 3D application to the specified EGL device.
+ ''/opt/VirtualGL/bin/eglinfo -e'' lists all valid EGL device IDs and their
+ associated DRI device paths.
| Environment Variable | {pcode: VGL_EGLLIB = __{l}__ } |
| Summary | __''{l}''__ = the location of an alternate EGL library |
diff --git a/doc/index.html b/doc/index.html
index 8f94ace5..f3725eb4 100644
--- a/doc/index.html
+++ b/doc/index.html
@@ -3,7 +3,7 @@
-
+
User’s Guide for VirtualGL 3.0.2
@@ -369,7 +369,7 @@
2.1 Terminology
API, so it can only access a GPU through an attached X server (the 3D X
server.) The EGL back end uses the EGL API with the
EGL_EXT_platform_device extension, so it accesses a GPU
- through an associated DRI device without the need for a 3D X server.
+ through an associated EGL device without the need for a 3D X server.
The EGL back end emulates a subset of the GLX API using the EGL API.
Since the EGL API does not support multi-buffering (double buffering or
quad-buffered stereo) with off-screen surfaces, the EGL back end
@@ -469,15 +469,14 @@
3 Overview
delivery of X11 2D drawing commands to the X server. For the most part,
VGL does not interfere with the delivery of OpenGL commands to the GPU,
either. VGL merely forces the OpenGL commands to be delivered to a GPU
-in the application server, either through the 3D X server attached to
-the GPU or through a DRI device, rather than to the X server to which
-the 2D drawing commands are delivered (the 2D X server.) Once the
-OpenGL rendering has been redirected to an off-screen buffer, everything
-(including esoteric OpenGL extensions, fragment/vertex shaders, etc.)
-should “just work.” If an OpenGL application runs correctly
-when accessing a 3D server/workstation locally, then the same
-application should run correctly with VirtualGL when accessing the same
-machine remotely.
+in the application server (through the 3D X server or EGL device
+attached to the GPU) rather than to the X server to which the 2D drawing
+commands are delivered (the 2D X server.) Once the OpenGL rendering has
+been redirected to an off-screen buffer, everything (including esoteric
+OpenGL extensions, fragment/vertex shaders, etc.) should “just
+work.” If an OpenGL application runs correctly when accessing a
+3D server/workstation locally, then the same application should run
+correctly with VirtualGL when accessing the same machine remotely.
VirtualGL has two built-in “image transports” that can be
used to deliver rendered frames to the 2D X server:
@@ -1206,10 +1205,9 @@
6.2.1 Sanity Check
6.3 EGL Back End: Granting Access to the GPU(s)
-
When using the EGL back end, accessing a GPU requires going through an
-associated DRI device, so the only way to share the application
+
When using the EGL back end, the only way to share the application
server’s GPU(s) among multiple users is to grant those users
-access to the DRI device(s) associated with the GPU(s).
+access to the device(s) associated with the GPU(s).
This section will explain how to configure a VirtualGL server such that
selected users can use the EGL back end.
This command should output a list of EGL configs and should complete
@@ -1299,11 +1297,12 @@
6.4 Using VirtualGL with Multiple GPUs
with) :0.0, :1.0, :2.0, etc.
Setting VGL_DISPLAY to (or invoking
-vglrun -d with) egl or the path to a DRI
-device enables the EGL back end. When using the EGL back end, a
-specific GPU can be selected by setting VGL_DISPLAY to (or
-invoking vglrun -d with) /dev/dri/card0,
-/dev/dri/card1, /dev/dri/card2, etc.
+vglrun -d with) a DRI device path
+(/dev/dri/card0, /dev/dri/card1,
+/dev/dri/card2, etc.) or an EGL device ID
+(egl0, egl1, egl2, etc.) enables
+the EGL back end and selects the specified GPU. See Section
+19.1 for more details.
@@ -3097,6 +3096,8 @@
19.1 Faker Settings
+
+
@@ -3109,7 +3110,7 @@
19.1 Faker Settings
Summary
-
{d} = the X display/screen or DRI device to use for 3D rendering
+
{d} = the X display/screen or EGL device to use for 3D rendering
Image Transports
@@ -3133,10 +3134,12 @@
19.1 Faker Settings
VirtualGL to use the GLX back end and redirect all of the OpenGL
rendering from the 3D application to a GPU attached to Screen 1 on X
display :0. Setting VGL_DISPLAY to (or invoking
- vglrun -d with) /dev/dri/card0 or
- egl would cause VirtualGL to use the EGL back end and
+ vglrun -d with) a DRI device path (such as
+ /dev/dri/card0) or an EGL device ID (such as
+ egl0) would cause VirtualGL to use the EGL back end and
redirect all of the OpenGL rendering from the 3D application to the
- first GPU in the system.
+ specified EGL device. /opt/VirtualGL/bin/eglinfo -e
+ lists all valid EGL device IDs and their associated DRI device paths.
diff --git a/doc/overview.txt b/doc/overview.txt
index 89658176..99e4ecd4 100644
--- a/doc/overview.txt
+++ b/doc/overview.txt
@@ -47,14 +47,14 @@ X11 commands and events to determine when windows have been resized, etc., but
it does not interfere in any way with the delivery of X11 2D drawing commands
to the X server. For the most part, VGL does not interfere with the delivery
of OpenGL commands to the GPU, either. VGL merely forces the OpenGL commands
-to be delivered to a GPU in the application server, either through the 3D X
-server attached to the GPU or through a DRI device, rather than to the X server
-to which the 2D drawing commands are delivered (the 2D X server.) Once the
-OpenGL rendering has been redirected to an off-screen buffer, everything
-(including esoteric OpenGL extensions, fragment/vertex shaders, etc.) should
-"just work." If an OpenGL application runs correctly when accessing a 3D
-server/workstation locally, then the same application should run correctly with
-VirtualGL when accessing the same machine remotely.
+to be delivered to a GPU in the application server (through the 3D X server or
+EGL device attached to the GPU) rather than to the X server to which the 2D
+drawing commands are delivered (the 2D X server.) Once the OpenGL rendering
+has been redirected to an off-screen buffer, everything (including esoteric
+OpenGL extensions, fragment/vertex shaders, etc.) should "just work." If an
+OpenGL application runs correctly when accessing a 3D server/workstation
+locally, then the same application should run correctly with VirtualGL when
+accessing the same machine remotely.
VirtualGL has two built-in "image transports" that can be used to deliver
rendered frames to the 2D X server:
diff --git a/doc/prefix.txt b/doc/prefix.txt
index c9bb978f..f8302c71 100644
--- a/doc/prefix.txt
+++ b/doc/prefix.txt
@@ -51,7 +51,7 @@ different directory, then adjust the instructions accordingly.
the GLX API, so it can only access a GPU through an attached X server (the 3D
X server.) The EGL back end uses the EGL API with the
''EGL_EXT_platform_device'' extension, so it accesses a GPU through an
- associated DRI device without the need for a 3D X server. The EGL back end
+ associated EGL device without the need for a 3D X server. The EGL back end
emulates a subset of the GLX API using the EGL API. Since the EGL API does
not support multi-buffering (double buffering or quad-buffered stereo) with
off-screen surfaces, the EGL back end emulates multi-buffering using OpenGL
diff --git a/doc/unixconfig.txt b/doc/unixconfig.txt
index deda928e..1f6f0775 100644
--- a/doc/unixconfig.txt
+++ b/doc/unixconfig.txt
@@ -239,9 +239,8 @@ OpenGL renderer string.
** EGL Back End: Granting Access to the GPU(s)
-When using the EGL back end, accessing a GPU requires going through an
-associated DRI device, so the only way to share the application server's GPU(s)
-among multiple users is to grant those users access to the DRI device(s)
+When using the EGL back end, the only way to share the application server's
+GPU(s) among multiple users is to grant those users access to the device(s)
associated with the GPU(s).
This section will explain how to configure a VirtualGL server such that
@@ -292,7 +291,7 @@ end, log out of the server, log back into the server using SSH, and execute the
following command in the SSH session:
#Verb <<---
- /opt/VirtualGL/bin/eglinfo /dev/dri/card0
+ /opt/VirtualGL/bin/eglinfo egl0
---
This command should output a list of EGL configs and should complete with no
@@ -310,11 +309,11 @@ by setting ''VGL_DISPLAY'' to (or invoking ''vglrun -d'' with) '':0.0'',
a specific GPU can be selected by setting ''VGL_DISPLAY'' to (or invoking
''vglrun -d'' with) '':0.0'', '':1.0'', '':2.0'', etc.
-Setting ''VGL_DISPLAY'' to (or invoking ''vglrun -d'' with) ''egl'' or the path
-to a DRI device enables the EGL back end. When using the EGL back end, a
-specific GPU can be selected by setting ''VGL_DISPLAY'' to (or invoking
-''vglrun -d'' with) ''/dev/dri/card0'', ''/dev/dri/card1'', ''/dev/dri/card2'',
-etc.
+Setting ''VGL_DISPLAY'' to (or invoking ''vglrun -d'' with) a DRI device path
+(''/dev/dri/card0'', ''/dev/dri/card1'', ''/dev/dri/card2'', etc.) or an EGL
+device ID (''egl0'', ''egl1'', ''egl2'', etc.) enables the EGL back end and
+selects the specified GPU. See {ref prefix="Section ": VGL_DISPLAY} for more
+details.
** SSH Server Configuration
diff --git a/server/faker.cpp b/server/faker.cpp
index 601cfa3e..5b64aaef 100644
--- a/server/faker.cpp
+++ b/server/faker.cpp
@@ -177,7 +177,7 @@ Display *init3D(void)
#ifdef EGLBACKEND
if(fconfig.egl)
{
- int numDevices = 0, i;
+ int numDevices = 0, i, validDevices = 0;
const char *exts = NULL;
EGLDeviceEXT *devices = NULL;
@@ -211,10 +211,19 @@ Display *init3D(void)
_eglTerminate(edpy);
if(!strcasecmp(fconfig.localdpystring, "egl"))
break;
+ if(!strncasecmp(fconfig.localdpystring, "egl", 3))
+ {
+ char temps[80];
+
+ snprintf(temps, 80, "egl%d", validDevices);
+ if(!strcasecmp(fconfig.localdpystring, temps))
+ break;
+ }
const char *devStr =
_eglQueryDeviceStringEXT(devices[i], EGL_DRM_DEVICE_FILE_EXT);
if(devStr && !strcmp(devStr, fconfig.localdpystring))
break;
+ validDevices++;
}
if(i == numDevices) THROW("Invalid EGL device");