diff --git a/doc/changelog.dox b/doc/changelog.dox index efb2fb9e8..3a715882f 100644 --- a/doc/changelog.dox +++ b/doc/changelog.dox @@ -458,6 +458,20 @@ See also: @ref Corrade::Containers::ArrayView are now removed. This should have a significant positive effect on compile times of code using the @ref GL, @ref Audio, @ref Trade and @ref Text libraries +- As part of the ongoing STL header dependency cleanup, + @ref GL::Context::vendorString(), + @relativeref{GL::Context,rendererString()}, + @relativeref{GL::Context,versionString()}, + @relativeref{GL::Context,shadingLanguageVersionString()}, + @relativeref{GL::Context,shadingLanguageVersionStrings()} and + @relativeref{GL::Context,extensionStrings()} now return + @relativeref{Corrade,Containers::StringView} or a + @relativeref{Corrade,Containers::Array} / + @relativeref{Corrade,Containers::ArrayView} of them, instead of a + @ref std::string and a @ref std::vector. For at least some backwards + compatibility the @ref Corrade/Containers/StringStl.h header is included to + provide implicit conversions to a @ref std::string, but in most cases + you'll be forced to change the code that uses those APIs. - @ref GL::TextureFormat::SR8 and @ref GL::TextureFormat::SRG8 were present on ES2 builds by mistake --- the @gl_extension{EXT,texture_sRGB_R8} and @gl_extension{EXT,texture_sRGB_RG8} extensions require OpenGL ES 3.0 at diff --git a/doc/snippets/MagnumPlatform-windowless.cpp b/doc/snippets/MagnumPlatform-windowless.cpp index 540684fec..17eff3276 100644 --- a/doc/snippets/MagnumPlatform-windowless.cpp +++ b/doc/snippets/MagnumPlatform-windowless.cpp @@ -24,7 +24,7 @@ */ /* [windowless] */ -#include +#include #include #include diff --git a/doc/snippets/getting-started-blue.cpp b/doc/snippets/getting-started-blue.cpp index 1385b487d..dba281b4f 100644 --- a/doc/snippets/getting-started-blue.cpp +++ b/doc/snippets/getting-started-blue.cpp @@ -26,7 +26,7 @@ #include #include /** [0] */ -#include +#include #include #include #include diff --git a/src/Magnum/GL/Context.cpp b/src/Magnum/GL/Context.cpp index 81509cecd..4c825c516 100644 --- a/src/Magnum/GL/Context.cpp +++ b/src/Magnum/GL/Context.cpp @@ -26,13 +26,10 @@ #include "Context.h" #include -#include /* for initialization log redirection */ -#include #include +#include #include #include -#include -#include #include "Magnum/GL/AbstractFramebuffer.h" #include "Magnum/GL/AbstractShaderProgram.h" @@ -68,6 +65,8 @@ namespace Magnum { namespace GL { +using namespace Containers::Literals; + /* When adding a new list, Extension::extensions() and Context::Context() needs to be adapted. Binary search is performed on the extensions, thus they have to be sorted alphabetically. */ @@ -523,6 +522,44 @@ constexpr Extension ExtensionListES320[]{ #endif #undef _extension +constexpr struct { + Version version; + Containers::ArrayView extensions; +} KnownExtensionsForVersion[]{ + #ifndef MAGNUM_TARGET_GLES + {Version::GL300, Containers::arrayView(ExtensionList300)}, + {Version::GL310, Containers::arrayView(ExtensionList310)}, + {Version::GL320, Containers::arrayView(ExtensionList320)}, + {Version::GL330, Containers::arrayView(ExtensionList330)}, + {Version::GL400, Containers::arrayView(ExtensionList400)}, + {Version::GL410, Containers::arrayView(ExtensionList410)}, + {Version::GL420, Containers::arrayView(ExtensionList420)}, + {Version::GL430, Containers::arrayView(ExtensionList430)}, + {Version::GL440, Containers::arrayView(ExtensionList440)}, + {Version::GL450, Containers::arrayView(ExtensionList450)}, + {Version::GL460, Containers::arrayView(ExtensionList460)}, + #else + {Version::GLES300, Containers::arrayView(ExtensionListES300)}, + #ifndef MAGNUM_TARGET_WEBGL + /* No extensions in ES 3.1 */ + {Version::GLES320, Containers::arrayView(ExtensionListES320)}, + #endif + #endif + {Version::None, Containers::arrayView(ExtensionList)} +}; + +const Extension* findExtension(const Containers::StringView extension, const std::size_t since = 0) { + for(std::size_t i = since; i != Containers::arraySize(KnownExtensionsForVersion); ++i) { + const auto found = std::lower_bound(KnownExtensionsForVersion[i].extensions.begin(), KnownExtensionsForVersion[i].extensions.end(), extension, [](const Extension& a, const Containers::StringView& b) { + return a.string() < b; + }); + if(found != KnownExtensionsForVersion[i].extensions.end() && found->string() == extension) + return found; + } + + return {}; +} + } Containers::ArrayView Extension::extensions(Version version) { @@ -657,21 +694,39 @@ Context::Context(NoCreateT, Utility::Arguments& args, Int argc, const char** arg if(args.value("gpu-validation") == "on" || args.value("gpu-validation") == "ON") _internalFlags |= InternalFlag::GpuValidation; - /* Disable driver workarounds */ - for(auto&& workaround: Utility::String::splitWithoutEmptyParts(args.value("disable-workarounds"))) - disableDriverWorkaround(workaround); + /* If there are any disabled workarounds, save them until tryCreate() uses + them. The disableWorkaround() function saves the internal string view + instead of the one passed from the command line so we don't need to + bother with String allocations. */ + const Containers::StringView disabledWorkarounds = args.value("disable-workarounds"); + if(!disabledWorkarounds.isEmpty()) { + const Containers::Array split = disabledWorkarounds.splitWithoutEmptyParts(); + arrayReserve(_driverWorkarounds, split.size()); + for(const Containers::StringView workaround: split) + disableDriverWorkaround(workaround); + } - /* Disable extensions */ - for(auto&& extension: Utility::String::splitWithoutEmptyParts(args.value("disable-extensions"))) - _disabledExtensions.push_back(extension); + /* Disable extensions. Here we search for them among the known extensions + and store the Extension objects instead, which avoids the string copying + and another binary search in tryCreate(). */ + const Containers::StringView disabledExtensions = args.value("disable-extensions"); + if(!disabledExtensions.isEmpty()) { + const Containers::Array split = disabledExtensions.splitWithoutEmptyParts(); + arrayReserve(_disabledExtensions, split.size()); + for(const Containers::StringView extension: split) { + if(const Extension* found = findExtension(extension)) { + arrayAppend(_disabledExtensions, *found); + } + } + } } Context::Context(Context&& other) noexcept: _version{other._version}, #ifndef MAGNUM_TARGET_WEBGL _flags{other._flags}, #endif - _extensionRequiredVersion{other._extensionRequiredVersion}, _extensionStatus{other._extensionStatus}, + _extensionRequiredVersion{other._extensionRequiredVersion}, _supportedExtensions{std::move(other._supportedExtensions)}, _state{std::move(other._state)}, _detectedDrivers{std::move(other._detectedDrivers)} @@ -710,8 +765,8 @@ bool Context::tryCreate() { /* WebGL 2.0, treat it as ES 3.0 */ #else - const std::string version = versionString(); - if(version.find("WebGL 2") == std::string::npos) { + const Containers::StringView version = versionString(); + if(!version.contains("WebGL 2"_s)) { Error{} << "GL::Context: unsupported version string:" << version; return false; } @@ -738,17 +793,17 @@ bool Context::tryCreate() { #endif /* Allow ES2 context on driver that reports ES3 as supported */ - const std::string version = versionString(); + const Containers::StringView version = versionString(); #ifndef MAGNUM_TARGET_GLES - if(version.compare(0, 3, "2.1") == 0) + if(version.hasPrefix("2.1"_s)) #elif defined(MAGNUM_TARGET_WEBGL) /* Internet Explorer currently has 0.94 */ - if(version.find("WebGL 1") != std::string::npos || - version.find("WebGL 0") != std::string::npos) + if(version.contains("WebGL 1"_s) || + version.contains("WebGL 0"_s)) #else - if(version.find("OpenGL ES 2.0") != std::string::npos || + if(version.contains("OpenGL ES 2.0"_s) || /* It is possible to use Magnum compiled for ES2 on ES3 contexts */ - version.find("OpenGL ES 3.") != std::string::npos) + version.contains("OpenGL ES 3."_s)) #endif { majorVersion = 2; @@ -804,51 +859,22 @@ bool Context::tryCreate() { glGetIntegerv(GL_CONTEXT_FLAGS, reinterpret_cast(&_flags)); #endif - constexpr struct { - Version version; - Containers::ArrayView extensions; - } versions[]{ - #ifndef MAGNUM_TARGET_GLES - {Version::GL300, Containers::arrayView(ExtensionList300)}, - {Version::GL310, Containers::arrayView(ExtensionList310)}, - {Version::GL320, Containers::arrayView(ExtensionList320)}, - {Version::GL330, Containers::arrayView(ExtensionList330)}, - {Version::GL400, Containers::arrayView(ExtensionList400)}, - {Version::GL410, Containers::arrayView(ExtensionList410)}, - {Version::GL420, Containers::arrayView(ExtensionList420)}, - {Version::GL430, Containers::arrayView(ExtensionList430)}, - {Version::GL440, Containers::arrayView(ExtensionList440)}, - {Version::GL450, Containers::arrayView(ExtensionList450)}, - {Version::GL460, Containers::arrayView(ExtensionList460)}, - #else - {Version::GLES300, Containers::arrayView(ExtensionListES300)}, - #ifndef MAGNUM_TARGET_WEBGL - /* No extensions in ES 3.1 */ - {Version::GLES320, Containers::arrayView(ExtensionListES320)}, - #endif - #endif - {Version::None, Containers::arrayView(ExtensionList)} - }; - /* Get first future (not supported) version */ std::size_t future = 0; - while(versions[future].version != Version::None && isVersionSupported(versions[future].version)) + while(KnownExtensionsForVersion[future].version != Version::None && isVersionSupported(KnownExtensionsForVersion[future].version)) ++future; /* Mark all extensions from past versions as supported */ for(std::size_t i = 0; i != future; ++i) - for(const Extension& extension: versions[i].extensions) + for(const Extension& extension: KnownExtensionsForVersion[i].extensions) _extensionStatus.set(extension.index(), true); /* Check for presence of future and vendor extensions */ - const std::vector extensions = extensionStrings(); - for(const std::string& extension: extensions) { - for(std::size_t i = future; i != Containers::arraySize(versions); ++i) { - const auto found = std::lower_bound(versions[i].extensions.begin(), versions[i].extensions.end(), extension, [](const Extension& a, const std::string& b) { return a.string() < b; }); - if(found != versions[i].extensions.end() && found->string() == extension) { - _supportedExtensions.push_back(*found); - _extensionStatus.set(found->index(), true); - } + const Containers::Array extensions = extensionStrings(); + for(const Containers::StringView extension: extensions) { + if(const Extension* found = findExtension(extension, future)) { + arrayAppend(_supportedExtensions, *found); + _extensionStatus.set(found->index(), true); } } @@ -856,7 +882,7 @@ bool Context::tryCreate() { for(auto& i: _extensionRequiredVersion) i = Version::None; /* Initialize required versions from extension info */ - for(const auto& version: versions) + for(const auto& version: KnownExtensionsForVersion) for(const Extension& extension: version.extensions) _extensionRequiredVersion[extension.index()] = extension.requiredVersion(); @@ -873,31 +899,16 @@ bool Context::tryCreate() { /* Print some info and initialize state tracker (which also prints some more info). Mesa's renderer string has a space at the end, trim that. */ - Debug{output} << "Renderer:" << Utility::String::trim(rendererString()) << "by" << vendorString(); + Debug{output} << "Renderer:" << rendererString().trimmed() << "by" << vendorString(); Debug{output} << "OpenGL version:" << versionString(); /* Disable extensions as requested by the user */ if(!_disabledExtensions.empty()) { - bool headerPrinted = false; - - /* Disable extensions that are known and supported and print a message - for each */ - for(auto&& extension: _disabledExtensions) { - for(const auto& version: versions) { - const auto found = std::lower_bound(version.extensions.begin(), version.extensions.end(), extension, [](const Extension& a, const std::string& b) { return a.string() < b; }); - /* No error message here because some of the extensions could - be from Vulkan or OpenAL. That also means we print the - header only when we actually have something to say */ - if(found == version.extensions.end() || found->string() != extension) - continue; - - _extensionRequiredVersion[found->index()] = Version::None; - if(!headerPrinted) { - Debug{output} << "Disabling extensions:"; - headerPrinted = true; - } - Debug{output} << " " << extension; - } + Debug{output} << "Disabling extensions:"; + + for(const Extension& extension: _disabledExtensions) { + _extensionRequiredVersion[extension.index()] = Version::None; + Debug{output} << " " << extension.string(); } } @@ -939,45 +950,42 @@ bool Context::tryCreate() { return true; } -std::string Context::vendorString() const { - return Utility::String::fromArray(reinterpret_cast(glGetString(GL_VENDOR))); +Containers::StringView Context::vendorString() const { + return {reinterpret_cast(glGetString(GL_VENDOR)), Containers::StringViewFlag::Global}; } -std::string Context::rendererString() const { - return Utility::String::fromArray(reinterpret_cast(glGetString(GL_RENDERER))); +Containers::StringView Context::rendererString() const { + return {reinterpret_cast(glGetString(GL_RENDERER)), Containers::StringViewFlag::Global}; } -std::string Context::versionString() const { - return Utility::String::fromArray(reinterpret_cast(glGetString(GL_VERSION))); +Containers::StringView Context::versionString() const { + return {reinterpret_cast(glGetString(GL_VERSION)), Containers::StringViewFlag::Global}; } -std::string Context::shadingLanguageVersionString() const { - return Utility::String::fromArray(reinterpret_cast(glGetString(GL_SHADING_LANGUAGE_VERSION))); +Containers::StringView Context::shadingLanguageVersionString() const { + return {reinterpret_cast(glGetString(GL_SHADING_LANGUAGE_VERSION)), Containers::StringViewFlag::Global}; } -std::vector Context::shadingLanguageVersionStrings() const { +Containers::Array Context::shadingLanguageVersionStrings() const { #ifndef MAGNUM_TARGET_GLES GLint versionCount = 0; glGetIntegerv(GL_NUM_SHADING_LANGUAGE_VERSIONS, &versionCount); - /* The implementation doesn't yet support this query (< OpenGL 4.3) */ - if(!versionCount) - return {shadingLanguageVersionString()}; - - /* Get all of them */ - std::vector versions; - versions.reserve(versionCount); - for(GLint i = 0; i != versionCount; ++i) - versions.emplace_back(reinterpret_cast(glGetStringi(GL_SHADING_LANGUAGE_VERSION, i))); - return versions; - #else - return {shadingLanguageVersionString()}; + /* If zero, the implementation doesn't yet support this query (< GL4.3) */ + /** @todo doesn't this throw a GL error? some better handling? */ + if(versionCount) { + /* Get all of them */ + Containers::Array versions{std::size_t(versionCount)}; + for(GLint i = 0; i != versionCount; ++i) + versions[i] = {reinterpret_cast(glGetStringi(GL_SHADING_LANGUAGE_VERSION, i)), Containers::StringViewFlag::Global}; + return versions; + } #endif -} -std::vector Context::extensionStrings() const { - std::vector extensions; + return Containers::array({shadingLanguageVersionString()}); +} +Containers::Array Context::extensionStrings() const { /* If we have GL 3.0 / GLES 3.0 at least, ask the new way. Otherwise don't even attempt to query GL_NUM_EXTENSIONS as that would cause a GL error on GL 2.1. Happens with Mesa's zink that's just 2.1 currently (Apr 2020) @@ -989,9 +997,10 @@ std::vector Context::extensionStrings() const { { GLint extensionCount = 0; glGetIntegerv(GL_NUM_EXTENSIONS, &extensionCount); - extensions.reserve(extensionCount); + Containers::Array extensions{std::size_t(extensionCount)}; for(GLint i = 0; i != extensionCount; ++i) - extensions.emplace_back(reinterpret_cast(glGetStringi(GL_EXTENSIONS, i))); + extensions[i] = {reinterpret_cast(glGetStringi(GL_EXTENSIONS, i)), Containers::StringViewFlag::Global}; + return extensions; } #ifndef MAGNUM_TARGET_GLES3 else @@ -1000,14 +1009,8 @@ std::vector Context::extensionStrings() const { #ifndef MAGNUM_TARGET_GLES3 /* OpenGL 2.1 / OpenGL ES 2.0 doesn't have glGetStringi() */ - { - /* Don't crash when glGetString() returns nullptr (i.e. don't trust the - old implementations) */ - extensions = Utility::String::splitWithoutEmptyParts(Utility::String::fromArray(reinterpret_cast(glGetString(GL_EXTENSIONS))), ' '); - } + return Containers::StringView{reinterpret_cast(glGetString(GL_EXTENSIONS)), Containers::StringViewFlag::Global}.splitWithoutEmptyParts(); #endif - - return extensions; } #ifndef MAGNUM_TARGET_GLES diff --git a/src/Magnum/GL/Context.h b/src/Magnum/GL/Context.h index 655e8168a..8b42a55ef 100644 --- a/src/Magnum/GL/Context.h +++ b/src/Magnum/GL/Context.h @@ -30,12 +30,11 @@ */ #include -#include +#include #include #include #include #include -#include #include "Magnum/Magnum.h" #include "Magnum/Math/BoolVector.h" @@ -45,6 +44,12 @@ #include "Magnum/GL/visibility.h" +#ifdef MAGNUM_BUILD_DEPRECATED +/* For return types of Context::versionString() etc., which used to be a + std::string. Not ideal, but at least something. */ +#include +#endif + namespace Magnum { namespace GL { @@ -513,52 +518,62 @@ class MAGNUM_GL_EXPORT Context { * @brief Vendor string * * The result is *not* cached, repeated queries will result in repeated - * OpenGL calls. + * OpenGL calls. The returned view is always + * @relativeref{Corrade,Containers::StringViewFlag::NullTerminated} and + * @relativeref{Corrade::Containers::StringViewFlag,Global}. * @see @ref rendererString(), @fn_gl{GetString} with * @def_gl_keyword{VENDOR} */ - std::string vendorString() const; + Containers::StringView vendorString() const; /** * @brief Renderer string * * The result is *not* cached, repeated queries will result in repeated - * OpenGL calls. + * OpenGL calls. The returned view is always + * @relativeref{Corrade,Containers::StringViewFlag::NullTerminated} and + * @relativeref{Corrade::Containers::StringViewFlag,Global}. * @see @ref vendorString(), @fn_gl{GetString} with * @def_gl_keyword{RENDERER} */ - std::string rendererString() const; + Containers::StringView rendererString() const; /** * @brief Version string * * The result is *not* cached, repeated queries will result in repeated - * OpenGL calls. + * OpenGL calls. The returned view is always + * @relativeref{Corrade,Containers::StringViewFlag::NullTerminated} and + * @relativeref{Corrade::Containers::StringViewFlag,Global}. * @see @ref shadingLanguageVersionString(), @ref version(), * @fn_gl{GetString} with @def_gl_keyword{VERSION} */ - std::string versionString() const; + Containers::StringView versionString() const; /** * @brief Shading language version string * * The result is *not* cached, repeated queries will result in repeated - * OpenGL calls. + * OpenGL calls. The returned view is always + * @relativeref{Corrade,Containers::StringViewFlag::NullTerminated} and + * @relativeref{Corrade::Containers::StringViewFlag,Global}. * @see @ref versionString(), @ref version(), @fn_gl{GetString} with * @def_gl_keyword{SHADING_LANGUAGE_VERSION} */ - std::string shadingLanguageVersionString() const; + Containers::StringView shadingLanguageVersionString() const; /** * @brief Shading language version strings * * The result is *not* cached, repeated queries will result in repeated - * OpenGL calls. + * OpenGL calls. The returned view is always + * @relativeref{Corrade,Containers::StringViewFlag::NullTerminated} and + * @relativeref{Corrade::Containers::StringViewFlag,Global}. * @see @ref versionString(), @ref version(), @fn_gl{Get} with * @def_gl_keyword{NUM_SHADING_LANGUAGE_VERSIONS}, @fn_gl{GetString} * with @def_gl_keyword{SHADING_LANGUAGE_VERSION} */ - std::vector shadingLanguageVersionStrings() const; + Containers::Array shadingLanguageVersionStrings() const; /** * @brief Extension strings @@ -567,11 +582,13 @@ class MAGNUM_GL_EXPORT Context { * OpenGL calls. Note that this function returns list of all extensions * reported by the driver (even those not supported by Magnum), see * @ref supportedExtensions(), @ref Extension::extensions() or - * @ref isExtensionSupported() for alternatives. + * @ref isExtensionSupported() for alternatives. The returned views are + * always @relativeref{Corrade,Containers::StringViewFlag::NullTerminated} + * and @relativeref{Corrade::Containers::StringViewFlag,Global}. * @see @fn_gl{Get} with @def_gl_keyword{NUM_EXTENSIONS}, * @fn_gl{GetString} with @def_gl_keyword{EXTENSIONS} */ - std::vector extensionStrings() const; + Containers::Array extensionStrings() const; #ifndef MAGNUM_TARGET_WEBGL /** @@ -589,7 +606,7 @@ class MAGNUM_GL_EXPORT Context { * the current. * @see @ref isExtensionSupported(), @ref Extension::extensions() */ - const std::vector& supportedExtensions() const { + Containers::ArrayView supportedExtensions() const { return _supportedExtensions; } @@ -750,7 +767,7 @@ class MAGNUM_GL_EXPORT Context { typedef Containers::EnumSet InternalFlags; CORRADE_ENUMSET_FRIEND_OPERATORS(InternalFlags) - bool isDriverWorkaroundDisabled(const char* workaround); + bool isDriverWorkaroundDisabled(Containers::StringView workaround); Implementation::State& state() { return *_state; } /* This function is called from MeshState constructor, which means the @@ -778,7 +795,7 @@ class MAGNUM_GL_EXPORT Context { friend Implementation::ContextState; #endif - void disableDriverWorkaround(const std::string& workaround); + void disableDriverWorkaround(Containers::StringView workaround); /* Defined in Implementation/driverSpecific.cpp */ MAGNUM_GL_LOCAL void setupDriverWorkarounds(); @@ -794,17 +811,20 @@ class MAGNUM_GL_EXPORT Context { Flags _flags; #endif - Containers::StaticArray _extensionRequiredVersion; Math::BoolVector _extensionStatus; - std::vector _supportedExtensions; + /* For all extensions that are marked as supported in _extensionStatus, + this field contains the minimal required GL version the extension + needs. Extensions that are disabled have None here. */ + Containers::StaticArray _extensionRequiredVersion; + Containers::Array _supportedExtensions; Containers::Pointer _state; Containers::Optional _detectedDrivers; /* True means known and disabled, false means known */ - std::vector> _driverWorkarounds; - std::vector _disabledExtensions; + Containers::Array> _driverWorkarounds; + Containers::Array _disabledExtensions; InternalFlags _internalFlags; }; diff --git a/src/Magnum/GL/Implementation/BufferState.cpp b/src/Magnum/GL/Implementation/BufferState.cpp index 1ecf23caf..c3b056da7 100644 --- a/src/Magnum/GL/Implementation/BufferState.cpp +++ b/src/Magnum/GL/Implementation/BufferState.cpp @@ -25,6 +25,7 @@ #include "BufferState.h" +#include #include #include "Magnum/GL/Context.h" diff --git a/src/Magnum/GL/Implementation/ContextState.cpp b/src/Magnum/GL/Implementation/ContextState.cpp index ca1343fec..da6478547 100644 --- a/src/Magnum/GL/Implementation/ContextState.cpp +++ b/src/Magnum/GL/Implementation/ContextState.cpp @@ -25,6 +25,8 @@ #include "ContextState.h" +#include + #include "Magnum/GL/Context.h" namespace Magnum { namespace GL { namespace Implementation { diff --git a/src/Magnum/GL/Implementation/FramebufferState.cpp b/src/Magnum/GL/Implementation/FramebufferState.cpp index b884a9c33..1f07ca2e5 100644 --- a/src/Magnum/GL/Implementation/FramebufferState.cpp +++ b/src/Magnum/GL/Implementation/FramebufferState.cpp @@ -25,6 +25,8 @@ #include "FramebufferState.h" +#include + #include "Magnum/GL/Context.h" #include "Magnum/GL/Extensions.h" #include "Magnum/GL/Renderbuffer.h" diff --git a/src/Magnum/GL/Implementation/MeshState.cpp b/src/Magnum/GL/Implementation/MeshState.cpp index 1f5075893..c5320a2ee 100644 --- a/src/Magnum/GL/Implementation/MeshState.cpp +++ b/src/Magnum/GL/Implementation/MeshState.cpp @@ -25,6 +25,8 @@ #include "MeshState.h" +#include + #include "Magnum/GL/Context.h" #include "Magnum/GL/Extensions.h" #include "Magnum/GL/MeshView.h" diff --git a/src/Magnum/GL/Implementation/QueryState.cpp b/src/Magnum/GL/Implementation/QueryState.cpp index 64d97475a..b2c4606a5 100644 --- a/src/Magnum/GL/Implementation/QueryState.cpp +++ b/src/Magnum/GL/Implementation/QueryState.cpp @@ -25,6 +25,8 @@ #include "QueryState.h" +#include + #include "Magnum/GL/AbstractQuery.h" #include "Magnum/GL/Context.h" #include "Magnum/GL/Extensions.h" diff --git a/src/Magnum/GL/Implementation/RendererState.cpp b/src/Magnum/GL/Implementation/RendererState.cpp index 666b3a2d9..1e909a992 100644 --- a/src/Magnum/GL/Implementation/RendererState.cpp +++ b/src/Magnum/GL/Implementation/RendererState.cpp @@ -25,6 +25,8 @@ #include "RendererState.h" +#include + #include "Magnum/PixelStorage.h" #include "Magnum/GL/Context.h" #include "Magnum/GL/Extensions.h" diff --git a/src/Magnum/GL/Implementation/ShaderProgramState.cpp b/src/Magnum/GL/Implementation/ShaderProgramState.cpp index 99ca2545f..1ca259ff8 100644 --- a/src/Magnum/GL/Implementation/ShaderProgramState.cpp +++ b/src/Magnum/GL/Implementation/ShaderProgramState.cpp @@ -25,6 +25,8 @@ #include "ShaderProgramState.h" +#include + #include "Magnum/GL/AbstractShaderProgram.h" #include "Magnum/GL/Context.h" #include "Magnum/GL/Extensions.h" diff --git a/src/Magnum/GL/Implementation/ShaderState.cpp b/src/Magnum/GL/Implementation/ShaderState.cpp index 8339e5069..762514c32 100644 --- a/src/Magnum/GL/Implementation/ShaderState.cpp +++ b/src/Magnum/GL/Implementation/ShaderState.cpp @@ -27,6 +27,8 @@ /* Needed only for Emscripten+pthread- / Windows+Intel-specific workarounds, but I won't bother crafting the preprocessor logic for this. */ +#include + #include "Magnum/GL/Context.h" #include "Magnum/GL/Shader.h" diff --git a/src/Magnum/GL/Implementation/TextureState.cpp b/src/Magnum/GL/Implementation/TextureState.cpp index 22534e671..a0502c123 100644 --- a/src/Magnum/GL/Implementation/TextureState.cpp +++ b/src/Magnum/GL/Implementation/TextureState.cpp @@ -26,6 +26,7 @@ #include "TextureState.h" #include +#include #include #include "Magnum/GL/AbstractTexture.h" diff --git a/src/Magnum/GL/Implementation/driverSpecific.cpp b/src/Magnum/GL/Implementation/driverSpecific.cpp index 6d06c3749..45ef76398 100644 --- a/src/Magnum/GL/Implementation/driverSpecific.cpp +++ b/src/Magnum/GL/Implementation/driverSpecific.cpp @@ -23,11 +23,8 @@ DEALINGS IN THE SOFTWARE. */ -#include -#include -#include -#include -#include +#include +#include #include "Magnum/GL/Context.h" #include "Magnum/GL/Extensions.h" @@ -37,14 +34,16 @@ namespace Magnum { namespace GL { namespace { -/* Search the code for the following strings to see where they are implemented. */ -const char* KnownWorkarounds[]{ +using namespace Containers::Literals; + +/* Search the code for the following strings to see where they are implemented */ +constexpr Containers::StringView KnownWorkarounds[]{ /* [workarounds] */ #if defined(MAGNUM_TARGET_GLES) && !defined(MAGNUM_TARGET_WEBGL) /* ANGLE's shader linker insists on returning a message consisting of a single newline on success, causing annoying noise in the console. Similar to "intel-windows-chatty-shader-compiler". */ -"angle-chatty-shader-compiler", +"angle-chatty-shader-compiler"_s, #endif #if defined(CORRADE_TARGET_APPLE) && !defined(MAGNUM_TARGET_GLES) @@ -69,7 +68,7 @@ const char* KnownWorkarounds[]{ data modification on *any* buffer, which would have extreme perf implications. So FORTUNATELY unbinding the textures worked around this too, and is a much nicer workaround after all. */ -"apple-buffer-texture-unbind-on-buffer-modify", +"apple-buffer-texture-unbind-on-buffer-modify"_s, #endif #if defined(CORRADE_TARGET_ANDROID) && defined(MAGNUM_TARGET_GLES) @@ -77,7 +76,7 @@ const char* KnownWorkarounds[]{ running from the Android shell (through ADB). No such error happens in an APK. Detecting using the $SHELL environment variable and disabling GL_EXT_disjoint_timer_query in that case. */ -"arm-mali-timer-queries-oom-in-shell", +"arm-mali-timer-queries-oom-in-shell"_s, #endif #if !defined(MAGNUM_TARGET_GLES) && defined(CORRADE_TARGET_WINDOWS) @@ -90,30 +89,30 @@ const char* KnownWorkarounds[]{ svga3d-texture-upload-slice-by-slice workaround. The compressed image up/ download is affected as well, but we lack APIs for easy format-dependent slicing and offset calculation, so those currently still fail. */ -"amd-windows-cubemap-image3d-slice-by-slice", +"amd-windows-cubemap-image3d-slice-by-slice"_s, /* AMD Windows drivers have broken the DSA glCopyTextureSubImage3D(), returning GL_INVALID_VALUE. The non-DSA code path works. */ -"amd-windows-broken-dsa-cubemap-copy", +"amd-windows-broken-dsa-cubemap-copy"_s, /* AMD Windows glCreateQueries() works for everything except GL_TRANSFORM_FEEDBACK_[STREAM_]OVERFLOW, probably they just forgot to adapt it to this new GL 4.6 addition. Calling the non-DSA code path in that case instead. Similar to "mesa-dsa-createquery-except-pipeline-stats". */ -"amd-windows-dsa-createquery-except-xfb-overflow", +"amd-windows-dsa-createquery-except-xfb-overflow"_s, #endif #if !defined(MAGNUM_TARGET_GLES) && !defined(CORRADE_TARGET_APPLE) /* Creating core context with specific version on AMD and NV proprietary drivers on Linux/Windows and Intel drivers on Windows causes the context to be forced to given version instead of selecting latest available version */ -"no-forward-compatible-core-context", +"no-forward-compatible-core-context"_s, #endif #if !defined(MAGNUM_TARGET_GLES) && defined(CORRADE_TARGET_WINDOWS) /* On Windows Intel drivers ARB_shading_language_420pack is exposed in GLSL even though the extension (e.g. binding keyword) is not supported */ -"intel-windows-glsl-exposes-unsupported-shading-language-420pack", +"intel-windows-glsl-exposes-unsupported-shading-language-420pack"_s, #endif #ifndef MAGNUM_TARGET_GLES @@ -121,12 +120,12 @@ const char* KnownWorkarounds[]{ ARB_pipeline_statistics_query, probably just forgotten. Calling the non-DSA code path in that case instead. Similar to "amd-windows-dsa-createquery-except-xfb-overflow". */ -"mesa-dsa-createquery-except-pipeline-stats", +"mesa-dsa-createquery-except-pipeline-stats"_s, /* Forward-compatible GL contexts on Mesa still report line width range as [1, 7], but setting wide line width fails. According to the specs the max value on forward compatible contexts should be 1.0, so patching it. */ -"mesa-forward-compatible-line-width-range", +"mesa-forward-compatible-line-width-range"_s, #endif #if !defined(MAGNUM_TARGET_GLES2) && defined(CORRADE_TARGET_WINDOWS) @@ -135,31 +134,31 @@ const char* KnownWorkarounds[]{ arrays are not in scope anymore. Enabling *synchronous* debug output circumvents this bug. Can be triggered by running TransformFeedbackGLTest with GL_KHR_debug extension disabled. */ -"nv-windows-dangling-transform-feedback-varying-names", +"nv-windows-dangling-transform-feedback-varying-names"_s, #endif #ifndef MAGNUM_TARGET_GLES /* Layout qualifier causes compiler error with GLSL 1.20 on Mesa, GLSL 1.30 on NVidia and 1.40 on macOS. Everything is fine when using a newer GLSL version. */ -"no-layout-qualifiers-on-old-glsl", +"no-layout-qualifiers-on-old-glsl"_s, /* NVidia drivers (358.16) report compressed block size from internal format query in bits instead of bytes */ -"nv-compressed-block-size-in-bits", +"nv-compressed-block-size-in-bits"_s, /* NVidia drivers (358.16) report different compressed image size for cubemaps based on whether the texture is immutable or not and not based on whether I'm querying all faces (ARB_DSA) or a single face (non-DSA, EXT_DSA) */ -"nv-cubemap-inconsistent-compressed-image-size", +"nv-cubemap-inconsistent-compressed-image-size"_s, /* NVidia drivers (358.16) return only the first slice of compressed cube map image when querying all six slices using the ARB_DSA API */ -"nv-cubemap-broken-full-compressed-image-query", +"nv-cubemap-broken-full-compressed-image-query"_s, /* NVidia drivers return 0 when asked for GL_CONTEXT_PROFILE_MASK, so it needs to be worked around by asking for GL_ARB_compatibility */ -"nv-zero-context-profile-mask", +"nv-zero-context-profile-mask"_s, /* (Headless) EGL contexts for desktop GL on NVidia 384 and 390 drivers don't have correct statically linked GL 1.0 and 1.1 functions (such as @@ -167,7 +166,7 @@ const char* KnownWorkarounds[]{ eglGetProcAddress(). Doesn't seem to happen on pre-384 and 396, but it's not possible to get driver version through EGL, so enabling this unconditionally on all EGL NV contexts. */ -"nv-egl-incorrect-gl11-function-pointers", +"nv-egl-incorrect-gl11-function-pointers"_s, /* On NV driver 450.80.02, eglQueryDeviceAttribEXT() segfaults when querying GPUs that the user does not have access to (i.e. via cgroup). Instead, @@ -175,19 +174,19 @@ const char* KnownWorkarounds[]{ error that can be retrieved via eglGetError() to see if the user has access to that device. On well-behaved driver versions, eglQueryDeviceAttribEXT() returns false instead of segfaulting. */ -"nv-egl-crashy-query-device-attrib", +"nv-egl-crashy-query-device-attrib"_s, #endif #ifndef MAGNUM_TARGET_GLES /* SVGA3D (VMware host GL driver) glDrawArrays() draws nothing when the vertex buffer memory is initialized using glNamedBufferData() from ARB_DSA. Using the non-DSA glBufferData() works. */ -"svga3d-broken-dsa-bufferdata", +"svga3d-broken-dsa-bufferdata"_s, /* SVGA3D does out-of-bound writes in some cases of glGetTexSubImage(), leading to memory corruption on client machines. That's nasty, so the whole ARB_get_texture_sub_image is disabled. */ -"svga3d-gettexsubimage-oob-write", +"svga3d-gettexsubimage-oob-write"_s, #endif /* SVGA3D has broken handling of glTex[ture][Sub]Image*D() for 1D arrays, 2D @@ -196,25 +195,25 @@ const char* KnownWorkarounds[]{ with buffer images. Seems to be fixed in Mesa 13, but I have no such system to verify that on. https://github.com/mesa3d/mesa/commit/2aa9ff0cda1f6ad97c83d5583fab7a84efabe19e */ -"svga3d-texture-upload-slice-by-slice", +"svga3d-texture-upload-slice-by-slice"_s, #if defined(CORRADE_TARGET_EMSCRIPTEN) && defined(__EMSCRIPTEN_PTHREADS__) /* Shader sources containing UTF-8 characters are converted to empty strings when running on Emscripten with -s USE_PTHREADS=1. Working around that by replacing all chars > 127 with spaces. Relevant code: https://github.com/kripken/emscripten/blob/7f89560101843198787530731f40a65288f6f15f/src/fetch-worker.js#L54-L58 */ -"emscripten-pthreads-broken-unicode-shader-sources", +"emscripten-pthreads-broken-unicode-shader-sources"_s, #endif #if defined(MAGNUM_TARGET_GLES) && !defined(MAGNUM_TARGET_WEBGL) /* Empty EGL_CONTEXT_FLAGS_KHR cause SwiftShader 3.3.0.1 to fail context creation with EGL_BAD_ATTRIBUTE. Not sending the flags then. Relevant code: https://github.com/google/swiftshader/blob/5fb5e817a20d3e60f29f7338493f922b5ac9d7c4/src/OpenGL/libEGL/libEGL.cpp#L794-L810 */ -"swiftshader-no-empty-egl-context-flags", +"swiftshader-no-empty-egl-context-flags"_s, /* SwiftShader 3.3.0.1 crashes deep inside eglMakeCurrent() when using EGL_NO_SURFACE. Supplying a 32x32 PBuffer to work around that. */ -"swiftshader-egl-context-needs-pbuffer", +"swiftshader-egl-context-needs-pbuffer"_s, #endif #if defined(MAGNUM_TARGET_GLES2) && !defined(MAGNUM_TARGET_WEBGL) @@ -225,14 +224,14 @@ const char* KnownWorkarounds[]{ ES3. OTOH, glVertexAttribDivisor is there for both ANGLE and EXT. Relevant code: https://github.com/google/swiftshader/blob/ad5c2952ca88730c07e04f6f1566194b66860c26/src/OpenGL/libGLESv2/libGLESv2.cpp#L6352-L6357 Disabling the two extensions on ES2 contexts to avoid nullptr crashes. */ -"swiftshader-no-es2-draw-instanced-entrypoints", +"swiftshader-no-es2-draw-instanced-entrypoints"_s, /* SwiftShader 4.1.0 on ES2 contexts reports GL_OES_texture_3D but from all its entrypoints only glTexImage3DOES is present, all others are present only in the ES3 unsuffixed versions. Relevant code: https://github.com/google/swiftshader/blob/ad5c2952ca88730c07e04f6f1566194b66860c26/src/OpenGL/libGLESv2/libGLESv2.cpp#L6504 Disabling the extension on ES2 contexts to avoid nullptr crashes. */ -"swiftshader-no-es2-oes-texture-3d-entrypoints", +"swiftshader-no-es2-oes-texture-3d-entrypoints"_s, #endif #if defined(MAGNUM_TARGET_GLES) && !defined(MAGNUM_TARGET_GLES2) && !defined(MAGNUM_TARGET_WEBGL) @@ -242,14 +241,14 @@ const char* KnownWorkarounds[]{ otherwise. No other driver does that. As a workaround, setting Buffer::TargetHint::TransformFeedback will make it use Buffer::TargetHint::Array instead, as that works okay. */ -"swiftshader-broken-xfb-buffer-binding-target", +"swiftshader-broken-xfb-buffer-binding-target"_s, /* SwiftShader 4.1.0 does implement gl_VertexID for ES3 contexts, but in practice it doesn't work, returning a constant value. In order to make this easier to check, there's a dummy MAGNUM_shader_vertex_id extension that's defined on all GL 3.0+ and GLES 3.0+ / WebGL 2+ contexts *except* for SwiftShader. */ -"swiftshader-broken-shader-vertex-id", +"swiftshader-broken-shader-vertex-id"_s, #endif #ifndef MAGNUM_TARGET_GLES @@ -258,7 +257,7 @@ const char* KnownWorkarounds[]{ bound for reading. Relevant code: https://github.com/mesa3d/mesa/blob/212c0c630a849e4737e2808a993d708cbb2f18f7/src/mesa/main/framebuffer.c#L841-L843 Workaround is to explicitly bind the framebuffer for reading. */ -"mesa-implementation-color-read-format-dsa-explicit-binding", +"mesa-implementation-color-read-format-dsa-explicit-binding"_s, #endif #if !defined(MAGNUM_TARGET_GLES2) && defined(CORRADE_TARGET_WINDOWS) @@ -272,7 +271,7 @@ const char* KnownWorkarounds[]{ glGetInteger() is actually able to return a correct value in *one circumstance*, it's preferrable to the other random shit the driver is doing. */ -"intel-windows-implementation-color-read-format-completely-broken", +"intel-windows-implementation-color-read-format-completely-broken"_s, #endif #if !defined(MAGNUM_TARGET_GLES) && defined(CORRADE_TARGET_WINDOWS) @@ -306,8 +305,8 @@ const char* KnownWorkarounds[]{ on DSA that's not there. It's clearly Intel drivers fault. - With both enabled, things seem to be fine, and I hope it stays that way also for future driver updates. */ -"intel-windows-crazy-broken-buffer-dsa", -"intel-windows-crazy-broken-vao-dsa", +"intel-windows-crazy-broken-buffer-dsa"_s, +"intel-windows-crazy-broken-vao-dsa"_s, /* ARB_direct_state_access implementation on Intel Windows drivers has broken *everything* related to cube map textures (but not cube map arrays) -- data @@ -315,37 +314,37 @@ const char* KnownWorkarounds[]{ complaining about "Wrong 6 provided for 34067" and similar (GL_TEXTURE_CUBE_MAP is 34067). Using the non-DSA code paths as a workaround (for the 3D image up/download as well). */ -"intel-windows-broken-dsa-for-cubemaps", +"intel-windows-broken-dsa-for-cubemaps"_s, /* DSA glBindTextureUnit() on Intel Windows drivers simply doesn't work when passing 0 to it. Non-zero IDs work correctly except for cube maps. Using the non-DSA code path for unbinding and cube maps as a workaround. */ -"intel-windows-half-baked-dsa-texture-bind", +"intel-windows-half-baked-dsa-texture-bind"_s, /* DSA glNamedFramebufferTexture() on Intel Windows drivers doesn't work for layered cube map array attachments. Non-layered or non-array cube map attachment works. Using the non-DSA code path as a workaround. */ -"intel-windows-broken-dsa-layered-cubemap-array-framebuffer-attachment", +"intel-windows-broken-dsa-layered-cubemap-array-framebuffer-attachment"_s, /* DSA glClearNamedFramebuffer*() on Intel Windows drivers doesn't do anything. Using the non-DSA code path as a workaournd. */ -"intel-windows-broken-dsa-framebuffer-clear", +"intel-windows-broken-dsa-framebuffer-clear"_s, /* Using DSA glCreateQueries() on Intel Windows drivers breaks glBeginQueryIndexed(). Using the non-DSA glGenQueries() instead makes it work properly. See TransformFeedbackGLTest for a test. */ -"intel-windows-broken-dsa-indexed-queries", +"intel-windows-broken-dsa-indexed-queries"_s, /* DSA-ified "vertex layout" glVertexArrayAttribIFormat() is broken when passing shorts instead of full 32bit ints. Using the old-style glVertexAttribIPointer() works correctly. No idea if the non-DSA glVertexAttribIFormat() works or not. A test that triggers this issue is in MeshGLTest::addVertexBufferIntWithShort(). */ -"intel-windows-broken-dsa-integer-vertex-attributes", +"intel-windows-broken-dsa-integer-vertex-attributes"_s, /* Shader compiler on Intel Windows drivers insists on telling me "No errors." when it should just stay silent. See also "angle-chatty-shader-compiler". */ -"intel-windows-chatty-shader-compiler", +"intel-windows-chatty-shader-compiler"_s, /* When using more than just a vertex and fragment shader (geometry shader, e.g.), ARB_explicit_uniform_location on Intel silently uses wrong @@ -359,7 +358,7 @@ const char* KnownWorkarounds[]{ location 1, setting color to location 2 didn't work, ending up with a Generic error again (driver version 27). Because this is impossible to prevent, the extension is completely disabled on all Intel Windows drivers. */ -"intel-windows-explicit-uniform-location-is-less-explicit-than-you-hoped", +"intel-windows-explicit-uniform-location-is-less-explicit-than-you-hoped"_s, #endif #ifndef MAGNUM_TARGET_GLES @@ -367,13 +366,13 @@ const char* KnownWorkarounds[]{ GL_IMPLEMENTATION_COLOR_READ_FORMAT and _TYPE is queried using glGetNamedFramebufferParameter(). Using either glGetInteger() or glGetFramebufferParameter() works correctly. */ -"nv-implementation-color-read-format-dsa-broken", +"nv-implementation-color-read-format-dsa-broken"_s, #endif #ifndef MAGNUM_TARGET_GLES /* ApiTrace needs an explicit initial glViewport() call to initialize its framebuffer size, otherwise it assumes it's zero-sized. */ -"apitrace-zero-initial-viewport", +"apitrace-zero-initial-viewport"_s, #endif #if defined(MAGNUM_TARGET_WEBGL) && !defined(MAGNUM_TARGET_GLES2) @@ -386,11 +385,29 @@ const char* KnownWorkarounds[]{ https://www.khronos.org/webgl/public-mailing-list/public_webgl/1705/msg00015.php and https://github.com/emscripten-core/emscripten/pull/9652 for the Emscripten-side part of this workaround. */ -"firefox-fake-disjoint-timer-query-webgl2", +"firefox-fake-disjoint-timer-query-webgl2"_s, #endif /* [workarounds] */ }; +/* I could use std::find(), right? Well, it'd be a whole lot more typing and + an #include *and* #include or whatever as well, + because apparently ONE CAN'T GET std::begin() / std::end() without including + tens thousands lines of irrelevant shit, FFS. + + Also the comparison to array end to discover if it wasn't found is just a + useless verbose crap shit as well, so we'll do better here and return a null + view instead. + + Since the workaround list isn't really huge for an average platform (16 on + Linux, Windows probably ~30?) and there's very few used heavily, I won't + bother with some binary search, which needs extra testing effort. */ +Containers::StringView findWorkaround(Containers::StringView workaround) { + for(Containers::StringView i: KnownWorkarounds) + if(workaround == i) return i; + return {}; +} + } auto Context::detectedDriver() -> DetectedDrivers { @@ -398,33 +415,33 @@ auto Context::detectedDriver() -> DetectedDrivers { _detectedDrivers = DetectedDrivers{}; - const std::string renderer = rendererString(); - const std::string vendor = vendorString(); - const std::string version = versionString(); + const Containers::StringView renderer = rendererString(); + const Containers::StringView vendor = vendorString(); + const Containers::StringView version = versionString(); /* Apple has its own drivers */ #if !defined(CORRADE_TARGET_APPLE) && !defined(MAGNUM_TARGET_WEBGL) /* AMD binary desktop drivers */ - if(vendor.find("ATI Technologies Inc.") != std::string::npos) + if(vendor.contains("ATI Technologies Inc."_s)) return *_detectedDrivers |= DetectedDriver::Amd; #ifdef CORRADE_TARGET_WINDOWS /* Intel Windows drivers */ - if(vendor.find("Intel") != std::string::npos) + if(vendor.contains("Intel"_s)) return *_detectedDrivers |= DetectedDriver::IntelWindows; #endif /* Mesa drivers */ - if(version.find("Mesa") != std::string::npos) { + if(version.contains("Mesa"_s)) { *_detectedDrivers |= DetectedDriver::Mesa; - if(renderer.find("SVGA3D") != std::string::npos) + if(renderer.contains("SVGA3D"_s)) *_detectedDrivers |= DetectedDriver::Svga3D; return *_detectedDrivers; } - if(vendor.find("NVIDIA Corporation") != std::string::npos) + if(vendor.contains("NVIDIA Corporation"_s)) return *_detectedDrivers |= DetectedDriver::NVidia; #endif @@ -433,53 +450,63 @@ auto Context::detectedDriver() -> DetectedDrivers { /* ANGLE. Can detect easily on ES, have to resort to hacks on WebGL. Sources: http://stackoverflow.com/a/20149090 + http://webglreport.com */ #ifndef MAGNUM_TARGET_WEBGL - if(renderer.find("ANGLE") != std::string::npos) + if(renderer.contains("ANGLE"_s)) return *_detectedDrivers |= DetectedDriver::Angle; #else { Range1Di range; glGetIntegerv(GL_ALIASED_LINE_WIDTH_RANGE, range.data()); - if(range.min() == 1 && range.max() == 1 && vendor != "Internet Explorer") + if(range.min() == 1 && range.max() == 1 && vendor != "Internet Explorer"_s) return *_detectedDrivers |= DetectedDriver::Angle; } #endif #ifndef MAGNUM_TARGET_WEBGL /* SwiftShader */ - if(renderer.find("SwiftShader") != std::string::npos) + if(renderer.contains("SwiftShader"_s)) return *_detectedDrivers |= DetectedDriver::SwiftShader; #endif #endif #ifdef CORRADE_TARGET_ANDROID - if(vendor.find("ARM") != std::string::npos && renderer.find("Mali") != std::string::npos) + if(vendor.contains("ARM"_s) && renderer.contains("Mali"_s)) return *_detectedDrivers |= DetectedDriver::ArmMali; #endif return *_detectedDrivers; } -void Context::disableDriverWorkaround(const std::string& workaround) { +void Context::disableDriverWorkaround(const Containers::StringView workaround) { + /* 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(std::find(std::begin(KnownWorkarounds), std::end(KnownWorkarounds), workaround) == std::end(KnownWorkarounds)) { - Warning() << "GL: unknown workaround" << workaround; + if(found.isEmpty()) { + Warning{} << "GL: unknown workaround" << workaround; return; } - _driverWorkarounds.emplace_back(workaround, true); + + arrayAppend(_driverWorkarounds, Containers::InPlaceInit, found, true); } -bool Context::isDriverWorkaroundDisabled(const char* workaround) { - CORRADE_INTERNAL_ASSERT(std::find_if(std::begin(KnownWorkarounds), std::end(KnownWorkarounds), [&](const char* a) { - return std::strcmp(a, workaround) == 0; - }) != std::end(KnownWorkarounds)); +bool Context::isDriverWorkaroundDisabled(const Containers::StringView workaround) { + /* 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 */ + Containers::StringView found = findWorkaround(workaround); + CORRADE_INTERNAL_ASSERT(!found.isEmpty()); /* If the workaround was already asked for or disabled, return its state, - otherwise add it to the list as used one */ + otherwise add it to the list as used one. Here we again cheat a bit and + compare just data pointers instead of the whole string as we store only + the views in the KnownWorkarounds list. */ for(const auto& i: _driverWorkarounds) - if(i.first == workaround) return i.second; - _driverWorkarounds.emplace_back(workaround, false); + if(i.first.data() == found.data()) return i.second; + arrayAppend(_driverWorkarounds, Containers::InPlaceInit, found, false); return false; } @@ -489,17 +516,17 @@ void Context::setupDriverWorkarounds() { _extensionRequiredVersion[Extensions::extension::Index] = Version::version #ifndef MAGNUM_TARGET_GLES - if(!isDriverWorkaroundDisabled("no-layout-qualifiers-on-old-glsl")) { + if(!isDriverWorkaroundDisabled("no-layout-qualifiers-on-old-glsl"_s)) { _setRequiredVersion(ARB::explicit_attrib_location, GL320); _setRequiredVersion(ARB::explicit_uniform_location, GL320); _setRequiredVersion(ARB::shading_language_420pack, GL320); } #ifdef CORRADE_TARGET_WINDOWS - if((detectedDriver() & DetectedDriver::IntelWindows) && !isExtensionSupported() && !isDriverWorkaroundDisabled("intel-windows-glsl-exposes-unsupported-shading-language-420pack")) + if((detectedDriver() & DetectedDriver::IntelWindows) && !isExtensionSupported() && !isDriverWorkaroundDisabled("intel-windows-glsl-exposes-unsupported-shading-language-420pack"_s)) _setRequiredVersion(ARB::shading_language_420pack, None); - if((detectedDriver() & DetectedDriver::IntelWindows) && isExtensionSupported() && !isDriverWorkaroundDisabled("intel-windows-explicit-uniform-location-is-less-explicit-than-you-hoped")) { + if((detectedDriver() & DetectedDriver::IntelWindows) && isExtensionSupported() && !isDriverWorkaroundDisabled("intel-windows-explicit-uniform-location-is-less-explicit-than-you-hoped"_s)) { _setRequiredVersion(ARB::explicit_uniform_location, None); } #endif @@ -508,7 +535,7 @@ void Context::setupDriverWorkarounds() { #ifndef MAGNUM_TARGET_GLES if((detectedDriver() & DetectedDriver::Svga3D) && isExtensionSupported() && - !isDriverWorkaroundDisabled("svga3d-gettexsubimage-oob-write")) + !isDriverWorkaroundDisabled("svga3d-gettexsubimage-oob-write"_s)) _setRequiredVersion(ARB::get_texture_sub_image, None); #endif @@ -516,26 +543,26 @@ void Context::setupDriverWorkarounds() { if(detectedDriver() & Context::DetectedDriver::SwiftShader) { if((isExtensionSupported() || isExtensionSupported()) && - !isDriverWorkaroundDisabled("swiftshader-no-es2-draw-instanced-entrypoints")) { + !isDriverWorkaroundDisabled("swiftshader-no-es2-draw-instanced-entrypoints"_s)) { _setRequiredVersion(ANGLE::instanced_arrays, None); _setRequiredVersion(EXT::instanced_arrays, None); } if(isExtensionSupported() && - !isDriverWorkaroundDisabled("swiftshader-no-es2-oes-texture-3d-entrypoints")) + !isDriverWorkaroundDisabled("swiftshader-no-es2-oes-texture-3d-entrypoints"_s)) _setRequiredVersion(OES::texture_3D, None); } #endif #if defined(MAGNUM_TARGET_GLES) && !defined(MAGNUM_TARGET_GLES2) && !defined(MAGNUM_TARGET_WEBGL) if((detectedDriver() & Context::DetectedDriver::SwiftShader) && - !isDriverWorkaroundDisabled("swiftshader-broken-shader-vertex-id")) + !isDriverWorkaroundDisabled("swiftshader-broken-shader-vertex-id"_s)) _setRequiredVersion(MAGNUM::shader_vertex_id, None); #endif #if defined(CORRADE_TARGET_ANDROID) && defined(MAGNUM_TARGET_GLES) if((detectedDriver() & Context::DetectedDriver::ArmMali) && - std::getenv("SHELL") && !isDriverWorkaroundDisabled("arm-mali-timer-queries-oom-in-shell")) + std::getenv("SHELL") && !isDriverWorkaroundDisabled("arm-mali-timer-queries-oom-in-shell"_s)) _setRequiredVersion(EXT::disjoint_timer_query, None); #endif @@ -565,7 +592,7 @@ void Context::setupDriverWorkarounds() { #ifndef MAGNUM_TARGET_GLES if(isExtensionSupported() && - !isDriverWorkaroundDisabled("apitrace-zero-initial-viewport")) { + !isDriverWorkaroundDisabled("apitrace-zero-initial-viewport"_s)) { GLint viewport[4]; glGetIntegerv(GL_VIEWPORT, viewport); glViewport(viewport[0], viewport[1], viewport[2], viewport[3]); @@ -573,9 +600,9 @@ void Context::setupDriverWorkarounds() { #endif #if defined(MAGNUM_TARGET_WEBGL) && !defined(MAGNUM_TARGET_GLES2) - if(rendererString() == "Mozilla") { + if(rendererString() == "Mozilla"_s) { for(const auto& extension: extensionStrings()) { - if(extension == "GL_EXT_disjoint_timer_query" && !isDriverWorkaroundDisabled("firefox-fake-disjoint-timer-query-webgl2")) { + if(extension == "GL_EXT_disjoint_timer_query"_s && !isDriverWorkaroundDisabled("firefox-fake-disjoint-timer-query-webgl2"_s)) { _extensionStatus.set(Extensions::EXT::disjoint_timer_query_webgl2::Index, true); } } diff --git a/src/Magnum/GL/Test/ContextGLTest.cpp b/src/Magnum/GL/Test/ContextGLTest.cpp index 29bda212a..c51635338 100644 --- a/src/Magnum/GL/Test/ContextGLTest.cpp +++ b/src/Magnum/GL/Test/ContextGLTest.cpp @@ -24,6 +24,8 @@ */ #include +#include +#include #include "Magnum/GL/Context.h" #include "Magnum/GL/Extensions.h" @@ -39,6 +41,8 @@ namespace Magnum { namespace GL { namespace Test { namespace { struct ContextGLTest: OpenGLTester { explicit ContextGLTest(); + void stringFlags(); + void makeCurrent(); #ifndef CORRADE_TARGET_EMSCRIPTEN @@ -56,6 +60,8 @@ struct ContextGLTest: OpenGLTester { ContextGLTest::ContextGLTest() { addTests({ + &ContextGLTest::stringFlags, + &ContextGLTest::makeCurrent, #ifndef CORRADE_TARGET_EMSCRIPTEN @@ -71,6 +77,45 @@ ContextGLTest::ContextGLTest() { &ContextGLTest::isExtensionDisabled}); } +void ContextGLTest::stringFlags() { + Context& context = Context::current(); + + CORRADE_VERIFY(!context.vendorString().isEmpty()); + CORRADE_COMPARE(context.vendorString().flags(), Containers::StringViewFlag::Global|Containers::StringViewFlag::NullTerminated); + + CORRADE_VERIFY(!context.rendererString().isEmpty()); + CORRADE_COMPARE(context.rendererString().flags(), Containers::StringViewFlag::Global|Containers::StringViewFlag::NullTerminated); + + CORRADE_VERIFY(!context.versionString().isEmpty()); + CORRADE_COMPARE(context.versionString().flags(), Containers::StringViewFlag::Global|Containers::StringViewFlag::NullTerminated); + + CORRADE_VERIFY(!context.shadingLanguageVersionString().isEmpty()); + CORRADE_COMPARE(context.shadingLanguageVersionString().flags(), Containers::StringViewFlag::Global|Containers::StringViewFlag::NullTerminated); + + for(Containers::StringView languageVersion: context.shadingLanguageVersionStrings()) { + /* One of these might be empty */ + CORRADE_COMPARE(languageVersion.flags(), Containers::StringViewFlag::Global|Containers::StringViewFlag::NullTerminated); + } + + for(Containers::StringView extension: context.extensionStrings()) { + CORRADE_VERIFY(!extension.isEmpty()); + + /* On GL 2.1 and GLES2 the extensions are split from a long string and + thus aren't all null-terminated, only the last one */ + #ifndef MAGNUM_TARGET_GLES + if(context.isVersionSupported(Version::GL300)) + #else + if(context.isVersionSupported(Version::GLES300)) + #endif + { + CORRADE_COMPARE(extension.flags(), Containers::StringViewFlag::Global|Containers::StringViewFlag::NullTerminated); + } else { + CORRADE_COMPARE_AS(extension.flags(), Containers::StringViewFlag::Global, + TestSuite::Compare::GreaterOrEqual); + } + } +} + void ContextGLTest::makeCurrent() { CORRADE_VERIFY(Context::hasCurrent()); @@ -166,7 +211,7 @@ void ContextGLTest::isExtensionSupported() { CORRADE_SKIP(Extensions::ARB::explicit_attrib_location::string() + std::string(" extension should be supported, can't test")); /* Test that we have proper extension list parser */ - std::vector extensions = Context::current().extensionStrings(); + Containers::Array extensions = Context::current().extensionStrings(); CORRADE_VERIFY(std::find(extensions.begin(), extensions.end(), Extensions::EXT::texture_filter_anisotropic::string()) != extensions.end()); CORRADE_VERIFY(std::find(extensions.begin(), extensions.end(), diff --git a/src/Magnum/Platform/WindowlessGlxApplication.cpp b/src/Magnum/Platform/WindowlessGlxApplication.cpp index d744cb2bb..9226476bc 100644 --- a/src/Magnum/Platform/WindowlessGlxApplication.cpp +++ b/src/Magnum/Platform/WindowlessGlxApplication.cpp @@ -27,6 +27,7 @@ #include "WindowlessGlxApplication.h" #include +#include #include #include diff --git a/src/Magnum/Platform/WindowlessWglApplication.cpp b/src/Magnum/Platform/WindowlessWglApplication.cpp index e697fb442..0d9c2cbb5 100644 --- a/src/Magnum/Platform/WindowlessWglApplication.cpp +++ b/src/Magnum/Platform/WindowlessWglApplication.cpp @@ -26,6 +26,7 @@ #include "WindowlessWglApplication.h" #include +#include #include #include diff --git a/src/Magnum/Platform/gl-info.cpp b/src/Magnum/Platform/gl-info.cpp index b354cfa10..28e205a59 100644 --- a/src/Magnum/Platform/gl-info.cpp +++ b/src/Magnum/Platform/gl-info.cpp @@ -195,6 +195,8 @@ class MagnumInfo: public Platform::WindowlessApplication { int exec() override { return 0; } }; +using namespace Containers::Literals; + MagnumInfo::MagnumInfo(const Arguments& arguments): Platform::WindowlessApplication{arguments, NoCreate} { Utility::Arguments args; args.addBooleanOption('s', "short").setHelp("short", "display just essential info and exit") @@ -359,7 +361,7 @@ MagnumInfo::MagnumInfo(const Arguments& arguments): Platform::WindowlessApplicat Debug{} << "Detected driver:" << c.detectedDriver(); Debug{} << "Supported GLSL versions:"; - Debug{} << " " << Utility::String::joinWithoutEmptyParts(c.shadingLanguageVersionStrings(), ", "); + Debug{} << " " << ", "_s.joinWithoutEmptyParts(c.shadingLanguageVersionStrings()); if(args.isSet("extension-strings")) { Debug{} << "Extension strings:" << Debug::newline diff --git a/src/Magnum/Shaders/Test/PhongGLTest.cpp b/src/Magnum/Shaders/Test/PhongGLTest.cpp index 90ad208ae..1e074b21a 100644 --- a/src/Magnum/Shaders/Test/PhongGLTest.cpp +++ b/src/Magnum/Shaders/Test/PhongGLTest.cpp @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -1246,13 +1247,13 @@ void PhongGLTest::renderShininess() { "ARM Mali has a much larger ring for the overflown shininess when it's exactly 0."); #endif #ifndef MAGNUM_TARGET_WEBGL - CORRADE_EXPECT_FAIL_IF(data.shininess == 0.0f && (GL::Context::current().detectedDriver() & GL::Context::DetectedDriver::Mesa) && GL::Context::current().rendererString().find("AMD") != std::string::npos, + CORRADE_EXPECT_FAIL_IF(data.shininess == 0.0f && (GL::Context::current().detectedDriver() & GL::Context::DetectedDriver::Mesa) && GL::Context::current().rendererString().contains("AMD"), "AMD Mesa drivers have a much larger ring for the overflown shininess when it's exactly 0."); - CORRADE_EXPECT_FAIL_IF(data.shininess <= 0.0011f && (GL::Context::current().detectedDriver() & GL::Context::DetectedDriver::Mesa) && GL::Context::current().rendererString().find("llvmpipe") != std::string::npos, + CORRADE_EXPECT_FAIL_IF(data.shininess <= 0.0011f && (GL::Context::current().detectedDriver() & GL::Context::DetectedDriver::Mesa) && GL::Context::current().rendererString().contains("llvmpipe"), "Mesa llvmpipe drivers have a much larger ring for the overflown shininess."); #endif #if defined(CORRADE_TARGET_APPLE) && !defined(CORRADE_TARGET_IOS) - CORRADE_EXPECT_FAIL_IF(data.shininess == 0.0f && GL::Context::current().rendererString().find("AMD") != std::string::npos, + CORRADE_EXPECT_FAIL_IF(data.shininess == 0.0f && GL::Context::current().rendererString().contains("AMD"), "AMD on macOS has a much larger ring for the overflown shininess when it's exactly 0."); #endif CORRADE_COMPARE_WITH( @@ -1268,10 +1269,10 @@ void PhongGLTest::renderShininess() { || (data.shininess <= 0.0011f && (GL::Context::current().detectedDriver() & GL::Context::DetectedDriver::SwiftShader)) #endif #ifndef MAGNUM_TARGET_WEBGL - || (data.shininess == 0.0f && (GL::Context::current().detectedDriver() & GL::Context::DetectedDriver::Mesa) && GL::Context::current().rendererString().find("AMD") != std::string::npos) + || (data.shininess == 0.0f && (GL::Context::current().detectedDriver() & GL::Context::DetectedDriver::Mesa) && GL::Context::current().rendererString().contains("AMD")) #endif #if defined(CORRADE_TARGET_APPLE) && !defined(CORRADE_TARGET_IOS) - || (data.shininess == 0.0f && GL::Context::current().rendererString().find("AMD") != std::string::npos) + || (data.shininess == 0.0f && GL::Context::current().rendererString().contains("AMD")) #endif #if defined(CORRADE_TARGET_ANDROID) && defined(MAGNUM_TARGET_GLES2) || (data.shininess == 0.0f && (GL::Context::current().detectedDriver() & GL::Context::DetectedDriver::ArmMali)) diff --git a/src/MagnumExternal/OpenGL/GL/flextGLPlatform.cpp b/src/MagnumExternal/OpenGL/GL/flextGLPlatform.cpp index 2d1c67cba..76fffe8e7 100644 --- a/src/MagnumExternal/OpenGL/GL/flextGLPlatform.cpp +++ b/src/MagnumExternal/OpenGL/GL/flextGLPlatform.cpp @@ -33,6 +33,7 @@ #ifdef MAGNUM_PLATFORM_USE_EGL #include #include +#include #include "Magnum/GL/Context.h" #endif diff --git a/src/MagnumExternal/OpenGL/GL/flextGLPlatform.cpp.template b/src/MagnumExternal/OpenGL/GL/flextGLPlatform.cpp.template index e0ccb0182..6fe6080e7 100644 --- a/src/MagnumExternal/OpenGL/GL/flextGLPlatform.cpp.template +++ b/src/MagnumExternal/OpenGL/GL/flextGLPlatform.cpp.template @@ -34,6 +34,7 @@ #ifdef MAGNUM_PLATFORM_USE_EGL #include #include +#include #include "Magnum/GL/Context.h" #endif