Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

EGL/X11 interposer (+ OpenGL ES support) #66

Closed
dcommander opened this issue Apr 20, 2018 · 5 comments
Closed

EGL/X11 interposer (+ OpenGL ES support) #66

dcommander opened this issue Apr 20, 2018 · 5 comments

Comments

@dcommander
Copy link
Member

dcommander commented Apr 20, 2018

In the process of looking into #56, I discovered that, because of the following functions:

eglCopyBuffers()
eglCreatePixmapSurface()
eglCreatePlatformPixmapSurface[EXT]()
eglCreateWindowSurface()
eglCreatePlatformWindowSurface[EXT]()
eglGetConfigAttrib()
eglGetDisplay()
eglGetPlatformDisplay[EXT]()
eglGetProcAddress()
eglQueryNativeDisplayNV()
eglQueryNativeWindowNV()
eglQueryNativePixmapNV()
eglTerminate()

EGL can now effectively be used like GLX. I guess that such is necessary for running OpenGL ES applications in a non-mobile environment, but it also creates problems for VirtualGL. Solving those problems the right way would be of similar scope to #43 (Wayland EGL interposer.) It would require duplicating much of the functionality of the GLX interposer-- including new EGL-specific VirtualWin, VirtualPixmap, and VirtualDrawable classes, mapping EGLConfigs to 2D X server visuals (in order to return correct values for eglGetConfigAttrib(..., EGL_NATIVE_VISUAL_TYPE|EGL_NATIVE_VISUAL_ID, ...)), hashing EGLDisplay instances to the corresponding 2D X server display string (also because of those native EGLConfig attributes), designing appropriate test programs (EGLspheres), adding appropriate tests to fakerut, handling applications that use dlopen() to load libEGL, etc. That starts to look like about 30-40 hours of work. Contact me if your organization is interested in funding this project.

