Page MenuHome

X11 EGL context
Needs ReviewPublic

Authored by Christian Rauch (christian.rauch) on Wed, Jan 15, 2:00 AM.

Details

Summary

In preparation for the Wayland backend, this patch enables the EGL context creation option for X11 as a replacement for GLX. The EGL context creation is activated on build time via:

make lite debug ninja BUILD_DIR=~/Development/blender_build_x11_egl BUILD_CMAKE_ARGS="-DWITH_GL_EGL=ON"

Previously, this would not build due to the use of GLX related functions. This patch enables the EGL context as option.

Diff Detail

Event Timeline

Christian Rauch (christian.rauch) edited the summary of this revision. (Show Details)

fix offscreen context creation

The EGL context creation on X11 now works as expected.

The on-screen (GUI) and off-screen (rendering) context creation works like in the GLX case.

This patch is ready for review.

While this would need some further updating to get all platforms to support EGL, this patch may bring a big additional benefit:
It may finally make headless rendering possible. I.e. allowing our OpenGL renderers (Eevee, Workbench) to be used on render farms. See T54638: OpenGL headless rendering

Brecht Van Lommel (brecht) added inline comments.
CMakeLists.txt
231

WITH_GL_PROFILE_ES20 already exists for this purpose, it even mentions EGL in the description.

Can you chqnge the code so WITH_GLES is not needed?

intern/ghost/intern/GHOST_ContextEGL.cpp
166

This is wrong because EGL_VERSION_1_2 is a #define that indicates if the header file contains EGL 1.2 functions. If it doesn't, there would be a compile error here.

EGLEW_VERSION_1_2 on the other hand checks at runtime that EGL 1.2 is supported, which is what is needed here.

