diff --git a/src/Magnum/Platform/WindowlessEglApplication.cpp b/src/Magnum/Platform/WindowlessEglApplication.cpp index a1d6ce23b..bd2a1622c 100644 --- a/src/Magnum/Platform/WindowlessEglApplication.cpp +++ b/src/Magnum/Platform/WindowlessEglApplication.cpp @@ -162,44 +162,49 @@ WindowlessEglContext::WindowlessEglContext(const Configuration& configuration, G UnsignedInt selectedDevice; Containers::Array devices; - if (configuration.cudaDevice() != (~UnsignedInt{})) { - if (!(extensionSupported(extensions, "EGL_EXT_device_query") || extensionSupported(extensions, "EGL_EXT_device_base"))) { + /* Look for CUDA devices */ + if(configuration.cudaDevice() != ~UnsignedInt{}) { + if(!(extensionSupported(extensions, "EGL_EXT_device_query") || extensionSupported(extensions, "EGL_EXT_device_base"))) { Error e; - e << "Platform::WindowlessEglApplication: CUDA device selection requires 'EGL_EXT_device_query' or 'EGL_EXT_device_base' extension, likely a driver issue"; - if(!magnumContext || !(magnumContext->internalFlags() & GL::Context::InternalFlag::GpuValidation)) - e << Debug::nospace << "; enable --magnum-gpu-validation to see additional info"; + e << "Platform::WindowlessEglApplication: CUDA device selection requires EGL_EXT_device_query or EGL_EXT_device_base extensions"; return; } + devices = Containers::Array{MaxEGLDevices}; + /* Assuming the same thing won't suddenly start failing when + called the second time */ CORRADE_INTERNAL_ASSERT_OUTPUT(eglQueryDevices(devices.size(), devices, &count)); + auto eglQueryDeviceAttribEXT = reinterpret_cast(eglGetProcAddress("eglQueryDeviceAttribEXT")); auto eglQueryDeviceStringEXT = reinterpret_cast(eglGetProcAddress("eglQueryDeviceStringEXT")); - - for (selectedDevice = 0; selectedDevice < UnsignedInt(count); ++selectedDevice) { + + /* Go through the EGL devices and find one that has the desired + CUDA device number */ + for(selectedDevice = 0; selectedDevice < UnsignedInt(count); ++selectedDevice) { if(magnumContext && (magnumContext->internalFlags() >= GL::Context::InternalFlag::DisplayVerboseInitializationLog)) Debug{} << "Platform::WindowlessEglApplication: eglQueryDeviceStringEXT(EGLDevice=" << Debug::nospace << selectedDevice << Debug::nospace << "):" << eglQueryDeviceStringEXT(devices[selectedDevice], EGL_EXTENSIONS); + EGLAttrib cudaDeviceNumber; - if ((eglQueryDeviceAttribEXT(devices[selectedDevice], EGL_CUDA_DEVICE_NV, &cudaDeviceNumber) == EGL_TRUE) && (cudaDeviceNumber == configuration.cudaDevice())) { + if(eglQueryDeviceAttribEXT(devices[selectedDevice], EGL_CUDA_DEVICE_NV, &cudaDeviceNumber) && cudaDeviceNumber == configuration.cudaDevice()) break; - } } - if (selectedDevice == UnsignedInt(count)) { + /* None found */ + if(selectedDevice == UnsignedInt(count)) { Error e; - e << "Platform::WindowlessEglApplication::tryCreateContext(): Unable to find EGL device for CUDA device" << configuration.cudaDevice(); - if (!magnumContext || !(magnumContext->internalFlags() & - GL::Context::InternalFlag::GpuValidation)) - e << Debug::nospace << "; enable --magnum-gpu-validation to see additional info"; + e << "Platform::WindowlessEglApplication::tryCreateContext(): unable to find EGL device for CUDA device" << configuration.cudaDevice(); return; } if(magnumContext && (magnumContext->internalFlags() >= GL::Context::InternalFlag::DisplayVerboseInitializationLog)) { Debug{} << "Platform::WindowlessEglApplication: found" << count << "EGL devices, choosing EGL device" << selectedDevice << "for CUDA device" << configuration.cudaDevice(); } + + /* Otherwise just a normal EGL device */ } else { devices = Containers::Array{configuration.device() + 1}; - /* Assuming the same thing won't suddenly start failing when called the - second time */ + /* Assuming the same thing won't suddenly start failing when + called the second time */ CORRADE_INTERNAL_ASSERT_OUTPUT(eglQueryDevices(configuration.device() + 1, devices, &count)); selectedDevice = configuration.device(); if(magnumContext && (magnumContext->internalFlags() >= GL::Context::InternalFlag::DisplayVerboseInitializationLog)) { @@ -497,7 +502,7 @@ WindowlessEglApplication::WindowlessEglApplication(const Arguments& arguments, N #ifndef MAGNUM_TARGET_WEBGL args.addOption("device", "").setHelp("device", "GPU device to use", "N") .setFromEnvironment("device") - .addOption("cuda-device", "").setHelp("cuda-device", "CUDA device to use. Supersedes --magnum-device.", "N") + .addOption("cuda-device", "").setHelp("cuda-device", "CUDA device to use. Takes precedence over --magnum-device.", "N") .setFromEnvironment("cuda-device"); #endif _context.reset(new GLContext{NoCreate, args, arguments.argc, arguments.argv}); diff --git a/src/Magnum/Platform/WindowlessEglApplication.h b/src/Magnum/Platform/WindowlessEglApplication.h index 12cdff544..6587dddfc 100644 --- a/src/Magnum/Platform/WindowlessEglApplication.h +++ b/src/Magnum/Platform/WindowlessEglApplication.h @@ -266,6 +266,9 @@ class WindowlessEglContext::Configuration { * set, this value is ignored and the device is picked to be the same * as in the shared context instead. * + * By default it's set to @cpp 0 @ce, taking the first found EGL + * device. + * @see @ref setCudaDevice() * @requires_gles Device selection is not available in WebGL. */ Configuration& setDevice(UnsignedInt id) { @@ -280,20 +283,20 @@ class WindowlessEglContext::Configuration { */ UnsignedInt cudaDevice() const { return _cudaDevice; } - /** * @brief Set the CUDA 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-cuda-device` command-line option and a - * `MAGNUM_CUDA_DEVICE` environment variable. If @ref setSharedContext() is - * set, this value is ignored and the device is picked to be the same - * as in the shared context instead. - * - * Takes precedence over the device ID set with @ref setDevice(). + * If a device with given CUDA ID is not found, context creation fails. + * When using @ref WindowlessEglApplication, this is also exposed as a + * `--magnum-cuda-device` command-line option and a + * `MAGNUM_CUDA_DEVICE` environment variable. If @ref setSharedContext() + * is set, this value is ignored and the device is picked to be the + * same as in the shared context instead. * + * If a CUDA device is set, it takes precedence over the device ID set + * with @ref setDevice(). By default it's set to @cpp 0xffffffffu @ce, + * indicating that @ref setDevice() is used instead. * @requires_gles Device selection is not available in WebGL. */ Configuration& setCudaDevice(UnsignedInt id) { @@ -340,7 +343,7 @@ class WindowlessEglContext::Configuration { #ifndef MAGNUM_TARGET_WEBGL Flags _flags; UnsignedInt _device; - // Assumes that you can't have 2^32 - 1 GPUs + /* Assumes that you can't have 2^32 - 1 GPUs */ UnsignedInt _cudaDevice = ~UnsignedInt{}; EGLDisplay _sharedDisplay = EGL_NO_DISPLAY; EGLContext _sharedContext = EGL_NO_CONTEXT; @@ -478,11 +481,12 @@ 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. -On systems with modern NVIDIA GPU(s)/CUDA, the device ID can also be interpreted as a CUDA device ID -(allowing for EGL and CUDA to both target the same physical device for a given ID). This can be -enabled via the `--magnum-cuda-device` command-line option (and the `MAGNUM_CUDA_DEVICE` environment variable). -If either of these are present, they take precedence over `--magnum-device`. This can also be specified -via @ref Configuration::setCudaDevice. +On systems with NVIDIA GPUs and CUDA, it's possible to directly select a +particular CUDA device, allowing for EGL and CUDA to both target the same +physical device for a given ID. This can be chosen via the +`--magnum-cuda-device` command-line option (and the `MAGNUM_CUDA_DEVICE` +environment variable), which then takes precedence over `--magnum-device`. The +same can be also specified via via @ref Configuration::setCudaDevice(). @m_class{m-block m-danger}