Browse Source

Platform: prefer EGL_EXT_device_enumeration to find an EGL display.

Makes things work on Mesa 19.2 when DISPLAY is not defined. And opens the
possibilities for *sane* GPU selection. No more environment variables,
globally exported symbols or other BAD SHIT.
pull/368/head
Vladimír Vondruš 7 years ago
parent
commit
53e86dd041
  1. 6
      doc/changelog.dox
  2. 74
      src/Magnum/Platform/WindowlessEglApplication.cpp
  3. 9
      src/Magnum/Platform/WindowlessEglApplication.h

6
doc/changelog.dox

@ -401,6 +401,12 @@ See also:
application. Users are encouraged to call
@ref Platform::BasicScreen::hasApplication() to check if the application is
accessible.
- @ref Platform::WindowlessEglApplication now prefers to use the
@m_class{m-doc-external} [EGL_EXT_device_enumeration](https://www.khronos.org/registry/EGL/extensions/EXT/EGL_EXT_device_enumeration.txt),
@m_class{m-doc-external} [EGL_EXT_platform_base](https://www.khronos.org/registry/EGL/extensions/EXT/EGL_EXT_platform_base.txt) and
@m_class{m-doc-external} [EGL_EXT_platform_device](https://www.khronos.org/registry/EGL/extensions/EXT/EGL_EXT_platform_device.txt) extensions where
available instead of `EGL_DEFAULT_DISPLAY` to work better on headless
setups
@subsubsection changelog-latest-changes-text Text library

74
src/Magnum/Platform/WindowlessEglApplication.cpp

@ -25,6 +25,7 @@
#include "WindowlessEglApplication.h"
#include <cstring>
#include <string>
#include <Corrade/Utility/Assert.h>
#include <Corrade/Utility/Debug.h>
@ -38,11 +39,80 @@
#include <Corrade/Containers/ArrayView.h>
#endif
#ifndef EGL_EXT_device_base
typedef void *EGLDeviceEXT;
#endif
#ifndef EGL_EXT_platform_device
#define EGL_PLATFORM_DEVICE_EXT 0x313F
#endif
namespace Magnum { namespace Platform {
namespace {
bool extensionSupported(const char* const extensions, Containers::ArrayView<const char> extension) {
CORRADE_INTERNAL_ASSERT(extensions);
const char* pos = std::strstr(extensions, extension);
/* Extension is supported if its string is delimited by a space or end of
the extension list. The extension.size() is the whole C array including
a 0-terminator, so subtract 1 to look at one character after. */
return pos && (pos[extension.size() - 1] == ' ' || pos[extension.size() - 1] == '\0');
}
}
WindowlessEglContext::WindowlessEglContext(const Configuration& configuration, GLContext* const magnumContext) {
/* Initialize */
_display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
/* If relevant extensions are supported, try to find some display using
those APIs, as that works reliably also when running headless. This
would ideally use EGL 1.5 APIs but since we still want to support
systems which either have old EGL headers or old EGL implementation,
we'd need to have a code path for 1.4 *and* 1.5, plus do complicated
version parsing from a string. Not feeling like doing that today, no. */
const char* const extensions = eglQueryString(EGL_NO_DISPLAY, EGL_EXTENSIONS);
if(extensions &&
/* eglQueryDevicesEXT() */
extensionSupported(extensions, "EGL_EXT_device_enumeration") &&
/* eglGetPlatformDisplayEXT() */
extensionSupported(extensions, "EGL_EXT_platform_base") &&
/* EGL_PLATFORM_DEVICE_EXT (FFS, why it has to be scattered over a
thousand extensions?!). This is supported only since Mesa 19.2. */
extensionSupported(extensions, "EGL_EXT_platform_device")
) {
EGLint count;
auto eglQueryDevices = reinterpret_cast<EGLBoolean(*)(EGLint, EGLDeviceEXT*, EGLint*)>(eglGetProcAddress("eglQueryDevicesEXT"));
if(!eglQueryDevices(0, nullptr, &count)) {
Error{} << "Platform::WindowlessEglApplication::tryCreateContext(): cannot query EGL devices:" << Implementation::eglErrorString(eglGetError());
return;
}
if(!count) {
Error{} << "Platform::WindowlessEglApplication::tryCreateContext(): no EGL devices found";
return;
}
if(magnumContext && (magnumContext->internalFlags() >= GL::Context::InternalFlag::DisplayVerboseInitializationLog)) {
Debug{} << "Platform::WindowlessEglApplication: found" << count << "EGL devices, choosing the first one";
}
/* Assuming the same thing won't suddenly start failing when called the
second time */
EGLDeviceEXT device;
CORRADE_INTERNAL_ASSERT_OUTPUT(eglQueryDevices(1, &device, &count));
if(!(_display = reinterpret_cast<EGLDisplay(*)(EGLenum, void*, const EGLint*)>(eglGetProcAddress("eglGetPlatformDisplayEXT"))(EGL_PLATFORM_DEVICE_EXT, device, nullptr))) {
Error{} << "Platform::WindowlessEglApplication::tryCreateContext(): cannot get platform display for a device:" << Implementation::eglErrorString(eglGetError());
return;
}
/* Otherwise initialize the classic way */
} else if(!(_display = eglGetDisplay(EGL_DEFAULT_DISPLAY))) {
Error{} << "Platform::WindowlessEglApplication::tryCreateContext(): cannot get default EGL display:" << Implementation::eglErrorString(eglGetError());
return;
}
if(!eglInitialize(_display, nullptr, nullptr)) {
Error() << "Platform::WindowlessEglApplication::tryCreateContext(): cannot initialize EGL:" << Implementation::eglErrorString(eglGetError());
return;

9
src/Magnum/Platform/WindowlessEglApplication.h

@ -349,6 +349,15 @@ MAGNUM_WINDOWLESSEGLAPPLICATION_MAIN(MyApplication)
If no other application header is included, this class is also aliased to
@cpp Platform::WindowlessApplication @ce and the macro is aliased to
@cpp MAGNUM_WINDOWLESSAPPLICATION_MAIN() @ce to simplify porting.
@subsection Platform-WindowlessEglApplication-usage-device-enumeration EGL device enumeration
The application prefers to use the @m_class{m-doc-external}
[EGL_EXT_device_enumeration](https://www.khronos.org/registry/EGL/extensions/EXT/EGL_EXT_device_enumeration.txt),
@m_class{m-doc-external} [EGL_EXT_platform_base](https://www.khronos.org/registry/EGL/extensions/EXT/EGL_EXT_platform_base.txt) and
@m_class{m-doc-external} [EGL_EXT_platform_device](https://www.khronos.org/registry/EGL/extensions/EXT/EGL_EXT_platform_device.txt)
where available instead of `EGL_DEFAULT_DISPLAY` to work better on headless
setups. The application always chooses the first found device.
*/
class WindowlessEglApplication {
public:

Loading…
Cancel
Save