From fd1492f56b23abd1846b2b13c5825ad19aa3037b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Wed, 24 Feb 2021 21:27:50 +0100 Subject: [PATCH] GL: introduce Context::Configuration mirroring --magnum-* arguments. Disabling engine startup log or modifying enabled extensions / workarounds from the application side was one of the common pain points and this should *finally* solve the problem. This Configuration is now inherited by the usual Platform::*Application::GLConfiguration / Platform::Windowless*Application::Configuration classes people are used to, so for the end user it's just as if these classes got a bunch new options. Having this, I also extended the ContextGLTest to verify that the Configuration and command-line options do what's expected because that hadn't automated tests until now. The test is mostly a copy of what I did for Vulkan already, nothing special. Additionally all Platform*ApplicationTest executables gained a new --quiet option to verify that the GL::Context::Configuration subset gets correctly passed from the Application code, because that's something we can't really verify in an automated way. --- doc/changelog.dox | 15 +- doc/getting-started.dox | 2 +- doc/opengl-workarounds.dox | 2 +- doc/troubleshooting.dox | 2 +- src/Magnum/Audio/Context.h | 6 +- src/Magnum/GL/Context.cpp | 75 ++++- src/Magnum/GL/Context.h | 291 ++++++++++++++++-- src/Magnum/GL/DebugOutput.h | 4 +- .../GL/Implementation/driverSpecific.cpp | 23 ++ src/Magnum/GL/OpenGLTester.h | 2 +- src/Magnum/GL/Test/ContextGLTest.cpp | 125 +++++++- src/Magnum/GL/Test/ContextTest.cpp | 227 +++++++++++++- src/Magnum/Platform/AbstractXApplication.cpp | 2 +- src/Magnum/Platform/AbstractXApplication.h | 21 +- src/Magnum/Platform/AndroidApplication.cpp | 2 +- src/Magnum/Platform/AndroidApplication.h | 21 +- src/Magnum/Platform/EmscriptenApplication.cpp | 7 +- src/Magnum/Platform/EmscriptenApplication.h | 44 ++- src/Magnum/Platform/GLContext.h | 42 ++- src/Magnum/Platform/GlfwApplication.cpp | 11 +- src/Magnum/Platform/GlfwApplication.h | 48 ++- src/Magnum/Platform/Sdl2Application.cpp | 26 +- src/Magnum/Platform/Sdl2Application.h | 79 +++-- .../Test/EmscriptenApplicationTest.cpp | 10 +- .../Platform/Test/GlfwApplicationTest.cpp | 12 +- .../Platform/Test/GlxApplicationTest.cpp | 6 +- .../Platform/Test/Sdl2ApplicationTest.cpp | 12 +- .../Test/WindowlessCglApplicationTest.cpp | 16 +- .../Test/WindowlessEglApplicationTest.cpp | 16 +- .../Test/WindowlessGlxApplicationTest.cpp | 16 +- .../Test/WindowlessIosApplicationTest.cpp | 16 +- .../Test/WindowlessWglApplicationTest.cpp | 16 +- .../WindowlessWindowsEglApplicationTest.cpp | 16 +- .../Platform/Test/XEglApplicationTest.cpp | 7 +- .../Platform/WindowlessCglApplication.cpp | 4 +- .../Platform/WindowlessCglApplication.h | 23 +- .../Platform/WindowlessEglApplication.cpp | 30 +- .../Platform/WindowlessEglApplication.h | 70 +++-- .../Platform/WindowlessGlxApplication.cpp | 28 +- .../Platform/WindowlessGlxApplication.h | 48 ++- .../Platform/WindowlessIosApplication.h | 22 +- .../Platform/WindowlessWglApplication.cpp | 22 +- .../Platform/WindowlessWglApplication.h | 48 ++- .../WindowlessWindowsEglApplication.cpp | 5 +- .../WindowlessWindowsEglApplication.h | 50 ++- src/Magnum/Platform/gl-info.cpp | 2 +- src/Magnum/Text/fontconverter.cpp | 2 +- .../TextureTools/distancefieldconverter.cpp | 2 +- 48 files changed, 1309 insertions(+), 267 deletions(-) diff --git a/doc/changelog.dox b/doc/changelog.dox index 2319a2209..ef79ad9d2 100644 --- a/doc/changelog.dox +++ b/doc/changelog.dox @@ -49,6 +49,12 @@ See also: @subsubsection changelog-latest-new-gl GL library +- New @ref GL::Context::Configuration class providing runtime alternatives to + the `--magnum-log`, `--magnum-gpu-validation`, `--magnum-disable-extensions` + and `--magnum-disable-workarounds` command line options. The class is then + inherited by all @ref Platform::Sdl2Application::GLConfiguration "Platform::*Application::GLConfiguration" + and @ref Platform::WindowlessEglApplication::Configuration "Platform::Windowless*Application::Configuration" + classes. - Implemented @gl_extension{EXT,texture_norm16} and @webgl_extension{EXT,texture_norm16} ES and WebGL extensions, making normalized 16-bit texture and renderbuffer formats available on all @@ -1412,7 +1418,8 @@ Released 2019-10-24, tagged as (see the @cpp "swiftshader-broken-shader-vertex-id" @ce workaround in @ref opengl-workarounds for more information). This pseudo-extension can be also explicitly disabled using the usual `--magnum-disable-extensions` - @ref GL-Context-command-line "command-line option" for testing purposes. + @ref GL-Context-usage-command-line "command-line option" for testing + purposes. - An assorted collection of workarounds for Intel Windows drivers "fixing" various issues related to @gl_extension{ARB,direct_state_access} by using a non-DSA code path in the affected cases --- see @@ -1463,7 +1470,7 @@ Released 2019-10-24, tagged as a defined output. On core and ES/WebGL contexts this is enabled implicitly, but for example NVidia drivers have @cpp gl_PointCoord @ce undefined when `GL_POINT_SPRITE` is not enabled on compatibility contexts. -- New `--magnum-gpu-validation` @ref GL-Context-command-line "command-line option" +- New `--magnum-gpu-validation` @ref GL-Context-usage-command-line "command-line option" and a corresponding environment variable to conveniently enable @gl_extension{KHR,debug} debug output. This flag also causes @ref Platform::Sdl2Application::GLConfiguration::Flag::Debug "GLConfiguration::Flag::Debug" @@ -1476,7 +1483,7 @@ Released 2019-10-24, tagged as @ref GL::Buffer::setData() / @ref GL::Buffer::setSubData() for a succint upload of basic types - Added an ability to use Magnum with multiple OpenGL contexts using - @ref GL::Context::makeCurrent(), see @ref GL-Context-multiple for more + @ref GL::Context::makeCurrent(), see @ref GL-Context-usage-multiple for more information - @ref GL::AbstractFramebuffer::read(), @ref GL::Texture::image(), @ref GL::Texture::subImage(), @ref GL::Texture::compressedImage(), @@ -1678,7 +1685,7 @@ Released 2019-10-24, tagged as - @ref GL::OpenGLTester no longer implicitly enables @ref GL::DebugOutput as it can be quite spammy when complex shaders or benchmarks are allowed. For easier debugging, users are encouraged to use the new - `--magnum-gpu-validation` @ref GL-Context-command-line "command line option" + `--magnum-gpu-validation` @ref GL-Context-usage-command-line "command line option" instead. - Added an ability to create @ref GL::DynamicAttribute directly from a @ref GL::Attribute diff --git a/doc/getting-started.dox b/doc/getting-started.dox index 9e9f35dd5..544bc2eb5 100644 --- a/doc/getting-started.dox +++ b/doc/getting-started.dox @@ -282,7 +282,7 @@ Hello! This application is running on OpenGL 4.5 using GeForce GT 740M @image html getting-started-blue.png width=410px -The barebones application accepts various @ref GL-Context-command-line "command-line arguments", +The barebones application accepts various @ref GL-Context-usage-command-line "command-line arguments", pass `--magnum-help` to see them all. Depending on your platform, these can adjust HiDPI scaling, enable GPU command validation or for example switch to a different GPU device. diff --git a/doc/opengl-workarounds.dox b/doc/opengl-workarounds.dox index 7cdc9fec1..6ec935452 100644 --- a/doc/opengl-workarounds.dox +++ b/doc/opengl-workarounds.dox @@ -49,7 +49,7 @@ Using driver workarounds: These identifiers correspond to the strings in the listing below. For debugging and diagnostic purposes it's possible to disable particular workarounds by passing their identifier string to the `--magnum-disable-workarounds` -command-line option. See @ref GL-Context-command-line for more information. +command-line option. See @ref GL-Context-usage-command-line for more information. @m_class{m-console-wrap} diff --git a/doc/troubleshooting.dox b/doc/troubleshooting.dox index f70d9054d..909788932 100644 --- a/doc/troubleshooting.dox +++ b/doc/troubleshooting.dox @@ -54,7 +54,7 @@ or crashes on GL calls, you might want to try these things: - Enable @ref GL::DebugOutput "debug output" to see more detailed errors, warnings and performance hints. You can do that easily through the - `--magnum-gpu-validation` @ref GL-Context-command-line "command-line option" + `--magnum-gpu-validation` @ref GL-Context-usage-command-line "command-line option" or an environment variable. - If you are on Mac, the native OpenGL implementation doesn't support this. Instead you can manually verify that diff --git a/src/Magnum/Audio/Context.h b/src/Magnum/Audio/Context.h index e9f7eeab3..25620bd79 100644 --- a/src/Magnum/Audio/Context.h +++ b/src/Magnum/Audio/Context.h @@ -110,9 +110,9 @@ 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. Moreover, `--magnum`-prefixed options unrelated to audio (such as those defined -by @ref GL-Context-command-line "GL::Context") are ignored as well. In order to -provide a complete help and command-line argument diagnostic, you should -instantiate this class *after* @ref GL::Context. +by @ref GL-Context-usage-command-line "GL::Context") are ignored as well. In +order to provide a complete help and command-line argument diagnostic, you +should instantiate this class *after* @ref GL::Context. */ class MAGNUM_AUDIO_EXPORT Context { public: diff --git a/src/Magnum/GL/Context.cpp b/src/Magnum/GL/Context.cpp index e47604bf6..2fe912ccc 100644 --- a/src/Magnum/GL/Context.cpp +++ b/src/Magnum/GL/Context.cpp @@ -749,15 +749,40 @@ Context::~Context() { if(currentContext == this) currentContext = nullptr; } -void Context::create() { +void Context::create(const Configuration& configuration) { /* Hard exit if the context cannot be created */ - if(!tryCreate()) std::exit(1); + if(!tryCreate(configuration)) std::exit(1); } -bool Context::tryCreate() { +bool Context::tryCreate(const Configuration& configuration) { CORRADE_ASSERT(_version == Version::None, "Platform::Context::tryCreate(): context already created", false); + /* Merge the configuration with parameters passed on the command line / + environment. For the log command-line gets a priority -- if it says + quiet, it'll override the verbose setting from the configuration; if + it says verbose, the quiet setting from the configuration will be + ignored */ + if((configuration.flags() & Configuration::Flag::VerboseLog) && (_internalFlags & InternalFlag::DisplayInitializationLog)) + _internalFlags |= InternalFlag::DisplayVerboseInitializationLog; + else if((configuration.flags() & Configuration::Flag::QuietLog) && !(_internalFlags >= InternalFlag::DisplayVerboseInitializationLog)) + _internalFlags &= ~InternalFlag::DisplayInitializationLog; + + /* GPU validation is enabled if either enables it */ + if(configuration.flags() & Configuration::Flag::GpuValidation) + _internalFlags |= InternalFlag::GpuValidation; + + /* Driver workarounds get merged. Not using disableDriverWorkaround() here + since the Configuration already contains the internal string views. */ + for(const Containers::StringView workaround: configuration.disabledWorkarounds()) + arrayAppend(_driverWorkarounds, Containers::InPlaceInit, workaround, true); + + /* Extensions get merged also. Here we had the chance to force users to + give us the predefined extension types so no need to search for their + IDs */ + for(const Extension& extension: configuration.disabledExtensions()) + arrayAppend(_disabledExtensions, extension); + /* Load GL function pointers. Pass this instance to it so it can use it for potential driver-specific workarounds. */ if(_functionLoader) _functionLoader(*this); @@ -1139,6 +1164,50 @@ void Context::resetState(const States states) { #endif } +Context::Configuration::Configuration() = default; + +Context::Configuration::Configuration(const Configuration& other): _flags{other._flags} { + addDisabledWorkarounds(other._disabledWorkarounds); + addDisabledExtensions(other._disabledExtensions); +} + +Context::Configuration::Configuration(Configuration&&) noexcept = default; + +Context::Configuration::~Configuration() = default; + +Context::Configuration& Context::Configuration::operator=(const Configuration& other) { + _flags = other._flags; + arrayResize(_disabledWorkarounds, 0); + /** @todo arrayClear(), ffs */ + arrayResize(_disabledExtensions, Containers::NoInit, 0); + addDisabledWorkarounds(other._disabledWorkarounds); + addDisabledExtensions(other._disabledExtensions); + return *this; +} + +Context::Configuration& Context::Configuration::operator=(Configuration&&) noexcept = default; + +Containers::ArrayView Context::Configuration::disabledWorkarounds() const { + return _disabledWorkarounds; +} + +Containers::ArrayView Context::Configuration::disabledExtensions() const { + return _disabledExtensions; +} + +Context::Configuration& Context::Configuration::addDisabledWorkarounds(std::initializer_list workarounds) { + return addDisabledWorkarounds(Containers::arrayView(workarounds)); +} + +Context::Configuration& Context::Configuration::addDisabledExtensions(Containers::ArrayView extensions) { + arrayAppend(_disabledExtensions, extensions); + return *this; +} + +Context::Configuration& Context::Configuration::addDisabledExtensions(std::initializer_list extensions) { + return addDisabledExtensions(Containers::arrayView(extensions)); +} + #ifndef DOXYGEN_GENERATING_OUTPUT #ifndef MAGNUM_TARGET_WEBGL Debug& operator<<(Debug& debug, const Context::Flag value) { diff --git a/src/Magnum/GL/Context.h b/src/Magnum/GL/Context.h index c776bee92..c26e72455 100644 --- a/src/Magnum/GL/Context.h +++ b/src/Magnum/GL/Context.h @@ -108,18 +108,32 @@ class MAGNUM_GL_EXPORT Extension { @brief Magnum OpenGL context Provides access to OpenGL version and extension information and manages -Magnum's internal OpenGL state tracker. An instance available through -@ref Context::current() is automatically created during construction of -`Platform::*Application` classes and you can safely assume the instance is -available during the whole `*Application` lifetime. It's also possible to -create the context without using any `*Application` class using the +Magnum's internal OpenGL state tracker. + +@section GL-Context-usage Creating a context + +In order to use any Magnum OpenGL functionality, an instance of this class has +to exist and be made current. If you use any `Platform::*Application` classes, +an instance available through @ref Context::current() is automatically created +during construction (or after @ref Platform::Sdl2Application::create() "Platform::*Application::create()" +/ @relativeref{Platform::Sdl2Application,tryCreate()} and you can safely assume +the instance is available during the whole `*Application` lifetime. It's also +possible to create the context without using any `*Application` class using the @ref Platform::GLContext subclass, see @ref platform for more information. -@section GL-Context-command-line Command-line options +Various options can be passed using the @ref Configuration class, which is then +extended by various +@ref Platform::Sdl2Application::GLConfiguration "Platform::*Application::GLConfiguration" +and @ref Platform::WindowlessEglContext::Configuration "Platform::Windowless*Application::Configuration" +subclasses. + +@subsection GL-Context-usage-command-line Command-line options -The context is configurable through command-line options, that are passed -either from the `Platform::*Application` classes or from the -@ref Platform::GLContext class. Usage: +In addition to the @ref Configuration, the context is configurable through +command-line options, that are passed either from the `Platform::*Application` +classes or from the @ref Platform::GLContext class. In case an option is set in +both the @ref Configuration and on command-line / environment, the two are +combined together --- flags ORed together, lists joined. Usage: @code{.sh} [--magnum-help] [--magnum-disable-workarounds LIST] @@ -134,20 +148,23 @@ Arguments: - `--magnum-help` --- display this help message and exit - `--magnum-disable-workarounds LIST` --- driver workarounds to disable (see @ref opengl-workarounds for detailed info) (environment: - `MAGNUM_DISABLE_WORKAROUNDS`) + `MAGNUM_DISABLE_WORKAROUNDS`). Corresponds to + @ref Configuration::addDisabledWorkarounds(). - `--magnum-disable-extensions LIST` --- API extensions to disable - (environment: `MAGNUM_DISABLE_EXTENSIONS`) + (environment: `MAGNUM_DISABLE_EXTENSIONS`). Corresponds to + @ref Configuration::addDisabledExtensions(). - `--magnum-gpu-validation off|on` --- GPU validation using @gl_extension{KHR,debug}, if present (environment: `MAGNUM_GPU_VALIDATION`) (default: `off`). This sets up @ref DebugOutput callbacks and also causes @ref Platform::Sdl2Application::GLConfiguration::Flag::Debug "GLConfiguration::Flag::Debug" to be enabled for context creation for both windowed and windowless - applications on supported platforms + applications on supported platforms. Corresponds to + @ref Configuration::Flag::GpuValidation. - `--magnum-log default|quiet|verbose` --- console logging - (environment: `MAGNUM_LOG`) (default: `default`). If you need to suppress - the engine startup log from code, the recommended way is to redirect - @ref Utility-Debug-scoped-output "debug output to null" during context creation. + (environment: `MAGNUM_LOG`) (default: `default`). Corresponds to + @ref Configuration::Flag::QuietLog and + @relativeref{Configuration::Flag,VerboseLog}. Note that all options are prefixed with `--magnum-` to avoid conflicts with options passed to the application itself. Options that don't have this prefix @@ -158,15 +175,7 @@ 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 -@ref hasCurrent() and @ref current() accessors are thread-local, matching the -OpenGL context thread locality. This might cause some performance penalties --- -if you are sure that you never need to have multiple independent thread-local -Magnum context, build Corrade with the option disabled. - -@section GL-Context-multiple Using multiple OpenGL contexts +@subsection GL-Context-usage-multiple Using multiple OpenGL contexts By default, Magnum assumes you have one OpenGL context active at all times, and all state tracking is done by the @ref Context instance that's associated with @@ -187,9 +196,19 @@ Once all needed instances are created, switch between them right after making the underlying GL context current: @snippet MagnumGL-framebuffer.cpp Context-makeCurrent + +@section GL-Context-multithreading Thread safety + +If Corrade is compiled with @ref CORRADE_BUILD_MULTITHREADED (the default), the +@ref hasCurrent() and @ref current() accessors are thread-local, matching the +OpenGL context thread locality. This might cause some performance penalties --- +if you are sure that you never need to have multiple independent thread-local +Magnum context, build Corrade with the option disabled. */ class MAGNUM_GL_EXPORT Context { public: + class Configuration; + #ifndef MAGNUM_TARGET_WEBGL /** * @brief Context flag @@ -204,7 +223,8 @@ class MAGNUM_GL_EXPORT Context { * Debug context. Enabled automatically by @ref Platform windowed * and windowless application implementations if the * `--magnum-gpu-validation` - * @ref GL-Context-command-line "command-line option" is present. + * @ref GL-Context-usage-command-line "command-line option" is + * present. * @requires_gl43 Extension @gl_extension{KHR,debug} * @requires_gles32 Extension @gl_extension{ANDROID,extension_pack_es31a} / * @gl_extension{KHR,debug} @@ -485,7 +505,7 @@ class MAGNUM_GL_EXPORT Context { * @m_since{2019,10} * * To be used when you need to manage multiple OpenGL contexts. See - * @ref GL-Context-multiple for more information. + * @ref GL-Context-usage-multiple for more information. */ static void makeCurrent(Context* context); @@ -693,8 +713,10 @@ class MAGNUM_GL_EXPORT Context { * @brief Whether given extension is disabled * * Can be used for detecting driver bug workarounds. Disabled - * extensions return `false` in @ref isExtensionSupported() even if - * they are advertised as being supported by the driver. + * extensions return @cpp false @ce in @ref isExtensionSupported() even + * if they are advertised as being supported by the driver. + * @see @ref Configuration::addDisabledExtensions(), + * @ref GL-Context-usage-command-line */ template bool isExtensionDisabled() const { return isExtensionDisabled(version()); @@ -705,6 +727,8 @@ class MAGNUM_GL_EXPORT Context { * * Similar to above, but can also check for extensions which are * disabled only for particular versions. + * @see @ref Configuration::addDisabledExtensions(), + * @ref GL-Context-usage-command-line */ template bool isExtensionDisabled(Version version) const { static_assert(Implementation::IsExtension::value, "expected an OpenGL extension"); @@ -717,8 +741,11 @@ class MAGNUM_GL_EXPORT Context { * @brief Whether given extension is disabled * * Can be used e.g. for listing extensions available on current - * hardware, but for general usage prefer @ref isExtensionDisabled() const, - * as it does most operations in compile time. + * hardware, but for general usage prefer + * @ref isExtensionDisabled() const, as it does most operations at + * compile time. + * @see @ref Configuration::addDisabledExtensions(), + * @ref GL-Context-usage-command-line */ bool isExtensionDisabled(const Extension& extension) const { return isVersionSupported(extension.requiredVersion()) && !isVersionSupported(_extensionRequiredVersion[extension.index()]); @@ -786,8 +813,8 @@ class MAGNUM_GL_EXPORT Context { explicit Context(NoCreateT, Utility::Arguments&& args, Int argc, const char** argv, void functionLoader(Context&)): Context{NoCreate, args, argc, argv, functionLoader} {} explicit Context(NoCreateT, Utility::Arguments& args, Int argc, const char** argv, void functionLoader(Context&)); - bool tryCreate(); - void create(); + bool tryCreate(const Configuration& configuration); + void create(const Configuration& configuration); private: #ifndef DOXYGEN_GENERATING_OUTPUT /* https://bugzilla.gnome.org/show_bug.cgi?id=776986 */ @@ -847,6 +874,206 @@ MAGNUM_GL_EXPORT Debug& operator<<(Debug& debug, Context::DetectedDriver value); /** @debugoperatorclassenum{Context,Context::DetectedDrivers} */ MAGNUM_GL_EXPORT Debug& operator<<(Debug& debug, Context::DetectedDrivers value); +/** +@brief Configuration +@m_since_latest + +Affects how Magnum's context creation behaves. See @ref GL-Context-usage for +more information. +@see @ref Platform::GLContext::GLContext(), + @ref Platform::GLContext::create(), + @ref Platform::GLContext::tryCreate() +*/ +class MAGNUM_GL_EXPORT Context::Configuration { + public: + /** + * @brief Context setup flag + * + * Flags affecting the actual GL context are merged with this enum in + * @ref Platform::Sdl2Application::GLConfiguration::Flag "Platform::*Application::GLConfiguration::Flag" + * and @ref Platform::WindowlessEglContext::Configuration::Flag "Platform::Windowless*Application::Configuration::Flag" + * and after context creation available through @ref Context::Flag / + * @ref Context::flags(). + * @see @ref Flags, @ref setFlags() + */ + enum class Flag: UnsignedLong { + /* Keeping the 32-bit range reserved for actual GL context flags */ + + /** + * Print only warnings and errors instead of the usual startup log + * listing used extensions and workarounds. Ignored if + * @ref Flag::VerboseLog is set. + * + * Corresponds to the `--magnum-log quiet` + * @ref GL-Context-usage-command-line "command-line option". + */ + QuietLog = 1ull << 61, + + /** + * Print additional information on startup in addition to the usual + * startup log that lists used extensions and workarounds. Has a + * precedence over @ref Flag::QuietLog. + * + * Corresponds to the `--magnum-log verbose` + * @ref GL-Context-usage-command-line "command-line option". + */ + VerboseLog = 1ull << 62, + + /** + * Enable GPU validation, if available. + * + * Corresponds to the `--magnum-gou-validation on` + * @ref GL-Context-usage-command-line "command-line option". + */ + GpuValidation = 1ull << 63 + }; + + /** + * @brief Context setup flags + * + * @see @ref setFlags(), @ref GL::Context::Flags + */ + typedef Containers::EnumSet Flags; + + /*implicit*/ Configuration(); + + /** @brief Copy constructor */ + /* The class has to be copyable in order to make command-line and + configuration options easy to merge in application implementations + -- these make a mutable copy and add what arrived via command line */ + Configuration(const Configuration& other); + + /** @brief Move constructor */ + Configuration(Configuration&&) noexcept; + + ~Configuration(); + + /** @brief Copy constructor */ + Configuration& operator=(const Configuration& other); + + /** @brief Move assignment */ + Configuration& operator=(Configuration&&) noexcept; + + /** @brief Context setup flags */ + Flags flags() const { return _flags; } + + /** + * @brief Set context setup flags + * @return Reference to self (for method chaining) + * + * By default no flags are set. Note that subclasses might have + * different flag defaults, see their documentation for more + * information. To avoid clearing default flags by accident, prefer to + * use @ref addFlags() and @ref clearFlags() instead. + * + * Particular @ref Flag values correspond to the `--magnum-log` and + * `--magnum-gpu-validation` + * @ref GL-Context-usage-command-line "command-line options". + */ + Configuration& setFlags(Flags flags) { + _flags = flags; + return *this; + } + + /** + * @brief Add context setup flags + * @return Reference to self (for method chaining) + * + * Unlike @ref setFlags(), ORs the flags with existing instead of + * replacing them. Useful for preserving the defaults. + * @see @ref clearFlags() + */ + Configuration& addFlags(Flags flags) { + _flags |= flags; + return *this; + } + + /** + * @brief Clear context setup flags + * @return Reference to self (for method chaining) + * + * Unlike @ref setFlags(), ANDs the inverse of @p flags with existing + * instead of replacing them. Useful for removing default flags. + * @see @ref addFlags() + */ + Configuration& clearFlags(Flags flags) { + _flags &= ~flags; + return *this; + } + + /** @brief Disabled driver workarounds */ + Containers::ArrayView disabledWorkarounds() const; + + /** + * @brief Add disabled driver workarounds + * @return Reference to self (for method chaining) + * + * Accepts strings from the list at @ref opengl-workarounds. Unknown + * workarounds are ignored with a warning. By default no workarounds + * are disabled. + * + * Corresponds to the `--magnum-disable-workarounds` + * @ref GL-Context-usage-command-line "command-line option". + */ + Configuration& addDisabledWorkarounds(Containers::ArrayView workarounds); + /** @overload */ + Configuration& addDisabledWorkarounds(std::initializer_list workarounds); + + /** @brief Disabled extensions */ + Containers::ArrayView disabledExtensions() const; + + /** + * @brief Add disabled extensions + * @return Reference to self (for method chaining) + * + * By default no extensions are disabled, except for those disabled by + * driver workarounds. + * + * Corresponds to the `--magnum-disable-extensions` + * @ref GL-Context-usage-command-line "command-line option". + */ + Configuration& addDisabledExtensions(Containers::ArrayView extensions); + /** @overload */ + Configuration& addDisabledExtensions(std::initializer_list extensions); + /** @overload */ + template Configuration& addDisabledExtensions() { + static_assert(Implementation::IsExtension::value, "expected only OpenGL extensions"); + return addDisabledExtensions({E{}...}); + } + + private: + Flags _flags; + Containers::Array _disabledWorkarounds; + Containers::Array _disabledExtensions; +}; + +#ifndef DOXYGEN_GENERATING_OUTPUT +#define MAGNUM_GL_CONTEXT_CONFIGURATION_SUBCLASS_IMPLEMENTATION(Type) \ + Type& addDisabledWorkarounds(Containers::ArrayView workarounds) { \ + GL::Context::Configuration::addDisabledWorkarounds(workarounds); \ + return *this; \ + } \ + Type& addDisabledWorkarounds(std::initializer_list workarounds) { \ + GL::Context::Configuration::addDisabledWorkarounds(workarounds); \ + return *this; \ + } \ + \ + Type& addDisabledExtensions(Containers::ArrayView extensions) { \ + GL::Context::Configuration::addDisabledExtensions(extensions); \ + return *this; \ + } \ + Type& addDisabledExtensions(std::initializer_list extensions) { \ + GL::Context::Configuration::addDisabledExtensions(extensions); \ + return *this; \ + } \ + template Type& addDisabledExtensions() { \ + GL::Context::Configuration::addDisabledExtensions(); \ + return *this; \ + } +#endif + +CORRADE_ENUMSET_OPERATORS(Context::Configuration::Flags) + /** @hideinitializer @brief Assert that given OpenGL version is supported @param version Version diff --git a/src/Magnum/GL/DebugOutput.h b/src/Magnum/GL/DebugOutput.h index 3982068c2..3bbe6a913 100644 --- a/src/Magnum/GL/DebugOutput.h +++ b/src/Magnum/GL/DebugOutput.h @@ -79,8 +79,8 @@ application itself by setting up message callback using @ref setCallback() or @par Enabling debug output from the command line / environment Apart from setting up the debug output callbacks manually, it's also possible to enable it conveniently using the `--magnum-gpu-validation` - @ref GL-Context-command-line "command-line or environment option" --- ideal - for quick debugging of rendering issues. If you are using application + @ref GL-Context-usage-command-line "command-line or environment option" --- + ideal for quick debugging of rendering issues. If you are using application classes from the @ref Platform namespace, this option also ensures that @ref Platform::Sdl2Application::GLConfiguration::Flag::Debug "GLConfiguration::Flag::Debug" is passed for context creation, both with windowed and windowless diff --git a/src/Magnum/GL/Implementation/driverSpecific.cpp b/src/Magnum/GL/Implementation/driverSpecific.cpp index 9b681b544..9ac84a136 100644 --- a/src/Magnum/GL/Implementation/driverSpecific.cpp +++ b/src/Magnum/GL/Implementation/driverSpecific.cpp @@ -616,4 +616,27 @@ void Context::setupDriverWorkarounds() { #endif } +Context::Configuration& Context::Configuration::addDisabledWorkarounds(Containers::ArrayView workarounds) { + arrayReserve(_disabledWorkarounds, _disabledWorkarounds.size() + workarounds.size()); + + for(const Containers::StringView workaround: workarounds) { + /* Find the workaround. Note that we'll add the found view to the array + and not the passed view, as the found view is guaranteed to stay in + scope */ + const Containers::StringView found = findWorkaround(workaround); + + /* Ignore unknown workarounds */ + /** @todo this will probably cause false positives when both GL and + Vulkan is used together? */ + if(found.isEmpty()) { + Warning{} << "GL::Context::Configuration::addDisabledWorkarounds(): unknown workaround" << workaround; + continue; + } + + arrayAppend(_disabledWorkarounds, Containers::InPlaceInit, found); + } + + return *this; +} + }} diff --git a/src/Magnum/GL/OpenGLTester.h b/src/Magnum/GL/OpenGLTester.h index d9da1a633..cf13f9aa0 100644 --- a/src/Magnum/GL/OpenGLTester.h +++ b/src/Magnum/GL/OpenGLTester.h @@ -132,7 +132,7 @@ by default to make the test output more readable. Instead of relying on debug output to report errors, the @ref MAGNUM_VERIFY_NO_GL_ERROR() macro should be used to reliably check for errors regardless of platform support. For easier debugging of OpenGL errors users are encuraged to use the -`--magnum-gpu-validation` @ref GL-Context-command-line "command line option", +`--magnum-gpu-validation` @ref GL-Context-usage-command-line "command line option", which is supported here as well as in all other application implementations. @section GL-OpenGLTester-benchmarks GPU time benchmarks diff --git a/src/Magnum/GL/Test/ContextGLTest.cpp b/src/Magnum/GL/Test/ContextGLTest.cpp index c51635338..d14910ca6 100644 --- a/src/Magnum/GL/Test/ContextGLTest.cpp +++ b/src/Magnum/GL/Test/ContextGLTest.cpp @@ -24,6 +24,9 @@ */ #include +#include +#include +#include #include #include @@ -43,6 +46,8 @@ struct ContextGLTest: OpenGLTester { void stringFlags(); + void constructConfiguration(); + void makeCurrent(); #ifndef CORRADE_TARGET_EMSCRIPTEN @@ -58,10 +63,89 @@ struct ContextGLTest: OpenGLTester { void isExtensionDisabled(); }; +using namespace Containers::Literals; + +struct { + const char* name; + Containers::Optional needsExtensionPresent, needsExtensionMissing; + Context::Configuration::Flags flags; + Containers::Array disabledWorkarounds; + Containers::Array disabledExtensions; + Containers::Array args; + Containers::StringView logShouldContain, logShouldNotContain; +} ConstructConfigurationData[] { + {"default log", {}, {}, + {}, + {}, {}, {}, + "Renderer: ", {}}, + {"quiet", {}, {}, + Context::Configuration::Flag::QuietLog, + {}, {}, {}, + {}, "Renderer: "}, + {"quiet on command line", {}, {}, {}, {}, {}, + Containers::array({"", "--magnum-log", "quiet"}), + {}, "Renderer: "}, + {"quiet and verbose", {}, {}, + Context::Configuration::Flag::QuietLog|Context::Configuration::Flag::VerboseLog, + {}, {}, {}, + /* Verbose has a precedence */ + "Renderer: ", {}}, + {"quiet and verbose on command line", {}, {}, + Context::Configuration::Flag::QuietLog, + {}, {}, + Containers::array({"", "--magnum-log", "verbose"}), + /* Command-line has a precedence */ + "Renderer: ", {}}, + {"verbose and quiet on command line", {}, {}, + Context::Configuration::Flag::VerboseLog, + {}, {}, + Containers::array({"", "--magnum-log", "quiet"}), + /* Command-line has a precedence */ + {}, "Renderer: "}, + #ifndef MAGNUM_TARGET_GLES + {"default workarounds", {}, {}, {}, {}, {}, {}, + "\nUsing driver workarounds:\n no-layout-qualifiers-on-old-glsl\n", {}}, + {"disabled workaround", {}, {}, {}, + Containers::array({"no-layout-qualifiers-on-old-glsl"_s}), {}, {}, + {}, "no-layout-qualifiers-on-old-glsl"}, + {"disabled workaround on command line", {}, {}, {}, {}, {}, + Containers::array({"", "--magnum-disable-workarounds", "no-layout-qualifiers-on-old-glsl"}), + {}, "no-layout-qualifiers-on-old-glsl"}, + #endif + #ifndef MAGNUM_TARGET_GLES + {"default extensions ARB", + Extension{Extensions::ARB::texture_filter_anisotropic{}}, + {}, {}, {}, {}, {}, + " GL_ARB_texture_filter_anisotropic\n", {}}, + #endif + {"default extensions EXT", + Extension{Extensions::EXT::texture_filter_anisotropic{}}, + #ifndef MAGNUM_TARGET_GLES + Extension{Extensions::ARB::texture_filter_anisotropic{}}, + #else + {}, + #endif + {}, {}, {}, {}, + " GL_EXT_texture_filter_anisotropic\n", {}}, + {"disabled extension", + Extension{Extensions::EXT::texture_filter_anisotropic{}}, + {}, {}, {}, + Containers::array({Extensions::EXT::texture_filter_anisotropic{}}), {}, + "Disabling extensions:\n GL_EXT_texture_filter_anisotropic\n", {}}, + {"disabled extension on command line", + Extension{Extensions::EXT::texture_filter_anisotropic{}}, + {}, {}, {}, {}, + Containers::array({"", "--magnum-disable-extensions", "GL_EXT_texture_filter_anisotropic"}), + "Disabling extensions:\n GL_EXT_texture_filter_anisotropic\n", {}}, +}; + ContextGLTest::ContextGLTest() { - addTests({ - &ContextGLTest::stringFlags, + addTests({&ContextGLTest::stringFlags}); + + addInstancedTests({&ContextGLTest::constructConfiguration}, + Containers::arraySize(ConstructConfigurationData)); + addTests({ &ContextGLTest::makeCurrent, #ifndef CORRADE_TARGET_EMSCRIPTEN @@ -116,6 +200,43 @@ void ContextGLTest::stringFlags() { } } +void ContextGLTest::constructConfiguration() { + auto&& data = ConstructConfigurationData[testCaseInstanceId()]; + setTestCaseDescription(data.name); + + if(std::getenv("MAGNUM_DISABLE_WORKAROUNDS")) + CORRADE_SKIP("Can't test with the MAGNUM_DISABLE_WORKAROUNDS environment variable set"); + if(std::getenv("MAGNUM_DISABLE_EXTENSIONS")) + CORRADE_SKIP("Can't test with the MAGNUM_DISABLE_EXTENSIONS environment variable set"); + + CORRADE_VERIFY(Context::hasCurrent()); + + if(data.needsExtensionPresent && !Context::current().isExtensionSupported(*data.needsExtensionPresent)) + CORRADE_SKIP(data.needsExtensionPresent->string() + std::string{" is not supported, skippping"}); + if(data.needsExtensionMissing && Context::current().isExtensionSupported(*data.needsExtensionMissing)) + CORRADE_SKIP(data.needsExtensionMissing->string() + std::string{" is supported, skippping"}); + + std::ostringstream out; + { + Context* current = &Context::current(); + Context::makeCurrent(nullptr); + Containers::ScopeGuard resetCurrent{current, Context::makeCurrent}; + + Debug redirectOut{&out}; + Platform::GLContext ctx{Int(data.args.size()), data.args, Context::Configuration{} + .setFlags(data.flags) + .addDisabledWorkarounds(data.disabledWorkarounds) + .addDisabledExtensions(data.disabledExtensions) + }; + } + + /** @todo TestSuite::Compare::StringContains / NotContains for proper diag */ + if(!data.logShouldContain.isEmpty()) + CORRADE_VERIFY(Containers::StringView{out.str()}.contains(data.logShouldContain)); + if(!data.logShouldNotContain.isEmpty()) + CORRADE_VERIFY(!Containers::StringView{out.str()}.contains(data.logShouldNotContain)); +} + void ContextGLTest::makeCurrent() { CORRADE_VERIFY(Context::hasCurrent()); diff --git a/src/Magnum/GL/Test/ContextTest.cpp b/src/Magnum/GL/Test/ContextTest.cpp index c393e1048..0651a2a31 100644 --- a/src/Magnum/GL/Test/ContextTest.cpp +++ b/src/Magnum/GL/Test/ContextTest.cpp @@ -25,7 +25,9 @@ #include #include +#include #include +#include #include #include "Magnum/GL/Context.h" @@ -39,6 +41,11 @@ struct ContextTest: TestSuite::Tester { void isExtension(); + void configurationConstruct(); + void configurationConstructUnknownWorkaround(); + void configurationConstructCopy(); + void configurationConstructMove(); + void constructNoCreate(); void constructCopyMove(); @@ -56,6 +63,11 @@ struct ContextTest: TestSuite::Tester { ContextTest::ContextTest() { addTests({&ContextTest::isExtension, + &ContextTest::configurationConstruct, + &ContextTest::configurationConstructUnknownWorkaround, + &ContextTest::configurationConstructCopy, + &ContextTest::configurationConstructMove, + &ContextTest::constructNoCreate, &ContextTest::constructCopyMove, @@ -71,7 +83,7 @@ ContextTest::ContextTest() { } void ContextTest::isExtension() { - CORRADE_VERIFY(Implementation::IsExtension::value); + CORRADE_VERIFY(Implementation::IsExtension::value); CORRADE_VERIFY(!Implementation::IsExtension::value); CORRADE_VERIFY(!Implementation::IsExtension::value); @@ -86,8 +98,9 @@ void ContextTest::isExtension() { CORRADE_VERIFY(!Implementation::IsExtension::value); } - /* Variadic check (used in variadic addEnabledExtensions()), check that it - properly fails for each occurence of a non-extension */ + /* Variadic check (used in variadic Configuration::addDisabledExtensions()), + check that it properly fails for each occurence of a non-extension */ + #ifndef MAGNUM_TARGET_WEBGL CORRADE_VERIFY((Implementation::IsExtension< Extensions::KHR::debug, Extensions::EXT::texture_filter_anisotropic, @@ -104,11 +117,219 @@ void ContextTest::isExtension() { Extensions::KHR::debug, Extensions::EXT::texture_filter_anisotropic, Extension>::value)); + #else + CORRADE_VERIFY((Implementation::IsExtension< + Extensions::OES::texture_float_linear, + Extensions::EXT::texture_filter_anisotropic, + Extensions::WEBGL::compressed_texture_s3tc>::value)); + CORRADE_VERIFY(!(Implementation::IsExtension< + Extension, + Extensions::OES::texture_float_linear, + Extensions::EXT::texture_filter_anisotropic>::value)); + CORRADE_VERIFY(!(Implementation::IsExtension< + Extensions::OES::texture_float_linear, + Extension, + Extensions::EXT::texture_filter_anisotropic>::value)); + CORRADE_VERIFY(!(Implementation::IsExtension< + Extensions::OES::texture_float_linear, + Extensions::EXT::texture_filter_anisotropic, + Extension>::value)); + #endif /* Empty variadic list should return true */ CORRADE_VERIFY(Implementation::IsExtension<>::value); } +void ContextTest::configurationConstruct() { + #ifndef MAGNUM_TARGET_GLES + const Containers::StringView a = "no-layout-qualifiers-on-old-glsl"; + const Containers::StringView b = "nv-compressed-block-size-in-bits"; + const Containers::StringView c = "nv-cubemap-inconsistent-compressed-image-size"; + #elif !defined(MAGNUM_TARGET_WEBGL) + const Containers::StringView a = "swiftshader-no-empty-egl-context-flags"; + const Containers::StringView b = "swiftshader-egl-context-needs-pbuffer"; + const Containers::StringView c = "angle-chatty-shader-compiler"; + #else + /* No general WebGL workarounds to test */ + #endif + /* Deliberately not having the literals global to test that they get + converted to something else */ + CORRADE_VERIFY(!(a.flags() & Containers::StringViewFlag::Global)); + + Context::Configuration configuration; + configuration + .setFlags(Context::Configuration::Flag::GpuValidation| + Context::Configuration::Flag::VerboseLog) + #ifndef MAGNUM_TARGET_WEBGL + .addDisabledWorkarounds({a, b}) + .addDisabledWorkarounds({c}) + #endif + #ifndef MAGNUM_TARGET_WEBGL + .addDisabledExtensions({Extensions::EXT::texture_filter_anisotropic{}, + Extensions::KHR::debug{}}) + .addDisabledExtensions() + #else + .addDisabledExtensions({Extensions::EXT::texture_filter_anisotropic{}, + Extensions::EXT::texture_compression_rgtc{}}) + .addDisabledExtensions() + #endif + ; + + CORRADE_COMPARE(UnsignedLong(configuration.flags()), UnsignedLong( + Context::Configuration::Flag::GpuValidation| + Context::Configuration::Flag::VerboseLog)); + + /* The workaround strings should get interned */ + #ifndef MAGNUM_TARGET_WEBGL + CORRADE_COMPARE_AS(configuration.disabledWorkarounds(), + Containers::arrayView({a, b, c}), + TestSuite::Compare::Container); + CORRADE_VERIFY(configuration.disabledWorkarounds()[0].data() != a.data()); + CORRADE_VERIFY(configuration.disabledWorkarounds()[1].data() != b.data()); + CORRADE_VERIFY(configuration.disabledWorkarounds()[2].data() != c.data()); + CORRADE_COMPARE(configuration.disabledWorkarounds()[0].flags(), + Containers::StringViewFlag::Global|Containers::StringViewFlag::NullTerminated); + CORRADE_COMPARE(configuration.disabledWorkarounds()[1].flags(), + Containers::StringViewFlag::Global|Containers::StringViewFlag::NullTerminated); + CORRADE_COMPARE(configuration.disabledWorkarounds()[2].flags(), + Containers::StringViewFlag::Global|Containers::StringViewFlag::NullTerminated); + #endif + + CORRADE_COMPARE(configuration.disabledExtensions().size(), 4); + #ifndef MAGNUM_TARGET_WEBGL + CORRADE_COMPARE(configuration.disabledExtensions()[0].index(), Extensions::EXT::texture_filter_anisotropic::Index); + CORRADE_COMPARE(configuration.disabledExtensions()[1].index(), Extensions::KHR::debug::Index); + CORRADE_COMPARE(configuration.disabledExtensions()[2].index(), Extensions::KHR::robustness::Index); + CORRADE_COMPARE(configuration.disabledExtensions()[3].index(), Extensions::KHR::texture_compression_astc_hdr::Index); + #else + CORRADE_COMPARE(configuration.disabledExtensions()[0].index(), Extensions::EXT::texture_filter_anisotropic::Index); + CORRADE_COMPARE(configuration.disabledExtensions()[1].index(), Extensions::EXT::texture_compression_rgtc::Index); + CORRADE_COMPARE(configuration.disabledExtensions()[2].index(), Extensions::EXT::float_blend::Index); + CORRADE_COMPARE(configuration.disabledExtensions()[3].index(), Extensions::OES::texture_float_linear::Index); + #endif +} + +void ContextTest::configurationConstructUnknownWorkaround() { + Context::Configuration configuration; + + /* Unknown workarounds should get ignored -- we're storing views on + internally known workaround strings to avoid allocations so there's no + other way */ + std::ostringstream out; + Warning redirectWarning{&out}; + configuration.addDisabledWorkarounds({"all-drivers-are-shit"}); + CORRADE_VERIFY(configuration.disabledWorkarounds().empty()); + CORRADE_COMPARE(out.str(), "GL::Context::Configuration::addDisabledWorkarounds(): unknown workaround all-drivers-are-shit\n"); +} + +void ContextTest::configurationConstructCopy() { + #ifndef MAGNUM_TARGET_GLES + Containers::StringView workaround = "no-layout-qualifiers-on-old-glsl"; + Containers::StringView another = "nv-compressed-block-size-in-bits"; + #elif !defined(MAGNUM_TARGET_WEBGL) + Containers::StringView workaround = "swiftshader-no-empty-egl-context-flags"; + Containers::StringView another = "angle-chatty-shader-compiler"; + #else + /* No general WebGL workarounds to test */ + #endif + + Context::Configuration a; + a.setFlags(Context::Configuration::Flag::VerboseLog) + #ifndef MAGNUM_TARGET_WEBGL + .addDisabledWorkarounds({workaround}) + #endif + .addDisabledExtensions(); + + Context::Configuration b = a; + CORRADE_COMPARE(UnsignedLong(b.flags()), UnsignedLong(Context::Configuration::Flag::VerboseLog)); + #ifndef MAGNUM_TARGET_WEBGL + CORRADE_COMPARE_AS(b.disabledWorkarounds(), + Containers::arrayView({workaround}), + TestSuite::Compare::Container); + #endif + CORRADE_COMPARE(b.disabledExtensions().size(), 1); + CORRADE_COMPARE(b.disabledExtensions()[0].index(), Extensions::EXT::texture_filter_anisotropic::Index); + + Context::Configuration c; + c.setFlags(Context::Configuration::Flag::QuietLog) + #ifndef MAGNUM_TARGET_WEBGL + .addDisabledWorkarounds({another}) + .addDisabledExtensions() + #else + .addDisabledExtensions() + #endif + ; + + c = b; + CORRADE_COMPARE(UnsignedLong(c.flags()), UnsignedLong(Context::Configuration::Flag::VerboseLog)); + #ifndef MAGNUM_TARGET_WEBGL + CORRADE_COMPARE_AS(c.disabledWorkarounds(), + Containers::arrayView({workaround}), + TestSuite::Compare::Container); + #endif + CORRADE_COMPARE(c.disabledExtensions().size(), 1); + CORRADE_COMPARE(c.disabledExtensions()[0].index(), Extensions::EXT::texture_filter_anisotropic::Index); +} + +void ContextTest::configurationConstructMove() { + #ifndef MAGNUM_TARGET_GLES + Containers::StringView workaround = "no-layout-qualifiers-on-old-glsl"; + Containers::StringView another = "nv-compressed-block-size-in-bits"; + #elif !defined(MAGNUM_TARGET_WEBGL) + Containers::StringView workaround = "swiftshader-no-empty-egl-context-flags"; + Containers::StringView another = "angle-chatty-shader-compiler"; + #else + /* No general WebGL workarounds to test */ + #endif + + Context::Configuration a; + a.setFlags(Context::Configuration::Flag::VerboseLog) + #ifndef MAGNUM_TARGET_WEBGL + .addDisabledWorkarounds({workaround}) + #endif + .addDisabledExtensions(); + + Context::Configuration b = std::move(a); + CORRADE_COMPARE(UnsignedLong(b.flags()), UnsignedLong(Context::Configuration::Flag::VerboseLog)); + CORRADE_VERIFY(a.disabledWorkarounds().empty()); + CORRADE_VERIFY(a.disabledExtensions().empty()); + #ifndef MAGNUM_TARGET_WEBGL + CORRADE_COMPARE_AS(b.disabledWorkarounds(), + Containers::arrayView({workaround}), + TestSuite::Compare::Container); + #endif + CORRADE_COMPARE(b.disabledExtensions().size(), 1); + CORRADE_COMPARE(b.disabledExtensions()[0].index(), Extensions::EXT::texture_filter_anisotropic::Index); + + Context::Configuration c; + c.setFlags(Context::Configuration::Flag::QuietLog) + #ifndef MAGNUM_TARGET_WEBGL + .addDisabledWorkarounds({another, another}) + .addDisabledExtensions() + #else + .addDisabledExtensions() + #endif + ; + + c = std::move(b); + #ifndef MAGNUM_TARGET_WEBGL + CORRADE_COMPARE(b.disabledWorkarounds().size(), 2); + #endif + CORRADE_COMPARE(b.disabledExtensions().size(), 2); + CORRADE_COMPARE(UnsignedLong(c.flags()), UnsignedLong(Context::Configuration::Flag::VerboseLog)); + #ifndef MAGNUM_TARGET_WEBGL + CORRADE_COMPARE_AS(c.disabledWorkarounds(), + Containers::arrayView({workaround}), + TestSuite::Compare::Container); + #endif + CORRADE_COMPARE(c.disabledExtensions().size(), 1); + CORRADE_COMPARE(c.disabledExtensions()[0].index(), Extensions::EXT::texture_filter_anisotropic::Index); +} + void ContextTest::constructNoCreate() { { /* Shouldn't crash during construction, shouldn't attempt to access GL, diff --git a/src/Magnum/Platform/AbstractXApplication.cpp b/src/Magnum/Platform/AbstractXApplication.cpp index 24b1e06c7..99f34a05d 100644 --- a/src/Magnum/Platform/AbstractXApplication.cpp +++ b/src/Magnum/Platform/AbstractXApplication.cpp @@ -105,7 +105,7 @@ bool AbstractXApplication::tryCreate(const Configuration& configuration, const G _contextHandler->makeCurrent(); /* Return true if the initialization succeeds */ - return _context->tryCreate(); + return _context->tryCreate(glConfiguration); } AbstractXApplication::~AbstractXApplication() { diff --git a/src/Magnum/Platform/AbstractXApplication.h b/src/Magnum/Platform/AbstractXApplication.h index e2745093f..adc4193ef 100644 --- a/src/Magnum/Platform/AbstractXApplication.h +++ b/src/Magnum/Platform/AbstractXApplication.h @@ -60,7 +60,7 @@ typedef int Bool; #include "Magnum/Magnum.h" #include "Magnum/Tags.h" -#include "Magnum/GL/GL.h" +#include "Magnum/GL/Context.h" #include "Magnum/Math/Vector2.h" #include "Magnum/Platform/Platform.h" @@ -336,7 +336,7 @@ Double-buffered OpenGL context. @ref Configuration, @ref create(), @ref tryCreate() @todo GLX_ARB_create_context_robustness/EGL_EXT_create_context_robustness */ -class AbstractXApplication::GLConfiguration { +class AbstractXApplication::GLConfiguration: public GL::Context::Configuration { public: explicit GLConfiguration(); ~GLConfiguration(); @@ -350,6 +350,23 @@ class AbstractXApplication::GLConfiguration { return *this; } + /* Overloads to remove WTF-factor from method chaining order */ + #ifndef DOXYGEN_GENERATING_OUTPUT + GLConfiguration& setFlags(Flags flags) { + GL::Context::Configuration::setFlags(flags); + return *this; + } + GLConfiguration& addFlags(Flags flags) { + GL::Context::Configuration::addFlags(flags); + return *this; + } + GLConfiguration& clearFlags(Flags flags) { + GL::Context::Configuration::clearFlags(flags); + return *this; + } + MAGNUM_GL_CONTEXT_CONFIGURATION_SUBCLASS_IMPLEMENTATION(GLConfiguration) + #endif + private: GL::Version _version; }; diff --git a/src/Magnum/Platform/AndroidApplication.cpp b/src/Magnum/Platform/AndroidApplication.cpp index abc5e983c..b45ea7d77 100644 --- a/src/Magnum/Platform/AndroidApplication.cpp +++ b/src/Magnum/Platform/AndroidApplication.cpp @@ -167,7 +167,7 @@ bool AndroidApplication::tryCreate(const Configuration& configuration, const GLC CORRADE_INTERNAL_ASSERT_OUTPUT(eglMakeCurrent(_display, _surface, _surface, _glContext)); /* Return true if the initialization succeeds */ - return _context->tryCreate(); + return _context->tryCreate(glConfiguration); } Vector2i AndroidApplication::framebufferSize() const { diff --git a/src/Magnum/Platform/AndroidApplication.h b/src/Magnum/Platform/AndroidApplication.h index dd12a508d..e09a2e368 100644 --- a/src/Magnum/Platform/AndroidApplication.h +++ b/src/Magnum/Platform/AndroidApplication.h @@ -36,7 +36,7 @@ #include "Magnum/Magnum.h" #include "Magnum/Tags.h" -#include "Magnum/GL/GL.h" +#include "Magnum/GL/Context.h" #include "Magnum/Math/Vector4.h" #include "Magnum/Platform/Platform.h" @@ -448,7 +448,7 @@ Double-buffered RGBA canvas with depth and stencil buffers. @see @ref AndroidApplication(), @ref Configuration, @ref create(), @ref tryCreate() */ -class AndroidApplication::GLConfiguration { +class AndroidApplication::GLConfiguration: public GL::Context::Configuration { public: /*implicit*/ GLConfiguration(); @@ -504,6 +504,23 @@ class AndroidApplication::GLConfiguration { return *this; } + /* Overloads to remove WTF-factor from method chaining order */ + #ifndef DOXYGEN_GENERATING_OUTPUT + GLConfiguration& setFlags(Flags flags) { + GL::Context::Configuration::setFlags(flags); + return *this; + } + GLConfiguration& addFlags(Flags flags) { + GL::Context::Configuration::addFlags(flags); + return *this; + } + GLConfiguration& clearFlags(Flags flags) { + GL::Context::Configuration::clearFlags(flags); + return *this; + } + MAGNUM_GL_CONTEXT_CONFIGURATION_SUBCLASS_IMPLEMENTATION(GLConfiguration) + #endif + private: Vector4i _colorBufferSize; Int _depthBufferSize, _stencilBufferSize; diff --git a/src/Magnum/Platform/EmscriptenApplication.cpp b/src/Magnum/Platform/EmscriptenApplication.cpp index 63d8fdeaf..86d826c6c 100644 --- a/src/Magnum/Platform/EmscriptenApplication.cpp +++ b/src/Magnum/Platform/EmscriptenApplication.cpp @@ -450,7 +450,7 @@ bool EmscriptenApplication::tryCreate(const Configuration& configuration, const setupAnimationFrame(!!(configuration.windowFlags() & Configuration::WindowFlag::AlwaysRequestAnimationFrame)); /* Return true if the initialization succeeds */ - return _context->tryCreate(); + return _context->tryCreate(glConfiguration); } #endif @@ -770,7 +770,10 @@ void EmscriptenApplication::textInputEvent(TextInputEvent&) {} #ifdef MAGNUM_TARGET_GL EmscriptenApplication::GLConfiguration::GLConfiguration(): _colorBufferSize{8, 8, 8, 8}, _depthBufferSize{24}, _stencilBufferSize{0}, - _sampleCount{0} {} + _sampleCount{0} +{ + addFlags(Flag::EnableExtensionsByDefault); +} #endif int EmscriptenApplication::exec() { diff --git a/src/Magnum/Platform/EmscriptenApplication.h b/src/Magnum/Platform/EmscriptenApplication.h index 1f16dfbb9..3d7d0b81f 100644 --- a/src/Magnum/Platform/EmscriptenApplication.h +++ b/src/Magnum/Platform/EmscriptenApplication.h @@ -40,7 +40,7 @@ #include "Magnum/Magnum.h" #include "Magnum/Tags.h" -#include "Magnum/GL/GL.h" +#include "Magnum/GL/Context.h" #include "Magnum/Math/Vector4.h" #include "Magnum/Platform/Platform.h" @@ -926,14 +926,15 @@ The created context is always with a double-buffered OpenGL context. @see @ref EmscriptenApplication(), @ref Configuration, @ref create(), @ref tryCreate() */ -class EmscriptenApplication::GLConfiguration { +class EmscriptenApplication::GLConfiguration: public GL::Context::Configuration { public: /** * @brief Context flag * + * Includes also everything from @ref GL::Context::Configuration::Flag. * @see @ref Flags, @ref setFlags(), @ref GL::Context::Flag */ - enum class Flag: Int { + enum class Flag: UnsignedLong { /** * Premultiplied alpha. If set, the alpha channel of the rendering * context will be treated as representing premultiplied alpha @@ -987,7 +988,25 @@ class EmscriptenApplication::GLConfiguration { * Proxy content to main thread. For more details, see the * [Emscripten API reference](https://emscripten.org/docs/api_reference/html5.h.html#c.EmscriptenWebGLContextAttributes.proxyContextToMainThread). */ - ProxyContextToMainThread = 1 << 7 + ProxyContextToMainThread = 1 << 7, + + /** + * @copydoc GL::Context::Configuration::Flag::QuietLog + * @m_since_latest + */ + QuietLog = UnsignedLong(GL::Context::Configuration::Flag::QuietLog), + + /** + * @copydoc GL::Context::Configuration::Flag::VerboseLog + * @m_since_latest + */ + VerboseLog = UnsignedLong(GL::Context::Configuration::Flag::VerboseLog), + + /** + * @copydoc GL::Context::Configuration::Flag::GpuValidation + * @m_since_latest + */ + GpuValidation = UnsignedLong(GL::Context::Configuration::Flag::GpuValidation) }; /** @@ -1000,7 +1019,9 @@ class EmscriptenApplication::GLConfiguration { /*implicit*/ GLConfiguration(); /** @brief Context flags */ - Flags flags() const { return _flags; } + Flags flags() const { + return Flag(UnsignedLong(GL::Context::Configuration::flags())); + } /** * @brief Set context flags @@ -1012,7 +1033,7 @@ class EmscriptenApplication::GLConfiguration { * @see @ref GL::Context::flags() */ GLConfiguration& setFlags(Flags flags) { - _flags = flags; + GL::Context::Configuration::setFlags(GL::Context::Configuration::Flag(UnsignedLong(flags))); return *this; } @@ -1025,7 +1046,7 @@ class EmscriptenApplication::GLConfiguration { * @see @ref clearFlags() */ GLConfiguration& addFlags(Flags flags) { - _flags |= flags; + GL::Context::Configuration::addFlags(GL::Context::Configuration::Flag(UnsignedLong(flags))); return *this; } @@ -1038,7 +1059,7 @@ class EmscriptenApplication::GLConfiguration { * @see @ref addFlags() */ GLConfiguration& clearFlags(Flags flags) { - _flags &= ~flags; + GL::Context::Configuration::clearFlags(GL::Context::Configuration::Flag(UnsignedLong(flags))); return *this; } @@ -1112,12 +1133,15 @@ class EmscriptenApplication::GLConfiguration { return *this; } + /* Overloads to remove WTF-factor from method chaining order */ + #ifndef DOXYGEN_GENERATING_OUTPUT + MAGNUM_GL_CONTEXT_CONFIGURATION_SUBCLASS_IMPLEMENTATION(GLConfiguration) + #endif + private: Vector4i _colorBufferSize; Int _depthBufferSize, _stencilBufferSize; Int _sampleCount; - - Flags _flags{Flag::EnableExtensionsByDefault}; }; CORRADE_ENUMSET_OPERATORS(EmscriptenApplication::GLConfiguration::Flags) diff --git a/src/Magnum/Platform/GLContext.h b/src/Magnum/Platform/GLContext.h index fda6110ac..dd372478e 100644 --- a/src/Magnum/Platform/GLContext.h +++ b/src/Magnum/Platform/GLContext.h @@ -58,26 +58,29 @@ class GLContext: public GL::Context { * @brief Constructor * * Equivalent to calling @ref GLContext(NoCreateT, Int, const char**) - * followed by @ref create(). + * followed by @ref create(const Configuration&). */ - explicit GLContext(Int argc, const char** argv): GLContext{NoCreate, argc, argv} { create(); } + explicit GLContext(Int argc, const char** argv, const Configuration& configuration = {}): GLContext{NoCreate, argc, argv} { + create(configuration); + } /** @overload */ - explicit GLContext(Int argc, char** argv): GLContext{argc, const_cast(argv)} {} + explicit GLContext(Int argc, char** argv, const Configuration& configuration = {}): GLContext{argc, const_cast(argv), configuration} {} /** @overload */ - explicit GLContext(Int argc, std::nullptr_t argv): GLContext{argc, static_cast(argv)} {} + explicit GLContext(Int argc, std::nullptr_t argv, const Configuration& configuration = {}): GLContext{argc, static_cast(argv), configuration} {} /** * @brief Default constructor * - * Equivalent to passing @cpp {0, nullptr} @ce to - * @ref GLContext(Int, const char**). Even if the command-line options - * are not propagated, it's still possible to affect the renderer - * behavior from the environment. See @ref GL-Context-command-line for - * more information. + * Equivalent to passing @cpp {0, nullptr, configuration} @ce to + * @ref GLContext(Int, const char**, const Configuration&). Even if the + * command-line options are not propagated, it's still possible to + * affect the setup behavior from the environment or by passing a + * @relativeref{GL::Context,Configuration} instance. See + * @ref GL-Context-usage for more information. */ - explicit GLContext(): GLContext{0, nullptr} {} + explicit GLContext(const Configuration& configuration = {}): GLContext{0, nullptr, configuration} {} /** * @brief Construct without creating the context @@ -85,7 +88,7 @@ class GLContext: public GL::Context { * Parses command-line arguments and sets @ref version() to * @ref GL::Version::None, everything else is left in an empty state. * Use @ref create() or @ref tryCreate() to create the context. - * @see @ref GLContext(Int, const char**) + * @see @ref GLContext(Int, const char**, const Configuration&) */ explicit GLContext(NoCreateT, Int argc, const char** argv): #ifndef CORRADE_TARGET_EMSCRIPTEN @@ -118,8 +121,9 @@ class GLContext: public GL::Context { * Equivalent to passing @cpp {NoCreate, 0, nullptr} @ce to * @ref GLContext(NoCreateT, Int, const char**). Even if the * command-line options are not propagated, it's still possible to - * affect the renderer behavior from the environment. See - * @ref GL-Context-command-line for more information. + * affect the renderer behavior from the environment or by passing + * a @relativeref{GL::Context,Configuration} instance to @ref create() + * or @ref tryCreate(). See @ref GL-Context-usage for more information. */ explicit GLContext(NoCreateT): GLContext{NoCreate, 0, nullptr} {} @@ -133,13 +137,15 @@ class GLContext: public GL::Context { * detected version is unsupported or any other error occurs, a message * is printed to output and the application exits. See @ref tryCreate() * for an alternative. - * @see @ref GLContext(Int, char**), @ref GL-Context-command-line, - * @fn_gl{Get} with @def_gl{MAJOR_VERSION}, + * @see @ref GLContext(Int, char**, const Configuration&), + * @ref GL-Context-usage, @fn_gl{Get} with @def_gl{MAJOR_VERSION}, * @def_gl{MINOR_VERSION}, @def_gl{CONTEXT_FLAGS}, * @def_gl{NUM_EXTENSIONS}, @fn_gl{GetString} with * @def_gl{EXTENSIONS} */ - void create() { return GL::Context::create(); } + void create(const Configuration& configuration = Configuration{}) { + return GL::Context::create(configuration); + } /** * @brief Try to create the context @@ -147,7 +153,9 @@ class GLContext: public GL::Context { * Unlike @ref create(), instead of exiting prints a message to error * output and returns `false` on error. */ - bool tryCreate() { return GL::Context::tryCreate(); } + bool tryCreate(const Configuration& configuration = Configuration{}) { + return GL::Context::tryCreate(configuration); + } }; }} diff --git a/src/Magnum/Platform/GlfwApplication.cpp b/src/Magnum/Platform/GlfwApplication.cpp index 0fcd147c7..4dc455378 100644 --- a/src/Magnum/Platform/GlfwApplication.cpp +++ b/src/Magnum/Platform/GlfwApplication.cpp @@ -578,7 +578,7 @@ bool GlfwApplication::tryCreate(const Configuration& configuration, const GLConf glfwMakeContextCurrent(_window); /* Destroy everything when the Magnum context creation fails */ - if(!_context->tryCreate()) { + if(!_context->tryCreate(glConfiguration)) { glfwDestroyWindow(_window); _window = nullptr; } @@ -894,13 +894,12 @@ void GlfwApplication::stopTextInput() { #ifdef MAGNUM_TARGET_GL GlfwApplication::GLConfiguration::GLConfiguration(): _colorBufferSize{8, 8, 8, 8}, _depthBufferSize{24}, _stencilBufferSize{0}, - _sampleCount{0}, _version{GL::Version::None}, + _sampleCount{0}, _version{GL::Version::None}, _srgbCapable{false} +{ #ifndef MAGNUM_TARGET_GLES - _flags{Flag::ForwardCompatible}, - #else - _flags{}, + addFlags(Flag::ForwardCompatible); #endif - _srgbCapable{false} {} +} GlfwApplication::GLConfiguration::~GLConfiguration() = default; #endif diff --git a/src/Magnum/Platform/GlfwApplication.h b/src/Magnum/Platform/GlfwApplication.h index c45d403ce..b0135b8f8 100644 --- a/src/Magnum/Platform/GlfwApplication.h +++ b/src/Magnum/Platform/GlfwApplication.h @@ -43,7 +43,7 @@ #include "Magnum/Platform/Platform.h" #ifdef MAGNUM_TARGET_GL -#include "Magnum/GL/GL.h" +#include "Magnum/GL/Context.h" #endif #ifndef DOXYGEN_GENERATING_OUTPUT @@ -777,14 +777,15 @@ The created window is always with a double-buffered OpenGL context. @see @ref GlfwApplication(), @ref create(), @ref tryCreate() */ -class GlfwApplication::GLConfiguration { +class GlfwApplication::GLConfiguration: public GL::Context::Configuration { public: /** * @brief Context flag * + * Includes also everything from @ref GL::Context::Configuration::Flag. * @see @ref Flags, @ref setFlags(), @ref GL::Context::Flag */ - enum class Flag: UnsignedByte { + enum class Flag: UnsignedLong { #ifndef MAGNUM_TARGET_GLES /** * Forward compatible context @@ -807,13 +808,32 @@ class GlfwApplication::GLConfiguration { #endif /** - * Debug context. Enabled automatically if the - * `--magnum-gpu-validation` @ref GL-Context-command-line "command-line option" + * Debug context. Enabled automatically if supported by the driver + * and the @ref Flag::GpuValidation flag is set or if the + * `--magnum-gpu-validation` @ref GL-Context-usage-command-line "command-line option" * is present. */ Debug = 1 << 2, - Stereo = 1 << 3 /**< Stereo rendering */ + Stereo = 1 << 3, /**< Stereo rendering */ + + /** + * @copydoc GL::Context::Configuration::Flag::QuietLog + * @m_since_latest + */ + QuietLog = UnsignedLong(GL::Context::Configuration::Flag::QuietLog), + + /** + * @copydoc GL::Context::Configuration::Flag::VerboseLog + * @m_since_latest + */ + VerboseLog = UnsignedLong(GL::Context::Configuration::Flag::VerboseLog), + + /** + * @copydoc GL::Context::Configuration::Flag::GpuValidation + * @m_since_latest + */ + GpuValidation = UnsignedLong(GL::Context::Configuration::Flag::GpuValidation) }; /** @@ -827,7 +847,9 @@ class GlfwApplication::GLConfiguration { ~GLConfiguration(); /** @brief Context flags */ - Flags flags() const { return _flags; } + Flags flags() const { + return Flag(UnsignedLong(GL::Context::Configuration::flags())); + } /** * @brief Set context flags @@ -839,7 +861,7 @@ class GlfwApplication::GLConfiguration { * @see @ref GL::Context::flags() */ GLConfiguration& setFlags(Flags flags) { - _flags = flags; + GL::Context::Configuration::setFlags(GL::Context::Configuration::Flag(UnsignedLong(flags))); return *this; } @@ -852,7 +874,7 @@ class GlfwApplication::GLConfiguration { * @see @ref clearFlags() */ GLConfiguration& addFlags(Flags flags) { - _flags |= flags; + GL::Context::Configuration::addFlags(GL::Context::Configuration::Flag(UnsignedLong(flags))); return *this; } @@ -865,7 +887,7 @@ class GlfwApplication::GLConfiguration { * @see @ref addFlags() */ GLConfiguration& clearFlags(Flags flags) { - _flags &= ~flags; + GL::Context::Configuration::clearFlags(GL::Context::Configuration::Flag(UnsignedLong(flags))); return *this; } @@ -958,12 +980,16 @@ class GlfwApplication::GLConfiguration { return *this; } + /* Overloads to remove WTF-factor from method chaining order */ + #ifndef DOXYGEN_GENERATING_OUTPUT + MAGNUM_GL_CONTEXT_CONFIGURATION_SUBCLASS_IMPLEMENTATION(GLConfiguration) + #endif + private: Vector4i _colorBufferSize; Int _depthBufferSize, _stencilBufferSize; Int _sampleCount; GL::Version _version; - Flags _flags; bool _srgbCapable; }; diff --git a/src/Magnum/Platform/Sdl2Application.cpp b/src/Magnum/Platform/Sdl2Application.cpp index ccec3f2d3..0c59ac235 100644 --- a/src/Magnum/Platform/Sdl2Application.cpp +++ b/src/Magnum/Platform/Sdl2Application.cpp @@ -484,7 +484,8 @@ bool Sdl2Application::tryCreate(const Configuration& configuration, const GLConf SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES); #endif - SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, int(glFlags)); + /* Mask out the upper 32bits used for other flags */ + SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, int(UnsignedLong(glFlags) & 0xffffffffu)); /* Request usable version otherwise */ } else { @@ -501,7 +502,8 @@ bool Sdl2Application::tryCreate(const Configuration& configuration, const GLConf SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 1); #endif SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE); - SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, int(glFlags)); + /* Mask out the upper 32bits used for other flags */ + SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, int(UnsignedLong(glFlags) & 0xffffffffu)); #else /* For ES the major context version is compile-time constant */ #ifdef MAGNUM_TARGET_GLES3 @@ -579,8 +581,10 @@ bool Sdl2Application::tryCreate(const Configuration& configuration, const GLConf SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_COMPATIBILITY); /* Discard the ForwardCompatible flag for the fallback. Having it set makes the fallback context creation fail on Mesa's Zink (which is - just 2.1) and I assume on others as well. */ - SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, int(glFlags) & int(~GLConfiguration::Flag::ForwardCompatible)); + just 2.1) and I assume on others as well. + + Also mask out the upper 32bits used for other flags. */ + SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, int(UnsignedLong(glFlags & ~GLConfiguration::Flag::ForwardCompatible) & 0xffffffffu)); if(!(_window = SDL_CreateWindow(configuration.title().data(), SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, @@ -666,7 +670,7 @@ bool Sdl2Application::tryCreate(const Configuration& configuration, const GLConf #endif /* Destroy everything also when the Magnum context creation fails */ - if(!_context->tryCreate()) { + if(!_context->tryCreate(glConfiguration)) { #ifndef CORRADE_TARGET_EMSCRIPTEN SDL_GL_DeleteContext(_glContext); SDL_DestroyWindow(_window); @@ -1184,15 +1188,13 @@ Sdl2Application::GLConfiguration::GLConfiguration(): _colorBufferSize{8, 8, 8, 8}, _depthBufferSize{24}, _stencilBufferSize{0}, _sampleCount(0) #ifndef CORRADE_TARGET_EMSCRIPTEN - , _version(GL::Version::None), - #ifndef MAGNUM_TARGET_GLES - _flags{Flag::ForwardCompatible}, - #else - _flags{}, + , _version{GL::Version::None}, _srgbCapable{false} #endif - _srgbCapable{false} +{ + #ifndef MAGNUM_TARGET_GLES + addFlags(Flag::ForwardCompatible); #endif - {} +} Sdl2Application::GLConfiguration::~GLConfiguration() = default; #endif diff --git a/src/Magnum/Platform/Sdl2Application.h b/src/Magnum/Platform/Sdl2Application.h index 91fb46abb..b35d10b5f 100644 --- a/src/Magnum/Platform/Sdl2Application.h +++ b/src/Magnum/Platform/Sdl2Application.h @@ -42,7 +42,7 @@ #include "Magnum/Platform/Platform.h" #ifdef MAGNUM_TARGET_GL -#include "Magnum/GL/GL.h" +#include "Magnum/GL/Context.h" #endif #ifdef CORRADE_TARGET_WINDOWS /* Windows version of SDL2 redefines main(), we don't want that */ @@ -1229,20 +1229,19 @@ The created window is always with a double-buffered OpenGL context. @see @ref Sdl2Application(), @ref create(), @ref tryCreate() */ -class Sdl2Application::GLConfiguration { +class Sdl2Application::GLConfiguration: public GL::Context::Configuration { public: - #ifndef CORRADE_TARGET_EMSCRIPTEN /** * @brief Context flag * + * Includes also everything from @ref GL::Context::Configuration::Flag. * @see @ref Flags, @ref setFlags(), @ref GL::Context::Flag - * @requires_gles Context flags are not available in WebGL. */ - enum class Flag: int { + enum class Flag: UnsignedLong { + #ifndef CORRADE_TARGET_EMSCRIPTEN #ifndef MAGNUM_TARGET_GLES /** - * Forward compatible context - * + * Forward compatible context. * @requires_gl Core/compatibility profile distinction and forward * compatibility applies only to desktop GL. */ @@ -1250,38 +1249,60 @@ class Sdl2Application::GLConfiguration { #endif /** - * Debug context. Enabled automatically if the - * `--magnum-gpu-validation` @ref GL-Context-command-line "command-line option" + * Debug context. Enabled automatically if supported by the driver + * and the @ref Flag::GpuValidation flag is set or if the + * `--magnum-gpu-validation` @ref GL-Context-usage-command-line "command-line option" * is present. + * @requires_gles Context flags are not available in WebGL. */ Debug = SDL_GL_CONTEXT_DEBUG_FLAG, - /** Context with robust access */ + /** + * Context with robust access. + * @requires_gles Context flags are not available in WebGL. + */ RobustAccess = SDL_GL_CONTEXT_ROBUST_ACCESS_FLAG, - /** Context with reset isolation */ - ResetIsolation = SDL_GL_CONTEXT_RESET_ISOLATION_FLAG + /** + * Context with reset isolation. + * @requires_gles Context flags are not available in WebGL. + */ + ResetIsolation = SDL_GL_CONTEXT_RESET_ISOLATION_FLAG, + #endif + + /** + * @copydoc GL::Context::Configuration::Flag::QuietLog + * @m_since_latest + */ + QuietLog = UnsignedLong(GL::Context::Configuration::Flag::QuietLog), + + /** + * @copydoc GL::Context::Configuration::Flag::VerboseLog + * @m_since_latest + */ + VerboseLog = UnsignedLong(GL::Context::Configuration::Flag::VerboseLog), + + /** + * @copydoc GL::Context::Configuration::Flag::GpuValidation + * @m_since_latest + */ + GpuValidation = UnsignedLong(GL::Context::Configuration::Flag::GpuValidation) }; /** * @brief Context flags * * @see @ref setFlags(), @ref GL::Context::Flags - * @requires_gles Context flags are not available in WebGL. */ typedef Containers::EnumSet Flags; - #endif explicit GLConfiguration(); ~GLConfiguration(); - #ifndef CORRADE_TARGET_EMSCRIPTEN - /** - * @brief Context flags - * - * @requires_gles Context flags are not available in WebGL. - */ - Flags flags() const { return _flags; } + /** @brief Context flags */ + Flags flags() const { + return Flag(UnsignedLong(GL::Context::Configuration::flags())); + } /** * @brief Set context flags @@ -1291,10 +1312,9 @@ class Sdl2Application::GLConfiguration { * on OpenGL ES. To avoid clearing default flags by accident, prefer to * use @ref addFlags() and @ref clearFlags() instead. * @see @ref GL::Context::flags() - * @requires_gles Context flags are not available in WebGL. */ GLConfiguration& setFlags(Flags flags) { - _flags = flags; + GL::Context::Configuration::setFlags(GL::Context::Configuration::Flag(UnsignedLong(flags))); return *this; } @@ -1305,10 +1325,9 @@ class Sdl2Application::GLConfiguration { * Unlike @ref setFlags(), ORs the flags with existing instead of * replacing them. Useful for preserving the defaults. * @see @ref clearFlags() - * @requires_gles Context flags are not available in WebGL. */ GLConfiguration& addFlags(Flags flags) { - _flags |= flags; + GL::Context::Configuration::addFlags(GL::Context::Configuration::Flag(UnsignedLong(flags))); return *this; } @@ -1319,13 +1338,13 @@ class Sdl2Application::GLConfiguration { * Unlike @ref setFlags(), ANDs the inverse of @p flags with existing * instead of replacing them. Useful for removing default flags. * @see @ref addFlags() - * @requires_gles Context flags are not available in WebGL. */ GLConfiguration& clearFlags(Flags flags) { - _flags &= ~flags; + GL::Context::Configuration::clearFlags(GL::Context::Configuration::Flag(UnsignedLong(flags))); return *this; } + #ifndef CORRADE_TARGET_EMSCRIPTEN /** * @brief Context version * @@ -1434,13 +1453,17 @@ class Sdl2Application::GLConfiguration { } #endif + /* Overloads to remove WTF-factor from method chaining order */ + #ifndef DOXYGEN_GENERATING_OUTPUT + MAGNUM_GL_CONTEXT_CONFIGURATION_SUBCLASS_IMPLEMENTATION(GLConfiguration) + #endif + private: Vector4i _colorBufferSize; Int _depthBufferSize, _stencilBufferSize; Int _sampleCount; #ifndef CORRADE_TARGET_EMSCRIPTEN GL::Version _version; - Flags _flags; bool _srgbCapable; #endif }; diff --git a/src/Magnum/Platform/Test/EmscriptenApplicationTest.cpp b/src/Magnum/Platform/Test/EmscriptenApplicationTest.cpp index 4de4bdb09..e330277e4 100644 --- a/src/Magnum/Platform/Test/EmscriptenApplicationTest.cpp +++ b/src/Magnum/Platform/Test/EmscriptenApplicationTest.cpp @@ -153,6 +153,7 @@ EmscriptenApplicationTest::EmscriptenApplicationTest(const Arguments& arguments) Utility::Arguments args; args.addSkippedPrefix("magnum", "engine-specific options") .addBooleanOption("exit-immediately").setHelp("exit-immediately", "exit the application immediately from the constructor, to test that the app doesn't run any event handlers after") + .addBooleanOption("quiet").setHelp("quiet", "like --magnum-log quiet, but specified via a Context::Configuration instead") .parse(arguments.argc, arguments.argv); /* Useful for bisecting Emscripten regressions, because they happen WAY TOO @@ -167,9 +168,12 @@ EmscriptenApplicationTest::EmscriptenApplicationTest(const Arguments& arguments) return; } - create(Configuration{}.setWindowFlags(Configuration::WindowFlag::Resizable) - //, GLConfiguration{}.setFlags({}) - ); + Configuration conf; + conf.setWindowFlags(Configuration::WindowFlag::Resizable); + if(args.isSet("quiet")) + create(conf, GLConfiguration{}.addFlags(GLConfiguration::Flag::QuietLog)); + else + create(conf); Debug{} << "window size" << windowSize() #ifdef MAGNUM_TARGET_GL diff --git a/src/Magnum/Platform/Test/GlfwApplicationTest.cpp b/src/Magnum/Platform/Test/GlfwApplicationTest.cpp index c9da740f6..bfb8d4447 100644 --- a/src/Magnum/Platform/Test/GlfwApplicationTest.cpp +++ b/src/Magnum/Platform/Test/GlfwApplicationTest.cpp @@ -108,6 +108,9 @@ GlfwApplicationTest::GlfwApplicationTest(const Arguments& arguments): Platform:: .addBooleanOption("exit-immediately").setHelp("exit-immediately", "exit the application immediately from the constructor, to test that the app doesn't run any event handlers after") .addBooleanOption("borderless").setHelp("borderless", "no window decoration") .addBooleanOption("always-on-top").setHelp("always-on-top", "always on top") + #ifdef MAGNUM_TARGET_GL + .addBooleanOption("quiet").setHelp("quiet", "like --magnum-log quiet, but specified via a Context::Configuration instead") + #endif .parse(arguments.argc, arguments.argv); if(args.isSet("exit-immediately")) { @@ -123,7 +126,14 @@ GlfwApplicationTest::GlfwApplicationTest(const Arguments& arguments): Platform:: conf.addWindowFlags(Configuration::WindowFlag::Borderless); if(args.isSet("always-on-top")) conf.addWindowFlags(Configuration::WindowFlag::AlwaysOnTop); - create(conf); + #ifdef MAGNUM_TARGET_GL + if(args.isSet("quiet")) { + create(conf, GLConfiguration{}.addFlags(GLConfiguration::Flag::QuietLog)); + } else + #endif + { + create(conf); + } /* For testing resize events */ Debug{} << "window size" << windowSize() diff --git a/src/Magnum/Platform/Test/GlxApplicationTest.cpp b/src/Magnum/Platform/Test/GlxApplicationTest.cpp index a82d1f7c3..17e27168f 100644 --- a/src/Magnum/Platform/Test/GlxApplicationTest.cpp +++ b/src/Magnum/Platform/Test/GlxApplicationTest.cpp @@ -42,6 +42,7 @@ GlxApplicationTest::GlxApplicationTest(const Arguments& arguments): Platform::Ap Utility::Arguments args; args.addSkippedPrefix("magnum", "engine-specific options") .addBooleanOption("exit-immediately").setHelp("exit-immediately", "exit the application immediately from the constructor, to test that the app doesn't run any event handlers after") + .addBooleanOption("quiet").setHelp("quiet", "like --magnum-log quiet, but specified via a Context::Configuration instead") .parse(arguments.argc, arguments.argv); if(args.isSet("exit-immediately")) { @@ -49,7 +50,10 @@ GlxApplicationTest::GlxApplicationTest(const Arguments& arguments): Platform::Ap return; } - create(Configuration{}); + if(args.isSet("quiet")) + create(Configuration{}, GLConfiguration{}.addFlags(GLConfiguration::Flag::QuietLog)); + else + create(); } }}}} diff --git a/src/Magnum/Platform/Test/Sdl2ApplicationTest.cpp b/src/Magnum/Platform/Test/Sdl2ApplicationTest.cpp index a12f36446..6565311ea 100644 --- a/src/Magnum/Platform/Test/Sdl2ApplicationTest.cpp +++ b/src/Magnum/Platform/Test/Sdl2ApplicationTest.cpp @@ -165,6 +165,9 @@ Sdl2ApplicationTest::Sdl2ApplicationTest(const Arguments& arguments): Platform:: .addBooleanOption("always-on-top").setHelp("always-on-top", "always on top") #endif #endif + #ifdef MAGNUM_TARGET_GL + .addBooleanOption("quiet").setHelp("quiet", "like --magnum-log quiet, but specified via a Context::Configuration instead") + #endif .parse(arguments.argc, arguments.argv); if(args.isSet("exit-immediately")) { @@ -184,7 +187,14 @@ Sdl2ApplicationTest::Sdl2ApplicationTest(const Arguments& arguments): Platform:: conf.addWindowFlags(Configuration::WindowFlag::AlwaysOnTop); #endif #endif - create(conf); + #ifdef MAGNUM_TARGET_GL + if(args.isSet("quiet")) { + create(conf, GLConfiguration{}.addFlags(GLConfiguration::Flag::QuietLog)); + } else + #endif + { + create(conf); + } /* For testing resize events */ Debug{} << "window size" << windowSize() diff --git a/src/Magnum/Platform/Test/WindowlessCglApplicationTest.cpp b/src/Magnum/Platform/Test/WindowlessCglApplicationTest.cpp index e3f83a1a4..a90c98eac 100644 --- a/src/Magnum/Platform/Test/WindowlessCglApplicationTest.cpp +++ b/src/Magnum/Platform/Test/WindowlessCglApplicationTest.cpp @@ -23,15 +23,29 @@ DEALINGS IN THE SOFTWARE. */ +#include + #include "Magnum/Platform/WindowlessCglApplication.h" namespace Magnum { namespace Platform { namespace Test { namespace { struct WindowlessCglApplicationTest: Platform::WindowlessApplication { - explicit WindowlessCglApplicationTest(const Arguments& arguments): Platform::WindowlessApplication{arguments} {} + explicit WindowlessCglApplicationTest(const Arguments& arguments); int exec() override { return 0; } }; +WindowlessCglApplicationTest::WindowlessCglApplicationTest(const Arguments& arguments): Platform::WindowlessApplication{arguments, NoCreate} { + Utility::Arguments args; + args.addSkippedPrefix("magnum", "engine-specific options") + .addBooleanOption("quiet").setHelp("quiet", "like --magnum-log quiet, but specified via a Context::Configuration instead") + .parse(arguments.argc, arguments.argv); + + if(args.isSet("quiet")) + createContext(Configuration{}.addFlags(Configuration::Flag::QuietLog)); + else + createContext(); +} + }}}} MAGNUM_WINDOWLESSAPPLICATION_MAIN(Magnum::Platform::Test::WindowlessCglApplicationTest) diff --git a/src/Magnum/Platform/Test/WindowlessEglApplicationTest.cpp b/src/Magnum/Platform/Test/WindowlessEglApplicationTest.cpp index c40029231..d6464e6fd 100644 --- a/src/Magnum/Platform/Test/WindowlessEglApplicationTest.cpp +++ b/src/Magnum/Platform/Test/WindowlessEglApplicationTest.cpp @@ -23,15 +23,29 @@ DEALINGS IN THE SOFTWARE. */ +#include + #include "Magnum/Platform/WindowlessEglApplication.h" namespace Magnum { namespace Platform { namespace Test { namespace { struct WindowlessEglApplicationTest: Platform::WindowlessApplication { - explicit WindowlessEglApplicationTest(const Arguments& arguments): Platform::WindowlessApplication{arguments} {} + explicit WindowlessEglApplicationTest(const Arguments& arguments); int exec() override { return 0; } }; +WindowlessEglApplicationTest::WindowlessEglApplicationTest(const Arguments& arguments): Platform::WindowlessApplication{arguments, NoCreate} { + Utility::Arguments args; + args.addSkippedPrefix("magnum", "engine-specific options") + .addBooleanOption("quiet").setHelp("quiet", "like --magnum-log quiet, but specified via a Context::Configuration instead") + .parse(arguments.argc, arguments.argv); + + if(args.isSet("quiet")) + createContext(Configuration{}.addFlags(Configuration::Flag::QuietLog)); + else + createContext(); +} + }}}} MAGNUM_WINDOWLESSAPPLICATION_MAIN(Magnum::Platform::Test::WindowlessEglApplicationTest) diff --git a/src/Magnum/Platform/Test/WindowlessGlxApplicationTest.cpp b/src/Magnum/Platform/Test/WindowlessGlxApplicationTest.cpp index 58b859549..e75b3d9c5 100644 --- a/src/Magnum/Platform/Test/WindowlessGlxApplicationTest.cpp +++ b/src/Magnum/Platform/Test/WindowlessGlxApplicationTest.cpp @@ -23,15 +23,29 @@ DEALINGS IN THE SOFTWARE. */ +#include + #include "Magnum/Platform/WindowlessGlxApplication.h" namespace Magnum { namespace Platform { namespace Test { namespace { struct WindowlessGlxApplicationTest: Platform::WindowlessApplication { - explicit WindowlessGlxApplicationTest(const Arguments& arguments): Platform::WindowlessApplication{arguments} {} + explicit WindowlessGlxApplicationTest(const Arguments& arguments); int exec() override { return 0; } }; +WindowlessGlxApplicationTest::WindowlessGlxApplicationTest(const Arguments& arguments): Platform::WindowlessApplication{arguments, NoCreate} { + Utility::Arguments args; + args.addSkippedPrefix("magnum", "engine-specific options") + .addBooleanOption("quiet").setHelp("quiet", "like --magnum-log quiet, but specified via a Context::Configuration instead") + .parse(arguments.argc, arguments.argv); + + if(args.isSet("quiet")) + createContext(Configuration{}.addFlags(Configuration::Flag::QuietLog)); + else + createContext(); +} + }}}} MAGNUM_WINDOWLESSAPPLICATION_MAIN(Magnum::Platform::Test::WindowlessGlxApplicationTest) diff --git a/src/Magnum/Platform/Test/WindowlessIosApplicationTest.cpp b/src/Magnum/Platform/Test/WindowlessIosApplicationTest.cpp index 8ba527548..a1f042616 100644 --- a/src/Magnum/Platform/Test/WindowlessIosApplicationTest.cpp +++ b/src/Magnum/Platform/Test/WindowlessIosApplicationTest.cpp @@ -23,15 +23,29 @@ DEALINGS IN THE SOFTWARE. */ +#include + #include "Magnum/Platform/WindowlessIosApplication.h" namespace Magnum { namespace Platform { namespace Test { namespace { struct WindowlessIosApplicationTest: Platform::WindowlessApplication { - explicit WindowlessIosApplicationTest(const Arguments& arguments): Platform::WindowlessApplication{arguments} {} + explicit WindowlessIosApplicationTest(const Arguments& arguments); int exec() override { return 0; } }; +WindowlessIosApplicationTest::WindowlessIosApplicationTest(const Arguments& arguments): Platform::WindowlessApplication{arguments, NoCreate} { + Utility::Arguments args; + args.addSkippedPrefix("magnum", "engine-specific options") + .addBooleanOption("quiet").setHelp("quiet", "like --magnum-log quiet, but specified via a Context::Configuration instead") + .parse(arguments.argc, arguments.argv); + + if(args.isSet("quiet")) + createContext(Configuration{}.addFlags(Configuration::Flag::QuietLog)); + else + createContext(); +} + }}}} MAGNUM_WINDOWLESSAPPLICATION_MAIN(Magnum::Platform::Test::WindowlessIosApplicationTest) diff --git a/src/Magnum/Platform/Test/WindowlessWglApplicationTest.cpp b/src/Magnum/Platform/Test/WindowlessWglApplicationTest.cpp index 1a79e7976..82b7baaa2 100644 --- a/src/Magnum/Platform/Test/WindowlessWglApplicationTest.cpp +++ b/src/Magnum/Platform/Test/WindowlessWglApplicationTest.cpp @@ -23,15 +23,29 @@ DEALINGS IN THE SOFTWARE. */ +#include + #include "Magnum/Platform/WindowlessWglApplication.h" namespace Magnum { namespace Platform { namespace Test { namespace { struct WindowlessWglApplicationTest: Platform::WindowlessApplication { - explicit WindowlessWglApplicationTest(const Arguments& arguments): Platform::WindowlessApplication{arguments} {} + explicit WindowlessWglApplicationTest(const Arguments& arguments); int exec() override { return 0; } }; +WindowlessWglApplicationTest::WindowlessWglApplicationTest(const Arguments& arguments): Platform::WindowlessApplication{arguments, NoCreate} { + Utility::Arguments args; + args.addSkippedPrefix("magnum", "engine-specific options") + .addBooleanOption("quiet").setHelp("quiet", "like --magnum-log quiet, but specified via a Context::Configuration instead") + .parse(arguments.argc, arguments.argv); + + if(args.isSet("quiet")) + createContext(Configuration{}.addFlags(Configuration::Flag::QuietLog)); + else + createContext(); +} + }}}} MAGNUM_WINDOWLESSAPPLICATION_MAIN(Magnum::Platform::Test::WindowlessWglApplicationTest) diff --git a/src/Magnum/Platform/Test/WindowlessWindowsEglApplicationTest.cpp b/src/Magnum/Platform/Test/WindowlessWindowsEglApplicationTest.cpp index 65b5745c7..9bc627507 100644 --- a/src/Magnum/Platform/Test/WindowlessWindowsEglApplicationTest.cpp +++ b/src/Magnum/Platform/Test/WindowlessWindowsEglApplicationTest.cpp @@ -23,15 +23,29 @@ DEALINGS IN THE SOFTWARE. */ +#include + #include "Magnum/Platform/WindowlessWindowsEglApplication.h" namespace Magnum { namespace Platform { namespace Test { namespace { struct WindowlessWindowsEglApplicationTest: Platform::WindowlessApplication { - explicit WindowlessWindowsEglApplicationTest(const Arguments& arguments): Platform::WindowlessApplication{arguments} {} + explicit WindowlessWindowsEglApplicationTest(const Arguments& arguments); int exec() override { return 0; } }; +WindowlessWindowsEglApplicationTest::WindowlessWindowsEglApplicationTest(const Arguments& arguments): Platform::WindowlessApplication{arguments, NoCreate} { + Utility::Arguments args; + args.addSkippedPrefix("magnum", "engine-specific options") + .addBooleanOption("quiet").setHelp("quiet", "like --magnum-log quiet, but specified via a Context::Configuration instead") + .parse(arguments.argc, arguments.argv); + + if(args.isSet("quiet")) + createContext(Configuration{}.addFlags(Configuration::Flag::QuietLog)); + else + createContext(); +} + }}}} MAGNUM_WINDOWLESSAPPLICATION_MAIN(Magnum::Platform::Test::WindowlessWindowsEglApplicationTest) diff --git a/src/Magnum/Platform/Test/XEglApplicationTest.cpp b/src/Magnum/Platform/Test/XEglApplicationTest.cpp index 103961972..739776e74 100644 --- a/src/Magnum/Platform/Test/XEglApplicationTest.cpp +++ b/src/Magnum/Platform/Test/XEglApplicationTest.cpp @@ -42,6 +42,7 @@ XEglApplicationTest::XEglApplicationTest(const Arguments& arguments): Platform:: Utility::Arguments args; args.addSkippedPrefix("magnum", "engine-specific options") .addBooleanOption("exit-immediately").setHelp("exit-immediately", "exit the application immediately from the constructor, to test that the app doesn't run any event handlers after") + .addBooleanOption("quiet").setHelp("quiet", "like --magnum-log quiet, but specified via a Context::Configuration instead") .parse(arguments.argc, arguments.argv); if(args.isSet("exit-immediately")) { @@ -49,10 +50,12 @@ XEglApplicationTest::XEglApplicationTest(const Arguments& arguments): Platform:: return; } - create(Configuration{}); + if(args.isSet("quiet")) + create(Configuration{}, GLConfiguration{}.addFlags(GLConfiguration::Flag::QuietLog)); + else + create(); } - }}}} MAGNUM_APPLICATION_MAIN(Magnum::Platform::Test::XEglApplicationTest) diff --git a/src/Magnum/Platform/WindowlessCglApplication.cpp b/src/Magnum/Platform/WindowlessCglApplication.cpp index 9ac9395be..3fb0d1b7e 100644 --- a/src/Magnum/Platform/WindowlessCglApplication.cpp +++ b/src/Magnum/Platform/WindowlessCglApplication.cpp @@ -36,7 +36,7 @@ namespace Magnum { namespace Platform { -WindowlessCglContext::WindowlessCglContext(const Configuration & configuration, GLContext*) { +WindowlessCglContext::WindowlessCglContext(const Configuration& configuration, GLContext*) { int formatCount; CGLPixelFormatAttribute attributes32[] = { kCGLPFAAccelerated, @@ -128,7 +128,7 @@ bool WindowlessCglApplication::tryCreateContext(const Configuration& configurati CORRADE_ASSERT(_context->version() == GL::Version::None, "Platform::WindowlessCglApplication::tryCreateContext(): context already created", false); WindowlessCglContext glContext{configuration, _context.get()}; - if(!glContext.isCreated() || !glContext.makeCurrent() || !_context->tryCreate()) + if(!glContext.isCreated() || !glContext.makeCurrent() || !_context->tryCreate(configuration)) return false; _glContext = std::move(glContext); diff --git a/src/Magnum/Platform/WindowlessCglApplication.h b/src/Magnum/Platform/WindowlessCglApplication.h index 271e0c70f..07e908bff 100644 --- a/src/Magnum/Platform/WindowlessCglApplication.h +++ b/src/Magnum/Platform/WindowlessCglApplication.h @@ -39,7 +39,7 @@ #include "Magnum/Magnum.h" #include "Magnum/Tags.h" -#include "Magnum/GL/OpenGL.h" +#include "Magnum/GL/Context.h" #include "Magnum/Platform/Platform.h" #ifndef DOXYGEN_GENERATING_OUTPUT @@ -164,10 +164,8 @@ class WindowlessCglContext { @ref WindowlessCglApplication::createContext(), @ref WindowlessCglApplication::tryCreateContext() */ -class WindowlessCglContext::Configuration { +class WindowlessCglContext::Configuration: public GL::Context::Configuration { public: - constexpr /*implicit*/ Configuration() {} - /** * @brief Create a shared context * @return Reference to self (for method chaining) @@ -192,6 +190,23 @@ class WindowlessCglContext::Configuration { */ CGLContextObj sharedContext() const { return _sharedContext; } + /* Overloads to remove WTF-factor from method chaining order */ + #ifndef DOXYGEN_GENERATING_OUTPUT + Configuration& setFlags(Flags flags) { + GL::Context::Configuration::setFlags(flags); + return *this; + } + Configuration& addFlags(Flags flags) { + GL::Context::Configuration::addFlags(flags); + return *this; + } + Configuration& clearFlags(Flags flags) { + GL::Context::Configuration::clearFlags(flags); + return *this; + } + MAGNUM_GL_CONTEXT_CONFIGURATION_SUBCLASS_IMPLEMENTATION(Configuration) + #endif + private: CGLContextObj _sharedContext = nullptr; }; diff --git a/src/Magnum/Platform/WindowlessEglApplication.cpp b/src/Magnum/Platform/WindowlessEglApplication.cpp index 41b2e5faa..1eb1154b3 100644 --- a/src/Magnum/Platform/WindowlessEglApplication.cpp +++ b/src/Magnum/Platform/WindowlessEglApplication.cpp @@ -328,8 +328,10 @@ WindowlessEglContext::WindowlessEglContext(const Configuration& configuration, G #endif #ifndef MAGNUM_TARGET_WEBGL /* Needs to be last because we're zeroing this out for SwiftShader (see - below) */ - EGL_CONTEXT_FLAGS_KHR, EGLint(flags), + below). + + Also mask out the upper 32bits used for other flags. */ + EGL_CONTEXT_FLAGS_KHR, EGLint(UnsignedLong(flags) & 0xffffffffu), #endif EGL_NONE }; @@ -369,8 +371,10 @@ WindowlessEglContext::WindowlessEglContext(const Configuration& configuration, G const EGLint fallbackAttributes[] = { /* Discard the ForwardCompatible flag for the fallback. Having it set makes the fallback context creation fail on Mesa's Zink - (which is just 2.1) and I assume on others as well. */ - EGL_CONTEXT_FLAGS_KHR, GLint(flags & ~Configuration::Flag::ForwardCompatible), + (which is just 2.1) and I assume on others as well. + + Also mask out the upper 32bits used for other flags. */ + EGL_CONTEXT_FLAGS_KHR, EGLint(UnsignedLong(flags & ~Configuration::Flag::ForwardCompatible) & 0xffffffffu), EGL_NONE }; _context = eglCreateContext(_display, config, configuration.sharedContext(), fallbackAttributes); @@ -409,8 +413,10 @@ WindowlessEglContext::WindowlessEglContext(const Configuration& configuration, G /* Discard the ForwardCompatible flag for the fallback. Compared to the above case of a 2.1 fallback it's not really needed here (AFAIK it works in both cases), but let's be - consistent. */ - EGL_CONTEXT_FLAGS_KHR, GLint(flags & ~Configuration::Flag::ForwardCompatible), + consistent. + + Also mask out the upper 32bits used for other flags. */ + EGL_CONTEXT_FLAGS_KHR, EGLint(UnsignedLong(flags & ~Configuration::Flag::ForwardCompatible) & 0xffffffffu), EGL_NONE }; _context = eglCreateContext(_display, config, configuration.sharedContext(), fallbackAttributes); @@ -519,12 +525,14 @@ bool WindowlessEglContext::release() { } WindowlessEglContext::Configuration::Configuration() + #ifndef MAGNUM_TARGET_WEBGL + : _device{} + #endif +{ #ifndef MAGNUM_TARGET_GLES - : _flags{Flag::ForwardCompatible}, _device{} - #elif !defined(MAGNUM_TARGET_WEBGL) - : _flags{}, _device{} + addFlags(Flag::ForwardCompatible); #endif - {} +} #ifndef DOXYGEN_GENERATING_OUTPUT WindowlessEglApplication::WindowlessEglApplication(const Arguments& arguments): WindowlessEglApplication{arguments, Configuration{}} {} @@ -574,7 +582,7 @@ bool WindowlessEglApplication::tryCreateContext(const Configuration& configurati #endif WindowlessEglContext glContext{mergedConfiguration, _context.get()}; - if(!glContext.isCreated() || !glContext.makeCurrent() || !_context->tryCreate()) + if(!glContext.isCreated() || !glContext.makeCurrent() || !_context->tryCreate(configuration)) return false; _glContext = std::move(glContext); diff --git a/src/Magnum/Platform/WindowlessEglApplication.h b/src/Magnum/Platform/WindowlessEglApplication.h index ec17eb69a..22340bfd1 100644 --- a/src/Magnum/Platform/WindowlessEglApplication.h +++ b/src/Magnum/Platform/WindowlessEglApplication.h @@ -58,7 +58,7 @@ typedef int Bool; #endif #include "Magnum/Magnum.h" -#include "Magnum/GL/OpenGL.h" +#include "Magnum/GL/Context.h" #include "Magnum/Tags.h" #include "Magnum/Platform/Platform.h" @@ -179,16 +179,16 @@ class WindowlessEglContext { @ref WindowlessEglApplication::createContext(), @ref WindowlessEglApplication::tryCreateContext() */ -class WindowlessEglContext::Configuration { +class WindowlessEglContext::Configuration: public GL::Context::Configuration { public: - #ifndef MAGNUM_TARGET_WEBGL /** * @brief Context flag * + * Includes also everything from @ref GL::Context::Configuration::Flag. * @see @ref Flags, @ref setFlags(), @ref GL::Context::Flag - * @requires_gles Context flags are not available in WebGL. */ - enum class Flag: int { + enum class Flag: UnsignedLong { + #ifndef MAGNUM_TARGET_WEBGL #ifndef MAGNUM_TARGET_GLES /** * Forward compatible context @@ -200,31 +200,47 @@ class WindowlessEglContext::Configuration { #endif /** - * Debug context. Enabled automatically if the - * `--magnum-gpu-validation` @ref GL-Context-command-line "command-line option" + * Debug context. Enabled automatically if supported by the driver + * and the @ref Flag::GpuValidation flag is set or if the + * `--magnum-gpu-validation` @ref GL-Context-usage-command-line "command-line option" * is present. + * @requires_gles Context flags are not available in WebGL. + */ + Debug = EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR, + #endif + + /** + * @copydoc GL::Context::Configuration::Flag::QuietLog + * @m_since_latest + */ + QuietLog = UnsignedLong(GL::Context::Configuration::Flag::QuietLog), + + /** + * @copydoc GL::Context::Configuration::Flag::VerboseLog + * @m_since_latest + */ + VerboseLog = UnsignedLong(GL::Context::Configuration::Flag::VerboseLog), + + /** + * @copydoc GL::Context::Configuration::Flag::GpuValidation + * @m_since_latest */ - Debug = EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR + GpuValidation = UnsignedLong(GL::Context::Configuration::Flag::GpuValidation) }; /** * @brief Context flags * * @see @ref setFlags(), @ref Context::Flags - * @requires_gles Context flags are not available in WebGL. */ typedef Containers::EnumSet Flags; - #endif /*implicit*/ Configuration(); - #ifndef MAGNUM_TARGET_WEBGL - /** - * @brief Context flags - * - * @requires_gles Context flags are not available in WebGL. - */ - Flags flags() const { return _flags; } + /** @brief Context flags */ + Flags flags() const { + return Flag(UnsignedLong(GL::Context::Configuration::flags())); + } /** * @brief Set context flags @@ -234,10 +250,9 @@ class WindowlessEglContext::Configuration { * on OpenGL ES. To avoid clearing default flags by accident, prefer to * use @ref addFlags() and @ref clearFlags() instead. * @see @ref GL::Context::flags() - * @requires_gles Context flags are not available in WebGL. */ Configuration& setFlags(Flags flags) { - _flags = flags; + GL::Context::Configuration::setFlags(GL::Context::Configuration::Flag(UnsignedLong(flags))); return *this; } @@ -248,10 +263,9 @@ class WindowlessEglContext::Configuration { * Unlike @ref setFlags(), ORs the flags with existing instead of * replacing them. Useful for preserving the defaults. * @see @ref clearFlags() - * @requires_gles Context flags are not available in WebGL. */ Configuration& addFlags(Flags flags) { - _flags |= flags; + GL::Context::Configuration::addFlags(GL::Context::Configuration::Flag(UnsignedLong(flags))); return *this; } @@ -262,13 +276,13 @@ class WindowlessEglContext::Configuration { * Unlike @ref setFlags(), ANDs the inverse of @p flags with existing * instead of replacing them. Useful for removing default flags. * @see @ref addFlags() - * @requires_gles Context flags are not available in WebGL. */ Configuration& clearFlags(Flags flags) { - _flags &= ~flags; + GL::Context::Configuration::clearFlags(GL::Context::Configuration::Flag(UnsignedLong(flags))); return *this; } + #ifndef MAGNUM_TARGET_WEBGL /** * @brief Device ID to use * @m_since{2019,10} @@ -364,9 +378,13 @@ class WindowlessEglContext::Configuration { EGLContext sharedContext() const { return _sharedContext; } #endif + /* Overloads to remove WTF-factor from method chaining order */ + #ifndef DOXYGEN_GENERATING_OUTPUT + MAGNUM_GL_CONTEXT_CONFIGURATION_SUBCLASS_IMPLEMENTATION(Configuration) + #endif + private: #ifndef MAGNUM_TARGET_WEBGL - Flags _flags; UnsignedInt _device; /* Assumes that you can't have 2^32 - 1 GPUs */ UnsignedInt _cudaDevice = ~UnsignedInt{}; @@ -503,7 +521,7 @@ 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", +printed by the `--magnum-log verbose` @ref GL-Context-usage-command-line "command-line option", and then going from `0` up to figure out the desired device ID. On systems with NVIDIA GPUs and CUDA, it's possible to directly select a @@ -521,7 +539,7 @@ Systems running Mesa 19.2 (which has the above extensions) that also have `libEGL_nvidia.so` installed (for example as a CUDA dependency) may fail to create the context with the following error (with additional output produced when the `--magnum-gpu-validation` -@ref GL-Context-command-line "command-line option" is enabled): +@ref GL-Context-usage-command-line "command-line option" is enabled): @m_class{m-console-wrap} diff --git a/src/Magnum/Platform/WindowlessGlxApplication.cpp b/src/Magnum/Platform/WindowlessGlxApplication.cpp index e010ef495..d94ea434c 100644 --- a/src/Magnum/Platform/WindowlessGlxApplication.cpp +++ b/src/Magnum/Platform/WindowlessGlxApplication.cpp @@ -126,12 +126,14 @@ WindowlessGlxContext::WindowlessGlxContext(const WindowlessGlxContext::Configura #endif GLX_CONTEXT_MINOR_VERSION_ARB, 0, GLX_CONTEXT_PROFILE_MASK_ARB, GLX_CONTEXT_ES2_PROFILE_BIT_EXT, - GLX_CONTEXT_FLAGS_ARB, GLint(flags), + /* Mask out the upper 32bits used for other flags */ + GLX_CONTEXT_FLAGS_ARB, GLint(UnsignedLong(flags) & 0xffffffffu), #else GLX_CONTEXT_MAJOR_VERSION_ARB, 3, GLX_CONTEXT_MINOR_VERSION_ARB, 1, GLX_CONTEXT_PROFILE_MASK_ARB, GLX_CONTEXT_CORE_PROFILE_BIT_ARB, - GLX_CONTEXT_FLAGS_ARB, GLint(flags), + /* Mask out the upper 32bits used for other flags */ + GLX_CONTEXT_FLAGS_ARB, GLint(UnsignedLong(flags) & 0xffffffffu), #endif 0 }; @@ -155,8 +157,10 @@ WindowlessGlxContext::WindowlessGlxContext(const WindowlessGlxContext::Configura const GLint fallbackContextAttributes[] = { /* Discard the ForwardCompatible flag for the fallback. Having it set makes the fallback context creation fail on Mesa's Zink - (which is just 2.1) and I assume on others as well. */ - GLX_CONTEXT_FLAGS_ARB, GLint(flags & ~Configuration::Flag::ForwardCompatible), + (which is just 2.1) and I assume on others as well. + + Also mask out the upper 32bits used for other flags. */ + GLX_CONTEXT_FLAGS_ARB, GLint(UnsignedLong(flags & ~Configuration::Flag::ForwardCompatible) & 0xffffffffu), 0 }; { @@ -198,8 +202,10 @@ WindowlessGlxContext::WindowlessGlxContext(const WindowlessGlxContext::Configura /* Discard the ForwardCompatible flag for the fallback. Compared to the above case of a 2.1 fallback it's not really needed here (AFAIK it works in both cases), but let's be - consistent. */ - GLX_CONTEXT_FLAGS_ARB, GLint(flags & ~Configuration::Flag::ForwardCompatible), + consistent. + + Also mask out the upper 32bits used for other flags. */ + GLX_CONTEXT_FLAGS_ARB, GLint(UnsignedLong(flags & ~Configuration::Flag::ForwardCompatible) & 0xffffffffu), 0 }; { @@ -267,13 +273,11 @@ bool WindowlessGlxContext::release() { return false; } -WindowlessGlxContext::Configuration::Configuration(): +WindowlessGlxContext::Configuration::Configuration() { #ifndef MAGNUM_TARGET_GLES - _flags{Flag::ForwardCompatible} - #else - _flags{} + addFlags(Flag::ForwardCompatible); #endif - {} +} #ifndef DOXYGEN_GENERATING_OUTPUT WindowlessGlxApplication::WindowlessGlxApplication(const Arguments& arguments): WindowlessGlxApplication{arguments, Configuration{}} {} @@ -295,7 +299,7 @@ bool WindowlessGlxApplication::tryCreateContext(const Configuration& configurati CORRADE_ASSERT(_context->version() == GL::Version::None, "Platform::WindowlessGlxApplication::tryCreateContext(): context already created", false); WindowlessGlxContext glContext{configuration, _context.get()}; - if(!glContext.isCreated() || !glContext.makeCurrent() || !_context->tryCreate()) + if(!glContext.isCreated() || !glContext.makeCurrent() || !_context->tryCreate(configuration)) return false; _glContext = std::move(glContext); diff --git a/src/Magnum/Platform/WindowlessGlxApplication.h b/src/Magnum/Platform/WindowlessGlxApplication.h index 9577f2197..1c1b0f85b 100644 --- a/src/Magnum/Platform/WindowlessGlxApplication.h +++ b/src/Magnum/Platform/WindowlessGlxApplication.h @@ -39,7 +39,7 @@ /* Include our GL headers first to avoid conflicts */ #include "Magnum/Magnum.h" #include "Magnum/Tags.h" -#include "Magnum/GL/OpenGL.h" +#include "Magnum/GL/Context.h" #include "Magnum/Platform/Platform.h" #include @@ -185,14 +185,15 @@ class WindowlessGlxContext { @ref WindowlessGlxApplication::createContext(), @ref WindowlessGlxApplication::tryCreateContext() */ -class WindowlessGlxContext::Configuration { +class WindowlessGlxContext::Configuration: public GL::Context::Configuration { public: /** * @brief Context flag * + * Includes also everything from @ref GL::Context::Configuration::Flag. * @see @ref Flags, @ref setFlags(), @ref GL::Context::Flag */ - enum class Flag: int { + enum class Flag: UnsignedLong { #ifndef MAGNUM_TARGET_GLES /** * Forward compatible context @@ -204,11 +205,30 @@ class WindowlessGlxContext::Configuration { #endif /** - * Debug context. Enabled automatically if the - * `--magnum-gpu-validation` @ref GL-Context-command-line "command-line option" + * Debug context. Enabled automatically if supported by the driver + * and the @ref Flag::GpuValidation flag is set or if the + * `--magnum-gpu-validation` @ref GL-Context-usage-command-line "command-line option" * is present. */ - Debug = GLX_CONTEXT_DEBUG_BIT_ARB + Debug = GLX_CONTEXT_DEBUG_BIT_ARB, + + /** + * @copydoc GL::Context::Configuration::Flag::QuietLog + * @m_since_latest + */ + QuietLog = UnsignedLong(GL::Context::Configuration::Flag::QuietLog), + + /** + * @copydoc GL::Context::Configuration::Flag::VerboseLog + * @m_since_latest + */ + VerboseLog = UnsignedLong(GL::Context::Configuration::Flag::VerboseLog), + + /** + * @copydoc GL::Context::Configuration::Flag::GpuValidation + * @m_since_latest + */ + GpuValidation = UnsignedLong(GL::Context::Configuration::Flag::GpuValidation) }; /** @@ -221,7 +241,9 @@ class WindowlessGlxContext::Configuration { /*implicit*/ Configuration(); /** @brief Context flags */ - Flags flags() const { return _flags; } + Flags flags() const { + return Flag(UnsignedLong(GL::Context::Configuration::flags())); + } /** * @brief Set context flags @@ -233,7 +255,7 @@ class WindowlessGlxContext::Configuration { * @see @ref GL::Context::flags() */ Configuration& setFlags(Flags flags) { - _flags = flags; + GL::Context::Configuration::setFlags(GL::Context::Configuration::Flag(UnsignedLong(flags))); return *this; } @@ -246,7 +268,7 @@ class WindowlessGlxContext::Configuration { * @see @ref clearFlags() */ Configuration& addFlags(Flags flags) { - _flags |= flags; + GL::Context::Configuration::addFlags(GL::Context::Configuration::Flag(UnsignedLong(flags))); return *this; } @@ -259,7 +281,7 @@ class WindowlessGlxContext::Configuration { * @see @ref addFlags() */ Configuration& clearFlags(Flags flags) { - _flags &= ~flags; + GL::Context::Configuration::clearFlags(GL::Context::Configuration::Flag(UnsignedLong(flags))); return *this; } @@ -287,8 +309,12 @@ class WindowlessGlxContext::Configuration { */ GLXContext sharedContext() const { return _sharedContext; } + /* Overloads to remove WTF-factor from method chaining order */ + #ifndef DOXYGEN_GENERATING_OUTPUT + MAGNUM_GL_CONTEXT_CONFIGURATION_SUBCLASS_IMPLEMENTATION(Configuration) + #endif + private: - Flags _flags; GLXContext _sharedContext = nullptr; }; diff --git a/src/Magnum/Platform/WindowlessIosApplication.h b/src/Magnum/Platform/WindowlessIosApplication.h index 2e922fc94..fdfb7cca2 100644 --- a/src/Magnum/Platform/WindowlessIosApplication.h +++ b/src/Magnum/Platform/WindowlessIosApplication.h @@ -37,7 +37,7 @@ #include "Magnum/Magnum.h" #include "Magnum/Tags.h" -#include "Magnum/GL/OpenGL.h" +#include "Magnum/GL/Context.h" #include "Magnum/Platform/Platform.h" #ifdef __OBJC__ @@ -154,9 +154,25 @@ class WindowlessIosContext { @ref WindowlessIosApplication::createContext(), @ref WindowlessIosApplication::tryCreateContext() */ -class WindowlessIosContext::Configuration { +class WindowlessIosContext::Configuration: public GL::Context::Configuration { public: - constexpr /*implicit*/ Configuration() {} + /* Overloads to remove WTF-factor from method chaining order */ + #ifndef DOXYGEN_GENERATING_OUTPUT + Configuration& setFlags(Flags flags) { + GL::Context::Configuration::setFlags(flags); + return *this; + } + Configuration& addFlags(Flags flags) { + GL::Context::Configuration::addFlags(flags); + return *this; + } + Configuration& clearFlags(Flags flags) { + GL::Context::Configuration::clearFlags(flags); + return *this; + } + MAGNUM_GL_CONTEXT_CONFIGURATION_SUBCLASS_IMPLEMENTATION(Configuration) + #endif + }; /** diff --git a/src/Magnum/Platform/WindowlessWglApplication.cpp b/src/Magnum/Platform/WindowlessWglApplication.cpp index 2dd1bbc29..76985b49b 100644 --- a/src/Magnum/Platform/WindowlessWglApplication.cpp +++ b/src/Magnum/Platform/WindowlessWglApplication.cpp @@ -139,12 +139,14 @@ WindowlessWglContext::WindowlessWglContext(const Configuration& configuration, G #endif WGL_CONTEXT_MINOR_VERSION_ARB, 0, WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_ES2_PROFILE_BIT_EXT, - WGL_CONTEXT_FLAGS_ARB, GLint(flags), + /* Mask out the upper 32bits used for other flags */ + WGL_CONTEXT_FLAGS_ARB, GLint(UnsignedLong(flags) & 0xffffffffu), #else WGL_CONTEXT_MAJOR_VERSION_ARB, 3, WGL_CONTEXT_MINOR_VERSION_ARB, 1, WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_CORE_PROFILE_BIT_ARB, - WGL_CONTEXT_FLAGS_ARB, GLint(flags), + /* Mask out the upper 32bits used for other flags */ + WGL_CONTEXT_FLAGS_ARB, GLint(UnsignedLong(flags) & 0xffffffffu), #endif 0 }; @@ -157,7 +159,8 @@ WindowlessWglContext::WindowlessWglContext(const Configuration& configuration, G const int fallbackContextAttributes[] = { /** @todo or keep the fwcompat? */ - WGL_CONTEXT_FLAGS_ARB, GLint(flags & ~Configuration::Flag::ForwardCompatible), + /* Mask out the upper 32bits used for other flags */ + WGL_CONTEXT_FLAGS_ARB, GLint(UnsignedLong(flags & ~Configuration::Flag::ForwardCompatible) & 0xffffffffu), 0 }; _context = wglCreateContextAttribsARB(_deviceContext, configuration.sharedContext(), fallbackContextAttributes); @@ -196,7 +199,8 @@ WindowlessWglContext::WindowlessWglContext(const Configuration& configuration, G wglDeleteContext(_context); const int fallbackContextAttributes[] = { /** @todo or keep the fwcompat? */ - WGL_CONTEXT_FLAGS_ARB, GLint(flags & ~Configuration::Flag::ForwardCompatible), + /* Mask out the upper 32bits used for other flags */ + WGL_CONTEXT_FLAGS_ARB, GLint(UnsignedLong(flags & ~Configuration::Flag::ForwardCompatible) & 0xffffffffu), 0 }; _context = wglCreateContextAttribsARB(_deviceContext, configuration.sharedContext(), fallbackContextAttributes); @@ -254,13 +258,11 @@ bool WindowlessWglContext::release() { return false; } -WindowlessWglContext::Configuration::Configuration(): +WindowlessWglContext::Configuration::Configuration() { #ifndef MAGNUM_TARGET_GLES - _flags{Flag::ForwardCompatible} - #else - _flags{} + addFlags(Flag::ForwardCompatible); #endif - {} +} #ifndef DOXYGEN_GENERATING_OUTPUT WindowlessWglApplication::WindowlessWglApplication(const Arguments& arguments): WindowlessWglApplication{arguments, Configuration{}} {} @@ -282,7 +284,7 @@ bool WindowlessWglApplication::tryCreateContext(const Configuration& configurati CORRADE_ASSERT(_context->version() == GL::Version::None, "Platform::WindowlessWglApplication::tryCreateContext(): context already created", false); WindowlessWglContext glContext{configuration, _context.get()}; - if(!glContext.isCreated() || !glContext.makeCurrent() || !_context->tryCreate()) + if(!glContext.isCreated() || !glContext.makeCurrent() || !_context->tryCreate(configuration)) return false; _glContext = std::move(glContext); diff --git a/src/Magnum/Platform/WindowlessWglApplication.h b/src/Magnum/Platform/WindowlessWglApplication.h index 999880de2..6bf035a4b 100644 --- a/src/Magnum/Platform/WindowlessWglApplication.h +++ b/src/Magnum/Platform/WindowlessWglApplication.h @@ -42,7 +42,7 @@ #include "Magnum/Magnum.h" #include "Magnum/Tags.h" -#include "Magnum/GL/OpenGL.h" +#include "Magnum/GL/Context.h" #include "Magnum/Platform/Platform.h" #ifndef DOXYGEN_GENERATING_OUTPUT @@ -172,14 +172,15 @@ class WindowlessWglContext { @ref WindowlessWglApplication::createContext(), @ref WindowlessWglApplication::tryCreateContext() */ -class WindowlessWglContext::Configuration { +class WindowlessWglContext::Configuration: public GL::Context::Configuration { public: /** * @brief Context flag * + * Includes also everything from @ref GL::Context::Configuration::Flag. * @see @ref Flags, @ref setFlags(), @ref GL::Context::Flag */ - enum class Flag: int { + enum class Flag: UnsignedLong { #ifndef MAGNUM_TARGET_GLES /** * Forward compatible context @@ -191,11 +192,30 @@ class WindowlessWglContext::Configuration { #endif /** - * Debug context. Enabled automatically if the - * `--magnum-gpu-validation` @ref GL-Context-command-line "command-line option" + * Debug context. Enabled automatically if supported by the driver + * and the @ref Flag::GpuValidation flag is set or if the + * `--magnum-gpu-validation` @ref GL-Context-usage-command-line "command-line option" * is present. */ - Debug = WGL_CONTEXT_DEBUG_BIT_ARB + Debug = WGL_CONTEXT_DEBUG_BIT_ARB, + + /** + * @copydoc GL::Context::Configuration::Flag::QuietLog + * @m_since_latest + */ + QuietLog = UnsignedLong(GL::Context::Configuration::Flag::QuietLog), + + /** + * @copydoc GL::Context::Configuration::Flag::VerboseLog + * @m_since_latest + */ + VerboseLog = UnsignedLong(GL::Context::Configuration::Flag::VerboseLog), + + /** + * @copydoc GL::Context::Configuration::Flag::GpuValidation + * @m_since_latest + */ + GpuValidation = UnsignedLong(GL::Context::Configuration::Flag::GpuValidation) }; /** @@ -208,7 +228,9 @@ class WindowlessWglContext::Configuration { /*implicit*/ Configuration(); /** @brief Context flags */ - Flags flags() const { return _flags; } + Flags flags() const { + return Flag(UnsignedLong(GL::Context::Configuration::flags())); + } /** * @brief Set context flags @@ -220,7 +242,7 @@ class WindowlessWglContext::Configuration { * @see @ref GL::Context::flags() */ Configuration& setFlags(Flags flags) { - _flags = flags; + GL::Context::Configuration::setFlags(GL::Context::Configuration::Flag(UnsignedLong(flags))); return *this; } @@ -233,7 +255,7 @@ class WindowlessWglContext::Configuration { * @see @ref clearFlags() */ Configuration& addFlags(Flags flags) { - _flags |= flags; + GL::Context::Configuration::addFlags(GL::Context::Configuration::Flag(UnsignedLong(flags))); return *this; } @@ -246,7 +268,7 @@ class WindowlessWglContext::Configuration { * @see @ref addFlags() */ Configuration& clearFlags(Flags flags) { - _flags &= ~flags; + GL::Context::Configuration::clearFlags(GL::Context::Configuration::Flag(UnsignedLong(flags))); return *this; } @@ -274,8 +296,12 @@ class WindowlessWglContext::Configuration { */ HGLRC sharedContext() const { return _sharedContext; } + /* Overloads to remove WTF-factor from method chaining order */ + #ifndef DOXYGEN_GENERATING_OUTPUT + MAGNUM_GL_CONTEXT_CONFIGURATION_SUBCLASS_IMPLEMENTATION(Configuration) + #endif + private: - Flags _flags; HGLRC _sharedContext = nullptr; }; diff --git a/src/Magnum/Platform/WindowlessWindowsEglApplication.cpp b/src/Magnum/Platform/WindowlessWindowsEglApplication.cpp index 685a30892..5cb872171 100644 --- a/src/Magnum/Platform/WindowlessWindowsEglApplication.cpp +++ b/src/Magnum/Platform/WindowlessWindowsEglApplication.cpp @@ -129,7 +129,8 @@ WindowlessWindowsEglContext::WindowlessWindowsEglContext(const Configuration& co #error unsupported OpenGL ES version #endif #endif - EGL_CONTEXT_FLAGS_KHR, EGLint(flags), + /* Mask out the upper 32bits used for other flags */ + EGL_CONTEXT_FLAGS_KHR, EGLint(UnsignedLong(flags) & 0xffffffffu), EGL_NONE }; @@ -201,7 +202,7 @@ bool WindowlessWindowsEglApplication::tryCreateContext(const Configuration& conf CORRADE_ASSERT(_context->version() == Version::None, "Platform::WindowlessWindowsEglApplication::tryCreateContext(): context already created", false); WindowlessWindowsEglContext glContext{configuration, _context.get()}; - if(!glContext.isCreated() || !glContext.makeCurrent() || !_context->tryCreate()) + if(!glContext.isCreated() || !glContext.makeCurrent() || !_context->tryCreate(configuration)) return false; _glContext = std::move(glContext); diff --git a/src/Magnum/Platform/WindowlessWindowsEglApplication.h b/src/Magnum/Platform/WindowlessWindowsEglApplication.h index 49c28621d..80694d9b3 100644 --- a/src/Magnum/Platform/WindowlessWindowsEglApplication.h +++ b/src/Magnum/Platform/WindowlessWindowsEglApplication.h @@ -44,7 +44,7 @@ #include "Magnum/Magnum.h" #include "Magnum/Tags.h" -#include "Magnum/GL/OpenGL.h" +#include "Magnum/GL/Context.h" #include "Magnum/Platform/Platform.h" namespace Magnum { namespace Platform { @@ -158,20 +158,40 @@ class WindowlessWindowsEglContext { @ref WindowlessWindowsEglApplication::createContext(), @ref WindowlessWindowsEglApplication::tryCreateContext() */ -class WindowlessWindowsEglContext::Configuration { +class WindowlessWindowsEglContext::Configuration: public GL::Context::Configuration { public: /** * @brief Context flag * + * Includes also everything from @ref GL::Context::Configuration::Flag. * @see @ref Flags, @ref setFlags(), @ref GL::Context::Flag */ - enum class Flag: int { + enum class Flag: UnsignedLong { /** - * Debug context. Enabled automatically if the - * `--magnum-gpu-validation` @ref GL-Context-command-line "command-line option" + * Debug context. Enabled automatically if supported by the driver + * and the @ref Flag::GpuValidation flag is set or if the + * `--magnum-gpu-validation` @ref GL-Context-usage-command-line "command-line option" * is present. */ - Debug = EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR + Debug = EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR, + + /** + * @copydoc GL::Context::Configuration::Flag::QuietLog + * @m_since_latest + */ + QuietLog = UnsignedLong(GL::Context::Configuration::Flag::QuietLog), + + /** + * @copydoc GL::Context::Configuration::Flag::VerboseLog + * @m_since_latest + */ + VerboseLog = UnsignedLong(GL::Context::Configuration::Flag::VerboseLog), + + /** + * @copydoc GL::Context::Configuration::Flag::GpuValidation + * @m_since_latest + */ + GpuValidation = UnsignedLong(GL::Context::Configuration::Flag::GpuValidation) }; /** @@ -181,10 +201,10 @@ class WindowlessWindowsEglContext::Configuration { */ typedef Containers::EnumSet Flags; - constexpr /*implicit*/ Configuration() {} - /** @brief Context flags */ - Flags flags() const { return _flags; } + Flags flags() const { + return Flag(UnsignedLong(GL::Context::Configuration::flags())); + } /** * @brief Set context flags @@ -195,7 +215,7 @@ class WindowlessWindowsEglContext::Configuration { * @see @ref GL::Context::flags() */ Configuration& setFlags(Flags flags) { - _flags = flags; + GL::Context::Configuration::setFlags(GL::Context::Configuration::Flag(UnsignedLong(flags))); return *this; } @@ -208,7 +228,7 @@ class WindowlessWindowsEglContext::Configuration { * @see @ref clearFlags() */ Configuration& addFlags(Flags flags) { - _flags |= flags; + GL::Context::Configuration::addFlags(GL::Context::Configuration::Flag(UnsignedLong(flags))); return *this; } @@ -221,7 +241,7 @@ class WindowlessWindowsEglContext::Configuration { * @see @ref addFlags() */ Configuration& clearFlags(Flags flags) { - _flags &= ~flags; + GL::Context::Configuration::clearFlags(GL::Context::Configuration::Flag(UnsignedLong(flags))); return *this; } @@ -249,8 +269,12 @@ class WindowlessWindowsEglContext::Configuration { */ EGLContext sharedContext() const { return _sharedContext; } + /* Overloads to remove WTF-factor from method chaining order */ + #ifndef DOXYGEN_GENERATING_OUTPUT + MAGNUM_GL_CONTEXT_CONFIGURATION_SUBCLASS_IMPLEMENTATION(Configuration) + #endif + private: - Flags _flags; EGLContext _sharedContext = EGL_NO_CONTEXT; }; diff --git a/src/Magnum/Platform/gl-info.cpp b/src/Magnum/Platform/gl-info.cpp index 28e205a59..4c452f5c9 100644 --- a/src/Magnum/Platform/gl-info.cpp +++ b/src/Magnum/Platform/gl-info.cpp @@ -118,7 +118,7 @@ Arguments: - `--all-extensions` --- display extensions also for fully supported versions - `--limits` --- display also limits and implementation-defined values - `--magnum-...` --- engine-specific options (see - @ref GL-Context-command-line for details) + @ref GL-Context-usage-command-line for details) @subsection magnum-gl-info-usage-emscripten Usage on Emscripten diff --git a/src/Magnum/Text/fontconverter.cpp b/src/Magnum/Text/fontconverter.cpp index 347578216..9ef08563c 100644 --- a/src/Magnum/Text/fontconverter.cpp +++ b/src/Magnum/Text/fontconverter.cpp @@ -103,7 +103,7 @@ Arguments: field computation will not be used. (default: `"256 256"`) - `--radius N` --- distance field computation radius (default: `24`) - `--magnum-...` --- engine-specific options (see - @ref GL-Context-command-line for details) + @ref GL-Context-usage-command-line for details) The resulting font files can be then used as specified in the documentation of `converter` plugin. diff --git a/src/Magnum/TextureTools/distancefieldconverter.cpp b/src/Magnum/TextureTools/distancefieldconverter.cpp index d5c81a3cc..087b93988 100644 --- a/src/Magnum/TextureTools/distancefieldconverter.cpp +++ b/src/Magnum/TextureTools/distancefieldconverter.cpp @@ -108,7 +108,7 @@ Arguments: - `--output-size "X Y"` --- size of output image - `--radius N` --- distance field computation radius - `--magnum-...` --- engine-specific options (see - @ref GL-Context-command-line for details) + @ref GL-Context-usage-command-line for details) Images with @ref PixelFormat::R8Unorm, @ref PixelFormat::RGB8Unorm or @ref PixelFormat::RGBA8Unorm are accepted on input.