intern/ghost/intern/GHOST_ContextEGL.h
29–30 ↗(On Diff #20916)

Is there a specific reason for using EGL/egl.h rather than GL/eglew.h?

We generally rely on GLEW rather than OpenGL system which can be too old, preferably we can do the same for EGL.

CMakeLists.txt
231

I did not use WITH_GL_PROFILE_ES20 since this specifically refers to OpenGL ES 2.0, while WITH_GLES is supposed to cover any OpenGL ES usage.

intern/ghost/intern/GHOST_ContextEGL.cpp
166

Good point. The reasons for using glew+egl in place of eglew have been stated in the other comment.

What would be the proper replacement for EGLEW_VERSION_* checks, when not using eglew?

intern/ghost/intern/GHOST_ContextEGL.h
29–30 ↗(On Diff #20916)

This looks a bit out of context. What is really happening here is that eglew is replaced by glew+egl. This also has implications for the use of EGLEW_* macros.

There are two reasons for using glew+egl in place of eglew.
Firstly, with eglew some functions would not be defined (point to NULL) and the context would crash in difficult to debug ways. A solution to this would be to manually define these functions via:

eglGetDisplay = (PFNEGLGETDISPLAYPROC)eglGetProcAddress("eglGetDisplay");
eglGetCurrentDisplay = (PFNEGLGETCURRENTDISPLAYPROC)eglGetProcAddress("eglGetCurrentDisplay");
eglGetCurrentSurface = (PFNEGLGETCURRENTSURFACEPROC)eglGetProcAddress("eglGetCurrentSurface");
eglGetCurrentContext = (PFNEGLGETCURRENTCONTEXTPROC)eglGetProcAddress("eglGetCurrentContext");
eglInitialize = (PFNEGLINITIALIZEPROC)eglGetProcAddress("eglInitialize");
eglMakeCurrent = (PFNEGLMAKECURRENTPROC)eglGetProcAddress("eglMakeCurrent");
eglChooseConfig = (PFNEGLCHOOSECONFIGPROC)eglGetProcAddress("eglChooseConfig");

(source by Julian Eisel's wayland work)

Secondly, glew can directly be used from the standard Ubuntu repo, which reduces compile times because the externally provided glew does not need to be compiled.

In summary, I rather use glew from the standard Ubuntu repo than having to compile another dependency and manually maintain any PFNEGLCHOOSECONFIGPROC that arise now or later.

CMakeLists.txt
231

WITH_GL_PROFILE_ES20 may have been better named WITH_GL_PROFILE_ES, but it really is intended for any OpenGL ES usage. If we have two flags it's too confusing.

intern/ghost/intern/GHOST_ContextEGL.h
29–30 ↗(On Diff #20916)

Firstly, with eglew some functions would not be defined (point to NULL) and the context would crash in difficult to debug ways.

I see that in the old code, it would first call eglInitialize and then initContextEGLEW containing eglewInit. Then I would indeed expect eglInitialize to be NULL still, but if you call them in the proper order it should work? I'm not sure why else those pointers would be NULL, unless the system actually does not support them or there is a bug in GLEW?

Compile time should not affect our design decision here, it's not significant compared to the rest of Blender. By default we use the GLEW bundled in extern/glew, so it shouldn't cause extra manual work when compiling.

CMakeLists.txt
231

Would you mind, if I would then rename WITH_GL_PROFILE_ES20 to WITH_GL_PROFILE_ES and use it in place of WITH_GLES?

intern/ghost/intern/GHOST_ContextEGL.h
29–30 ↗(On Diff #20916)

if you call them in the proper order it should work?

Alright, I will give this a try.

Out of curiosity, what is the advantage of eglew over plain glew?

I don't even know why we still have opengl es backend available since we don't support it.

To me I would remove the ES support.

intern/ghost/intern/GHOST_ContextEGL.h
29–30 ↗(On Diff #20916)

I don't get how this is supposed to work.
eglewInit needs a display, but a valid display is only available via eglGetDisplay, which is only defined after eglewInit? Do you have a real world example of how eglew is supposed to be used?

use eglew again, but with some ugly workarounds

I reverted some changes and let the commits in the git history to trace these changes and maybe apply them again. Let me know before you merge this so that I can squash the commits.

I am still not sure about eglew. I could only get it running my manually setting at least one function.

As far as I understand, eglewInit is supposed to set all EGL function pointers. But it requires an EGLDisplay which is passed to eglInitialize. This, in turn, requires function eglGetDisplay, whose pointer is not set, since eglewInit hasn't been called yet :-)

  1. How is eglew supposed to be used? Can someone point me to a real-world example that used eglew?
  2. What is the advantage of eglew over glew+egl? Or why can't Blender use glew+egl instead of eglew?

As far as I understand, eglewInit is supposed to set all EGL function pointers. But it requires an EGLDisplay which is passed to eglInitialize. This, in turn, requires function eglGetDisplay, whose pointer is not set, since eglewInit hasn't been called yet :-)

This indeed seems to be a weakness in the eglew API. In the implementation of glewInit() there is this:

getCurrentDisplay = (PFNEGLGETCURRENTDISPLAYPROC) glewGetProcAddress("eglGetCurrentDisplay");
return eglewInit(getCurrentDisplay());

So it seems fine to do the same here. Alternatively we can call glewInit() here so that it initializes both glew and eglew, which if it causes no problems is the easiest solution. But I'm not sure it will work, so probably keeping the code as in this patch will be fine.

  1. How is eglew supposed to be used? Can someone point me to a real-world example that used eglew?
  2. What is the advantage of eglew over glew+egl? Or why can't Blender use glew+egl instead of eglew?

The advantage of using glew and eglew is that the symbols are loaded at runtime, which means that if they are missing Blender does not fail to start.

There may be systems without EGL that we want to run Blender on, either using GLX, or in background mode when we don't need OpenGL at all.

For OpenGL and EGL extensions, it allows us to check at runtime if the functions are available and if not provide some fallback so Blender still works.

So eglew is just EGL and once initialized the function calls work the same way. It just additionally provides a way to check at runtime which version and extensions are available.

As far as I understand, eglewInit is supposed to set all EGL function pointers. But it requires an EGLDisplay which is passed to eglInitialize. This, in turn, requires function eglGetDisplay, whose pointer is not set, since eglewInit hasn't been called yet :-)

This indeed seems to be a weakness in the eglew API. In the implementation of glewInit() there is this:

getCurrentDisplay = (PFNEGLGETCURRENTDISPLAYPROC) glewGetProcAddress("eglGetCurrentDisplay");
return eglewInit(getCurrentDisplay());

So it seems fine to do the same here. Alternatively we can call glewInit() here so that it initializes both glew and eglew, which if it causes no problems is the easiest solution. But I'm not sure it will work, so probably keeping the code as in this patch will be fine.

Unfortunately, that did not work. This branch inside glewInit is only reached if glewContextInit() returns 0, which it does not in my case.

For OpenGL and EGL extensions, it allows us to check at runtime if the functions are available and if not provide some fallback so Blender still works.

Is the only advantage of using elgew instead of glew that you have access variables like EGLEW_VERSION_1_5 to check at runtime of EGL version 1.5 is available?
While this is convenient, you could query the EGL version at runtime via eglInitialize and do these checks.

At the moment, using eglew instead of glew has some maintenance costs for manually defining function pointer like eglGetDisplay and having to call initContextEGLEW at the beginning and again initContextGLEW at the end, to properly initialise an EGL context. This might also be because I am using it in the wrong way, but then there aren't many examples out there that demonstrate how to properly use eglew. I personally, would use glew, since it is widely used and seems to be established, and manually check the EGL version if I have to handle different versions.

In any case, if you are happy with the current eglew workaround, I would be happy if you could review the remaining parts of this PR :-)

fix compiler warnings about type casts

Let me know if you are fine with the eglew workaround, so I can squash my commits and rebase.

Is there anything left that has to be addressed by this patch?