Browse Source

Platform: device selection in WindowlessEglApplication.

findsdl-include-root
Vladimír Vondruš 7 years ago
parent
commit
f7d739058b
  1. 13
      doc/changelog.dox
  2. 4
      src/Magnum/GL/Context.h
  3. 63
      src/Magnum/Platform/WindowlessEglApplication.cpp
  4. 40
      src/Magnum/Platform/WindowlessEglApplication.h

13
doc/changelog.dox

@ -272,6 +272,13 @@ See also:
in @ref Platform::GlfwApplication and @ref Platform::EmscriptenApplication)
for changing window title at runtime as opposed to setting them on
application startup
- @ref Platform::WindowlessEglApplication now uses 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`, working better on headless
setups and allowing selection of an arbitrary GPU device on multi-GPU
systems
@subsubsection changelog-latest-new-primitives Primitives library
@ -484,12 +491,6 @@ 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

4
src/Magnum/GL/Context.h

@ -153,6 +153,10 @@ options passed to the application itself. Options that don't have this prefix
are completely ignored, see documentation of the
@ref Utility-Arguments-delegating "Utility::Arguments" class for details.
Particular application implementations add more options for DPI scaling or
GPU selection, see @ref Platform::Sdl2Application, @ref Platform::GlfwApplication
and @ref Platform::WindowlessEglApplication for details.
@section GL-Context-multithreading Thread safety
If Corrade is compiled with @ref CORRADE_BUILD_MULTITHREADED (the default), the

63
src/Magnum/Platform/WindowlessEglApplication.cpp

@ -27,6 +27,7 @@
#include <cstring>
#include <string>
#include <Corrade/Utility/Arguments.h>
#include <Corrade/Utility/Assert.h>
#include <Corrade/Utility/Debug.h>
#include <Corrade/Utility/DebugStl.h>
@ -37,13 +38,10 @@
#include "Implementation/Egl.h"
#if defined(MAGNUM_TARGET_GLES) && !defined(MAGNUM_TARGET_WEBGL)
#include <Corrade/Containers/ArrayView.h>
#endif
/* None of this is in the Emscripten emulation layer, so no need to include
that there */
#ifndef MAGNUM_TARGET_WEBGL
#include <Corrade/Containers/Array.h>
#ifndef EGL_EXT_device_base
typedef void *EGLDeviceEXT;
@ -138,16 +136,21 @@ WindowlessEglContext::WindowlessEglContext(const Configuration& configuration, G
return;
}
if(configuration.device() >= UnsignedInt(count)) {
Error{} << "Platform::WindowlessEglContext: requested EGL device" << configuration.device() << "but found only" << count;
return;
}
if(magnumContext && (magnumContext->internalFlags() >= GL::Context::InternalFlag::DisplayVerboseInitializationLog)) {
Debug{} << "Platform::WindowlessEglApplication: found" << count << "EGL devices, choosing the first one";
Debug{} << "Platform::WindowlessEglApplication: found" << count << "EGL devices, choosing device" << configuration.device();
}
/* Assuming the same thing won't suddenly start failing when called the
second time */
EGLDeviceEXT device;
CORRADE_INTERNAL_ASSERT_OUTPUT(eglQueryDevices(1, &device, &count));
Containers::Array<EGLDeviceEXT> devices{configuration.device() + 1};
CORRADE_INTERNAL_ASSERT_OUTPUT(eglQueryDevices(configuration.device() + 1, devices, &count));
if(!(_display = reinterpret_cast<EGLDisplay(*)(EGLenum, void*, const EGLint*)>(eglGetProcAddress("eglGetPlatformDisplayEXT"))(EGL_PLATFORM_DEVICE_EXT, device, nullptr))) {
if(!(_display = reinterpret_cast<EGLDisplay(*)(EGLenum, void*, const EGLint*)>(eglGetProcAddress("eglGetPlatformDisplayEXT"))(EGL_PLATFORM_DEVICE_EXT, devices[configuration.device()], nullptr))) {
Error{} << "Platform::WindowlessEglApplication::tryCreateContext(): cannot get platform display for a device:" << Implementation::eglErrorString(eglGetError());
return;
}
@ -155,9 +158,18 @@ WindowlessEglContext::WindowlessEglContext(const Configuration& configuration, G
#endif
/* Otherwise initialize the classic way. WebGL doesn't have any of the
above, so no need to compile that at all. */
if(!(_display = eglGetDisplay(EGL_DEFAULT_DISPLAY))) {
Error{} << "Platform::WindowlessEglApplication::tryCreateContext(): cannot get default EGL display:" << Implementation::eglErrorString(eglGetError());
return;
{
#ifndef MAGNUM_TARGET_WEBGL
if(configuration.device() != 0) {
Error{} << "Platform::WindowlessEglContext: requested EGL device" << configuration.device() << "but EGL_EXT_platform_device is not supported and there's just the default one";
return;
}
#endif
if(!(_display = eglGetDisplay(EGL_DEFAULT_DISPLAY))) {
Error{} << "Platform::WindowlessEglApplication::tryCreateContext(): cannot get default EGL display:" << Implementation::eglErrorString(eglGetError());
return;
}
}
if(!eglInitialize(_display, nullptr, nullptr)) {
@ -327,9 +339,9 @@ bool WindowlessEglContext::makeCurrent() {
WindowlessEglContext::Configuration::Configuration()
#ifndef MAGNUM_TARGET_GLES
: _flags{Flag::ForwardCompatible}
: _flags{Flag::ForwardCompatible}, _device{}
#elif !defined(MAGNUM_TARGET_WEBGL)
: _flags{}
: _flags{}, _device{}
#endif
{}
@ -341,7 +353,21 @@ WindowlessEglApplication::WindowlessEglApplication(const Arguments& arguments, c
createContext(configuration);
}
WindowlessEglApplication::WindowlessEglApplication(const Arguments& arguments, NoCreateT): _glContext{NoCreate}, _context{new GLContext{NoCreate, arguments.argc, arguments.argv}} {}
WindowlessEglApplication::WindowlessEglApplication(const Arguments& arguments, NoCreateT): _glContext{NoCreate} {
Utility::Arguments args{"magnum"};
#ifndef MAGNUM_TARGET_WEBGL
args.addOption("device", "").setHelp("device", "GPU device to use", "N")
.setFromEnvironment("device");
#endif
_context.reset(new GLContext{NoCreate, args, arguments.argc, arguments.argv});
#ifndef MAGNUM_TARGET_WEBGL
if(args.value("device").empty())
_commandLineDevice = 0;
else
_commandLineDevice = args.value<UnsignedInt>("device");
#endif
}
void WindowlessEglApplication::createContext() { createContext({}); }
@ -352,7 +378,14 @@ void WindowlessEglApplication::createContext(const Configuration& configuration)
bool WindowlessEglApplication::tryCreateContext(const Configuration& configuration) {
CORRADE_ASSERT(_context->version() == GL::Version::None, "Platform::WindowlessEglApplication::tryCreateContext(): context already created", false);
WindowlessEglContext glContext{configuration, _context.get()};
/* Command-line arguments override what's set programatically */
Configuration mergedConfiguration{configuration};
#ifndef MAGNUM_TARGET_WEBGL
if(!mergedConfiguration.device())
mergedConfiguration.setDevice(_commandLineDevice);
#endif
WindowlessEglContext glContext{mergedConfiguration, _context.get()};
if(!glContext.isCreated() || !glContext.makeCurrent() || !_context->tryCreate())
return false;

40
src/Magnum/Platform/WindowlessEglApplication.h

@ -234,11 +234,34 @@ class WindowlessEglContext::Configuration {
_flags &= ~flags;
return *this;
}
/**
* @brief Device ID to use
*
* @requires_gles Device selection is not available in WebGL.
*/
UnsignedInt device() const { return _device; }
/**
* @brief Set device ID to use
* @return Reference to self (for method chaining)
*
* The device ID is expected to be smaller than the count of devices
* reported by EGL. When using @ref WindowlessEglApplication, this is
* also exposed as a `--magnum-device` command-line option and a
* `MAGNUM_DEVICE` environment variable.
* @requires_gles Device selection is not available in WebGL.
*/
Configuration& setDevice(UnsignedInt id) {
_device = id;
return *this;
}
#endif
private:
#ifndef MAGNUM_TARGET_WEBGL
Flags _flags;
UnsignedInt _device;
#endif
};
@ -350,14 +373,20 @@ 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
@section Platform-WindowlessEglApplication-device-selection GPU device selection
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.
extensions where available instead of `EGL_DEFAULT_DISPLAY` to work better on
headless setups. The application chooses the first found device by default, you
can override that either with @ref Configuration::setDevice() or using a
`--magnum-device` command-line option (and the `MAGNUM_DEVICE` environment
variable). Unfortunately EGL doesn't provide any reasonable way to enumerate or
filter named devices, so the best you can do is checking reported device count
printed by the `--magnum-log verbose` @ref GL-Context-command-line "command-line option",
and then going from `0` up to figure out the desired device ID.
@m_class{m-block m-danger}
@ -492,6 +521,11 @@ class WindowlessEglApplication {
private:
WindowlessEglContext _glContext;
Containers::Pointer<Platform::GLContext> _context;
#ifndef MAGNUM_TARGET_WEBGL
/* These are saved from command-line arguments */
UnsignedInt _commandLineDevice;
#endif
};
/** @hideinitializer

Loading…
Cancel
Save