Skip to content

Commit

Permalink
EGLBE: Allow specifying an EGL device without DRI
Browse files Browse the repository at this point in the history
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
  • Loading branch information
dcommander committed Jul 8, 2022
1 parent 46d0952 commit a1d485a
Show file tree
Hide file tree
Showing 8 changed files with 114 additions and 64 deletions.
5 changes: 5 additions & 0 deletions ChangeLog.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
=====
Expand Down
65 changes: 48 additions & 17 deletions demos/eglinfo.c
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -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)
{
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -610,8 +615,9 @@ static void
usage(void)
{
printf("Usage: eglinfo <device> [-v] [-h] [-l] [-s]\n");
printf("\t<device>: Print EGL configs for the specified DRI device.\n");
printf("\t (\"egl\" = print EGL configs for the first DRI device)\n");
printf("\t<device>: Print EGL configs for the specified EGL device. <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");
Expand All @@ -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;
Expand Down Expand Up @@ -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);
}
Expand Down Expand Up @@ -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");
Expand All @@ -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");

Expand Down
11 changes: 7 additions & 4 deletions doc/advancedconfig.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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'' |
Expand All @@ -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 |
Expand Down
51 changes: 27 additions & 24 deletions doc/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<head>
<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1">
<meta name="language" content="en">
<meta name="date" content="2022-06-14T11:36:37">
<meta name="date" content="2022-07-08T11:41:34">
<meta name="generator" content="deplate.rb 0.8.5">
<title>User&rsquo;s Guide for VirtualGL 3.0.2</title>
<link rel="start" href="index.html" title="Frontpage">
Expand Down Expand Up @@ -369,7 +369,7 @@ <h2 id="hd002001">2.1&nbsp;Terminology</h2>
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
<code>EGL_EXT_platform_device</code> 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
Expand Down Expand Up @@ -469,15 +469,14 @@ <h1 id="hd003"><a name="file003"></a>3&nbsp;Overview</h1>
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 &ldquo;just work.&rdquo; 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.</p>
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 &ldquo;just
work.&rdquo; 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.</p>

<p>VirtualGL has two built-in &ldquo;image transports&rdquo; that can be
used to deliver rendered frames to the 2D X server:</p>
Expand Down Expand Up @@ -1206,10 +1205,9 @@ <h3 id="hd006002001">6.2.1&nbsp;Sanity Check</h3>

<h2 id="hd006003">6.3&nbsp;EGL Back End: Granting Access to the GPU(s)</h2>

<p>When using the EGL back end, accessing a GPU requires going through an
associated DRI device, so the only way to share the application
<p>When using the EGL back end, the only way to share the application
server&rsquo;s GPU(s) among multiple users is to grant those users
access to the DRI device(s) associated with the GPU(s).</p>
access to the device(s) associated with the GPU(s).</p>

<p>This section will explain how to configure a VirtualGL server such that
selected users can use the EGL back end.</p>
Expand Down Expand Up @@ -1276,7 +1274,7 @@ <h3 id="hd006003001">6.3.1&nbsp;Sanity Check</h3>
execute the following command in the SSH session:</p>

<pre class="verbatim">
/opt/VirtualGL/bin/eglinfo&nbsp;/dev/dri/card0
/opt/VirtualGL/bin/eglinfo&nbsp;egl0
</pre>

<p>This command should output a list of EGL configs and should complete
Expand All @@ -1299,11 +1297,12 @@ <h2 id="hd006004">6.4&nbsp;Using VirtualGL with Multiple GPUs</h2>
with) <code>:0.0</code>, <code>:1.0</code>, <code>:2.0</code>, etc.</p>

<p>Setting <code>VGL_DISPLAY</code> to (or invoking
<code>vglrun&nbsp;-d</code> with) <code>egl</code> 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 <code>VGL_DISPLAY</code> to (or
invoking <code>vglrun&nbsp;-d</code> with) <code>/dev/dri/card0</code>,
<code>/dev/dri/card1</code>, <code>/dev/dri/card2</code>, etc.</p>
<code>vglrun&nbsp;-d</code> with) a DRI device path
(<code>/dev/dri/card0</code>, <code>/dev/dri/card1</code>,
<code>/dev/dri/card2</code>, etc.) or an EGL device ID
(<code>egl0</code>, <code>egl1</code>, <code>egl2</code>, etc.) enables
the EGL back end and selects the specified GPU. See Section
<a href="#VGL_DISPLAY" class="ref">19.1</a> for more details.</p>



Expand Down Expand Up @@ -3097,6 +3096,8 @@ <h2 id="hd0019001">19.1&nbsp;Faker Settings</h2>
</dd>
</dl>

<p><a name="VGL_DISPLAY"></a></p>

<div class="table">
<table class="standard">
<tr class="standard">
Expand All @@ -3109,7 +3110,7 @@ <h2 id="hd0019001">19.1&nbsp;Faker Settings</h2>
</tr>
<tr class="standard">
<td class="high standard">Summary</td>
<td class="standard"><em><code>{d}</code></em> = the X display/screen or DRI device to use for 3D rendering</td>
<td class="standard"><em><code>{d}</code></em> = the X display/screen or EGL device to use for 3D rendering</td>
</tr>
<tr class="standard">
<td class="high standard">Image Transports</td>
Expand All @@ -3133,10 +3134,12 @@ <h2 id="hd0019001">19.1&nbsp;Faker Settings</h2>
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 <code>VGL_DISPLAY</code> to (or invoking
<code>vglrun&nbsp;-d</code> with) <code>/dev/dri/card0</code> or
<code>egl</code> would cause VirtualGL to use the EGL back end and
<code>vglrun&nbsp;-d</code> with) a DRI device path (such as
<code>/dev/dri/card0</code>) or an EGL device ID (such as
<code>egl0</code>) 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. <code>/opt/VirtualGL/bin/eglinfo&nbsp;-e</code>
lists all valid EGL device IDs and their associated DRI device paths.
</dd>
</dl>

Expand Down
16 changes: 8 additions & 8 deletions doc/overview.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
2 changes: 1 addition & 1 deletion doc/prefix.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
17 changes: 8 additions & 9 deletions doc/unixconfig.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand All @@ -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

Expand Down
11 changes: 10 additions & 1 deletion server/faker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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");

Expand Down

0 comments on commit a1d485a

Please sign in to comment.