From db2cb492797ac3379b843f3c31ff3fbe8114832f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Thu, 29 Dec 2022 19:25:41 +0100 Subject: [PATCH] GL: port Shader and ShaderProgram away from std::string. Same as in the previous commit, most cases are inputs so a StringStl.h compatibility include will do, the only breaking change is GL::Shader::sources() which now returns a StringIterable instead of a std::vector (ew). Awesome about this whole thing is that The Shader API now allows creating a shader from sources coming either from string view literals or Utility::Resource completely without having to allocate any strings internally, because all those can be just non-owning references wrapped with String::nullTerminatedGlobalView(). The only parts which aren't references are the #line markers, but (especially on 64bit) those can easily fit into the 22-byte (or 10-byte on 32bit) SSO storage. Also, various Shader constructors and assignment operators had to be deinlined in order to avoid having to include the String header, which would be needed for Array destruction during a move. Co-authored-by: Hugo Amiard --- doc/changelog.dox | 6 + doc/snippets/MagnumGL.cpp | 2 + doc/snippets/MagnumShaders-gl.cpp | 5 +- src/Magnum/DebugTools/TextureImage.cpp | 1 - src/Magnum/GL/AbstractShaderProgram.cpp | 121 +++++++------- src/Magnum/GL/AbstractShaderProgram.h | 86 +++------- .../GL/Implementation/ShaderProgramState.h | 6 +- src/Magnum/GL/Implementation/ShaderState.h | 6 +- src/Magnum/GL/Shader.cpp | 153 +++++++++++------- src/Magnum/GL/Shader.h | 90 ++++++----- .../GL/Test/AbstractShaderProgramGLTest.cpp | 122 ++++++++++---- src/Magnum/GL/Test/MeshGLTest.cpp | 70 ++++---- src/Magnum/GL/Test/PrimitiveQueryGLTest.cpp | 1 + src/Magnum/GL/Test/ShaderGLTest.cpp | 141 +++++++++++----- .../GL/Test/TransformFeedbackGLTest.cpp | 79 ++++++--- src/Magnum/Shaders/DistanceFieldVectorGL.cpp | 7 +- src/Magnum/Shaders/DistanceFieldVectorGL.h | 4 +- src/Magnum/Shaders/FlatGL.cpp | 11 +- src/Magnum/Shaders/FlatGL.h | 8 +- .../CreateCompatibilityShader.h | 1 - src/Magnum/Shaders/MeshVisualizerGL.cpp | 18 ++- src/Magnum/Shaders/MeshVisualizerGL.h | 13 +- src/Magnum/Shaders/PhongGL.cpp | 18 +-- src/Magnum/Shaders/PhongGL.h | 8 +- src/Magnum/Shaders/VectorGL.cpp | 7 +- src/Magnum/Shaders/VectorGL.h | 4 +- src/Magnum/Shaders/VertexColorGL.cpp | 5 +- src/Magnum/Shaders/VertexColorGL.h | 4 +- src/Magnum/TextureTools/DistanceField.cpp | 5 +- 29 files changed, 607 insertions(+), 395 deletions(-) diff --git a/doc/changelog.dox b/doc/changelog.dox index 5a6a92c1c..12175f7c2 100644 --- a/doc/changelog.dox +++ b/doc/changelog.dox @@ -1137,6 +1137,12 @@ See also: - As part of the ongoing STL header dependency cleanup, the following breaking changes related to @ref std::string and a @ref std::vector are done: + - @ref GL::AbstractShaderProgram::validate() now returns a + @relativeref{Corrade,Containers::String} instead of a @ref std::string; + @ref GL::Shader::sources() now returns a + @relativeref{Corrade,Containers::StringIterable} instead of a + @ref std::vector of a @ref std::string See also [mosra/magnum#499](https://github.com/mosra/magnum/pull/499) + and [mosra/magnum#608](https://github.com/mosra/magnum/pull/608). - @ref GL::Context::vendorString(), @relativeref{GL::Context,rendererString()}, @relativeref{GL::Context,versionString()}, diff --git a/doc/snippets/MagnumGL.cpp b/doc/snippets/MagnumGL.cpp index e0c682d53..423de2efd 100644 --- a/doc/snippets/MagnumGL.cpp +++ b/doc/snippets/MagnumGL.cpp @@ -27,6 +27,8 @@ #include #include #include +#include +#include #include #include diff --git a/doc/snippets/MagnumShaders-gl.cpp b/doc/snippets/MagnumShaders-gl.cpp index 9e85f9db3..617402907 100644 --- a/doc/snippets/MagnumShaders-gl.cpp +++ b/doc/snippets/MagnumShaders-gl.cpp @@ -28,7 +28,8 @@ #include #include #include -#include +#include +#include #include "Magnum/ImageView.h" #include "Magnum/PixelFormat.h" @@ -683,7 +684,7 @@ bindAttributeLocation(Shaders::GenericGL3D::Normal::Location, "normal"); { GL::Shader vert{GL::Version::None, GL::Shader::Type::Vertex}; /* [GenericGL-custom-preprocessor] */ -vert.addSource(Utility::formatString( +vert.addSource(Utility::format( "#define POSITION_ATTRIBUTE_LOCATION {}\n" "#define NORMAL_ATTRIBUTE_LOCATION {}\n", Shaders::GenericGL3D::Position::Location, diff --git a/src/Magnum/DebugTools/TextureImage.cpp b/src/Magnum/DebugTools/TextureImage.cpp index df2bf5020..bf01784f5 100644 --- a/src/Magnum/DebugTools/TextureImage.cpp +++ b/src/Magnum/DebugTools/TextureImage.cpp @@ -37,7 +37,6 @@ #if defined(MAGNUM_TARGET_GLES) && !defined(MAGNUM_TARGET_GLES2) #include #include -#include /** @todo remove once GL::Shader is -free */ #include #include "Magnum/GL/AbstractShaderProgram.h" diff --git a/src/Magnum/GL/AbstractShaderProgram.cpp b/src/Magnum/GL/AbstractShaderProgram.cpp index fb9ad3b68..611820117 100644 --- a/src/Magnum/GL/AbstractShaderProgram.cpp +++ b/src/Magnum/GL/AbstractShaderProgram.cpp @@ -29,16 +29,12 @@ #include #include -#include -#ifndef MAGNUM_TARGET_WEBGL -#include -#endif -#include /** @todo remove once -free */ #ifdef MAGNUM_BUILD_DEPRECATED #include #endif -#include -#include +#include +#include +#include #include "Magnum/GL/Context.h" #include "Magnum/GL/Extensions.h" @@ -343,7 +339,7 @@ AbstractShaderProgram& AbstractShaderProgram::setLabel(const Containers::StringV } #endif -std::pair AbstractShaderProgram::validate() { +std::pair AbstractShaderProgram::validate() { glValidateProgram(_id); /* Check validation status */ @@ -351,18 +347,21 @@ std::pair AbstractShaderProgram::validate() { glGetProgramiv(_id, GL_VALIDATE_STATUS, &success); glGetProgramiv(_id, GL_INFO_LOG_LENGTH, &logLength); - /* Error or warning message. The string is returned null-terminated, scrap - the \0 at the end afterwards */ - std::string message(logLength, '\n'); - if(message.size() > 1) - glGetProgramInfoLog(_id, message.size(), nullptr, &message[0]); - message.resize(Math::max(logLength, 1)-1); + /* Error or warning message. The length is reported including the null + terminator and the string implicitly has a storage for that, thus + specify one byte less. */ + Containers::String message{NoInit, std::size_t(Math::max(logLength, 1) - 1)}; + if(logLength > 1) + glGetProgramInfoLog(_id, logLength, nullptr, message.data()); /* On some drivers (such as SwiftShader) the message contains a newline at the end, on some (such as Mesa) it doesn't. Same as with link() or compile() message trimming it doesn't make sense to add driver-specific workarounds for this, so just trim it always. */ - return {success, Utility::String::trim(std::move(message))}; + /** @todo this allocates a new string, revisit once String is capable of + trimming in-place, e.g. `std::move(message).trimmed()` would just + shift the data around */ + return {success, message.trimmed()}; } AbstractShaderProgram& AbstractShaderProgram::draw(Mesh& mesh) { @@ -547,48 +546,62 @@ void AbstractShaderProgram::attachShaders(const Containers::Iterable& sh for(Shader& s: shaders) attachShader(s); } -void AbstractShaderProgram::bindAttributeLocationInternal(const UnsignedInt location, const Containers::ArrayView name) { - glBindAttribLocation(_id, location, name); +void AbstractShaderProgram::bindAttributeLocation(const UnsignedInt location, const Containers::StringView name) { + glBindAttribLocation(_id, location, Containers::String::nullTerminatedView(name).data()); } #ifndef MAGNUM_TARGET_GLES -void AbstractShaderProgram::bindFragmentDataLocationInternal(const UnsignedInt location, const Containers::ArrayView name) { - glBindFragDataLocation(_id, location, name); +void AbstractShaderProgram::bindFragmentDataLocation(const UnsignedInt location, const Containers::StringView name) { + glBindFragDataLocation(_id, location, Containers::String::nullTerminatedView(name).data()); } -void AbstractShaderProgram::bindFragmentDataLocationIndexedInternal(const UnsignedInt location, UnsignedInt index, const Containers::ArrayView name) { - glBindFragDataLocationIndexed(_id, location, index, name); +void AbstractShaderProgram::bindFragmentDataLocationIndexed(const UnsignedInt location, UnsignedInt index, const Containers::StringView name) { + glBindFragDataLocationIndexed(_id, location, index, Containers::String::nullTerminatedView(name).data()); } #endif #ifndef MAGNUM_TARGET_GLES2 -void AbstractShaderProgram::setTransformFeedbackOutputs(const Containers::ArrayView outputs, const TransformFeedbackBufferMode bufferMode) { +void AbstractShaderProgram::setTransformFeedbackOutputs(const Containers::StringIterable& outputs, const TransformFeedbackBufferMode bufferMode) { (this->*Context::current().state().shaderProgram.transformFeedbackVaryingsImplementation)(outputs, bufferMode); } -void AbstractShaderProgram::setTransformFeedbackOutputs(const std::initializer_list outputs, const TransformFeedbackBufferMode bufferMode) { - setTransformFeedbackOutputs(Containers::arrayView(outputs), bufferMode); -} - -void AbstractShaderProgram::transformFeedbackVaryingsImplementationDefault(const Containers::ArrayView outputs, const TransformFeedbackBufferMode bufferMode) { - /** @todo VLAs */ - Containers::Array names{outputs.size()}; - - Int i = 0; - for(const std::string& output: outputs) names[i++] = output.data(); +void AbstractShaderProgram::transformFeedbackVaryingsImplementationDefault(const Containers::StringIterable& outputs, const TransformFeedbackBufferMode bufferMode) { + Containers::ArrayView nameData; + Containers::ArrayView names; + Containers::ArrayTuple data{ + {NoInit, outputs.size(), nameData}, + {NoInit, outputs.size(), names} + }; + for(std::size_t i = 0; i != outputs.size(); ++i) { + new(&nameData[i]) Containers::String{Containers::String::nullTerminatedView(outputs[i])}; + names[i] = nameData[i].data(); + } glTransformFeedbackVaryings(_id, outputs.size(), names, GLenum(bufferMode)); } #ifdef CORRADE_TARGET_WINDOWS -void AbstractShaderProgram::transformFeedbackVaryingsImplementationDanglingWorkaround(const Containers::ArrayView outputs, const TransformFeedbackBufferMode bufferMode) { +void AbstractShaderProgram::transformFeedbackVaryingsImplementationDanglingWorkaround(const Containers::StringIterable& outputs, const TransformFeedbackBufferMode bufferMode) { /* NVidia on Windows doesn't copy the names when calling - glTransformFeedbackVaryings() so it then fails at link time because the - char* are dangling. We have to do the copy on the engine side and keep - the values until link time (which can happen any time and multiple - times, so basically for the remaining lifetime of the shader program) */ - _transformFeedbackVaryingNames.assign(outputs.begin(), outputs.end()); + glTransformFeedbackVaryings() so it then might fail at link time because + the char* get dangling. We have to do the copy on the engine side and + keep the values until link time (which can happen any time and multiple + times, so basically for the remaining lifetime of the shader program). + + Compared to the above case we thus do a copy also if the view is not + global in addition to not null-terminated, and we keep the string memory + in a member variable. */ + Containers::ArrayView nameData; + Containers::ArrayView names; + _transformFeedbackVaryingNames = Containers::ArrayTuple{ + {NoInit, outputs.size(), nameData}, + {NoInit, outputs.size(), names} + }; + for(std::size_t i = 0; i != outputs.size(); ++i) { + new(&nameData[i]) Containers::String{Containers::String::nullTerminatedGlobalView(outputs[i])}; + names[i] = nameData[i].data(); + } - transformFeedbackVaryingsImplementationDefault({_transformFeedbackVaryingNames.data(), _transformFeedbackVaryingNames.size()}, bufferMode); + glTransformFeedbackVaryings(_id, outputs.size(), names, GLenum(bufferMode)); } #endif #endif @@ -613,12 +626,12 @@ bool AbstractShaderProgram::checkLink(const Containers::Iterable& shader glGetProgramiv(_id, GL_LINK_STATUS, &success); glGetProgramiv(_id, GL_INFO_LOG_LENGTH, &logLength); - /* Error or warning message. The string is returned null-terminated, - strip the \0 at the end afterwards. */ - std::string message(logLength, '\n'); - if(message.size() > 1) - glGetProgramInfoLog(_id, message.size(), nullptr, &message[0]); - message.resize(Math::max(logLength, 1)-1); + /* Error or warning message. The length is reported including the null + terminator and the string implicitly has a storage for that, thus + specify one byte less. */ + Containers::String message{NoInit, std::size_t(Math::max(logLength, 1)) - 1}; + if(logLength > 1) + glGetProgramInfoLog(_id, logLength, nullptr, message.data()); /* Some drivers are chatty and can't keep shut when there's nothing to be said, handle that as well. */ @@ -662,16 +675,16 @@ bool AbstractShaderProgram::isLinkFinished() { return success == GL_TRUE; } -void AbstractShaderProgram::cleanLogImplementationNoOp(std::string&) {} +void AbstractShaderProgram::cleanLogImplementationNoOp(Containers::String&) {} #if defined(CORRADE_TARGET_WINDOWS) && !defined(MAGNUM_TARGET_GLES) -void AbstractShaderProgram::cleanLogImplementationIntelWindows(std::string& message) { +void AbstractShaderProgram::cleanLogImplementationIntelWindows(Containers::String& message) { if(message == "No errors.\n") message = {}; } #endif #if defined(MAGNUM_TARGET_GLES) && !defined(MAGNUM_TARGET_WEBGL) -void AbstractShaderProgram::cleanLogImplementationAngle(std::string& message) { +void AbstractShaderProgram::cleanLogImplementationAngle(Containers::String& message) { if(message == "\n") message = {}; } #endif @@ -680,18 +693,18 @@ void AbstractShaderProgram::completionStatusImplementationFallback(GLuint, GLenu *value = GL_TRUE; } -Int AbstractShaderProgram::uniformLocationInternal(const Containers::ArrayView name) { - const GLint location = glGetUniformLocation(_id, name); +Int AbstractShaderProgram::uniformLocation(const Containers::StringView name) { + const GLint location = glGetUniformLocation(_id, Containers::String::nullTerminatedView(name).data()); if(location == -1) - Warning{} << "GL::AbstractShaderProgram: location of uniform \'" << Debug::nospace << std::string{name, name.size()} << Debug::nospace << "\' cannot be retrieved"; + Warning{} << "GL::AbstractShaderProgram: location of uniform \'" << Debug::nospace << name << Debug::nospace << "\' cannot be retrieved"; return location; } #ifndef MAGNUM_TARGET_GLES2 -UnsignedInt AbstractShaderProgram::uniformBlockIndexInternal(const Containers::ArrayView name) { - const GLuint index = glGetUniformBlockIndex(_id, name); +UnsignedInt AbstractShaderProgram::uniformBlockIndex(const Containers::StringView name) { + const GLuint index = glGetUniformBlockIndex(_id, Containers::String::nullTerminatedView(name).data()); if(index == GL_INVALID_INDEX) - Warning{} << "GL::AbstractShaderProgram: index of uniform block \'" << Debug::nospace << std::string{name, name.size()} << Debug::nospace << "\' cannot be retrieved"; + Warning{} << "GL::AbstractShaderProgram: index of uniform block \'" << Debug::nospace << name << Debug::nospace << "\' cannot be retrieved"; return index; } #endif diff --git a/src/Magnum/GL/AbstractShaderProgram.h b/src/Magnum/GL/AbstractShaderProgram.h index b800a1cca..639eac9e8 100644 --- a/src/Magnum/GL/AbstractShaderProgram.h +++ b/src/Magnum/GL/AbstractShaderProgram.h @@ -31,15 +31,12 @@ * @brief Class @ref Magnum::GL::AbstractShaderProgram, macro @ref MAGNUM_GL_ABSTRACTSHADERPROGRAM_SUBCLASS_DRAW_IMPLEMENTATION(), @ref MAGNUM_GL_ABSTRACTSHADERPROGRAM_SUBCLASS_DISPATCH_IMPLEMENTATION() */ -#include -#include - #include "Magnum/Tags.h" #include "Magnum/GL/AbstractObject.h" #include "Magnum/GL/GL.h" #if defined(CORRADE_TARGET_WINDOWS) && !defined(MAGNUM_TARGET_GLES2) -#include +#include #endif #ifdef MAGNUM_BUILD_DEPRECATED @@ -47,8 +44,14 @@ /* For attachShaders(), which used to take a std::initializer_list, and draw({MeshView}) as well */ #include -/* For label() / setLabel(), which used to be a std::string */ +/* For label() / setLabel() and all uniform/attribute/... name stuff that used + to be a std::string. Since that's all only function parameters and no return + types, it should cover all cases. */ #include +/* For setTransformFeedbackOutputs(), which used to take + std::initializer_list. Usually people passed C string literals, + so it should convert directly to a StringIterable. */ +#include #endif namespace Magnum { namespace GL { @@ -831,7 +834,7 @@ class MAGNUM_GL_EXPORT AbstractShaderProgram: public AbstractObject { * @def_gl{VALIDATE_STATUS}, @def_gl{INFO_LOG_LENGTH}, * @fn_gl_keyword{GetProgramInfoLog} */ - std::pair validate(); + std::pair validate(); /** * @brief Draw a mesh @@ -1432,14 +1435,7 @@ class MAGNUM_GL_EXPORT AbstractShaderProgram: public AbstractObject { * @ref GL-AbstractShaderProgram-attribute-location "class documentation" * for more information. */ - void bindAttributeLocation(UnsignedInt location, const std::string& name) { - bindAttributeLocationInternal(location, {name.data(), name.size()}); - } - - /** @overload */ - template void bindAttributeLocation(UnsignedInt location, const char(&name)[size]) { - bindAttributeLocationInternal(location, {name, size - 1}); - } + void bindAttributeLocation(UnsignedInt location, Containers::StringView name); #ifndef MAGNUM_TARGET_GLES /** @@ -1461,14 +1457,7 @@ class MAGNUM_GL_EXPORT AbstractShaderProgram: public AbstractObject { * @requires_gl Multiple blend function inputs are not available in * OpenGL ES or WebGL. */ - void bindFragmentDataLocationIndexed(UnsignedInt location, UnsignedInt index, const std::string& name) { - bindFragmentDataLocationIndexedInternal(location, index, {name.data(), name.size()}); - } - - /** @overload */ - template void bindFragmentDataLocationIndexed(UnsignedInt location, UnsignedInt index, const char(&name)[size]) { - bindFragmentDataLocationIndexedInternal(location, index, {name, size - 1}); - } + void bindFragmentDataLocationIndexed(UnsignedInt location, UnsignedInt index, Containers::StringView name); /** * @brief Bind fragment data to given location and first color input index @@ -1488,15 +1477,7 @@ class MAGNUM_GL_EXPORT AbstractShaderProgram: public AbstractObject { * in OpenGL ES 2.0 and @webgl_extension{WEBGL,draw_buffers} in * WebGL 1.0. */ - void bindFragmentDataLocation(UnsignedInt location, const std::string& name) { - bindFragmentDataLocationInternal(location, {name.data(), name.size()}); - } - - /** @overload */ - template void bindFragmentDataLocation(UnsignedInt location, const char(&name)[size]) { - /* Not using const char* parameter, because this way it avoids most accidents with non-zero-terminated strings */ - bindFragmentDataLocationInternal(location, {name, size - 1}); - } + void bindFragmentDataLocation(UnsignedInt location, Containers::StringView name); #endif #ifndef MAGNUM_TARGET_GLES2 @@ -1531,8 +1512,7 @@ class MAGNUM_GL_EXPORT AbstractShaderProgram: public AbstractObject { * @requires_gl Special output names `gl_NextBuffer` and * `gl_SkipComponents#` are not available in OpenGL ES or WebGL. */ - void setTransformFeedbackOutputs(Containers::ArrayView outputs, TransformFeedbackBufferMode bufferMode); - void setTransformFeedbackOutputs(std::initializer_list outputs, TransformFeedbackBufferMode bufferMode); /**< @overload */ + void setTransformFeedbackOutputs(const Containers::StringIterable& outputs, TransformFeedbackBufferMode bufferMode); #endif /** @@ -1600,14 +1580,7 @@ class MAGNUM_GL_EXPORT AbstractShaderProgram: public AbstractObject { * @ref GL-AbstractShaderProgram-uniform-location "class documentation" * for more information. */ - Int uniformLocation(const std::string& name) { - return uniformLocationInternal({name.data(), name.size()}); - } - - /** @overload */ - template Int uniformLocation(const char(&name)[size]) { - return uniformLocationInternal({name, size - 1}); - } + Int uniformLocation(Containers::StringView name); #ifndef MAGNUM_TARGET_GLES2 /** @@ -1626,14 +1599,7 @@ class MAGNUM_GL_EXPORT AbstractShaderProgram: public AbstractObject { * @ref GL-AbstractShaderProgram-uniform-block-binding "class documentation" * for more information. */ - UnsignedInt uniformBlockIndex(const std::string& name) { - return uniformBlockIndexInternal({name.data(), name.size()}); - } - - /** @overload */ - template UnsignedInt uniformBlockIndex(const char(&name)[size]) { - return uniformBlockIndexInternal({name, size - 1}); - } + UnsignedInt uniformBlockIndex(Containers::StringView name); #endif /** @@ -1910,27 +1876,21 @@ class MAGNUM_GL_EXPORT AbstractShaderProgram: public AbstractObject { #endif private: - void bindAttributeLocationInternal(UnsignedInt location, Containers::ArrayView name); - #ifndef MAGNUM_TARGET_GLES - void bindFragmentDataLocationIndexedInternal(UnsignedInt location, UnsignedInt index, Containers::ArrayView name); - void bindFragmentDataLocationInternal(UnsignedInt location, Containers::ArrayView name); - #endif - Int uniformLocationInternal(Containers::ArrayView name); - UnsignedInt uniformBlockIndexInternal(Containers::ArrayView name); - #ifndef MAGNUM_TARGET_GLES2 - void MAGNUM_GL_LOCAL transformFeedbackVaryingsImplementationDefault(Containers::ArrayView outputs, TransformFeedbackBufferMode bufferMode); + void MAGNUM_GL_LOCAL transformFeedbackVaryingsImplementationDefault(const Containers::StringIterable& outputs, TransformFeedbackBufferMode bufferMode); #ifdef CORRADE_TARGET_WINDOWS - void MAGNUM_GL_LOCAL transformFeedbackVaryingsImplementationDanglingWorkaround(Containers::ArrayView outputs, TransformFeedbackBufferMode bufferMode); + /* See the "nv-windows-dangling-transform-feedback-varying-names" + workaround */ + void MAGNUM_GL_LOCAL transformFeedbackVaryingsImplementationDanglingWorkaround(const Containers::StringIterable& outputs, TransformFeedbackBufferMode bufferMode); #endif #endif - static MAGNUM_GL_LOCAL void cleanLogImplementationNoOp(std::string& message); + static MAGNUM_GL_LOCAL void cleanLogImplementationNoOp(Containers::String& message); #if defined(CORRADE_TARGET_WINDOWS) && !defined(MAGNUM_TARGET_GLES) - static MAGNUM_GL_LOCAL void cleanLogImplementationIntelWindows(std::string& message); + static MAGNUM_GL_LOCAL void cleanLogImplementationIntelWindows(Containers::String& message); #endif #if defined(MAGNUM_TARGET_GLES) && !defined(MAGNUM_TARGET_WEBGL) - static MAGNUM_GL_LOCAL void cleanLogImplementationAngle(std::string& message); + static MAGNUM_GL_LOCAL void cleanLogImplementationAngle(Containers::String& message); #endif MAGNUM_GL_LOCAL static void APIENTRY completionStatusImplementationFallback(GLuint, GLenum, GLint*); @@ -2008,7 +1968,7 @@ class MAGNUM_GL_EXPORT AbstractShaderProgram: public AbstractObject { #if defined(CORRADE_TARGET_WINDOWS) && !defined(MAGNUM_TARGET_GLES2) /* Needed for the nv-windows-dangling-transform-feedback-varying-names workaround */ - std::vector _transformFeedbackVaryingNames; + Containers::ArrayTuple _transformFeedbackVaryingNames; #endif }; diff --git a/src/Magnum/GL/Implementation/ShaderProgramState.h b/src/Magnum/GL/Implementation/ShaderProgramState.h index f5473374a..613d2af6b 100644 --- a/src/Magnum/GL/Implementation/ShaderProgramState.h +++ b/src/Magnum/GL/Implementation/ShaderProgramState.h @@ -27,8 +27,6 @@ DEALINGS IN THE SOFTWARE. */ -#include - #include "Magnum/Magnum.h" #include "Magnum/GL/GL.h" #include "Magnum/GL/OpenGL.h" @@ -46,9 +44,9 @@ struct ShaderProgramState { void reset(); #ifndef MAGNUM_TARGET_GLES2 - void(AbstractShaderProgram::*transformFeedbackVaryingsImplementation)(Containers::ArrayView, AbstractShaderProgram::TransformFeedbackBufferMode); + void(AbstractShaderProgram::*transformFeedbackVaryingsImplementation)(const Containers::StringIterable&, AbstractShaderProgram::TransformFeedbackBufferMode); #endif - void(*cleanLogImplementation)(std::string&); + void(*cleanLogImplementation)(Containers::String&); /* This is a direct pointer to a GL function, so needs a __stdcall on Windows to compile properly on 32 bits */ void(APIENTRY *completionStatusImplementation)(GLuint, GLenum, GLint* value); diff --git a/src/Magnum/GL/Implementation/ShaderState.h b/src/Magnum/GL/Implementation/ShaderState.h index f4ad5e502..df0a72a58 100644 --- a/src/Magnum/GL/Implementation/ShaderState.h +++ b/src/Magnum/GL/Implementation/ShaderState.h @@ -26,8 +26,6 @@ DEALINGS IN THE SOFTWARE. */ -#include - #include "Magnum/Magnum.h" #include "Magnum/GL/GL.h" #include "Magnum/GL/OpenGL.h" @@ -52,8 +50,8 @@ struct ShaderState { #endif }; - void(Shader::*addSourceImplementation)(std::string); - void(*cleanLogImplementation)(std::string&); + void(Shader::*addSourceImplementation)(Containers::String&&); + void(*cleanLogImplementation)(Containers::String&); /* This is a direct pointer to a GL function, so needs a __stdcall on Windows to compile properly on 32 bits */ void(APIENTRY *completionStatusImplementation)(GLuint, GLenum, GLint* value); diff --git a/src/Magnum/GL/Shader.cpp b/src/Magnum/GL/Shader.cpp index eeb435856..63c28da34 100644 --- a/src/Magnum/GL/Shader.cpp +++ b/src/Magnum/GL/Shader.cpp @@ -27,16 +27,15 @@ #include "Shader.h" #include +#include #ifdef MAGNUM_BUILD_DEPRECATED #include #endif -#ifndef MAGNUM_TARGET_WEBGL #include -#endif -#include /** @todo remove once Shader is -free */ +#include #include #include -#include +#include #include #include "Magnum/GL/Context.h" @@ -55,18 +54,20 @@ typedef char GLchar; namespace Magnum { namespace GL { +using namespace Containers::Literals; + namespace { -std::string shaderName(const Shader::Type type) { +Containers::StringView shaderName(const Shader::Type type) { switch(type) { - case Shader::Type::Vertex: return "vertex"; + case Shader::Type::Vertex: return "vertex"_s; #if !defined(MAGNUM_TARGET_GLES2) && !defined(MAGNUM_TARGET_WEBGL) - case Shader::Type::Geometry: return "geometry"; - case Shader::Type::TessellationControl: return "tessellation control"; - case Shader::Type::TessellationEvaluation: return "tessellation evaluation"; - case Shader::Type::Compute: return "compute"; + case Shader::Type::Geometry: return "geometry"_s; + case Shader::Type::TessellationControl: return "tessellation control"_s; + case Shader::Type::TessellationEvaluation: return "tessellation evaluation"_s; + case Shader::Type::Compute: return "compute"_s; #endif - case Shader::Type::Fragment: return "fragment"; + case Shader::Type::Fragment: return "fragment"_s; } CORRADE_INTERNAL_ASSERT_UNREACHABLE(); /* LCOV_EXCL_LINE */ @@ -659,34 +660,37 @@ Shader::Shader(const Version version, const Type type): _type{type}, _flags{Obje _offsetLineByOneOnOldGlsl = false; #endif + Containers::StringView versionString; switch(version) { #ifndef MAGNUM_TARGET_GLES - case Version::GL210: _sources.emplace_back("#version 120\n"); return; - case Version::GL300: _sources.emplace_back("#version 130\n"); return; - case Version::GL310: _sources.emplace_back("#version 140\n"); return; - case Version::GL320: _sources.emplace_back("#version 150\n"); return; - case Version::GL330: _sources.emplace_back("#version 330\n"); return; - case Version::GL400: _sources.emplace_back("#version 400\n"); return; - case Version::GL410: _sources.emplace_back("#version 410\n"); return; - case Version::GL420: _sources.emplace_back("#version 420\n"); return; - case Version::GL430: _sources.emplace_back("#version 430\n"); return; - case Version::GL440: _sources.emplace_back("#version 440\n"); return; - case Version::GL450: _sources.emplace_back("#version 450\n"); return; - case Version::GL460: _sources.emplace_back("#version 460\n"); return; + case Version::GL210: versionString = "#version 120\n"_s; break; + case Version::GL300: versionString = "#version 130\n"_s; break; + case Version::GL310: versionString = "#version 140\n"_s; break; + case Version::GL320: versionString = "#version 150\n"_s; break; + case Version::GL330: versionString = "#version 330\n"_s; break; + case Version::GL400: versionString = "#version 400\n"_s; break; + case Version::GL410: versionString = "#version 410\n"_s; break; + case Version::GL420: versionString = "#version 420\n"_s; break; + case Version::GL430: versionString = "#version 430\n"_s; break; + case Version::GL440: versionString = "#version 440\n"_s; break; + case Version::GL450: versionString = "#version 450\n"_s; break; + case Version::GL460: versionString = "#version 460\n"_s; break; #endif /* `#version 100` really is GLSL ES 1.00 and *not* GLSL 1.00. What a mess. */ - case Version::GLES200: _sources.emplace_back("#version 100\n"); return; - case Version::GLES300: _sources.emplace_back("#version 300 es\n"); return; + case Version::GLES200: versionString = "#version 100\n"_s; break; + case Version::GLES300: versionString = "#version 300 es\n"_s; break; #ifndef MAGNUM_TARGET_WEBGL - case Version::GLES310: _sources.emplace_back("#version 310 es\n"); return; - case Version::GLES320: _sources.emplace_back("#version 320 es\n"); return; + case Version::GLES310: versionString = "#version 310 es\n"_s; break; + case Version::GLES320: versionString = "#version 320 es\n"_s; break; #endif /* The user is responsible for (not) adding #version directive */ case Version::None: return; } - CORRADE_ASSERT_UNREACHABLE("GL::Shader::Shader(): unsupported version" << version, ); + CORRADE_ASSERT(!versionString.isEmpty(), "GL::Shader::Shader(): unsupported version" << version, ); + + arrayAppend(_sources, Containers::String::nullTerminatedGlobalView(versionString)); } Shader::Shader(const Type type, const GLuint id, ObjectFlags flags) noexcept: _type{type}, _id{id}, _flags{flags} @@ -695,6 +699,17 @@ Shader::Shader(const Type type, const GLuint id, ObjectFlags flags) noexcept: _t #endif {} +Shader::Shader(NoCreateT) noexcept: _type{}, _id{0} {} + +Shader::Shader(Shader&& other) noexcept: _type{other._type}, _id{other._id}, _flags{other._flags}, + #ifndef MAGNUM_TARGET_GLES + _offsetLineByOneOnOldGlsl{other._flags}, + #endif + _sources{std::move(other._sources)} +{ + other._id = 0; +} + Shader::~Shader() { /* Moved out or not deleting on destruction, nothing to do */ if(!_id || !(_flags & ObjectFlag::DeleteOnDestruction)) return; @@ -702,6 +717,18 @@ Shader::~Shader() { glDeleteShader(_id); } +Shader& Shader::operator=(Shader&& other) noexcept { + using std::swap; + swap(_type, other._type); + swap(_id, other._id); + swap(_flags, other._flags); + #ifndef MAGNUM_TARGET_GLES + swap(_offsetLineByOneOnOldGlsl, other._offsetLineByOneOnOldGlsl); + #endif + swap(_sources, other._sources); + return *this; +} + #ifndef MAGNUM_TARGET_WEBGL Containers::String Shader::label() const { #ifndef MAGNUM_TARGET_GLES2 @@ -721,12 +748,14 @@ Shader& Shader::setLabel(const Containers::StringView label) { } #endif -std::vector Shader::sources() const { return _sources; } +Containers::StringIterable Shader::sources() const { return _sources; } -Shader& Shader::addSource(std::string source) { - if(!source.empty()) { - auto addSource = Context::current().state().shader.addSourceImplementation; +Shader& Shader::addSource(const Containers::StringView source) { + return addSourceInternal(Containers::String::nullTerminatedGlobalView(source)); +} +Shader& Shader::addSourceInternal(Containers::String&& source) { + if(!source.isEmpty()) { /* Fix line numbers, so line 41 of third added file is marked as 3(41) in case shader version was not Version::None, because then source 0 is the #version directive added in constructor. @@ -738,42 +767,46 @@ Shader& Shader::addSource(std::string source) { order to avoid complex logic in compile() where we assert for at least some user-provided source, an empty string is added here instead. */ - if(!_sources.empty()) (this->*addSource)( - /* GLSL < 330 interprets #line 0 as the next line being line 1, - while GLSL >= 330 which interprets #line 1 as next line being - line 1; the latter is consistent with the C preprocessor. GLSL ES - behaves like GLSL >= 330 always. */ - ( + if(!_sources.isEmpty()) arrayAppend(_sources, + /* GLSL < 330 interprets #line 0 as the next line being line 1, + while GLSL >= 330 which interprets #line 1 as next line being + line 1; the latter is consistent with the C preprocessor. GLSL + ES behaves like GLSL >= 330 always. */ + Utility::format( #ifndef MAGNUM_TARGET_GLES - _offsetLineByOneOnOldGlsl ? "#line 0 " : + _offsetLineByOneOnOldGlsl ? "#line 0 {}\n" : #endif - "#line 1 " - ) + std::to_string((_sources.size()+1)/2) + '\n'); - else (this->*addSource)({}); + "#line 1 {}\n", + (_sources.size() + 1)/2)); + else arrayAppend(_sources, Containers::String::nullTerminatedGlobalView(""_s)); - (this->*addSource)(std::move(source)); + (this->*Context::current().state().shader.addSourceImplementation)(std::move(source)); } return *this; } -void Shader::addSourceImplementationDefault(std::string source) { - _sources.push_back(std::move(source)); +void Shader::addSourceImplementationDefault(Containers::String&& source) { + arrayAppend(_sources, std::move(source)); } #if defined(CORRADE_TARGET_EMSCRIPTEN) && defined(__EMSCRIPTEN_PTHREADS__) -void Shader::addSourceImplementationEmscriptenPthread(std::string source) { - /* See the "emscripten-pthreads-broken-unicode-shader-sources" - workaround description for details */ +void Shader::addSourceImplementationEmscriptenPthread(Containers::String&& source) { + /* Modify the string to remove non-ASCII characters. Ensure we're only + modifying a string we actually own, if not make a copy first. See the + "emscripten-pthreads-broken-unicode-shader-sources" workaround + description for details. */ + if(!source.isSmall() && !source.deleter()) + source = Containers::String{source}; for(char& c: source) if(c < 0) c = ' '; - _sources.push_back(std::move(source)); + arrayAppend(_sources, std::move(source)); } #endif -Shader& Shader::addFile(const std::string& filename) { - const Containers::Optional string = Utility::Path::readString(filename); +Shader& Shader::addFile(const Containers::StringView filename) { + Containers::Optional string = Utility::Path::readString(filename); CORRADE_ASSERT(string, "GL::Shader::addFile(): can't read" << filename, *this); - addSource(*string); + addSource(*std::move(string)); return *this; } @@ -804,12 +837,12 @@ bool Shader::checkCompile() { glGetShaderiv(_id, GL_COMPILE_STATUS, &success); glGetShaderiv(_id, GL_INFO_LOG_LENGTH, &logLength); - /* Error or warning message. The string is returned null-terminated, - strip the \0 at the end afterwards. */ - std::string message(logLength, '\0'); - if(message.size() > 1) - glGetShaderInfoLog(_id, message.size(), nullptr, &message[0]); - message.resize(Math::max(logLength, 1)-1); + /* Error or warning message. The length is reported including the null + terminator and the string implicitly has a storage for that, thus + specify one byte less. */ + Containers::String message{NoInit, std::size_t(Math::max(logLength, 1)) - 1}; + if(logLength > 1) + glGetShaderInfoLog(_id, logLength, nullptr, message.data()); /* Some drivers are chatty and can't keep shut when there's nothing to be said, handle that as well. */ @@ -856,10 +889,10 @@ bool Shader::isCompileFinished() { return success == GL_TRUE; } -void Shader::cleanLogImplementationNoOp(std::string&) {} +void Shader::cleanLogImplementationNoOp(Containers::String&) {} #if defined(CORRADE_TARGET_WINDOWS) && !defined(MAGNUM_TARGET_GLES) -void Shader::cleanLogImplementationIntelWindows(std::string& message) { +void Shader::cleanLogImplementationIntelWindows(Containers::String& message) { if(message == "No errors.\n") message = {}; } #endif diff --git a/src/Magnum/GL/Shader.h b/src/Magnum/GL/Shader.h index db2e4f699..ec2bb154b 100644 --- a/src/Magnum/GL/Shader.h +++ b/src/Magnum/GL/Shader.h @@ -30,9 +30,7 @@ * @brief Class @ref Magnum::GL::Shader */ -#include -#include -#include +#include #include "Magnum/Tags.h" #include "Magnum/GL/AbstractObject.h" @@ -40,8 +38,8 @@ #ifdef MAGNUM_BUILD_DEPRECATED #include -/* For label() / setLabel(), which used to be a std::string. Not ideal for the - return type, but at least something. */ +/* For label() / setLabel() and all name/source stuff, which used to be a + std::string. Not ideal for the return types, but at least something. */ #include #endif @@ -570,14 +568,13 @@ class MAGNUM_GL_EXPORT Shader: public AbstractObject { * API, see the documentation of @ref NoCreate for alternatives. * @see @ref Shader() */ - explicit Shader(NoCreateT) noexcept: _type{}, _id{0} {} + explicit Shader(NoCreateT) noexcept; /** @brief Copying is not allowed */ Shader(const Shader&) = delete; /** @brief Move constructor */ - /* MinGW complains loudly if the declaration doesn't also have inline */ - inline Shader(Shader&& other) noexcept; + Shader(Shader&& other) noexcept; /** * @brief Destructor @@ -591,8 +588,7 @@ class MAGNUM_GL_EXPORT Shader: public AbstractObject { Shader& operator=(const Shader&) = delete; /** @brief Move assignment */ - /* MinGW complains loudly if the declaration doesn't also have inline */ - inline Shader& operator=(Shader&& other) noexcept; + Shader& operator=(Shader&& other) noexcept; /** @brief OpenGL shader ID */ GLuint id() const { return _id; } @@ -645,20 +641,46 @@ class MAGNUM_GL_EXPORT Shader: public AbstractObject { /** @brief Shader type */ Type type() const { return _type; } - /** @brief Shader sources */ - std::vector sources() const; + /** + * @brief Shader sources + * + * The returned views are all + * @relativeref{Corrade,Containers::StringViewFlag::NullTerminated}, + * @relativeref{Corrade,Containers::StringViewFlag::Global} is set for + * the initial @glsl #version @ce directive and for global + * null-terminated views that were passed to @ref addSource(). + */ + Containers::StringIterable sources() const; /** * @brief Add shader source * @param source String with shader source * @return Reference to self (for method chaining) * - * Adds given source to source list, preceded with a - * @glsl #line n 1 @ce directive for improved - * @ref GL-Shader-errors "compilation error reporting". + * If the string is not empty, adds it to the shader source list, + * preceded with a @glsl #line n 1 @ce directive for improved + * @ref GL-Shader-errors "compilation error reporting". If it's empty, + * the function is a no-op. + * + * If the view is both @relativeref{Corrade,Containers::StringViewFlag::NullTerminated} + * and @relativeref{Corrade,Containers::StringViewFlag::Global}, it's + * directly referenced, otherwise a copy is made internally. For + * dynamic strings prefer to use the @ref addSource(Containers::String&&) + * overload to avoid copies. * @see @ref addFile() */ - Shader& addSource(std::string source); + Shader& addSource(Containers::StringView source); + /** @overload */ + #ifdef DOXYGEN_GENERATING_OUTPUT + Shader& addSource(Containers::String&& source); + #else + /* Otherwise passing a char* is ambiguous between this and the + StringView overload. Sigh, C++. */ + template::value>::type> + Shader& addSource(U&& source) { + return addSourceInternal(std::move(source)); + } + #endif /** * @brief Add shader source file @@ -668,7 +690,7 @@ class MAGNUM_GL_EXPORT Shader: public AbstractObject { * The file must exist and must be readable. Calls @ref addSource() * with the contents. */ - Shader& addFile(const std::string& filename); + Shader& addFile(const Containers::StringView filename); /** * @brief Compile the shader @@ -745,14 +767,17 @@ class MAGNUM_GL_EXPORT Shader: public AbstractObject { private: explicit Shader(Type type, GLuint id, ObjectFlags flags) noexcept; - void MAGNUM_GL_LOCAL addSourceImplementationDefault(std::string source); + /* Used by addSource(Containers::String&&) */ + Shader& addSourceInternal(Containers::String&& source); + + void MAGNUM_GL_LOCAL addSourceImplementationDefault(Containers::String&& source); #if defined(CORRADE_TARGET_EMSCRIPTEN) && defined(__EMSCRIPTEN_PTHREADS__) - void MAGNUM_GL_LOCAL addSourceImplementationEmscriptenPthread(std::string source); + void MAGNUM_GL_LOCAL addSourceImplementationEmscriptenPthread(Containers::String&& source); #endif - static MAGNUM_GL_LOCAL void cleanLogImplementationNoOp(std::string& message); + static MAGNUM_GL_LOCAL void cleanLogImplementationNoOp(Containers::String& message); #if defined(CORRADE_TARGET_WINDOWS) && !defined(MAGNUM_TARGET_GLES) - static MAGNUM_GL_LOCAL void cleanLogImplementationIntelWindows(std::string& message); + static MAGNUM_GL_LOCAL void cleanLogImplementationIntelWindows(Containers::String& message); #endif MAGNUM_GL_LOCAL static void APIENTRY completionStatusImplementationFallback(GLuint, GLenum, GLint*); @@ -765,33 +790,12 @@ class MAGNUM_GL_EXPORT Shader: public AbstractObject { bool _offsetLineByOneOnOldGlsl; #endif - std::vector _sources; + Containers::Array _sources; }; /** @debugoperatorclassenum{Shader,Shader::Type} */ MAGNUM_GL_EXPORT Debug& operator<<(Debug& debug, Shader::Type value); -inline Shader::Shader(Shader&& other) noexcept: _type{other._type}, _id{other._id}, _flags{other._flags}, - #ifndef MAGNUM_TARGET_GLES - _offsetLineByOneOnOldGlsl{other._flags}, - #endif - _sources{std::move(other._sources)} -{ - other._id = 0; -} - -inline Shader& Shader::operator=(Shader&& other) noexcept { - using std::swap; - swap(_type, other._type); - swap(_id, other._id); - swap(_flags, other._flags); - #ifndef MAGNUM_TARGET_GLES - swap(_offsetLineByOneOnOldGlsl, other._offsetLineByOneOnOldGlsl); - #endif - swap(_sources, other._sources); - return *this; -} - inline GLuint Shader::release() { const GLuint id = _id; _id = 0; diff --git a/src/Magnum/GL/Test/AbstractShaderProgramGLTest.cpp b/src/Magnum/GL/Test/AbstractShaderProgramGLTest.cpp index 9167a266b..85f8e79e5 100644 --- a/src/Magnum/GL/Test/AbstractShaderProgramGLTest.cpp +++ b/src/Magnum/GL/Test/AbstractShaderProgramGLTest.cpp @@ -28,7 +28,7 @@ #include #include #include -#include /** @todo remove once Debug is stream-free */ +#include /* StringHasPrefix / StringHasSuffix */ #include #include #include @@ -116,6 +116,52 @@ struct AbstractShaderProgramGLTest: OpenGLTester { #endif }; +using namespace Containers::Literals; + +const struct { + const char* name; + Containers::StringView positionName, matrixName, multiplierName, colorName, additionsName; +} CreateData[]{ + {"", + "position", + "matrix", + "multiplier", + "color", + "additions"}, + {"non-null-terminated strings", + "position!"_s.exceptSuffix(1), + "matrix!"_s.exceptSuffix(1), + "multiplier!"_s.exceptSuffix(1), + "color!"_s.exceptSuffix(1), + "additions!"_s.exceptSuffix(1)}, +}; + +const struct { + const char* name; + Containers::StringView firstName, secondName; +} CreateMultipleOutputsData[]{ + {"", + "first", + "second"}, + {"non-null-terminated strings", + "first!"_s.exceptSuffix(1), + "second!"_s.exceptSuffix(1)} +}; + +#ifndef MAGNUM_TARGET_GLES2 +const struct { + const char* name; + Containers::StringView matricesName, materialName; +} CreateUniformBlocksData[]{ + {"", + "matrices", + "material"}, + {"non-null-terminated strings", + "matrices!"_s.exceptSuffix(1), + "material!"_s.exceptSuffix(1)} +}; +#endif + AbstractShaderProgramGLTest::AbstractShaderProgramGLTest() { addTests({&AbstractShaderProgramGLTest::construct, &AbstractShaderProgramGLTest::constructMove, @@ -123,15 +169,21 @@ AbstractShaderProgramGLTest::AbstractShaderProgramGLTest() { #ifndef MAGNUM_TARGET_WEBGL &AbstractShaderProgramGLTest::label, #endif + }); - &AbstractShaderProgramGLTest::create, - &AbstractShaderProgramGLTest::createAsync, - &AbstractShaderProgramGLTest::createMultipleOutputs, - #ifndef MAGNUM_TARGET_GLES - &AbstractShaderProgramGLTest::createMultipleOutputsIndexed, - #endif + addInstancedTests({&AbstractShaderProgramGLTest::create}, + Containers::arraySize(CreateData)); + + addTests({&AbstractShaderProgramGLTest::createAsync}); + + addInstancedTests({ + &AbstractShaderProgramGLTest::createMultipleOutputs, + #ifndef MAGNUM_TARGET_GLES + &AbstractShaderProgramGLTest::createMultipleOutputsIndexed, + #endif + }, Containers::arraySize(CreateMultipleOutputsData)); - &AbstractShaderProgramGLTest::linkFailure, + addTests({&AbstractShaderProgramGLTest::linkFailure, &AbstractShaderProgramGLTest::linkFailureAsync, &AbstractShaderProgramGLTest::linkFailureAsyncShaderList, @@ -149,9 +201,15 @@ AbstractShaderProgramGLTest::AbstractShaderProgramGLTest() { &AbstractShaderProgramGLTest::uniformDoubleMatrix, &AbstractShaderProgramGLTest::uniformDoubleArray, #endif + }); + + #ifndef MAGNUM_TARGET_GLES2 + addInstancedTests({&AbstractShaderProgramGLTest::createUniformBlocks}, + Containers::arraySize(CreateUniformBlocksData)); + #endif + addTests({ #ifndef MAGNUM_TARGET_GLES2 - &AbstractShaderProgramGLTest::createUniformBlocks, &AbstractShaderProgramGLTest::uniformBlockIndexNotFound, &AbstractShaderProgramGLTest::uniformBlock, @@ -248,6 +306,9 @@ struct MyPublicShader: AbstractShaderProgram { }; void AbstractShaderProgramGLTest::create() { + auto&& data = CreateData[testCaseInstanceId()]; + setTestCaseDescription(data.name); + Utility::Resource rs("AbstractShaderProgramGLTest"); Shader vert( @@ -287,7 +348,7 @@ void AbstractShaderProgramGLTest::create() { MAGNUM_VERIFY_NO_GL_ERROR(); - program.bindAttributeLocation(0, "position"); + program.bindAttributeLocation(0, data.positionName); const bool linked = program.link(); const bool valid = program.validate().first; @@ -304,10 +365,10 @@ void AbstractShaderProgramGLTest::create() { CORRADE_VERIFY(valid); } - const Int matrixUniform = program.uniformLocation("matrix"); - const Int multiplierUniform = program.uniformLocation("multiplier"); - const Int colorUniform = program.uniformLocation("color"); - const Int additionsUniform = program.uniformLocation("additions"); + const Int matrixUniform = program.uniformLocation(data.matrixName); + const Int multiplierUniform = program.uniformLocation(data.multiplierName); + const Int colorUniform = program.uniformLocation(data.colorName); + const Int additionsUniform = program.uniformLocation(data.additionsName); MAGNUM_VERIFY_NO_GL_ERROR(); CORRADE_VERIFY(matrixUniform >= 0); @@ -387,6 +448,9 @@ void AbstractShaderProgramGLTest::createAsync() { } void AbstractShaderProgramGLTest::createMultipleOutputs() { + auto&& data = CreateMultipleOutputsData[testCaseInstanceId()]; + setTestCaseDescription(data.name); + #ifndef MAGNUM_TARGET_GLES if(!GL::Context::current().isExtensionSupported()) CORRADE_SKIP(GL::Extensions::EXT::gpu_shader4::string() << "is not supported."); @@ -423,8 +487,10 @@ void AbstractShaderProgramGLTest::createMultipleOutputs() { MAGNUM_VERIFY_NO_GL_ERROR(); program.bindAttributeLocation(0, "position"); - program.bindFragmentDataLocation(0, "first"); - program.bindFragmentDataLocation(1, "second"); + /* Testing just what wasn't verified for non-null-terminated strings in + create() already */ + program.bindFragmentDataLocation(0, data.firstName); + program.bindFragmentDataLocation(1, data.secondName); const bool linked = program.link(); const bool valid = program.validate().first; @@ -445,6 +511,9 @@ void AbstractShaderProgramGLTest::createMultipleOutputs() { #ifndef MAGNUM_TARGET_GLES void AbstractShaderProgramGLTest::createMultipleOutputsIndexed() { + auto&& data = CreateMultipleOutputsData[testCaseInstanceId()]; + setTestCaseDescription(data.name); + if(!GL::Context::current().isExtensionSupported()) CORRADE_SKIP(GL::Extensions::EXT::gpu_shader4::string() << "is not supported."); if(!GL::Context::current().isExtensionSupported()) @@ -482,8 +551,8 @@ void AbstractShaderProgramGLTest::createMultipleOutputsIndexed() { MAGNUM_VERIFY_NO_GL_ERROR(); program.bindAttributeLocation(0, "position"); - program.bindFragmentDataLocationIndexed(0, 0, "first"); - program.bindFragmentDataLocationIndexed(0, 1, "second"); + program.bindFragmentDataLocationIndexed(0, 0, data.firstName); + program.bindFragmentDataLocationIndexed(0, 1, data.secondName); const bool linked = program.link(); const bool valid = program.validate().first; @@ -713,7 +782,7 @@ void main() { program.setUniform(program.uniformLocation("textureData2D"), 0); program.setUniform(program.uniformLocation("textureData3D"), 0); - std::pair result = program.validate(); + std::pair result = program.validate(); MAGNUM_VERIFY_NO_GL_ERROR(); CORRADE_VERIFY(!result.first); /* The message shouldn't be empty */ @@ -769,10 +838,8 @@ void AbstractShaderProgramGLTest::uniformNotFound() { std::ostringstream out; Warning redirectWarning{&out}; program.uniformLocation("nonexistent"); - program.uniformLocation(std::string{"another"}); CORRADE_COMPARE(out.str(), - "GL::AbstractShaderProgram: location of uniform 'nonexistent' cannot be retrieved\n" - "GL::AbstractShaderProgram: location of uniform 'another' cannot be retrieved\n"); + "GL::AbstractShaderProgram: location of uniform 'nonexistent' cannot be retrieved\n"); } struct MyShader: AbstractShaderProgram { @@ -977,6 +1044,9 @@ void AbstractShaderProgramGLTest::uniformDoubleArray() { #ifndef MAGNUM_TARGET_GLES2 void AbstractShaderProgramGLTest::createUniformBlocks() { + auto&& data = CreateUniformBlocksData[testCaseInstanceId()]; + setTestCaseDescription(data.name); + #ifndef MAGNUM_TARGET_GLES if(!GL::Context::current().isExtensionSupported()) CORRADE_SKIP(GL::Extensions::ARB::uniform_buffer_object::string() << "is not supported."); @@ -1025,8 +1095,8 @@ void AbstractShaderProgramGLTest::createUniformBlocks() { CORRADE_VERIFY(valid); } - const Int matricesUniformBlock = program.uniformBlockIndex("matrices"); - const Int materialUniformBlock = program.uniformBlockIndex("material"); + const Int matricesUniformBlock = program.uniformBlockIndex(data.matricesName); + const Int materialUniformBlock = program.uniformBlockIndex(data.materialName); MAGNUM_VERIFY_NO_GL_ERROR(); CORRADE_VERIFY(matricesUniformBlock >= 0); @@ -1066,10 +1136,8 @@ void AbstractShaderProgramGLTest::uniformBlockIndexNotFound() { std::ostringstream out; Warning redirectWarning{&out}; program.uniformBlockIndex("nonexistent"); - program.uniformBlockIndex(std::string{"another"}); CORRADE_COMPARE(out.str(), - "GL::AbstractShaderProgram: index of uniform block 'nonexistent' cannot be retrieved\n" - "GL::AbstractShaderProgram: index of uniform block 'another' cannot be retrieved\n"); + "GL::AbstractShaderProgram: index of uniform block 'nonexistent' cannot be retrieved\n"); } struct UniformBlockShader: AbstractShaderProgram { diff --git a/src/Magnum/GL/Test/MeshGLTest.cpp b/src/Magnum/GL/Test/MeshGLTest.cpp index 496b3523c..a4ea500d1 100644 --- a/src/Magnum/GL/Test/MeshGLTest.cpp +++ b/src/Magnum/GL/Test/MeshGLTest.cpp @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -770,7 +771,7 @@ void MeshGLTest::construct() { } struct FloatShader: AbstractShaderProgram { - explicit FloatShader(const std::string& type, const std::string& conversion); + explicit FloatShader(Containers::StringView type, Containers::StringView conversion); }; void MeshGLTest::constructMove() { @@ -949,13 +950,13 @@ void MeshGLTest::label() { #ifndef MAGNUM_TARGET_GLES2 struct IntegerShader: AbstractShaderProgram { - explicit IntegerShader(const std::string& type); + explicit IntegerShader(Containers::StringView type); }; #endif #ifndef MAGNUM_TARGET_GLES struct DoubleShader: AbstractShaderProgram { - explicit DoubleShader(const std::string& type, const std::string& outputType, const std::string& conversion); + explicit DoubleShader(Containers::StringView type, Containers::StringView outputType, Containers::StringView conversion); }; #endif @@ -969,7 +970,7 @@ struct Checker { }; #ifndef DOXYGEN_GENERATING_OUTPUT -FloatShader::FloatShader(const std::string& type, const std::string& conversion) { +FloatShader::FloatShader(Containers::StringView type, Containers::StringView conversion) { /* We need special version for ES3, because GLSL in ES2 doesn't support rectangle matrices */ #ifndef MAGNUM_TARGET_GLES @@ -995,7 +996,7 @@ FloatShader::FloatShader(const std::string& type, const std::string& conversion) Shader frag(Version::GLES300, Shader::Type::Fragment); #endif - vert.addSource( + vert.addSource(Utility::format( "#if !defined(GL_ES) && __VERSION__ == 120\n" "#define mediump\n" "#endif\n" @@ -1003,14 +1004,14 @@ FloatShader::FloatShader(const std::string& type, const std::string& conversion) "#define in attribute\n" "#define out varying\n" "#endif\n" - "in mediump " + type + " value;\n" - "out mediump " + type + " valueInterpolated;\n" - "void main() {\n" + "in mediump {0} value;\n" + "out mediump {0} valueInterpolated;\n" + "void main() {{\n" " valueInterpolated = value;\n" " gl_PointSize = 1.0;\n" " gl_Position = vec4(0.0, 0.0, 0.0, 1.0);\n" - "}\n"); - frag.addSource( + "}}\n", type)); + frag.addSource(Utility::format( "#if !defined(GL_ES) && __VERSION__ == 120\n" "#define mediump\n" "#endif\n" @@ -1018,11 +1019,11 @@ FloatShader::FloatShader(const std::string& type, const std::string& conversion) "#define in varying\n" "#define result gl_FragColor\n" "#endif\n" - "in mediump " + type + " valueInterpolated;\n" + "in mediump {0} valueInterpolated;\n" "#if (defined(GL_ES) && __VERSION__ >= 300) || (!defined(GL_ES) && __VERSION__ >= 130)\n" "out mediump vec4 result;\n" "#endif\n" - "void main() { result = " + conversion + "; }\n"); + "void main() {{ result = {1}; }}\n", type, conversion)); CORRADE_INTERNAL_ASSERT_OUTPUT(vert.compile() && frag.compile()); @@ -1034,7 +1035,7 @@ FloatShader::FloatShader(const std::string& type, const std::string& conversion) } #ifndef MAGNUM_TARGET_GLES2 -IntegerShader::IntegerShader(const std::string& type) { +IntegerShader::IntegerShader(const Containers::StringView type) { #ifndef MAGNUM_TARGET_GLES Shader vert( #ifndef CORRADE_TARGET_APPLE @@ -1055,16 +1056,18 @@ IntegerShader::IntegerShader(const std::string& type) { Shader frag(Version::GLES300, Shader::Type::Fragment); #endif - vert.addSource("in mediump " + type + " value;\n" - "flat out mediump " + type + " valueInterpolated;\n" - "void main() {\n" - " valueInterpolated = value;\n" - " gl_PointSize = 1.0;\n" - " gl_Position = vec4(0.0, 0.0, 0.0, 1.0);\n" - "}\n"); - frag.addSource("flat in mediump " + type + " valueInterpolated;\n" - "out mediump " + type + " result;\n" - "void main() { result = valueInterpolated; }\n"); + vert.addSource(Utility::format( + "in mediump {0} value;\n" + "flat out mediump {0} valueInterpolated;\n" + "void main() {{\n" + " valueInterpolated = value;\n" + " gl_PointSize = 1.0;\n" + " gl_Position = vec4(0.0, 0.0, 0.0, 1.0);\n" + "}}\n", type)); + frag.addSource(Utility::format( + "flat in mediump {0} valueInterpolated;\n" + "out mediump {0} result;\n" + "void main() {{ result = valueInterpolated; }}\n", type)); CORRADE_INTERNAL_ASSERT_OUTPUT(vert.compile() && frag.compile()); @@ -1077,7 +1080,7 @@ IntegerShader::IntegerShader(const std::string& type) { #endif #ifndef MAGNUM_TARGET_GLES -DoubleShader::DoubleShader(const std::string& type, const std::string& outputType, const std::string& conversion) { +DoubleShader::DoubleShader(const Containers::StringView type, const Containers::StringView outputType, const Containers::StringView conversion) { constexpr const Version version = #ifndef CORRADE_TARGET_APPLE Version::GL300; @@ -1087,19 +1090,20 @@ DoubleShader::DoubleShader(const std::string& type, const std::string& outputTyp Shader vert{version, Shader::Type::Vertex}; Shader frag(version, Shader::Type::Fragment); - vert.addSource( + vert.addSource(Utility::format( "#extension GL_ARB_vertex_attrib_64bit: require\n" "#extension GL_ARB_gpu_shader_fp64: require\n" - "in " + type + " value;\n" - "out " + outputType + " valueInterpolated;\n" - "void main() {\n" - " valueInterpolated = " + conversion + ";\n" + "in {0} value;\n" + "out {1} valueInterpolated;\n" + "void main() {{\n" + " valueInterpolated = {2};\n" " gl_PointSize = 1.0;\n" " gl_Position = vec4(0.0, 0.0, 0.0, 1.0);\n" - "}\n"); - frag.addSource("in " + outputType + " valueInterpolated;\n" - "out " + outputType + " result;\n" - "void main() { result = valueInterpolated; }\n"); + "}}\n", type, outputType, conversion)); + frag.addSource(Utility::format( + "in {0} valueInterpolated;\n" + "out {0} result;\n" + "void main() {{ result = valueInterpolated; }}\n", outputType)); CORRADE_INTERNAL_ASSERT_OUTPUT(vert.compile() && frag.compile()); diff --git a/src/Magnum/GL/Test/PrimitiveQueryGLTest.cpp b/src/Magnum/GL/Test/PrimitiveQueryGLTest.cpp index 70293f3d2..3831a4351 100644 --- a/src/Magnum/GL/Test/PrimitiveQueryGLTest.cpp +++ b/src/Magnum/GL/Test/PrimitiveQueryGLTest.cpp @@ -24,6 +24,7 @@ */ #include +#include #include #include diff --git a/src/Magnum/GL/Test/ShaderGLTest.cpp b/src/Magnum/GL/Test/ShaderGLTest.cpp index 3e31e74b9..ae2efd521 100644 --- a/src/Magnum/GL/Test/ShaderGLTest.cpp +++ b/src/Magnum/GL/Test/ShaderGLTest.cpp @@ -26,7 +26,9 @@ #include #include -#include /** @todo remove once Shader is -free */ +#include +#include /* StringHasPrefix / StringHasSuffix */ +#include #include #include #include @@ -126,9 +128,13 @@ void ShaderGLTest::construct() { CORRADE_VERIFY(shader.id() > 0); CORRADE_COMPARE(shader.type(), Shader::Type::Fragment); #ifndef MAGNUM_TARGET_GLES - CORRADE_COMPARE(shader.sources(), std::vector{"#version 130\n"}); + CORRADE_COMPARE_AS(shader.sources(), + Containers::StringIterable{"#version 130\n"}, + TestSuite::Compare::Container); #else - CORRADE_COMPARE(shader.sources(), std::vector{"#version 300 es\n"}); + CORRADE_COMPARE_AS(shader.sources(), + Containers::StringIterable{"#version 300 es\n"}, + TestSuite::Compare::Container); #endif } @@ -137,7 +143,7 @@ void ShaderGLTest::construct() { void ShaderGLTest::constructNoVersion() { const Shader shader(Version::None, Shader::Type::Fragment); - CORRADE_VERIFY(shader.sources().empty()); + CORRADE_VERIFY(shader.sources().isEmpty()); } void ShaderGLTest::constructMove() { @@ -157,9 +163,13 @@ void ShaderGLTest::constructMove() { CORRADE_COMPARE(b.id(), id); CORRADE_COMPARE(b.type(), Shader::Type::Fragment); #ifndef MAGNUM_TARGET_GLES - CORRADE_COMPARE(b.sources(), std::vector{"#version 130\n"}); + CORRADE_COMPARE_AS(b.sources(), + Containers::StringIterable{"#version 130\n"}, + TestSuite::Compare::Container); #else - CORRADE_COMPARE(b.sources(), std::vector{"#version 300 es\n"}); + CORRADE_COMPARE_AS(b.sources(), + Containers::StringIterable{"#version 300 es\n"}, + TestSuite::Compare::Container); #endif #ifndef MAGNUM_TARGET_GLES @@ -176,9 +186,13 @@ void ShaderGLTest::constructMove() { CORRADE_COMPARE(c.id(), id); CORRADE_COMPARE(c.type(), Shader::Type::Fragment); #ifndef MAGNUM_TARGET_GLES - CORRADE_COMPARE(c.sources(), std::vector{"#version 130\n"}); + CORRADE_COMPARE_AS(c.sources(), + Containers::StringIterable{"#version 130\n"}, + TestSuite::Compare::Container); #else - CORRADE_COMPARE(c.sources(), std::vector{"#version 300 es\n"}); + CORRADE_COMPARE_AS(c.sources(), + Containers::StringIterable{"#version 300 es\n"}, + TestSuite::Compare::Container); #endif CORRADE_VERIFY(std::is_nothrow_move_constructible::value); @@ -231,64 +245,106 @@ void ShaderGLTest::addSource() { Shader shader(Version::GLES200, Shader::Type::Fragment); #endif - shader.addSource("#define FOO BAR\n") - .addSource("void main() {}\n"); + const char* data = "// r-value String\n"; + shader.addSource("// global, null-terminated\n"_s) + .addSource("// global, non-null-terminated\n!"_s.exceptSuffix(1)) + .addSource("// local, null-terminated\n") + .addSource(Containers::StringView{"// local, non-null-terminated\n!"}.exceptSuffix(1)) + .addSource(Containers::String{data, [](char*, std::size_t) {}}) + .addSource("") /* gets ignored */ + .addSource("void main() {}\n"_s); + + /* On (desktop) GLSL < 330 the #line affect next line, not current + line; see compileFailure() for a correctness verification */ #ifndef MAGNUM_TARGET_GLES - CORRADE_COMPARE(shader.sources(), (std::vector{ - "#version 120\n", - /* On (desktop) GLSL < 330 the #line affect next line, not current - line; see compileFailure() for a correctness verification */ - "#line 0 1\n", - "#define FOO BAR\n", - "#line 0 2\n", - "void main() {}\n" - })); + #define _zero " 0 " #else - CORRADE_COMPARE(shader.sources(), (std::vector{ - "#version 100\n", - "#line 1 1\n", - "#define FOO BAR\n", - "#line 1 2\n", - "void main() {}\n" - })); + #define _zero " 1 " #endif + Containers::StringView expected[]{ + #ifndef MAGNUM_TARGET_GLES + "#version 120\n", // 0 + #else + "#version 100\n", // 0 + #endif + "#line" _zero "1\n", + "// global, null-terminated\n", // 2 + "#line" _zero "2\n", + "// global, non-null-terminated\n", + "#line" _zero "3\n", + "// local, null-terminated\n", + "#line" _zero "4\n", + "// local, non-null-terminated\n", + "#line" _zero "5\n", + "// r-value String\n", // isn't global but is moved + "#line" _zero "6\n", + /* Empty source gets ignored */ + "void main() {}\n" // 12 + }; + #undef _zero + CORRADE_COMPARE_AS(shader.sources(), + Containers::StringIterable{expected}, + TestSuite::Compare::Container); + + /* Verify that strings get copied only when not null terminated or not + global, and when not moved */ + for(std::size_t i: {0, 2, 12}) { + CORRADE_ITERATION(i); + CORRADE_COMPARE(shader.sources()[i].flags(), Containers::StringViewFlag::NullTerminated|Containers::StringViewFlag::Global); + } + for(std::size_t i: {1, 3, 4, 5, 6, 7, 8, 9, 10, 11}) { + CORRADE_ITERATION(i); + CORRADE_COMPARE(shader.sources()[i].flags(), Containers::StringViewFlag::NullTerminated); + } + CORRADE_VERIFY(shader.sources()[10].data() == data); } void ShaderGLTest::addSourceNoVersion() { Shader shader(Version::None, Shader::Type::Fragment); #ifndef MAGNUM_TARGET_GLES - shader.addSource("#version 120\n"); + shader.addSource("#version 120\n"_s); #else - shader.addSource("#version 100\n"); + shader.addSource("#version 100\n"_s); #endif - shader.addSource("#define FOO BAR\n") - .addSource("void main() {}\n"); + shader.addSource("#define FOO BAR\n"_s) + .addSource("void main() {}\n"_s); #ifndef MAGNUM_TARGET_GLES - CORRADE_COMPARE(shader.sources(), (std::vector{ + CORRADE_COMPARE_AS(shader.sources(), (Containers::StringIterable{ "", /* Here, even though there's #version 120 eventually added by the user, it assumes the specified version was new GLSL, not old. Explicitly specified old GLSL is such a rare use case that I don't bother looking for the #version directive and adjusting. */ "#version 120\n", - "#line 1 1\n", + "#line 1 1\n", // 2 "#define FOO BAR\n", - "#line 1 2\n", + "#line 1 2\n", // 4 "void main() {}\n" - })); + }), TestSuite::Compare::Container); #else - CORRADE_COMPARE(shader.sources(), (std::vector{ + CORRADE_COMPARE_AS(shader.sources(), (Containers::StringIterable{ "", "#version 100\n", "#line 1 1\n", "#define FOO BAR\n", "#line 1 2\n", "void main() {}\n" - })); + }), TestSuite::Compare::Container); #endif + + /* Everything except the line numbers should be global in this case, + including the empty string */ + for(std::size_t i: {0, 1, 3, 5}) { + CORRADE_ITERATION(i); + CORRADE_COMPARE(shader.sources()[i].flags(), Containers::StringViewFlag::NullTerminated|Containers::StringViewFlag::Global); + } + for(std::size_t i: {2, 4}) { + CORRADE_ITERATION(i); + CORRADE_COMPARE(shader.sources()[i].flags(), Containers::StringViewFlag::NullTerminated); + } } void ShaderGLTest::addFile() { @@ -301,20 +357,25 @@ void ShaderGLTest::addFile() { shader.addFile(Utility::Path::join(SHADERGLTEST_FILES_DIR, "shader.glsl")); #ifndef MAGNUM_TARGET_GLES - CORRADE_COMPARE(shader.sources(), (std::vector{ + CORRADE_COMPARE_AS(shader.sources(), (Containers::StringIterable{ "#version 120\n", /* On (desktop) GLSL < 330 the #line affect next line, not current line; see compileFailure() for a correctness verification */ "#line 0 1\n", "void main() {}\n" - })); + }), TestSuite::Compare::Container); #else - CORRADE_COMPARE(shader.sources(), (std::vector{ + CORRADE_COMPARE_AS(shader.sources(), (Containers::StringIterable{ "#version 100\n", "#line 1 1\n", "void main() {}\n" - })); + }), TestSuite::Compare::Container); #endif + + /* The file source and the line number isn't global */ + CORRADE_COMPARE(shader.sources()[0].flags(), Containers::StringViewFlag::NullTerminated|Containers::StringViewFlag::Global); + CORRADE_COMPARE(shader.sources()[1].flags(), Containers::StringViewFlag::NullTerminated); + CORRADE_COMPARE(shader.sources()[2].flags(), Containers::StringViewFlag::NullTerminated); } void ShaderGLTest::addFileNonexistent() { diff --git a/src/Magnum/GL/Test/TransformFeedbackGLTest.cpp b/src/Magnum/GL/Test/TransformFeedbackGLTest.cpp index aa7637739..be54b9bf0 100644 --- a/src/Magnum/GL/Test/TransformFeedbackGLTest.cpp +++ b/src/Magnum/GL/Test/TransformFeedbackGLTest.cpp @@ -25,7 +25,10 @@ #include #include +#include +#include #include +#include #include "Magnum/Image.h" #include "Magnum/GL/AbstractShaderProgram.h" @@ -44,10 +47,6 @@ #include "Magnum/GL/TransformFeedback.h" #include "Magnum/Math/Vector2.h" -#ifndef MAGNUM_TARGET_WEBGL -#include -#endif - namespace Magnum { namespace GL { namespace Test { namespace { struct TransformFeedbackGLTest: OpenGLTester { @@ -74,6 +73,38 @@ struct TransformFeedbackGLTest: OpenGLTester { }; #ifndef MAGNUM_TARGET_GLES +using namespace Containers::Literals; + +const struct { + const char* name; + Containers::StringView output1Name; + Containers::StringView glSkipComponents1Name; + Containers::StringView output2Name; +} InterleavedData[]{ + {"", + "output1"_s, + "gl_SkipComponents1"_s, + "output2"_s}, + {"non-null-terminated strings", + "output1!"_s.exceptSuffix(1), + "gl_SkipComponents1!"_s.exceptSuffix(1), + "output2!"_s.exceptSuffix(1)}, + #ifdef CORRADE_TARGET_WINDOWS + /* Testing the "nv-windows-dangling-transform-feedback-varying-names" + bug / workaround. "output1" alone *is* a global string, however a + StringView created from it doesn't know that and so it should get copied + to a local, null-terminated String first. Without the workaround present + this case would do the right thing as well tho (but the above not) -- + the driver assumes the string is global (which it is), while StringView + assumes the driver doesn't need a global string so it doesn't do + anything extra. */ + {"non-global strings", + "output1", + "gl_SkipComponents1", + "output2"}, + #endif +}; + const struct { const char* name; UnsignedInt stream; @@ -101,14 +132,12 @@ TransformFeedbackGLTest::TransformFeedbackGLTest() { &TransformFeedbackGLTest::attachBase, &TransformFeedbackGLTest::attachRange, &TransformFeedbackGLTest::attachBases, - &TransformFeedbackGLTest::attachRanges, - - #ifndef MAGNUM_TARGET_GLES - &TransformFeedbackGLTest::interleaved, - #endif - }); + &TransformFeedbackGLTest::attachRanges}); #ifndef MAGNUM_TARGET_GLES + addInstancedTests({&TransformFeedbackGLTest::interleaved}, + Containers::arraySize(InterleavedData)); + addInstancedTests({&TransformFeedbackGLTest::draw}, Containers::arraySize(DrawData)); #endif @@ -266,6 +295,7 @@ XfbShader::XfbShader() { attachShaders({vert, frag}); #endif bindAttributeLocation(Input::Location, "inputData"); + /* Non-null-terminated strings tested in interleaved() */ setTransformFeedbackOutputs({"outputData"}, TransformFeedbackBufferMode::SeparateAttributes); CORRADE_INTERNAL_ASSERT_OUTPUT(link()); } @@ -402,6 +432,7 @@ XfbMultiShader::XfbMultiShader() { attachShaders({vert, frag}); #endif bindAttributeLocation(Input::Location, "inputData"); + /* Non-null-terminated input tested in interleaved() */ setTransformFeedbackOutputs({"output1", "output2"}, TransformFeedbackBufferMode::SeparateAttributes); CORRADE_INTERNAL_ASSERT_OUTPUT(link()); } @@ -519,6 +550,9 @@ void TransformFeedbackGLTest::attachRanges() { #ifndef MAGNUM_TARGET_GLES void TransformFeedbackGLTest::interleaved() { + auto&& data = InterleavedData[testCaseInstanceId()]; + setTestCaseDescription(data.name); + /* ARB_transform_feedback3 needed for gl_SkipComponents1 */ if(!Context::current().isExtensionSupported()) CORRADE_SKIP(Extensions::ARB::transform_feedback3::string() << "is not supported."); @@ -533,7 +567,7 @@ void TransformFeedbackGLTest::interleaved() { struct XfbInterleavedShader: AbstractShaderProgram { typedef Attribute<0, Vector2> Input; - explicit XfbInterleavedShader() { + explicit XfbInterleavedShader(Containers::StringView output1Name, Containers::StringView glSkipComponents1Name, Containers::StringView output2Name) { Shader vert( #ifndef CORRADE_TARGET_APPLE Version::GL300 @@ -554,10 +588,10 @@ void TransformFeedbackGLTest::interleaved() { "}\n").compile()); attachShader(vert); bindAttributeLocation(Input::Location, "inputData"); - setTransformFeedbackOutputs({"output1", "gl_SkipComponents1", "output2"}, TransformFeedbackBufferMode::InterleavedAttributes); + setTransformFeedbackOutputs({output1Name, glSkipComponents1Name, output2Name}, TransformFeedbackBufferMode::InterleavedAttributes); CORRADE_INTERNAL_ASSERT_OUTPUT(link()); } - } shader; + } shader{data.output1Name, data.glSkipComponents1Name, data.output2Name}; Buffer input{Buffer::TargetHint::Array}; input.setData(inputData, BufferUsage::StaticDraw); @@ -581,11 +615,11 @@ void TransformFeedbackGLTest::interleaved() { MAGNUM_VERIFY_NO_GL_ERROR(); - auto data = Containers::arrayCast(output.mapRead(0, 4*sizeof(Vector2))); - CORRADE_COMPARE(data[0], Vector2(1.0f, -1.0f)); - CORRADE_COMPARE(data[1].y(), 5.0f); - CORRADE_COMPARE(data[2], Vector2(0.0f, 0.0f)); - CORRADE_COMPARE(data[3].y(), 3.0f); + auto outputData = Containers::arrayCast(output.mapRead(0, 4*sizeof(Vector2))); + CORRADE_COMPARE(outputData[0], Vector2(1.0f, -1.0f)); + CORRADE_COMPARE(outputData[1].y(), 5.0f); + CORRADE_COMPARE(outputData[2], Vector2(0.0f, 0.0f)); + CORRADE_COMPARE(outputData[3].y(), 3.0f); output.unmap(); } @@ -617,11 +651,12 @@ void TransformFeedbackGLTest::draw() { " vertexOutput = vec2(0.3);\n" " gl_Position = vec4(0.0, 0.0, 0.0, 1.0);\n" "}\n"); - if(stream) geom.addSource( + if(stream) geom.addSource(Utility::format( "#extension GL_ARB_gpu_shader5: require\n" - "#define STREAM " + std::to_string(stream) + "\n" + - "layout(stream = 0) out mediump float otherOutput;\n" + - "layout(stream = STREAM) out mediump vec2 geomOutput;\n"); + "#define STREAM {}\n" + "layout(stream = 0) out mediump float otherOutput;\n" + "layout(stream = STREAM) out mediump vec2 geomOutput;\n", + stream)); else geom.addSource( "out mediump vec2 geomOutput;\n"); geom.addSource( diff --git a/src/Magnum/Shaders/DistanceFieldVectorGL.cpp b/src/Magnum/Shaders/DistanceFieldVectorGL.cpp index 77de6d56d..7c6592445 100644 --- a/src/Magnum/Shaders/DistanceFieldVectorGL.cpp +++ b/src/Magnum/Shaders/DistanceFieldVectorGL.cpp @@ -39,7 +39,8 @@ #include "Magnum/Math/Matrix4.h" #ifndef MAGNUM_TARGET_GLES2 -#include +#include +#include #include "Magnum/GL/Buffer.h" #endif @@ -110,7 +111,7 @@ template typename DistanceFieldVectorGL::Com .addSource(dimensions == 2 ? "#define TWO_DIMENSIONS\n" : "#define THREE_DIMENSIONS\n"); #ifndef MAGNUM_TARGET_GLES2 if(configuration.flags() >= Flag::UniformBuffers) { - vert.addSource(Utility::formatString( + vert.addSource(Utility::format( "#define UNIFORM_BUFFERS\n" "#define DRAW_COUNT {}\n", configuration.drawCount())); @@ -121,7 +122,7 @@ template typename DistanceFieldVectorGL::Com .addSource(rs.getString("Vector.vert")); #ifndef MAGNUM_TARGET_GLES2 if(configuration.flags() >= Flag::UniformBuffers) { - frag.addSource(Utility::formatString( + frag.addSource(Utility::format( "#define UNIFORM_BUFFERS\n" "#define MATERIAL_COUNT {}\n" "#define DRAW_COUNT {}\n", diff --git a/src/Magnum/Shaders/DistanceFieldVectorGL.h b/src/Magnum/Shaders/DistanceFieldVectorGL.h index 7a31c67e5..d4d84af9f 100644 --- a/src/Magnum/Shaders/DistanceFieldVectorGL.h +++ b/src/Magnum/Shaders/DistanceFieldVectorGL.h @@ -31,6 +31,8 @@ * @m_since_latest */ +#include + #include "Magnum/DimensionTraits.h" #include "Magnum/GL/AbstractShaderProgram.h" #include "Magnum/Shaders/GenericGL.h" @@ -752,7 +754,7 @@ template class DistanceFieldVectorGL::Compil #ifndef MAGNUM_TARGET_GLES , GL::Version version #endif - ): DistanceFieldVectorGL{std::move(shader)}, _vert{std::move(vert)}, _frag{std::move(frag)} + ): DistanceFieldVectorGL{Utility::move(shader)}, _vert{Utility::move(vert)}, _frag{Utility::move(frag)} #ifndef MAGNUM_TARGET_GLES , _version{version} #endif diff --git a/src/Magnum/Shaders/FlatGL.cpp b/src/Magnum/Shaders/FlatGL.cpp index 5f9e5aa14..3362cea71 100644 --- a/src/Magnum/Shaders/FlatGL.cpp +++ b/src/Magnum/Shaders/FlatGL.cpp @@ -41,7 +41,8 @@ #include "Magnum/Shaders/Implementation/CreateCompatibilityShader.h" #ifndef MAGNUM_TARGET_GLES2 -#include +#include +#include #include "Magnum/GL/Buffer.h" #include "Magnum/GL/TextureArray.h" @@ -178,7 +179,7 @@ template typename FlatGL::CompileState FlatG .addSource(configuration.flags() >= Flag::InstancedTextureOffset ? "#define INSTANCED_TEXTURE_OFFSET\n" : ""); #ifndef MAGNUM_TARGET_GLES2 if(configuration.jointCount()) { - vert.addSource(Utility::formatString( + vert.addSource(Utility::format( "#define JOINT_COUNT {}\n" "#define PER_VERTEX_JOINT_COUNT {}u\n" "#define SECONDARY_PER_VERTEX_JOINT_COUNT {}u\n" @@ -195,7 +196,7 @@ template typename FlatGL::CompileState FlatG out._perInstanceJointCountUniform)); } if(configuration.flags() >= Flag::DynamicPerVertexJointCount) { - vert.addSource(Utility::formatString( + vert.addSource(Utility::format( "#define DYNAMIC_PER_VERTEX_JOINT_COUNT\n" "#define PER_VERTEX_JOINT_COUNT_LOCATION {}\n", out._perVertexJointCountUniform)); @@ -203,7 +204,7 @@ template typename FlatGL::CompileState FlatG #endif #ifndef MAGNUM_TARGET_GLES2 if(configuration.flags() >= Flag::UniformBuffers) { - vert.addSource(Utility::formatString( + vert.addSource(Utility::format( "#define UNIFORM_BUFFERS\n" "#define DRAW_COUNT {}\n", configuration.drawCount())); @@ -226,7 +227,7 @@ template typename FlatGL::CompileState FlatG ; #ifndef MAGNUM_TARGET_GLES2 if(configuration.flags() >= Flag::UniformBuffers) { - frag.addSource(Utility::formatString( + frag.addSource(Utility::format( "#define UNIFORM_BUFFERS\n" "#define DRAW_COUNT {}\n" "#define MATERIAL_COUNT {}\n", diff --git a/src/Magnum/Shaders/FlatGL.h b/src/Magnum/Shaders/FlatGL.h index 9200d860b..8d1e364da 100644 --- a/src/Magnum/Shaders/FlatGL.h +++ b/src/Magnum/Shaders/FlatGL.h @@ -31,12 +31,18 @@ * @m_since_latest */ +#include + #include "Magnum/DimensionTraits.h" #include "Magnum/GL/AbstractShaderProgram.h" #include "Magnum/Shaders/GenericGL.h" #include "Magnum/Shaders/glShaderWrapper.h" #include "Magnum/Shaders/visibility.h" +#ifndef MAGNUM_TARGET_GLES2 +#include +#endif + namespace Magnum { namespace Shaders { namespace Implementation { @@ -1520,7 +1526,7 @@ template class FlatGL::CompileState: public #ifndef MAGNUM_TARGET_GLES , GL::Version version #endif - ): FlatGL{std::move(shader)}, _vert{std::move(vert)}, _frag{std::move(frag)} + ): FlatGL{Utility::move(shader)}, _vert{Utility::move(vert)}, _frag{Utility::move(frag)} #ifndef MAGNUM_TARGET_GLES , _version{version} #endif diff --git a/src/Magnum/Shaders/Implementation/CreateCompatibilityShader.h b/src/Magnum/Shaders/Implementation/CreateCompatibilityShader.h index d8e82ab73..00344f0d7 100644 --- a/src/Magnum/Shaders/Implementation/CreateCompatibilityShader.h +++ b/src/Magnum/Shaders/Implementation/CreateCompatibilityShader.h @@ -25,7 +25,6 @@ DEALINGS IN THE SOFTWARE. */ -#include /** @todo remove when Shader is -free */ #include #include diff --git a/src/Magnum/Shaders/MeshVisualizerGL.cpp b/src/Magnum/Shaders/MeshVisualizerGL.cpp index fc5481b52..81103e3b8 100644 --- a/src/Magnum/Shaders/MeshVisualizerGL.cpp +++ b/src/Magnum/Shaders/MeshVisualizerGL.cpp @@ -28,7 +28,6 @@ #include #include -#include #include #include "Magnum/Math/Color.h" @@ -40,6 +39,9 @@ #include "Magnum/GL/Texture.h" #ifndef MAGNUM_TARGET_GLES2 +#include +#include + #include "Magnum/GL/Buffer.h" #include "Magnum/GL/TextureArray.h" #endif @@ -196,7 +198,7 @@ GL::Version MeshVisualizerGLBase::setupShaders(GL::Shader& vert, GL::Shader& fra ; #ifndef MAGNUM_TARGET_GLES2 if(jointCount) { - vert.addSource(Utility::formatString( + vert.addSource(Utility::format( "#define JOINT_COUNT {}\n" "#define PER_VERTEX_JOINT_COUNT {}u\n" "#define SECONDARY_PER_VERTEX_JOINT_COUNT {}u\n" @@ -213,7 +215,7 @@ GL::Version MeshVisualizerGLBase::setupShaders(GL::Shader& vert, GL::Shader& fra perInstanceJointCountUniform)); } if(flags >= FlagBase::DynamicPerVertexJointCount) { - vert.addSource(Utility::formatString( + vert.addSource(Utility::format( "#define DYNAMIC_PER_VERTEX_JOINT_COUNT\n" "#define PER_VERTEX_JOINT_COUNT_LOCATION {}\n", perVertexJointCountUniform)); @@ -221,7 +223,7 @@ GL::Version MeshVisualizerGLBase::setupShaders(GL::Shader& vert, GL::Shader& fra #endif #ifndef MAGNUM_TARGET_GLES2 if(flags >= FlagBase::UniformBuffers) { - vert.addSource(Utility::formatString( + vert.addSource(Utility::format( "#define UNIFORM_BUFFERS\n" "#define DRAW_COUNT {}\n" "#define MATERIAL_COUNT {}\n", @@ -245,7 +247,7 @@ GL::Version MeshVisualizerGLBase::setupShaders(GL::Shader& vert, GL::Shader& fra ; #ifndef MAGNUM_TARGET_GLES2 if(flags >= FlagBase::UniformBuffers) { - frag.addSource(Utility::formatString( + frag.addSource(Utility::format( "#define UNIFORM_BUFFERS\n" "#define DRAW_COUNT {}\n" "#define MATERIAL_COUNT {}\n", @@ -539,7 +541,7 @@ MeshVisualizerGL2D::CompileState MeshVisualizerGL2D::compile(const Configuration "#define PRIMITIVE_ID\n") : ""); #ifndef MAGNUM_TARGET_GLES2 if(configuration.flags() >= Flag::UniformBuffers) { - geom->addSource(Utility::formatString( + geom->addSource(Utility::format( "#define TWO_DIMENSIONS\n" "#define UNIFORM_BUFFERS\n" "#define DRAW_COUNT {}\n" @@ -1002,7 +1004,7 @@ MeshVisualizerGL3D::CompileState MeshVisualizerGL3D::compile(const Configuration geom = Implementation::createCompatibilityShader(rs, version, GL::Shader::Type::Geometry); (*geom) - .addSource(Utility::formatString("#define MAX_VERTICES {}\n", maxVertices)) + .addSource(Utility::format("#define MAX_VERTICES {}\n", maxVertices)) .addSource(configuration.flags() & Flag::Wireframe ? "#define WIREFRAME_RENDERING\n" : "") .addSource(baseFlags >= FlagBase::ObjectIdTexture ? "#define TEXTURED\n" : "") .addSource(baseFlags & FlagBase::TextureArrays ? "#define TEXTURE_ARRAYS\n" : "") @@ -1018,7 +1020,7 @@ MeshVisualizerGL3D::CompileState MeshVisualizerGL3D::compile(const Configuration .addSource(configuration.flags() & Flag::NormalDirection ? "#define NORMAL_DIRECTION\n" : ""); #ifndef MAGNUM_TARGET_GLES2 if(configuration.flags() >= Flag::UniformBuffers) { - geom->addSource(Utility::formatString( + geom->addSource(Utility::format( "#define THREE_DIMENSIONS\n" "#define UNIFORM_BUFFERS\n" "#define DRAW_COUNT {}\n" diff --git a/src/Magnum/Shaders/MeshVisualizerGL.h b/src/Magnum/Shaders/MeshVisualizerGL.h index 634a03883..e6580ef42 100644 --- a/src/Magnum/Shaders/MeshVisualizerGL.h +++ b/src/Magnum/Shaders/MeshVisualizerGL.h @@ -31,6 +31,7 @@ * @m_since_latest */ +#include #include #include "Magnum/DimensionTraits.h" @@ -39,6 +40,10 @@ #include "Magnum/Shaders/glShaderWrapper.h" #include "Magnum/Shaders/visibility.h" +#ifndef MAGNUM_TARGET_GLES2 +#include +#endif + namespace Magnum { namespace Shaders { namespace Implementation { @@ -1320,13 +1325,13 @@ class MeshVisualizerGL2D::CompileState: public MeshVisualizerGL2D { #ifndef MAGNUM_TARGET_GLES , GL::Version version #endif - ): MeshVisualizerGL2D{std::move(shader)}, _vert{std::move(vert)}, _frag{std::move(frag)} + ): MeshVisualizerGL2D{Utility::move(shader)}, _vert{Utility::move(vert)}, _frag{Utility::move(frag)} #ifndef MAGNUM_TARGET_GLES , _version{version} #endif { #if !defined(MAGNUM_TARGET_WEBGL) && !defined(MAGNUM_TARGET_GLES2) - if(geom) _geom = Implementation::GLShaderWrapper{std::move(*geom)}; + if(geom) _geom = Implementation::GLShaderWrapper{Utility::move(*geom)}; #endif } @@ -3288,13 +3293,13 @@ class MeshVisualizerGL3D::CompileState: public MeshVisualizerGL3D { #ifndef MAGNUM_TARGET_GLES , GL::Version version #endif - ): MeshVisualizerGL3D{std::move(shader)}, _vert{std::move(vert)}, _frag{std::move(frag)} + ): MeshVisualizerGL3D{Utility::move(shader)}, _vert{Utility::move(vert)}, _frag{Utility::move(frag)} #ifndef MAGNUM_TARGET_GLES , _version{version} #endif { #if !defined(MAGNUM_TARGET_WEBGL) && !defined(MAGNUM_TARGET_GLES2) - if(geom) _geom = Implementation::GLShaderWrapper{std::move(*geom)}; + if(geom) _geom = Implementation::GLShaderWrapper{Utility::move(*geom)}; #endif } diff --git a/src/Magnum/Shaders/PhongGL.cpp b/src/Magnum/Shaders/PhongGL.cpp index 59a9531b7..36d35c956 100644 --- a/src/Magnum/Shaders/PhongGL.cpp +++ b/src/Magnum/Shaders/PhongGL.cpp @@ -32,8 +32,8 @@ #endif #include #include -#include -#include +#include +#include #include #include "Magnum/GL/Context.h" @@ -192,9 +192,9 @@ PhongGL::CompileState PhongGL::compile(const Configuration& configuration) { /* Initializer for the light color / position / range arrays -- we need a list of initializers joined by commas. For GLES we'll simply upload the values directly. */ - std::string lightInitializer; + Containers::String lightInitializer; if(!(configuration.flags() >= Flag::UniformBuffers) && configuration.lightCount()) - lightInitializer = Utility::formatString( + lightInitializer = Utility::format( "#define LIGHT_POSITION_INITIALIZER {}\n" "#define LIGHT_COLOR_INITIALIZER {}\n" "#define LIGHT_RANGE_INITIALIZER {}\n", @@ -223,7 +223,7 @@ PhongGL::CompileState PhongGL::compile(const Configuration& configuration) { .addSource(configuration.flags() >= Flag::InstancedTextureOffset ? "#define INSTANCED_TEXTURE_OFFSET\n" : ""); #ifndef MAGNUM_TARGET_GLES2 if(configuration.jointCount()) { - vert.addSource(Utility::formatString( + vert.addSource(Utility::format( "#define JOINT_COUNT {}\n" "#define PER_VERTEX_JOINT_COUNT {}u\n" "#define SECONDARY_PER_VERTEX_JOINT_COUNT {}u\n" @@ -242,7 +242,7 @@ PhongGL::CompileState PhongGL::compile(const Configuration& configuration) { out._perInstanceJointCountUniform)); } if(configuration.flags() >= Flag::DynamicPerVertexJointCount) { - vert.addSource(Utility::formatString( + vert.addSource(Utility::format( "#define DYNAMIC_PER_VERTEX_JOINT_COUNT\n" "#define PER_VERTEX_JOINT_COUNT_LOCATION {}\n", out._perVertexJointCountUniform)); @@ -250,7 +250,7 @@ PhongGL::CompileState PhongGL::compile(const Configuration& configuration) { #endif #ifndef MAGNUM_TARGET_GLES2 if(configuration.flags() >= Flag::UniformBuffers) { - vert.addSource(Utility::formatString( + vert.addSource(Utility::format( "#define UNIFORM_BUFFERS\n" "#define DRAW_COUNT {}\n", configuration.drawCount(), @@ -279,7 +279,7 @@ PhongGL::CompileState PhongGL::compile(const Configuration& configuration) { ; #ifndef MAGNUM_TARGET_GLES2 if(configuration.flags() >= Flag::UniformBuffers) { - frag.addSource(Utility::formatString( + frag.addSource(Utility::format( "#define UNIFORM_BUFFERS\n" "#define DRAW_COUNT {}\n" "#define MATERIAL_COUNT {}\n" @@ -292,7 +292,7 @@ PhongGL::CompileState PhongGL::compile(const Configuration& configuration) { } else #endif { - frag.addSource(Utility::formatString( + frag.addSource(Utility::format( "#define LIGHT_COUNT {}\n" "#define LIGHT_COLORS_LOCATION {}\n" "#define LIGHT_SPECULAR_COLORS_LOCATION {}\n" diff --git a/src/Magnum/Shaders/PhongGL.h b/src/Magnum/Shaders/PhongGL.h index 740f0d2ea..b6cc2af60 100644 --- a/src/Magnum/Shaders/PhongGL.h +++ b/src/Magnum/Shaders/PhongGL.h @@ -32,11 +32,17 @@ * @m_since_latest */ +#include + #include "Magnum/GL/AbstractShaderProgram.h" #include "Magnum/Shaders/GenericGL.h" #include "Magnum/Shaders/glShaderWrapper.h" #include "Magnum/Shaders/visibility.h" +#ifndef MAGNUM_TARGET_GLES2 +#include +#endif + namespace Magnum { namespace Shaders { /** @@ -2301,7 +2307,7 @@ class PhongGL::CompileState: public PhongGL { #ifndef MAGNUM_TARGET_GLES , GL::Version version #endif - ): PhongGL{std::move(shader)}, _vert{std::move(vert)}, _frag{std::move(frag)} + ): PhongGL{Utility::move(shader)}, _vert{Utility::move(vert)}, _frag{Utility::move(frag)} #ifndef MAGNUM_TARGET_GLES , _version{version} #endif diff --git a/src/Magnum/Shaders/VectorGL.cpp b/src/Magnum/Shaders/VectorGL.cpp index 1a733d8c4..b04b64f15 100644 --- a/src/Magnum/Shaders/VectorGL.cpp +++ b/src/Magnum/Shaders/VectorGL.cpp @@ -39,7 +39,8 @@ #include "Magnum/Math/Matrix4.h" #ifndef MAGNUM_TARGET_GLES2 -#include +#include +#include #include "Magnum/GL/Buffer.h" #endif @@ -110,7 +111,7 @@ template typename VectorGL::CompileState Vec .addSource(dimensions == 2 ? "#define TWO_DIMENSIONS\n" : "#define THREE_DIMENSIONS\n"); #ifndef MAGNUM_TARGET_GLES2 if(configuration.flags() >= Flag::UniformBuffers) { - vert.addSource(Utility::formatString( + vert.addSource(Utility::format( "#define UNIFORM_BUFFERS\n" "#define DRAW_COUNT {}\n", configuration.drawCount())); @@ -121,7 +122,7 @@ template typename VectorGL::CompileState Vec .addSource(rs.getString("Vector.vert")); #ifndef MAGNUM_TARGET_GLES2 if(configuration.flags() >= Flag::UniformBuffers) { - frag.addSource(Utility::formatString( + frag.addSource(Utility::format( "#define UNIFORM_BUFFERS\n" "#define DRAW_COUNT {}\n" "#define MATERIAL_COUNT {}\n", diff --git a/src/Magnum/Shaders/VectorGL.h b/src/Magnum/Shaders/VectorGL.h index d4ee04a3d..a88600c90 100644 --- a/src/Magnum/Shaders/VectorGL.h +++ b/src/Magnum/Shaders/VectorGL.h @@ -31,6 +31,8 @@ * @m_since_latest */ +#include + #include "Magnum/DimensionTraits.h" #include "Magnum/GL/AbstractShaderProgram.h" #include "Magnum/Shaders/GenericGL.h" @@ -702,7 +704,7 @@ template class VectorGL::CompileState: publi #ifndef MAGNUM_TARGET_GLES , GL::Version version #endif - ): VectorGL{std::move(shader)}, _vert{std::move(vert)}, _frag{std::move(frag)} + ): VectorGL{Utility::move(shader)}, _vert{Utility::move(vert)}, _frag{Utility::move(frag)} #ifndef MAGNUM_TARGET_GLES , _version{version} #endif diff --git a/src/Magnum/Shaders/VertexColorGL.cpp b/src/Magnum/Shaders/VertexColorGL.cpp index e2b995587..d1018559c 100644 --- a/src/Magnum/Shaders/VertexColorGL.cpp +++ b/src/Magnum/Shaders/VertexColorGL.cpp @@ -37,7 +37,8 @@ #include "Magnum/Math/Matrix4.h" #ifndef MAGNUM_TARGET_GLES2 -#include +#include +#include #include "Magnum/GL/Buffer.h" #endif @@ -100,7 +101,7 @@ template typename VertexColorGL::CompileStat vert.addSource(dimensions == 2 ? "#define TWO_DIMENSIONS\n" : "#define THREE_DIMENSIONS\n"); #ifndef MAGNUM_TARGET_GLES2 if(configuration.flags() >= Flag::UniformBuffers) { - vert.addSource(Utility::formatString( + vert.addSource(Utility::format( "#define UNIFORM_BUFFERS\n" "#define DRAW_COUNT {}\n", configuration.drawCount())); diff --git a/src/Magnum/Shaders/VertexColorGL.h b/src/Magnum/Shaders/VertexColorGL.h index a45d0cc6e..ec86062c3 100644 --- a/src/Magnum/Shaders/VertexColorGL.h +++ b/src/Magnum/Shaders/VertexColorGL.h @@ -31,6 +31,8 @@ * @m_since_latest */ +#include + #include "Magnum/DimensionTraits.h" #include "Magnum/GL/AbstractShaderProgram.h" #include "Magnum/Shaders/GenericGL.h" @@ -519,7 +521,7 @@ template class VertexColorGL::CompileState: #ifndef MAGNUM_TARGET_GLES , GL::Version version #endif - ): VertexColorGL{std::move(shader)}, _vert{std::move(vert)}, _frag{std::move(frag)} + ): VertexColorGL{Utility::move(shader)}, _vert{Utility::move(vert)}, _frag{Utility::move(frag)} #ifndef MAGNUM_TARGET_GLES , _version{version} #endif diff --git a/src/Magnum/TextureTools/DistanceField.cpp b/src/Magnum/TextureTools/DistanceField.cpp index 841ead75a..6fd8cd1b3 100644 --- a/src/Magnum/TextureTools/DistanceField.cpp +++ b/src/Magnum/TextureTools/DistanceField.cpp @@ -26,7 +26,8 @@ #include "DistanceField.h" #include -#include +#include +#include #include #include "Magnum/Math/Range.h" @@ -101,7 +102,7 @@ DistanceFieldShader::DistanceFieldShader(const UnsignedInt radius) { vert.addSource(rs.getString("FullScreenTriangle.glsl")) .addSource(rs.getString("DistanceFieldShader.vert")); - frag.addSource(Utility::formatString("#define RADIUS {}\n", radius)) + frag.addSource(Utility::format("#define RADIUS {}\n", radius)) .addSource(rs.getString("DistanceFieldShader.frag")); CORRADE_INTERNAL_ASSERT_OUTPUT(vert.compile() && frag.compile());