Browse Source

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<std::string> (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 <hugo.amiard@wonderlandengine.com>
pull/499/head
Vladimír Vondruš 3 years ago
parent
commit
db2cb49279
  1. 6
      doc/changelog.dox
  2. 2
      doc/snippets/MagnumGL.cpp
  3. 5
      doc/snippets/MagnumShaders-gl.cpp
  4. 1
      src/Magnum/DebugTools/TextureImage.cpp
  5. 121
      src/Magnum/GL/AbstractShaderProgram.cpp
  6. 86
      src/Magnum/GL/AbstractShaderProgram.h
  7. 6
      src/Magnum/GL/Implementation/ShaderProgramState.h
  8. 6
      src/Magnum/GL/Implementation/ShaderState.h
  9. 153
      src/Magnum/GL/Shader.cpp
  10. 90
      src/Magnum/GL/Shader.h
  11. 122
      src/Magnum/GL/Test/AbstractShaderProgramGLTest.cpp
  12. 70
      src/Magnum/GL/Test/MeshGLTest.cpp
  13. 1
      src/Magnum/GL/Test/PrimitiveQueryGLTest.cpp
  14. 141
      src/Magnum/GL/Test/ShaderGLTest.cpp
  15. 79
      src/Magnum/GL/Test/TransformFeedbackGLTest.cpp
  16. 7
      src/Magnum/Shaders/DistanceFieldVectorGL.cpp
  17. 4
      src/Magnum/Shaders/DistanceFieldVectorGL.h
  18. 11
      src/Magnum/Shaders/FlatGL.cpp
  19. 8
      src/Magnum/Shaders/FlatGL.h
  20. 1
      src/Magnum/Shaders/Implementation/CreateCompatibilityShader.h
  21. 18
      src/Magnum/Shaders/MeshVisualizerGL.cpp
  22. 13
      src/Magnum/Shaders/MeshVisualizerGL.h
  23. 18
      src/Magnum/Shaders/PhongGL.cpp
  24. 8
      src/Magnum/Shaders/PhongGL.h
  25. 7
      src/Magnum/Shaders/VectorGL.cpp
  26. 4
      src/Magnum/Shaders/VectorGL.h
  27. 5
      src/Magnum/Shaders/VertexColorGL.cpp
  28. 4
      src/Magnum/Shaders/VertexColorGL.h
  29. 5
      src/Magnum/TextureTools/DistanceField.cpp

6
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()},

2
doc/snippets/MagnumGL.cpp

@ -27,6 +27,8 @@
#include <Corrade/Containers/ArrayViewStl.h>
#include <Corrade/Containers/Iterable.h>
#include <Corrade/Containers/Reference.h>
#include <Corrade/Containers/StringIterable.h>
#include <Corrade/Containers/StringView.h>
#include <Corrade/Containers/Triple.h>
#include <Corrade/TestSuite/Tester.h>

5
doc/snippets/MagnumShaders-gl.cpp

@ -28,7 +28,8 @@
#include <Corrade/Containers/ArrayViewStl.h>
#include <Corrade/Containers/Iterable.h>
#include <Corrade/Containers/Pair.h>
#include <Corrade/Utility/FormatStl.h>
#include <Corrade/Containers/String.h>
#include <Corrade/Utility/Format.h>
#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,

1
src/Magnum/DebugTools/TextureImage.cpp

@ -37,7 +37,6 @@
#if defined(MAGNUM_TARGET_GLES) && !defined(MAGNUM_TARGET_GLES2)
#include <Corrade/Containers/Iterable.h>
#include <Corrade/Containers/Reference.h>
#include <Corrade/Containers/StringStl.h> /** @todo remove once GL::Shader is <string>-free */
#include <Corrade/Utility/Resource.h>
#include "Magnum/GL/AbstractShaderProgram.h"

121
src/Magnum/GL/AbstractShaderProgram.cpp

@ -29,16 +29,12 @@
#include <Corrade/Containers/Array.h>
#include <Corrade/Containers/Iterable.h>
#include <Corrade/Containers/StridedArrayView.h>
#ifndef MAGNUM_TARGET_WEBGL
#include <Corrade/Containers/String.h>
#endif
#include <Corrade/Containers/StringStl.h> /** @todo remove once <string>-free */
#ifdef MAGNUM_BUILD_DEPRECATED
#include <Corrade/Containers/Reference.h>
#endif
#include <Corrade/Utility/DebugStl.h>
#include <Corrade/Utility/String.h>
#include <Corrade/Containers/StridedArrayView.h>
#include <Corrade/Containers/String.h>
#include <Corrade/Containers/StringIterable.h>
#include "Magnum/GL/Context.h"
#include "Magnum/GL/Extensions.h"
@ -343,7 +339,7 @@ AbstractShaderProgram& AbstractShaderProgram::setLabel(const Containers::StringV
}
#endif
std::pair<bool, std::string> AbstractShaderProgram::validate() {
std::pair<bool, Containers::String> AbstractShaderProgram::validate() {
glValidateProgram(_id);
/* Check validation status */
@ -351,18 +347,21 @@ std::pair<bool, std::string> 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<Shader>& sh
for(Shader& s: shaders) attachShader(s);
}
void AbstractShaderProgram::bindAttributeLocationInternal(const UnsignedInt location, const Containers::ArrayView<const char> 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<const char> 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<const char> 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<const std::string> 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<std::string> outputs, const TransformFeedbackBufferMode bufferMode) {
setTransformFeedbackOutputs(Containers::arrayView(outputs), bufferMode);
}
void AbstractShaderProgram::transformFeedbackVaryingsImplementationDefault(const Containers::ArrayView<const std::string> outputs, const TransformFeedbackBufferMode bufferMode) {
/** @todo VLAs */
Containers::Array<const char*> 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<Containers::String> nameData;
Containers::ArrayView<const char*> 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<const std::string> 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<Containers::String> nameData;
Containers::ArrayView<const char*> 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>& 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<const char> 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<const char> 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

86
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 <string>
#include <Corrade/Containers/ArrayView.h>
#include "Magnum/Tags.h"
#include "Magnum/GL/AbstractObject.h"
#include "Magnum/GL/GL.h"
#if defined(CORRADE_TARGET_WINDOWS) && !defined(MAGNUM_TARGET_GLES2)
#include <vector>
#include <Corrade/Containers/ArrayTuple.h>
#endif
#ifdef MAGNUM_BUILD_DEPRECATED
@ -47,8 +44,14 @@
/* For attachShaders(), which used to take a std::initializer_list<Reference>,
and draw({MeshView}) as well */
#include <Corrade/Containers/Iterable.h>
/* 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 <Corrade/Containers/StringStl.h>
/* For setTransformFeedbackOutputs(), which used to take
std::initializer_list<std::string>. Usually people passed C string literals,
so it should convert directly to a StringIterable. */
#include <Corrade/Containers/StringIterable.h>
#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<bool, std::string> validate();
std::pair<bool, Containers::String> 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<std::size_t size> 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<std::size_t size> 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<std::size_t size> 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<const std::string> outputs, TransformFeedbackBufferMode bufferMode);
void setTransformFeedbackOutputs(std::initializer_list<std::string> 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<std::size_t size> 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<std::size_t size> 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<const char> name);
#ifndef MAGNUM_TARGET_GLES
void bindFragmentDataLocationIndexedInternal(UnsignedInt location, UnsignedInt index, Containers::ArrayView<const char> name);
void bindFragmentDataLocationInternal(UnsignedInt location, Containers::ArrayView<const char> name);
#endif
Int uniformLocationInternal(Containers::ArrayView<const char> name);
UnsignedInt uniformBlockIndexInternal(Containers::ArrayView<const char> name);
#ifndef MAGNUM_TARGET_GLES2
void MAGNUM_GL_LOCAL transformFeedbackVaryingsImplementationDefault(Containers::ArrayView<const std::string> 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<const std::string> 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<std::string> _transformFeedbackVaryingNames;
Containers::ArrayTuple _transformFeedbackVaryingNames;
#endif
};

6
src/Magnum/GL/Implementation/ShaderProgramState.h

@ -27,8 +27,6 @@
DEALINGS IN THE SOFTWARE.
*/
#include <Corrade/Utility/StlForwardString.h>
#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<const std::string>, 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);

6
src/Magnum/GL/Implementation/ShaderState.h

@ -26,8 +26,6 @@
DEALINGS IN THE SOFTWARE.
*/
#include <Corrade/Utility/StlForwardString.h>
#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);

153
src/Magnum/GL/Shader.cpp

@ -27,16 +27,15 @@
#include "Shader.h"
#include <Corrade/Containers/Array.h>
#include <Corrade/Containers/GrowableArray.h>
#ifdef MAGNUM_BUILD_DEPRECATED
#include <Corrade/Containers/Reference.h>
#endif
#ifndef MAGNUM_TARGET_WEBGL
#include <Corrade/Containers/String.h>
#endif
#include <Corrade/Containers/StringStl.h> /** @todo remove once Shader is <string>-free */
#include <Corrade/Containers/StringIterable.h>
#include <Corrade/Utility/Assert.h>
#include <Corrade/Utility/Debug.h>
#include <Corrade/Utility/DebugStl.h>
#include <Corrade/Utility/Format.h>
#include <Corrade/Utility/Path.h>
#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<std::string> 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<Containers::String> string = Utility::Path::readString(filename);
Shader& Shader::addFile(const Containers::StringView filename) {
Containers::Optional<Containers::String> 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

90
src/Magnum/GL/Shader.h

@ -30,9 +30,7 @@
* @brief Class @ref Magnum::GL::Shader
*/
#include <string>
#include <vector>
#include <Corrade/Containers/ArrayView.h>
#include <Corrade/Containers/Array.h>
#include "Magnum/Tags.h"
#include "Magnum/GL/AbstractObject.h"
@ -40,8 +38,8 @@
#ifdef MAGNUM_BUILD_DEPRECATED
#include <Corrade/Utility/Macros.h>
/* 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 <Corrade/Containers/StringStl.h>
#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<std::string> 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<class U, class = typename std::enable_if<std::is_same<U&&, Containers::String&&>::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<std::string> _sources;
Containers::Array<Containers::String> _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;

122
src/Magnum/GL/Test/AbstractShaderProgramGLTest.cpp

@ -28,7 +28,7 @@
#include <Corrade/Containers/Iterable.h>
#include <Corrade/Containers/Reference.h>
#include <Corrade/Containers/StridedArrayView.h>
#include <Corrade/Containers/StringStl.h> /** @todo remove once Debug is stream-free */
#include <Corrade/Containers/StringStl.h> /* StringHasPrefix / StringHasSuffix */
#include <Corrade/TestSuite/Compare/Container.h>
#include <Corrade/TestSuite/Compare/Numeric.h>
#include <Corrade/TestSuite/Compare/String.h>
@ -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<GL::Extensions::EXT::gpu_shader4>())
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<GL::Extensions::EXT::gpu_shader4>())
CORRADE_SKIP(GL::Extensions::EXT::gpu_shader4::string() << "is not supported.");
if(!GL::Context::current().isExtensionSupported<GL::Extensions::ARB::blend_func_extended>())
@ -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<bool, std::string> result = program.validate();
std::pair<bool, Containers::String> 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<GL::Extensions::ARB::uniform_buffer_object>())
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 {

70
src/Magnum/GL/Test/MeshGLTest.cpp

@ -27,6 +27,7 @@
#include <sstream>
#include <Corrade/Containers/Iterable.h>
#include <Corrade/Containers/StridedArrayView.h>
#include <Corrade/Containers/StringView.h>
#include <Corrade/TestSuite/Compare/Numeric.h>
#include <Corrade/Utility/DebugStl.h>
#include <Corrade/Utility/FormatStl.h>
@ -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());

1
src/Magnum/GL/Test/PrimitiveQueryGLTest.cpp

@ -24,6 +24,7 @@
*/
#include <Corrade/Containers/Reference.h>
#include <Corrade/Containers/StringIterable.h>
#include <Corrade/Utility/Assert.h>
#include <Corrade/Utility/Resource.h>

141
src/Magnum/GL/Test/ShaderGLTest.cpp

@ -26,7 +26,9 @@
#include <sstream>
#include <Corrade/Containers/String.h>
#include <Corrade/Containers/StringStl.h> /** @todo remove once Shader is <string>-free */
#include <Corrade/Containers/StringIterable.h>
#include <Corrade/Containers/StringStl.h> /* StringHasPrefix / StringHasSuffix */
#include <Corrade/TestSuite/Compare/Container.h>
#include <Corrade/TestSuite/Compare/String.h>
#include <Corrade/Utility/DebugStl.h>
#include <Corrade/Utility/System.h>
@ -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<std::string>{"#version 130\n"});
CORRADE_COMPARE_AS(shader.sources(),
Containers::StringIterable{"#version 130\n"},
TestSuite::Compare::Container);
#else
CORRADE_COMPARE(shader.sources(), std::vector<std::string>{"#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<std::string>{"#version 130\n"});
CORRADE_COMPARE_AS(b.sources(),
Containers::StringIterable{"#version 130\n"},
TestSuite::Compare::Container);
#else
CORRADE_COMPARE(b.sources(), std::vector<std::string>{"#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<std::string>{"#version 130\n"});
CORRADE_COMPARE_AS(c.sources(),
Containers::StringIterable{"#version 130\n"},
TestSuite::Compare::Container);
#else
CORRADE_COMPARE(c.sources(), std::vector<std::string>{"#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<Shader>::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<std::string>{
"#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<std::string>{
"#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<std::string>{
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<std::string>{
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<std::string>{
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<std::string>{
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() {

79
src/Magnum/GL/Test/TransformFeedbackGLTest.cpp

@ -25,7 +25,10 @@
#include <Corrade/Containers/Iterable.h>
#include <Corrade/Containers/Reference.h>
#include <Corrade/Containers/String.h>
#include <Corrade/Containers/StringIterable.h>
#include <Corrade/Containers/Triple.h>
#include <Corrade/Utility/Format.h>
#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 <Corrade/Containers/String.h>
#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<Extensions::ARB::transform_feedback3>())
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<const Vector2>(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<const Vector2>(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(

7
src/Magnum/Shaders/DistanceFieldVectorGL.cpp

@ -39,7 +39,8 @@
#include "Magnum/Math/Matrix4.h"
#ifndef MAGNUM_TARGET_GLES2
#include <Corrade/Utility/FormatStl.h>
#include <Corrade/Containers/String.h>
#include <Corrade/Utility/Format.h>
#include "Magnum/GL/Buffer.h"
#endif
@ -110,7 +111,7 @@ template<UnsignedInt dimensions> typename DistanceFieldVectorGL<dimensions>::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<UnsignedInt dimensions> typename DistanceFieldVectorGL<dimensions>::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",

4
src/Magnum/Shaders/DistanceFieldVectorGL.h

@ -31,6 +31,8 @@
* @m_since_latest
*/
#include <Corrade/Utility/Move.h>
#include "Magnum/DimensionTraits.h"
#include "Magnum/GL/AbstractShaderProgram.h"
#include "Magnum/Shaders/GenericGL.h"
@ -752,7 +754,7 @@ template<UnsignedInt dimensions> class DistanceFieldVectorGL<dimensions>::Compil
#ifndef MAGNUM_TARGET_GLES
, GL::Version version
#endif
): DistanceFieldVectorGL<dimensions>{std::move(shader)}, _vert{std::move(vert)}, _frag{std::move(frag)}
): DistanceFieldVectorGL<dimensions>{Utility::move(shader)}, _vert{Utility::move(vert)}, _frag{Utility::move(frag)}
#ifndef MAGNUM_TARGET_GLES
, _version{version}
#endif

11
src/Magnum/Shaders/FlatGL.cpp

@ -41,7 +41,8 @@
#include "Magnum/Shaders/Implementation/CreateCompatibilityShader.h"
#ifndef MAGNUM_TARGET_GLES2
#include <Corrade/Utility/FormatStl.h>
#include <Corrade/Containers/String.h>
#include <Corrade/Utility/Format.h>
#include "Magnum/GL/Buffer.h"
#include "Magnum/GL/TextureArray.h"
@ -178,7 +179,7 @@ template<UnsignedInt dimensions> typename FlatGL<dimensions>::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<UnsignedInt dimensions> typename FlatGL<dimensions>::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<UnsignedInt dimensions> typename FlatGL<dimensions>::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<UnsignedInt dimensions> typename FlatGL<dimensions>::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",

8
src/Magnum/Shaders/FlatGL.h

@ -31,12 +31,18 @@
* @m_since_latest
*/
#include <Corrade/Utility/Move.h>
#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 <initializer_list>
#endif
namespace Magnum { namespace Shaders {
namespace Implementation {
@ -1520,7 +1526,7 @@ template<UnsignedInt dimensions> class FlatGL<dimensions>::CompileState: public
#ifndef MAGNUM_TARGET_GLES
, GL::Version version
#endif
): FlatGL<dimensions>{std::move(shader)}, _vert{std::move(vert)}, _frag{std::move(frag)}
): FlatGL<dimensions>{Utility::move(shader)}, _vert{Utility::move(vert)}, _frag{Utility::move(frag)}
#ifndef MAGNUM_TARGET_GLES
, _version{version}
#endif

1
src/Magnum/Shaders/Implementation/CreateCompatibilityShader.h

@ -25,7 +25,6 @@
DEALINGS IN THE SOFTWARE.
*/
#include <Corrade/Containers/StringStl.h> /** @todo remove when Shader is <string>-free */
#include <Corrade/Containers/StringView.h>
#include <Corrade/Utility/Resource.h>

18
src/Magnum/Shaders/MeshVisualizerGL.cpp

@ -28,7 +28,6 @@
#include <Corrade/Containers/EnumSet.hpp>
#include <Corrade/Containers/Iterable.h>
#include <Corrade/Utility/FormatStl.h>
#include <Corrade/Utility/Resource.h>
#include "Magnum/Math/Color.h"
@ -40,6 +39,9 @@
#include "Magnum/GL/Texture.h"
#ifndef MAGNUM_TARGET_GLES2
#include <Corrade/Containers/String.h>
#include <Corrade/Utility/Format.h>
#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"

13
src/Magnum/Shaders/MeshVisualizerGL.h

@ -31,6 +31,7 @@
* @m_since_latest
*/
#include <Corrade/Utility/Move.h>
#include <Corrade/Utility/Utility.h>
#include "Magnum/DimensionTraits.h"
@ -39,6 +40,10 @@
#include "Magnum/Shaders/glShaderWrapper.h"
#include "Magnum/Shaders/visibility.h"
#ifndef MAGNUM_TARGET_GLES2
#include <initializer_list>
#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
}

18
src/Magnum/Shaders/PhongGL.cpp

@ -32,8 +32,8 @@
#endif
#include <Corrade/Containers/EnumSet.hpp>
#include <Corrade/Containers/Iterable.h>
#include <Corrade/Containers/StringView.h>
#include <Corrade/Utility/FormatStl.h>
#include <Corrade/Containers/String.h>
#include <Corrade/Utility/Format.h>
#include <Corrade/Utility/Resource.h>
#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"

8
src/Magnum/Shaders/PhongGL.h

@ -32,11 +32,17 @@
* @m_since_latest
*/
#include <Corrade/Utility/Move.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 <initializer_list>
#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

7
src/Magnum/Shaders/VectorGL.cpp

@ -39,7 +39,8 @@
#include "Magnum/Math/Matrix4.h"
#ifndef MAGNUM_TARGET_GLES2
#include <Corrade/Utility/FormatStl.h>
#include <Corrade/Containers/String.h>
#include <Corrade/Utility/Format.h>
#include "Magnum/GL/Buffer.h"
#endif
@ -110,7 +111,7 @@ template<UnsignedInt dimensions> typename VectorGL<dimensions>::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<UnsignedInt dimensions> typename VectorGL<dimensions>::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",

4
src/Magnum/Shaders/VectorGL.h

@ -31,6 +31,8 @@
* @m_since_latest
*/
#include <Corrade/Utility/Move.h>
#include "Magnum/DimensionTraits.h"
#include "Magnum/GL/AbstractShaderProgram.h"
#include "Magnum/Shaders/GenericGL.h"
@ -702,7 +704,7 @@ template<UnsignedInt dimensions> class VectorGL<dimensions>::CompileState: publi
#ifndef MAGNUM_TARGET_GLES
, GL::Version version
#endif
): VectorGL<dimensions>{std::move(shader)}, _vert{std::move(vert)}, _frag{std::move(frag)}
): VectorGL<dimensions>{Utility::move(shader)}, _vert{Utility::move(vert)}, _frag{Utility::move(frag)}
#ifndef MAGNUM_TARGET_GLES
, _version{version}
#endif

5
src/Magnum/Shaders/VertexColorGL.cpp

@ -37,7 +37,8 @@
#include "Magnum/Math/Matrix4.h"
#ifndef MAGNUM_TARGET_GLES2
#include <Corrade/Utility/FormatStl.h>
#include <Corrade/Containers/String.h>
#include <Corrade/Utility/Format.h>
#include "Magnum/GL/Buffer.h"
#endif
@ -100,7 +101,7 @@ template<UnsignedInt dimensions> typename VertexColorGL<dimensions>::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()));

4
src/Magnum/Shaders/VertexColorGL.h

@ -31,6 +31,8 @@
* @m_since_latest
*/
#include <Corrade/Utility/Move.h>
#include "Magnum/DimensionTraits.h"
#include "Magnum/GL/AbstractShaderProgram.h"
#include "Magnum/Shaders/GenericGL.h"
@ -519,7 +521,7 @@ template<UnsignedInt dimensions> class VertexColorGL<dimensions>::CompileState:
#ifndef MAGNUM_TARGET_GLES
, GL::Version version
#endif
): VertexColorGL<dimensions>{std::move(shader)}, _vert{std::move(vert)}, _frag{std::move(frag)}
): VertexColorGL<dimensions>{Utility::move(shader)}, _vert{Utility::move(vert)}, _frag{Utility::move(frag)}
#ifndef MAGNUM_TARGET_GLES
, _version{version}
#endif

5
src/Magnum/TextureTools/DistanceField.cpp

@ -26,7 +26,8 @@
#include "DistanceField.h"
#include <Corrade/Containers/Iterable.h>
#include <Corrade/Utility/FormatStl.h>
#include <Corrade/Containers/String.h>
#include <Corrade/Utility/Format.h>
#include <Corrade/Utility/Resource.h>
#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());

Loading…
Cancel
Save