The justification for this feature is two-fold:

  1. To the best of my understanding, this will allow VirtualGL to support OpenGL ES applications in an X11 environment, although it doesn't seem that there are many (any?) workstation applications that use OpenGL ES.
  2. Since EGL/X11 can also be used for "regular" OpenGL applications, this will head off any potential incompatibilities with newer applications or GUI frameworks that may decide to use EGL/X11 rather than GLX (although, at the moment, the only framework I know of that does this is JOGL, it's only in the context of enabling optional OpenGL ES support, and that feature can easily be disabled at run time.)
@dcommander dcommander changed the title EGL/X11 interposer EGL/X11 interposer (+ OpenGL ES support) Apr 25, 2018
dcommander added a commit that referenced this issue Nov 13, 2020
The AMDGPU GLX implementation apparently lacks glXSwapIntervalEXT(),
which Chrome needs.  VGL's interposed version of glXGetProcAddress[ARB]()
was unnecessarily strict, checking for the presence of
glXSwapIntervalEXT() in the underlying GLX implementation even though
the interposed version of glXSwapIntervalEXT() never calls the
underlying implementation unless overlay rendering is enabled or the
X display is excluded.  Because the interposed version of
glXGetProcAddress[ARB]() returned NULL for glXSwapIntervalEXT(), Chrome
fell back to using EGL/X11, which we don't support yet (refer to #66),
and failing to intialize EGL, it disabled GPU acceleration.

NOTE: This commit also pre-emptively fixes the same issue with
glXSwapIntervalSGI().

Fixes #146
@dcommander
Copy link
Member Author

dcommander commented Nov 3, 2021

More specific implementation notes:

Fortunately, the EGL API cleanly separates all handles to 2D X server objects, so it will be a lot easier to develop an EGL/X11 front end for VirtualGL than it was to develop the existing GLX front end. Since a 3D application must call eglGet*Display() in order to wrap an X11 ("native") Display * handle with an EGLDisplay handle, we can redirect the creation of EGLDisplay handles to the existing EGL back end code, which creates an EGLDisplay handle for a DRI device. Thus, it will not be necessary to interpose and modify most of the EGL API functions. As near as I can figure, we would only need to interpose the following functions:

eglChooseConfig()
may need to modify/emulate EGL_SURFACE_TYPE, since we will be using Pbuffer surfaces to represent Window and Pixmap surfaces.

eglCopyBuffers()
will transport the pixels from an EGL surface (in GPU memory) to a native Pixmap (on the 2D X server.) This will probably look similar to our existing interposed XCopyArea() function.

eglCreatePbufferFromClientBuffer()
Since OpenVG interfaces with the native display via EGL, OpenVG rendering will ideally be redirected to the GPU by way of the rest of the modifications herein proposed. Thus, I hope that we won't need to interpose this function, but I'm not sure of that.

eglCreatePixmapSurface()
eglCreatePlatformPixmapSurface()
will create a back-end Pbuffer surface to represent the native Pixmap (which is on the 2D X server) and hash the two. This will probably look similar to our existing interposed glXCreatePixmap() function. The actual EGLSurface returned will be a Pbuffer surface.

eglCreateWindowSurface()
eglCreatePlatformWindowSurface()
will create a back-end Pbuffer surface to represent the native Window (which is on the 2D X server) and hash the two.
This will probably look similar to our existing interposed glXCreateWindow() function. The actual EGLSurface returned will be a Pbuffer surface. If a Window surface is created with EGL_RENDER_BUFFER=EGL_BACK_BUFFER, then no special accommodations will need to be made except in eglSwapBuffers(). If a Window surface is created with EGL_RENDER_BUFFER=EGL_SINGLE_BUFFER, then the faker will need to transport the pixels from the back-end Pbuffer surface (in GPU memory) to the native Window (on the 2D X server) in response to glFlush(), glFinish(), and eglWaitGL() calls made while the Window surface is current. (This is similar to how the GLX front end handles front-buffer rendering.)

eglGetDisplay()
eglGetPlatformDisplay(EGL_PLATFORM_X11_KHR, ...)
will return an EGLDisplay handle from the EGL back end, which is created against a DRI device. It can reuse the main EGLDisplay handle from the EGL back end if passed EGL_DEFAULT_DISPLAY. It will probably need to create new EGLDisplay handles otherwise, and perhaps hash the 2D X server Display * handles to the corresponding EGLDisplay handles.

eglGetProcAddress()
will return the addresses of any EGL functions that we interpose. This will probably look similar to our existing interposed glXGetProcAddress() function.

eglQuerySurface()
will need to modify/emulate EGL_LARGEST_PBUFFER and EGL_RENDER_BUFFER, since we will be using Pbuffer surfaces to represent Window and Pixmap surfaces.

eglSurfaceAttrib()
may need to modify/emulate EGL_SWAP_BEHAVIOR.

eglSwapBuffers()
For emulated Window surfaces created with EGL_RENDER_BUFFER=EGL_BACK_BUFFER, this will transport the pixels from the back-end Pbuffer surface (in GPU memory) to the native Window (on the 2D X server), which will probably look similar to our existing interposed glXSwapBuffers() function. Otherwise, this will be a no-op.

eglSwapInterval()
will probably have to emulate the swap interval, much like our existing interposed glXSwapIntervalEXT() function does.

eglWaitGL()
will transport the pixels from the back-end Pbuffer surface to the corresponding native Window if the Window surface was created with EGL_RENDER_BUFFER=EGL_SINGLE_BUFFER.

@dcommander
Copy link
Member Author

A bit of a wrinkle:

I was under the mistaken impression that EGL window surfaces did not have independent front and back buffers, but in fact, they do. Thus, it will be necessary to emulate EGL windows using FBOs in much the same way that we emulate GLX windows when using the EGL back end.

@dcommander
Copy link
Member Author

Perhaps less wrinkly than I previously thought:

Front buffer rendering with EGL window surfaces is only available when using desktop OpenGL (as opposed to OpenGL ES), and it mainly seems to be implemented as a backward compatibility hack for GLX applications that are being ported to EGL. "Back in the day", some 3D applications used front buffer rendering to draw cursors and selection rectangles on top of rendered frames, but this was mainly a performance hack to avoid re-rendering a complex scene every time the mouse moved. With modern GPUs, the usefulness of such a hack is very limited, and even if it is desirable, there are ways to accomplish it without resorting to front buffer rendering ("back in the day", FBOs didn't exist.)

The nVidia drivers fully support front buffer rendering with EGL window surfaces, but Mesa seems to silently return a context with EGL_RENDER_BUFFER set to EGL_BACK_BUFFER when a single-buffered window surface is made current. The EGL spec says, "Client APIs may not be able to respect the requested rendering buffer. To determine the actual buffer being rendered to by a context, call eglQueryContext." Thus, it seems perfectly safe to forego support for EGL_SINGLE_BUFFER and relatively safe to forego support for front buffer rendering in general, at least for now. The EGL back end's Pbuffer emulation code relies on desktop OpenGL, so attempting to reuse that code for OpenGL ES would introduce numerous problems.

@dcommander
Copy link
Member Author

Progress! The EGL/X11 front end is now working with an EGL/X11 port of glxinfo and glxspheres.

dcommander added a commit that referenced this issue Dec 11, 2021
Things that aren't implemented (yet):
- An EGL/X11 equivalent of fakerut (not sure if it's really needed)
- Pixmap surfaces
- Front buffer/single buffer rendering with window surfaces (but this is
  only relevant with desktop OpenGL and is a legacy feature)

The relevant piglit tests all pass.

Closes #66
@dcommander
Copy link
Member Author

Implemented and pushed. See commit log for limitations and other notes. The feature is not documented yet (will get to that next week.)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant