Browse Source

Shaders: add SSBO support to all shaders.

For when there's so much to render that it wouldn't fit into an UBO and
splitting draw calls and binding buffers under an offset is unwanted
overhead.
pull/617/head
Vladimír Vondruš 3 years ago
parent
commit
b38d3eea89
  1. 7
      doc/changelog.dox
  2. 5
      doc/shaders.dox
  3. 2
      package/archlinux/PKGBUILD
  4. 2
      package/archlinux/PKGBUILD-coverage
  5. 37
      src/Magnum/Shaders/DistanceFieldVector.frag
  6. 158
      src/Magnum/Shaders/DistanceFieldVectorGL.cpp
  7. 54
      src/Magnum/Shaders/DistanceFieldVectorGL.h
  8. 37
      src/Magnum/Shaders/Flat.frag
  9. 49
      src/Magnum/Shaders/Flat.vert
  10. 186
      src/Magnum/Shaders/FlatGL.cpp
  11. 71
      src/Magnum/Shaders/FlatGL.h
  12. 37
      src/Magnum/Shaders/Line.frag
  13. 43
      src/Magnum/Shaders/Line.vert
  14. 151
      src/Magnum/Shaders/LineGL.cpp
  15. 55
      src/Magnum/Shaders/LineGL.h
  16. 37
      src/Magnum/Shaders/MeshVisualizer.frag
  17. 33
      src/Magnum/Shaders/MeshVisualizer.geom
  18. 72
      src/Magnum/Shaders/MeshVisualizer.vert
  19. 325
      src/Magnum/Shaders/MeshVisualizerGL.cpp
  20. 139
      src/Magnum/Shaders/MeshVisualizerGL.h
  21. 48
      src/Magnum/Shaders/Phong.frag
  22. 55
      src/Magnum/Shaders/Phong.vert
  23. 222
      src/Magnum/Shaders/PhongGL.cpp
  24. 85
      src/Magnum/Shaders/PhongGL.h
  25. 179
      src/Magnum/Shaders/Test/DistanceFieldVectorGLTest.cpp
  26. 22
      src/Magnum/Shaders/Test/DistanceFieldVectorGL_Test.cpp
  27. 757
      src/Magnum/Shaders/Test/FlatGLTest.cpp
  28. 25
      src/Magnum/Shaders/Test/FlatGL_Test.cpp
  29. 358
      src/Magnum/Shaders/Test/LineGLTest.cpp
  30. 17
      src/Magnum/Shaders/Test/LineGL_Test.cpp
  31. 867
      src/Magnum/Shaders/Test/MeshVisualizerGLTest.cpp
  32. 39
      src/Magnum/Shaders/Test/MeshVisualizerGL_Test.cpp
  33. 615
      src/Magnum/Shaders/Test/PhongGLTest.cpp
  34. 36
      src/Magnum/Shaders/Test/PhongGL_Test.cpp
  35. 179
      src/Magnum/Shaders/Test/VectorGLTest.cpp
  36. 22
      src/Magnum/Shaders/Test/VectorGL_Test.cpp
  37. 179
      src/Magnum/Shaders/Test/VertexColorGLTest.cpp
  38. 22
      src/Magnum/Shaders/Test/VertexColorGL_Test.cpp
  39. 37
      src/Magnum/Shaders/Vector.frag
  40. 32
      src/Magnum/Shaders/Vector.vert
  41. 158
      src/Magnum/Shaders/VectorGL.cpp
  42. 54
      src/Magnum/Shaders/VectorGL.h
  43. 26
      src/Magnum/Shaders/VertexColor.vert
  44. 86
      src/Magnum/Shaders/VertexColorGL.cpp
  45. 36
      src/Magnum/Shaders/VertexColorGL.h

7
doc/changelog.dox

@ -278,9 +278,10 @@ See also:
[mosra/magnum#601](https://github.com/mosra/magnum/pull/601) and
[mosra/magnum#610](https://github.com/mosra/magnum/pull/610).
- All builtin shaders now have opt-in support for uniform buffers on desktop,
OpenGL ES 3.0+ and WebGL 2.0, including multi-draw functionality for
massive driver overhead reduction. The @ref shaders overview page was
updated with an introduction the new features.
OpenGL ES 3.0+ and WebGL 2.0, as well as shader storage buffers on desktop
and ES 3.1+. This includes multi-draw functionality for massive driver
overhead reduction. The @ref shaders overview page was updated with an
introduction to the new features.
- All builtin shaders now have opt-in capability of
@ref shaders-async "async compilation and linking" (see
[mosra/magnum534](https://github.com/mosra/magnum/issues/534) and

5
doc/shaders.dox

@ -207,6 +207,11 @@ like this, uniform upload and binding is the same as before:
fit into the limit. For convenience, all uniform structures are guaranteed
to fit evenly into multiples of 768 bytes, which should be large enough for
even the strictest @ref GL::Buffer::uniformOffsetAlignment() requirements.
@par
An alternative solution to overcome the size limits is to enable @relativeref{Shaders::PhongGL,Flag::ShaderStorageBuffers} instead
(available on OpenGL 4.3+ and OpenGL ES 3.1+), which have no size limits.
The cost is narrower platform support and potentially slower access
compared to uniform buffers.
@subsection shaders-usage-instancing Instancing

2
package/archlinux/PKGBUILD

@ -74,7 +74,7 @@ check() {
MAGNUM_DISABLE_EXTENSIONS="GL_ARB_direct_state_access" ctest -C $config --output-on-failure -j9 -R GLTest
MAGNUM_DISABLE_EXTENSIONS="GL_ARB_get_texture_sub_image" ctest -C $config --output-on-failure -j9 -R GLTest
MAGNUM_DISABLE_EXTENSIONS="GL_ARB_vertex_array_object" ctest -C $config --output-on-failure -j9 -R GLTest
MAGNUM_DISABLE_EXTENSIONS="GL_ARB_uniform_buffer_object" ctest -C $config --output-on-failure -j9 -R GLTest
MAGNUM_DISABLE_EXTENSIONS="GL_ARB_uniform_buffer_object GL_ARB_shader_storage_buffer_object" ctest -C $config --output-on-failure -j9 -R GLTest
MAGNUM_DISABLE_EXTENSIONS="GL_KHR_debug" ctest -C $config --output-on-failure -j9 -R GLTest
# Run all Vulkan tests with llvmpipe as well

2
package/archlinux/PKGBUILD-coverage

@ -74,7 +74,7 @@ check() {
MAGNUM_DISABLE_EXTENSIONS="GL_ARB_direct_state_access GL_ARB_robustness GL_ARB_multi_bind" ctest --output-on-failure -j9 -R GLTest || true
MAGNUM_DISABLE_EXTENSIONS="GL_ARB_get_texture_sub_image" ctest --output-on-failure -j9 -R GLTest || true
MAGNUM_DISABLE_EXTENSIONS="GL_ARB_vertex_array_object" ctest --output-on-failure -j9 -R GLTest || true
MAGNUM_DISABLE_EXTENSIONS="GL_ARB_uniform_buffer_object" ctest --output-on-failure -j9 -R GLTest || true
MAGNUM_DISABLE_EXTENSIONS="GL_ARB_uniform_buffer_object GL_ARB_shader_storage_buffer_object" ctest --output-on-failure -j9 -R GLTest || true
MAGNUM_DISABLE_EXTENSIONS="GL_KHR_debug" ctest --output-on-failure -j9 -R GLTest || true
# Run all Vulkan tests with llvmpipe as well

37
src/Magnum/Shaders/DistanceFieldVector.frag

@ -23,6 +23,10 @@
DEALINGS IN THE SOFTWARE.
*/
#if defined(SHADER_STORAGE_BUFFERS) && !defined(GL_ES)
#extension GL_ARB_shader_storage_buffer_object: require
#endif
#ifndef NEW_GLSL
#define in varying
#define fragmentColor gl_FragColor
@ -68,11 +72,24 @@ uniform lowp float smoothness
#endif
;
/* Uniform buffers */
/* Uniform / shader storage buffers */
#else
/* For SSBOs, the per-draw and material arrays are unbounded */
#ifdef SHADER_STORAGE_BUFFERS
#define DRAW_COUNT
#define MATERIAL_COUNT
#define BUFFER_OR_UNIFORM buffer
#define BUFFER_READONLY readonly
#else
#define BUFFER_OR_UNIFORM uniform
#define BUFFER_READONLY
#endif
#ifndef MULTI_DRAW
#if DRAW_COUNT > 1
/* With SSBOs DRAW_COUNT is defined to be empty, +0 makes the condition not
cause a compile error */
#if defined(SHADER_STORAGE_BUFFERS) || DRAW_COUNT+0 > 1
#ifdef EXPLICIT_UNIFORM_LOCATION
layout(location = 0)
#endif
@ -93,11 +110,11 @@ struct DrawUniform {
};
layout(std140
#ifdef EXPLICIT_BINDING
#if defined(EXPLICIT_BINDING) || defined(SHADER_STORAGE_BUFFERS)
, binding = 2
#endif
) uniform Draw {
DrawUniform draws[DRAW_COUNT];
) BUFFER_OR_UNIFORM Draw {
BUFFER_READONLY DrawUniform draws[DRAW_COUNT];
};
struct MaterialUniform {
@ -110,11 +127,11 @@ struct MaterialUniform {
};
layout(std140
#ifdef EXPLICIT_BINDING
#if defined(EXPLICIT_BINDING) || defined(SHADER_STORAGE_BUFFERS)
, binding = 4
#endif
) uniform Material {
MaterialUniform materials[MATERIAL_COUNT];
) BUFFER_OR_UNIFORM Material {
BUFFER_READONLY MaterialUniform materials[MATERIAL_COUNT];
};
#endif
@ -144,7 +161,9 @@ out lowp vec4 fragmentColor;
void main() {
#ifdef UNIFORM_BUFFERS
#if MATERIAL_COUNT > 1
/* With SSBOs MATERIAL_COUNT is defined to be empty, +0 makes the condition
not cause a compile error */
#if defined(SHADER_STORAGE_BUFFERS) || MATERIAL_COUNT+0 > 1
mediump const uint materialId = draws[drawId].draw_materialIdReserved & 0xffffu;
#else
#define materialId 0u

158
src/Magnum/Shaders/DistanceFieldVectorGL.cpp

@ -68,17 +68,31 @@ namespace {
}
template<UnsignedInt dimensions> typename DistanceFieldVectorGL<dimensions>::CompileState DistanceFieldVectorGL<dimensions>::compile(const Configuration& configuration) {
#ifndef MAGNUM_TARGET_GLES2
CORRADE_ASSERT(!(configuration.flags() >= Flag::UniformBuffers) || configuration.materialCount(),
"Shaders::DistanceFieldVectorGL: material count can't be zero", CompileState{NoCreate});
CORRADE_ASSERT(!(configuration.flags() >= Flag::UniformBuffers) || configuration.drawCount(),
"Shaders::DistanceFieldVectorGL: draw count can't be zero", CompileState{NoCreate});
#if !defined(MAGNUM_TARGET_GLES2) && !defined(CORRADE_NO_ASSERT)
#ifndef MAGNUM_TARGET_WEBGL
if(!(configuration.flags() >= Flag::ShaderStorageBuffers))
#endif
{
CORRADE_ASSERT(!(configuration.flags() >= Flag::UniformBuffers) || configuration.materialCount(),
"Shaders::DistanceFieldVectorGL: material count can't be zero", CompileState{NoCreate});
CORRADE_ASSERT(!(configuration.flags() >= Flag::UniformBuffers) || configuration.drawCount(),
"Shaders::DistanceFieldVectorGL: draw count can't be zero", CompileState{NoCreate});
}
#endif
#ifndef MAGNUM_TARGET_GLES
if(configuration.flags() >= Flag::UniformBuffers)
MAGNUM_ASSERT_GL_EXTENSION_SUPPORTED(GL::Extensions::ARB::uniform_buffer_object);
#endif
#if !defined(MAGNUM_TARGET_GLES2) && !defined(MAGNUM_TARGET_WEBGL)
if(configuration.flags() >= Flag::ShaderStorageBuffers) {
#ifndef MAGNUM_TARGET_GLES
MAGNUM_ASSERT_GL_EXTENSION_SUPPORTED(GL::Extensions::ARB::shader_storage_buffer_object);
#else
MAGNUM_ASSERT_GL_VERSION_SUPPORTED(GL::Version::GLES310);
#endif
}
#endif
#ifndef MAGNUM_TARGET_GLES2
if(configuration.flags() >= Flag::MultiDraw) {
#ifndef MAGNUM_TARGET_GLES
@ -115,10 +129,21 @@ template<UnsignedInt dimensions> typename DistanceFieldVectorGL<dimensions>::Com
.addSource(dimensions == 2 ? "#define TWO_DIMENSIONS\n"_s : "#define THREE_DIMENSIONS\n"_s);
#ifndef MAGNUM_TARGET_GLES2
if(configuration.flags() >= Flag::UniformBuffers) {
vert.addSource(Utility::format(
"#define UNIFORM_BUFFERS\n"
"#define DRAW_COUNT {}\n",
configuration.drawCount()));
#ifndef MAGNUM_TARGET_WEBGL
/* SSBOs have unbounded per-draw arrays so just a plain string can be
passed */
if(configuration.flags() >= Flag::ShaderStorageBuffers) {
vert.addSource(
"#define UNIFORM_BUFFERS\n"
"#define SHADER_STORAGE_BUFFERS\n"_s);
} else
#endif
{
vert.addSource(Utility::format(
"#define UNIFORM_BUFFERS\n"
"#define DRAW_COUNT {}\n",
configuration.drawCount()));
}
vert.addSource(configuration.flags() >= Flag::MultiDraw ? "#define MULTI_DRAW\n"_s : ""_s);
}
#endif
@ -129,12 +154,23 @@ template<UnsignedInt dimensions> typename DistanceFieldVectorGL<dimensions>::Com
GL::Shader frag = Implementation::createCompatibilityShader(rs, version, GL::Shader::Type::Fragment);
#ifndef MAGNUM_TARGET_GLES2
if(configuration.flags() >= Flag::UniformBuffers) {
frag.addSource(Utility::format(
"#define UNIFORM_BUFFERS\n"
"#define MATERIAL_COUNT {}\n"
"#define DRAW_COUNT {}\n",
configuration.materialCount(),
configuration.drawCount()));
#ifndef MAGNUM_TARGET_WEBGL
/* SSBOs have unbounded per-draw and material arrays so just a plain
string can be passed */
if(configuration.flags() >= Flag::ShaderStorageBuffers) {
frag.addSource(
"#define UNIFORM_BUFFERS\n"
"#define SHADER_STORAGE_BUFFERS\n"_s);
} else
#endif
{
frag.addSource(Utility::format(
"#define UNIFORM_BUFFERS\n"
"#define MATERIAL_COUNT {}\n"
"#define DRAW_COUNT {}\n",
configuration.materialCount(),
configuration.drawCount()));
}
frag.addSource(configuration.flags() >= Flag::MultiDraw ? "#define MULTI_DRAW\n"_s : ""_s);
}
#endif
@ -204,7 +240,11 @@ template<UnsignedInt dimensions> DistanceFieldVectorGL<dimensions>::DistanceFiel
{
#ifndef MAGNUM_TARGET_GLES2
if(_flags >= Flag::UniformBuffers) {
if(_drawCount > 1) _drawOffsetUniform = uniformLocation("drawOffset"_s);
if(_drawCount > 1
#ifndef MAGNUM_TARGET_WEBGL
|| flags() >= Flag::ShaderStorageBuffers
#endif
) _drawOffsetUniform = uniformLocation("drawOffset"_s);
} else
#endif
{
@ -226,7 +266,12 @@ template<UnsignedInt dimensions> DistanceFieldVectorGL<dimensions>::DistanceFiel
{
setUniform(uniformLocation("vectorTexture"_s), TextureUnit);
#ifndef MAGNUM_TARGET_GLES2
if(_flags >= Flag::UniformBuffers) {
/* SSBOs have bindings defined in the source always */
if(_flags >= Flag::UniformBuffers
#ifndef MAGNUM_TARGET_WEBGL
&& !(_flags >= Flag::ShaderStorageBuffers)
#endif
) {
setUniformBlockBinding(uniformBlockIndex("TransformationProjection"_s), TransformationProjectionBufferBinding);
setUniformBlockBinding(uniformBlockIndex("Draw"_s), DrawBufferBinding);
setUniformBlockBinding(uniformBlockIndex("Material"_s), MaterialBufferBinding);
@ -331,37 +376,62 @@ template<UnsignedInt dimensions> DistanceFieldVectorGL<dimensions>& DistanceFiel
template<UnsignedInt dimensions> DistanceFieldVectorGL<dimensions>& DistanceFieldVectorGL<dimensions>::setDrawOffset(const UnsignedInt offset) {
CORRADE_ASSERT(_flags >= Flag::UniformBuffers,
"Shaders::DistanceFieldVectorGL::setDrawOffset(): the shader was not created with uniform buffers enabled", *this);
#ifndef MAGNUM_TARGET_WEBGL
CORRADE_ASSERT(_flags >= Flag::ShaderStorageBuffers || offset < _drawCount,
"Shaders::DistanceFieldVectorGL::setDrawOffset(): draw offset" << offset << "is out of bounds for" << _drawCount << "draws", *this);
#else
CORRADE_ASSERT(offset < _drawCount,
"Shaders::DistanceFieldVectorGL::setDrawOffset(): draw offset" << offset << "is out of bounds for" << _drawCount << "draws", *this);
if(_drawCount > 1) setUniform(_drawOffsetUniform, offset);
#endif
if(_drawCount > 1
#ifndef MAGNUM_TARGET_WEBGL
|| _flags >= Flag::ShaderStorageBuffers
#endif
) setUniform(_drawOffsetUniform, offset);
return *this;
}
template<UnsignedInt dimensions> DistanceFieldVectorGL<dimensions>& DistanceFieldVectorGL<dimensions>::bindTransformationProjectionBuffer(GL::Buffer& buffer) {
CORRADE_ASSERT(_flags >= Flag::UniformBuffers,
"Shaders::DistanceFieldVectorGL::bindTransformationProjectionBuffer(): the shader was not created with uniform buffers enabled", *this);
buffer.bind(GL::Buffer::Target::Uniform, TransformationProjectionBufferBinding);
buffer.bind(
#ifndef MAGNUM_TARGET_WEBGL
_flags >= Flag::ShaderStorageBuffers ? GL::Buffer::Target::ShaderStorage :
#endif
GL::Buffer::Target::Uniform, TransformationProjectionBufferBinding);
return *this;
}
template<UnsignedInt dimensions> DistanceFieldVectorGL<dimensions>& DistanceFieldVectorGL<dimensions>::bindTransformationProjectionBuffer(GL::Buffer& buffer, const GLintptr offset, const GLsizeiptr size) {
CORRADE_ASSERT(_flags >= Flag::UniformBuffers,
"Shaders::DistanceFieldVectorGL::bindTransformationProjectionBuffer(): the shader was not created with uniform buffers enabled", *this);
buffer.bind(GL::Buffer::Target::Uniform, TransformationProjectionBufferBinding, offset, size);
buffer.bind(
#ifndef MAGNUM_TARGET_WEBGL
_flags >= Flag::ShaderStorageBuffers ? GL::Buffer::Target::ShaderStorage :
#endif
GL::Buffer::Target::Uniform, TransformationProjectionBufferBinding, offset, size);
return *this;
}
template<UnsignedInt dimensions> DistanceFieldVectorGL<dimensions>& DistanceFieldVectorGL<dimensions>::bindDrawBuffer(GL::Buffer& buffer) {
CORRADE_ASSERT(_flags >= Flag::UniformBuffers,
"Shaders::DistanceFieldVectorGL::bindDrawBuffer(): the shader was not created with uniform buffers enabled", *this);
buffer.bind(GL::Buffer::Target::Uniform, DrawBufferBinding);
buffer.bind(
#ifndef MAGNUM_TARGET_WEBGL
_flags >= Flag::ShaderStorageBuffers ? GL::Buffer::Target::ShaderStorage :
#endif
GL::Buffer::Target::Uniform, DrawBufferBinding);
return *this;
}
template<UnsignedInt dimensions> DistanceFieldVectorGL<dimensions>& DistanceFieldVectorGL<dimensions>::bindDrawBuffer(GL::Buffer& buffer, const GLintptr offset, const GLsizeiptr size) {
CORRADE_ASSERT(_flags >= Flag::UniformBuffers,
"Shaders::DistanceFieldVectorGL::bindDrawBuffer(): the shader was not created with uniform buffers enabled", *this);
buffer.bind(GL::Buffer::Target::Uniform, DrawBufferBinding, offset, size);
buffer.bind(
#ifndef MAGNUM_TARGET_WEBGL
_flags >= Flag::ShaderStorageBuffers ? GL::Buffer::Target::ShaderStorage :
#endif
GL::Buffer::Target::Uniform, DrawBufferBinding, offset, size);
return *this;
}
@ -370,7 +440,11 @@ template<UnsignedInt dimensions> DistanceFieldVectorGL<dimensions>& DistanceFiel
"Shaders::DistanceFieldVectorGL::bindTextureTransformationBuffer(): the shader was not created with uniform buffers enabled", *this);
CORRADE_ASSERT(_flags & Flag::TextureTransformation,
"Shaders::DistanceFieldVectorGL::bindTextureTransformationBuffer(): the shader was not created with texture transformation enabled", *this);
buffer.bind(GL::Buffer::Target::Uniform, TextureTransformationBufferBinding);
buffer.bind(
#ifndef MAGNUM_TARGET_WEBGL
_flags >= Flag::ShaderStorageBuffers ? GL::Buffer::Target::ShaderStorage :
#endif
GL::Buffer::Target::Uniform, TextureTransformationBufferBinding);
return *this;
}
@ -379,21 +453,33 @@ template<UnsignedInt dimensions> DistanceFieldVectorGL<dimensions>& DistanceFiel
"Shaders::DistanceFieldVectorGL::bindTextureTransformationBuffer(): the shader was not created with uniform buffers enabled", *this);
CORRADE_ASSERT(_flags & Flag::TextureTransformation,
"Shaders::DistanceFieldVectorGL::bindTextureTransformationBuffer(): the shader was not created with texture transformation enabled", *this);
buffer.bind(GL::Buffer::Target::Uniform, TextureTransformationBufferBinding, offset, size);
buffer.bind(
#ifndef MAGNUM_TARGET_WEBGL
_flags >= Flag::ShaderStorageBuffers ? GL::Buffer::Target::ShaderStorage :
#endif
GL::Buffer::Target::Uniform, TextureTransformationBufferBinding, offset, size);
return *this;
}
template<UnsignedInt dimensions> DistanceFieldVectorGL<dimensions>& DistanceFieldVectorGL<dimensions>::bindMaterialBuffer(GL::Buffer& buffer) {
CORRADE_ASSERT(_flags >= Flag::UniformBuffers,
"Shaders::DistanceFieldVectorGL::bindMaterialBuffer(): the shader was not created with uniform buffers enabled", *this);
buffer.bind(GL::Buffer::Target::Uniform, MaterialBufferBinding);
buffer.bind(
#ifndef MAGNUM_TARGET_WEBGL
_flags >= Flag::ShaderStorageBuffers ? GL::Buffer::Target::ShaderStorage :
#endif
GL::Buffer::Target::Uniform, MaterialBufferBinding);
return *this;
}
template<UnsignedInt dimensions> DistanceFieldVectorGL<dimensions>& DistanceFieldVectorGL<dimensions>::bindMaterialBuffer(GL::Buffer& buffer, const GLintptr offset, const GLsizeiptr size) {
CORRADE_ASSERT(_flags >= Flag::UniformBuffers,
"Shaders::DistanceFieldVectorGL::bindMaterialBuffer(): the shader was not created with uniform buffers enabled", *this);
buffer.bind(GL::Buffer::Target::Uniform, MaterialBufferBinding, offset, size);
buffer.bind(
#ifndef MAGNUM_TARGET_WEBGL
_flags >= Flag::ShaderStorageBuffers ? GL::Buffer::Target::ShaderStorage :
#endif
GL::Buffer::Target::Uniform, MaterialBufferBinding, offset, size);
return *this;
}
#endif
@ -409,6 +495,14 @@ template class MAGNUM_SHADERS_EXPORT DistanceFieldVectorGL<3>;
namespace Implementation {
Debug& operator<<(Debug& debug, const DistanceFieldVectorGLFlag value) {
#if !defined(MAGNUM_TARGET_GLES2) && !defined(MAGNUM_TARGET_WEBGL)
/* Special case coming from the Flags printer. As both flags are a superset
of UniformBuffers, printing just one would result in
`Flag::MultiDraw|Flag(0x8)` in the output. */
if(value == DistanceFieldVectorGLFlag(UnsignedByte(DistanceFieldVectorGLFlag::MultiDraw|DistanceFieldVectorGLFlag::ShaderStorageBuffers)))
return debug << DistanceFieldVectorGLFlag::MultiDraw << Debug::nospace << "|" << Debug::nospace << DistanceFieldVectorGLFlag::ShaderStorageBuffers;
#endif
debug << "Shaders::DistanceFieldVectorGL::Flag" << Debug::nospace;
switch(value) {
@ -417,6 +511,9 @@ Debug& operator<<(Debug& debug, const DistanceFieldVectorGLFlag value) {
_c(TextureTransformation)
#ifndef MAGNUM_TARGET_GLES2
_c(UniformBuffers)
#ifndef MAGNUM_TARGET_WEBGL
_c(ShaderStorageBuffers)
#endif
_c(MultiDraw)
#endif
#undef _c
@ -430,7 +527,16 @@ Debug& operator<<(Debug& debug, const DistanceFieldVectorGLFlags value) {
return Containers::enumSetDebugOutput(debug, value, "Shaders::DistanceFieldVectorGL::Flags{}", {
DistanceFieldVectorGLFlag::TextureTransformation,
#ifndef MAGNUM_TARGET_GLES2
#ifndef MAGNUM_TARGET_WEBGL
/* Both are a superset of UniformBuffers, meaning printing just one
would result in `Flag::MultiDraw|Flag(0x8)` in the output. So we
pass both and let the Flag printer deal with that. */
DistanceFieldVectorGLFlag(UnsignedByte(DistanceFieldVectorGLFlag::MultiDraw|DistanceFieldVectorGLFlag::ShaderStorageBuffers)),
#endif
DistanceFieldVectorGLFlag::MultiDraw, /* Superset of UniformBuffers */
#ifndef MAGNUM_TARGET_WEBGL
DistanceFieldVectorGLFlag::ShaderStorageBuffers, /* Superset of UniformBuffers */
#endif
DistanceFieldVectorGLFlag::UniformBuffers
#endif
});

54
src/Magnum/Shaders/DistanceFieldVectorGL.h

@ -46,6 +46,9 @@ namespace Implementation {
TextureTransformation = 1 << 0,
#ifndef MAGNUM_TARGET_GLES2
UniformBuffers = 1 << 1,
#ifndef MAGNUM_TARGET_WEBGL
ShaderStorageBuffers = UniformBuffers|(1 << 3),
#endif
MultiDraw = UniformBuffers|(1 << 2)
#endif
};
@ -178,6 +181,7 @@ template<UnsignedInt dimensions> class MAGNUM_SHADERS_EXPORT DistanceFieldVector
* @ref bindTransformationProjectionBuffer(),
* @ref bindDrawBuffer(), @ref bindTextureTransformationBuffer(),
* and @ref bindMaterialBuffer() instead of direct uniform setters.
* @see @ref Flag::ShaderStorageBuffers
* @requires_gl31 Extension @gl_extension{ARB,uniform_buffer_object}
* @requires_gles30 Uniform buffers are not available in OpenGL ES
* 2.0.
@ -187,6 +191,23 @@ template<UnsignedInt dimensions> class MAGNUM_SHADERS_EXPORT DistanceFieldVector
*/
UniformBuffers = 1 << 1,
#ifndef MAGNUM_TARGET_WEBGL
/**
* Use shader storage buffers. Superset of functionality provided
* by @ref Flag::UniformBuffers, compared to it doesn't have any
* size limits on @ref Configuration::setMaterialCount() and
* @relativeref{Configuration,setDrawCount()} in exchange for
* potentially more costly access and narrower platform support.
* @requires_gl43 Extension @gl_extension{ARB,shader_storage_buffer_object}
* @requires_gles31 Shader storage buffers are not available in
* OpenGL ES 3.0 and older.
* @requires_gles Shader storage buffers are not available in
* WebGL.
* @m_since_latest
*/
ShaderStorageBuffers = UniformBuffers|(1 << 3),
#endif
/**
* Enable multidraw functionality. Implies @ref Flag::UniformBuffers
* and adds the value from @ref setDrawOffset() with the
@ -344,7 +365,7 @@ template<UnsignedInt dimensions> class MAGNUM_SHADERS_EXPORT DistanceFieldVector
* Statically defined size of the
* @ref DistanceFieldVectorMaterialUniform uniform buffer bound with
* @ref bindMaterialBuffer(). Has use only if @ref Flag::UniformBuffers
* is set.
* is set and @ref Flag::ShaderStorageBuffers is not set.
* @see @ref Configuration::setMaterialCount()
* @requires_gles30 Not defined on OpenGL ES 2.0 builds.
* @requires_webgl20 Not defined on WebGL 1.0 builds.
@ -362,7 +383,8 @@ template<UnsignedInt dimensions> class MAGNUM_SHADERS_EXPORT DistanceFieldVector
* @ref TextureTransformationUniform uniform buffers bound with
* @ref bindTransformationProjectionBuffer(), @ref bindDrawBuffer() and
* @ref bindTextureTransformationBuffer(). Has use only if
* @ref Flag::UniformBuffers is set.
* @ref Flag::UniformBuffers is set and @ref Flag::ShaderStorageBuffers
* is not set.
* @see @ref Configuration::setDrawCount()
* @requires_gles30 Not defined on OpenGL ES 2.0 builds.
* @requires_webgl20 Not defined on WebGL 1.0 builds.
@ -472,7 +494,7 @@ template<UnsignedInt dimensions> class MAGNUM_SHADERS_EXPORT DistanceFieldVector
#ifndef MAGNUM_TARGET_GLES2
/** @{
* @name Uniform buffer binding and related uniform setters
* @name Uniform / shader storage buffer binding and related uniform setters
*
* Used if @ref Flag::UniformBuffers is set.
*/
@ -504,7 +526,7 @@ template<UnsignedInt dimensions> class MAGNUM_SHADERS_EXPORT DistanceFieldVector
DistanceFieldVectorGL<dimensions>& setDrawOffset(UnsignedInt offset);
/**
* @brief Bind a transformation and projection uniform buffer
* @brief Bind a transformation and projection uniform / shader storage buffer
* @return Reference to self (for method chaining)
* @m_since_latest
*
@ -525,7 +547,7 @@ template<UnsignedInt dimensions> class MAGNUM_SHADERS_EXPORT DistanceFieldVector
DistanceFieldVectorGL<dimensions>& bindTransformationProjectionBuffer(GL::Buffer& buffer, GLintptr offset, GLsizeiptr size);
/**
* @brief Bind a draw uniform buffer
* @brief Bind a draw uniform / shader storage buffer
* @return Reference to self (for method chaining)
* @m_since_latest
*
@ -546,7 +568,7 @@ template<UnsignedInt dimensions> class MAGNUM_SHADERS_EXPORT DistanceFieldVector
DistanceFieldVectorGL<dimensions>& bindDrawBuffer(GL::Buffer& buffer, GLintptr offset, GLsizeiptr size);
/**
* @brief Bind a texture transformation uniform buffer
* @brief Bind a texture transformation uniform / shader storage buffer
* @return Reference to self (for method chaining)
* @m_since_latest
*
@ -566,7 +588,7 @@ template<UnsignedInt dimensions> class MAGNUM_SHADERS_EXPORT DistanceFieldVector
DistanceFieldVectorGL<dimensions>& bindTextureTransformationBuffer(GL::Buffer& buffer, GLintptr offset, GLsizeiptr size);
/**
* @brief Bind a material uniform buffer
* @brief Bind a material uniform / shader storage buffer
* @return Reference to self (for method chaining)
* @m_since_latest
*
@ -675,11 +697,11 @@ template<UnsignedInt dimensions> class DistanceFieldVectorGL<dimensions>::Config
* @ref DistanceFieldVectorMaterialUniform buffer bound with
* @ref bindMaterialBuffer(). Uniform buffers have a statically defined
* size and @cpp count*sizeof(DistanceFieldVectorMaterialUniform) @ce
* has to be within @ref GL::AbstractShaderProgram::maxUniformBlockSize().
*
* The per-draw materials are then specified via
* @ref DistanceFieldVectorDrawUniform::materialId. Default value is
* @cpp 1 @ce.
* has to be within @ref GL::AbstractShaderProgram::maxUniformBlockSize(),
* if @ref Flag::ShaderStorageBuffers is set as well, the buffer is
* unbounded and @p count is ignored. The per-draw materials are
* specified via @ref DistanceFieldVectorDrawUniform::materialId.
* Default value is @cpp 1 @ce.
*
* If @ref Flag::UniformBuffers isn't set, this value is ignored.
* @see @ref setFlags(), @ref setDrawCount(),
@ -716,10 +738,10 @@ template<UnsignedInt dimensions> class DistanceFieldVectorGL<dimensions>::Config
* @cpp count*sizeof(TransformationProjectionUniform3D) @ce,
* @cpp count*sizeof(DistanceFieldVectorDrawUniform) @ce and
* @cpp count*sizeof(TextureTransformationUniform) @ce has to be within
* @ref GL::AbstractShaderProgram::maxUniformBlockSize().
*
* The draw offset is then set via @ref setDrawOffset(). Default value
* is @cpp 1 @ce.
* @ref GL::AbstractShaderProgram::maxUniformBlockSize(), if
* @ref Flag::ShaderStorageBuffers is set as well, the buffers are
* unbounded and @p count is ignored. The draw offset is set via
* @ref setDrawOffset(). Default value is @cpp 1 @ce.
*
* If @ref Flag::UniformBuffers isn't set, this value is ignored.
* @see @ref setFlags(), @ref setMaterialCount(),

37
src/Magnum/Shaders/Flat.frag

@ -27,6 +27,10 @@
#extension GL_EXT_gpu_shader4: require
#endif
#if defined(SHADER_STORAGE_BUFFERS) && !defined(GL_ES)
#extension GL_ARB_shader_storage_buffer_object: require
#endif
#ifndef NEW_GLSL
#define fragmentColor gl_FragColor
#define texture texture2D
@ -68,11 +72,24 @@ layout(location = 5)
uniform highp uint objectId; /* defaults to zero */
#endif
/* Uniform buffers */
/* Uniform / shader storage buffers */
#else
/* For SSBOs, the per-draw and material arrays are unbounded */
#ifdef SHADER_STORAGE_BUFFERS
#define DRAW_COUNT
#define MATERIAL_COUNT
#define BUFFER_OR_UNIFORM buffer
#define BUFFER_READONLY readonly
#else
#define BUFFER_OR_UNIFORM uniform
#define BUFFER_READONLY
#endif
#ifndef MULTI_DRAW
#if DRAW_COUNT > 1
/* With SSBOs DRAW_COUNT is defined to be empty, +0 makes the condition not
cause a compile error */
#if defined(SHADER_STORAGE_BUFFERS) || DRAW_COUNT+0 > 1
#ifdef EXPLICIT_UNIFORM_LOCATION
layout(location = 0)
#endif
@ -95,11 +112,11 @@ struct DrawUniform {
};
layout(std140
#ifdef EXPLICIT_BINDING
#if defined(EXPLICIT_BINDING) || defined(SHADER_STORAGE_BUFFERS)
, binding = 2
#endif
) uniform Draw {
DrawUniform draws[DRAW_COUNT];
) BUFFER_OR_UNIFORM Draw {
BUFFER_READONLY DrawUniform draws[DRAW_COUNT];
};
struct MaterialUniform {
@ -109,11 +126,11 @@ struct MaterialUniform {
};
layout(std140
#ifdef EXPLICIT_BINDING
#if defined(EXPLICIT_BINDING) || defined(SHADER_STORAGE_BUFFERS)
, binding = 4
#endif
) uniform Material {
MaterialUniform materials[MATERIAL_COUNT];
) BUFFER_OR_UNIFORM Material {
BUFFER_READONLY MaterialUniform materials[MATERIAL_COUNT];
};
#endif
@ -190,7 +207,9 @@ void main() {
#ifdef OBJECT_ID
highp const uint objectId = draws[drawId].draw_objectId;
#endif
#if MATERIAL_COUNT > 1
/* With SSBOs MATERIAL_COUNT is defined to be empty, +0 makes the condition
not cause a compile error */
#if defined(SHADER_STORAGE_BUFFERS) || MATERIAL_COUNT+0 > 1
mediump const uint materialId = draws[drawId].draw_materialIdReserved & 0xffffu;
#else
#define materialId 0u

49
src/Magnum/Shaders/Flat.vert

@ -31,6 +31,10 @@
#extension GL_ARB_shader_bit_encoding: require
#endif
#if defined(SHADER_STORAGE_BUFFERS) && !defined(GL_ES)
#extension GL_ARB_shader_storage_buffer_object: require
#endif
#ifdef MULTI_DRAW
#ifndef GL_ES
#extension GL_ARB_shader_draw_parameters: require
@ -128,10 +132,27 @@ layout(location = PER_INSTANCE_JOINT_COUNT_LOCATION)
uniform uint perInstanceJointCount; /* defaults to zero */
#endif
/* Uniform buffers */
/* Uniform / shader storage buffers */
#else
#if DRAW_COUNT > 1
/* For SSBOs, the per-draw and joint arrays are unbounded */
#ifdef SHADER_STORAGE_BUFFERS
#define DRAW_COUNT
/* Define JOINT_COUNT only if there are any per-vertex attributes, otherwise
the buffer would be useless */
#if defined(PER_VERTEX_JOINT_COUNT) || defined(SECONDARY_PER_VERTEX_JOINT_COUNT)
#define JOINT_COUNT
#endif
#define BUFFER_OR_UNIFORM buffer
#define BUFFER_READONLY readonly
#else
#define BUFFER_OR_UNIFORM uniform
#define BUFFER_READONLY
#endif
/* With SSBOs DRAW_COUNT is defined to be empty, +0 makes the condition not
cause a compile error */
#if defined(SHADER_STORAGE_BUFFERS) || DRAW_COUNT+0 > 1
#ifdef EXPLICIT_UNIFORM_LOCATION
layout(location = 0)
#endif
@ -152,19 +173,19 @@ struct DrawUniform {
};
layout(std140
#ifdef EXPLICIT_BINDING
#if defined(EXPLICIT_BINDING) || defined(SHADER_STORAGE_BUFFERS)
, binding = 2
#endif
) uniform Draw {
DrawUniform draws[DRAW_COUNT];
) BUFFER_OR_UNIFORM Draw {
BUFFER_READONLY DrawUniform draws[DRAW_COUNT];
};
layout(std140
#ifdef EXPLICIT_BINDING
#if defined(EXPLICIT_BINDING) || defined(SHADER_STORAGE_BUFFERS)
, binding = 1
#endif
) uniform TransformationProjection {
highp
) BUFFER_OR_UNIFORM TransformationProjection {
BUFFER_READONLY highp
#ifdef TWO_DIMENSIONS
/* Can't be a mat3 because of ANGLE, see DrawUniform in Phong.vert for
details */
@ -179,11 +200,11 @@ layout(std140
#ifdef JOINT_COUNT
layout(std140
#ifdef EXPLICIT_BINDING
#if defined(EXPLICIT_BINDING) || defined(SHADER_STORAGE_BUFFERS)
, binding = 6
#endif
) uniform Joint {
highp
) BUFFER_OR_UNIFORM Joint {
BUFFER_READONLY highp
#ifdef TWO_DIMENSIONS
/* Can't be a mat3 because of ANGLE, see DrawUniform in Phong.vert for
details */
@ -206,11 +227,11 @@ struct TextureTransformationUniform {
};
layout(std140
#ifdef EXPLICIT_BINDING
#if defined(EXPLICIT_BINDING) || defined(SHADER_STORAGE_BUFFERS)
, binding = 3
#endif
) uniform TextureTransformation {
TextureTransformationUniform textureTransformations[DRAW_COUNT];
) BUFFER_OR_UNIFORM TextureTransformation {
BUFFER_READONLY TextureTransformationUniform textureTransformations[DRAW_COUNT];
};
#endif
#endif

186
src/Magnum/Shaders/FlatGL.cpp

@ -89,11 +89,18 @@ template<UnsignedInt dimensions> typename FlatGL<dimensions>::CompileState FlatG
}
#endif
#ifndef MAGNUM_TARGET_GLES2
CORRADE_ASSERT(!(configuration.flags() >= Flag::UniformBuffers) || configuration.materialCount(),
"Shaders::FlatGL: material count can't be zero", CompileState{NoCreate});
CORRADE_ASSERT(!(configuration.flags() >= Flag::UniformBuffers) || configuration.drawCount(),
"Shaders::FlatGL: draw count can't be zero", CompileState{NoCreate});
#if !defined(MAGNUM_TARGET_GLES2) && !defined(CORRADE_NO_ASSERT)
#ifndef MAGNUM_TARGET_WEBGL
if(!(configuration.flags() >= Flag::ShaderStorageBuffers))
#endif
{
CORRADE_ASSERT(!configuration.jointCount() == (!configuration.perVertexJointCount() && !configuration.secondaryPerVertexJointCount()),
"Shaders::FlatGL: joint count can't be zero if per-vertex joint count is non-zero", CompileState{NoCreate});
CORRADE_ASSERT(!(configuration.flags() >= Flag::UniformBuffers) || configuration.materialCount(),
"Shaders::FlatGL: material count can't be zero", CompileState{NoCreate});
CORRADE_ASSERT(!(configuration.flags() >= Flag::UniformBuffers) || configuration.drawCount(),
"Shaders::FlatGL: draw count can't be zero", CompileState{NoCreate});
}
#endif
#ifndef MAGNUM_TARGET_GLES2
@ -116,6 +123,15 @@ template<UnsignedInt dimensions> typename FlatGL<dimensions>::CompileState FlatG
if(configuration.flags() >= Flag::UniformBuffers)
MAGNUM_ASSERT_GL_EXTENSION_SUPPORTED(GL::Extensions::ARB::uniform_buffer_object);
#endif
#if !defined(MAGNUM_TARGET_GLES2) && !defined(MAGNUM_TARGET_WEBGL)
if(configuration.flags() >= Flag::ShaderStorageBuffers) {
#ifndef MAGNUM_TARGET_GLES
MAGNUM_ASSERT_GL_EXTENSION_SUPPORTED(GL::Extensions::ARB::shader_storage_buffer_object);
#else
MAGNUM_ASSERT_GL_VERSION_SUPPORTED(GL::Version::GLES310);
#endif
}
#endif
#ifndef MAGNUM_TARGET_GLES2
if(configuration.flags() >= Flag::MultiDraw) {
#ifndef MAGNUM_TARGET_GLES
@ -210,9 +226,15 @@ template<UnsignedInt dimensions> typename FlatGL<dimensions>::CompileState FlatG
#endif
{
vert.addSource(Utility::format(
"#define JOINT_COUNT {}\n"
"#define PER_VERTEX_JOINT_COUNT {}u\n"
"#define SECONDARY_PER_VERTEX_JOINT_COUNT {}u\n",
/* SSBOs have an unbounded joints array */
#ifndef MAGNUM_TARGET_WEBGL
configuration.flags() >= Flag::ShaderStorageBuffers ?
"#define PER_VERTEX_JOINT_COUNT {1}u\n"
"#define SECONDARY_PER_VERTEX_JOINT_COUNT {2}u\n" :
#endif
"#define JOINT_COUNT {}\n"
"#define PER_VERTEX_JOINT_COUNT {1}u\n"
"#define SECONDARY_PER_VERTEX_JOINT_COUNT {2}u\n",
configuration.jointCount(),
configuration.perVertexJointCount(),
configuration.secondaryPerVertexJointCount()));
@ -222,7 +244,7 @@ template<UnsignedInt dimensions> typename FlatGL<dimensions>::CompileState FlatG
#ifndef MAGNUM_TARGET_WEBGL
/* The _LOCATION is needed only if explicit uniform location (desktop /
ES3.1) is supported, a plain string can be added otherwise. This is
an immediate uniform also in the UBO case. */
an immediate uniform also in the UBO / SSBO case. */
#ifndef MAGNUM_TARGET_GLES
if(context.isExtensionSupported<GL::Extensions::ARB::explicit_uniform_location>(version))
#else
@ -242,10 +264,21 @@ template<UnsignedInt dimensions> typename FlatGL<dimensions>::CompileState FlatG
#endif
#ifndef MAGNUM_TARGET_GLES2
if(configuration.flags() >= Flag::UniformBuffers) {
vert.addSource(Utility::format(
"#define UNIFORM_BUFFERS\n"
"#define DRAW_COUNT {}\n",
configuration.drawCount()));
#ifndef MAGNUM_TARGET_WEBGL
/* SSBOs have unbounded per-draw arrays so just a plain string can be
passed */
if(configuration.flags() >= Flag::ShaderStorageBuffers) {
vert.addSource(
"#define UNIFORM_BUFFERS\n"
"#define SHADER_STORAGE_BUFFERS\n"_s);
} else
#endif
{
vert.addSource(Utility::format(
"#define UNIFORM_BUFFERS\n"
"#define DRAW_COUNT {}\n",
configuration.drawCount()));
}
vert.addSource(configuration.flags() >= Flag::MultiDraw ? "#define MULTI_DRAW\n"_s : ""_s);
}
#endif
@ -268,12 +301,23 @@ template<UnsignedInt dimensions> typename FlatGL<dimensions>::CompileState FlatG
;
#ifndef MAGNUM_TARGET_GLES2
if(configuration.flags() >= Flag::UniformBuffers) {
frag.addSource(Utility::format(
"#define UNIFORM_BUFFERS\n"
"#define DRAW_COUNT {}\n"
"#define MATERIAL_COUNT {}\n",
configuration.drawCount(),
configuration.materialCount()));
#ifndef MAGNUM_TARGET_WEBGL
/* SSBOs have unbounded per-draw and material arrays so just a plain
string can be passed */
if(configuration.flags() >= Flag::ShaderStorageBuffers) {
frag.addSource(
"#define UNIFORM_BUFFERS\n"
"#define SHADER_STORAGE_BUFFERS\n"_s);
} else
#endif
{
frag.addSource(Utility::format(
"#define UNIFORM_BUFFERS\n"
"#define DRAW_COUNT {}\n"
"#define MATERIAL_COUNT {}\n",
configuration.drawCount(),
configuration.materialCount()));
}
frag.addSource(configuration.flags() >= Flag::MultiDraw ? "#define MULTI_DRAW\n"_s : ""_s);
}
#endif
@ -372,7 +416,11 @@ template<UnsignedInt dimensions> FlatGL<dimensions>::FlatGL(CompileState&& state
if(_flags >= Flag::DynamicPerVertexJointCount)
_perVertexJointCountUniform = uniformLocation("perVertexJointCount"_s);
if(_flags >= Flag::UniformBuffers) {
if(_drawCount > 1) _drawOffsetUniform = uniformLocation("drawOffset"_s);
if(_drawCount > 1
#ifndef MAGNUM_TARGET_WEBGL
|| flags() >= Flag::ShaderStorageBuffers
#endif
) _drawOffsetUniform = uniformLocation("drawOffset"_s);
} else
#endif
{
@ -406,7 +454,12 @@ template<UnsignedInt dimensions> FlatGL<dimensions>::FlatGL(CompileState&& state
if(_flags & Flag::Textured) setUniform(uniformLocation("textureData"_s), TextureUnit);
#ifndef MAGNUM_TARGET_GLES2
if(_flags >= Flag::ObjectIdTexture) setUniform(uniformLocation("objectIdTextureData"_s), ObjectIdTextureUnit);
if(_flags >= Flag::UniformBuffers) {
/* SSBOs have bindings defined in the source always */
if(_flags >= Flag::UniformBuffers
#ifndef MAGNUM_TARGET_WEBGL
&& !(_flags >= Flag::ShaderStorageBuffers)
#endif
) {
setUniformBlockBinding(uniformBlockIndex("TransformationProjection"_s), TransformationProjectionBufferBinding);
setUniformBlockBinding(uniformBlockIndex("Draw"_s), DrawBufferBinding);
if(_flags & Flag::TextureTransformation)
@ -571,37 +624,62 @@ template<UnsignedInt dimensions> FlatGL<dimensions>& FlatGL<dimensions>::setPerI
template<UnsignedInt dimensions> FlatGL<dimensions>& FlatGL<dimensions>::setDrawOffset(const UnsignedInt offset) {
CORRADE_ASSERT(_flags >= Flag::UniformBuffers,
"Shaders::FlatGL::setDrawOffset(): the shader was not created with uniform buffers enabled", *this);
#ifndef MAGNUM_TARGET_WEBGL
CORRADE_ASSERT(_flags >= Flag::ShaderStorageBuffers || offset < _drawCount,
"Shaders::FlatGL::setDrawOffset(): draw offset" << offset << "is out of bounds for" << _drawCount << "draws", *this);
#else
CORRADE_ASSERT(offset < _drawCount,
"Shaders::FlatGL::setDrawOffset(): draw offset" << offset << "is out of bounds for" << _drawCount << "draws", *this);
if(_drawCount > 1) setUniform(_drawOffsetUniform, offset);
#endif
if(_drawCount > 1
#ifndef MAGNUM_TARGET_WEBGL
|| _flags >= Flag::ShaderStorageBuffers
#endif
) setUniform(_drawOffsetUniform, offset);
return *this;
}
template<UnsignedInt dimensions> FlatGL<dimensions>& FlatGL<dimensions>::bindTransformationProjectionBuffer(GL::Buffer& buffer) {
CORRADE_ASSERT(_flags >= Flag::UniformBuffers,
"Shaders::FlatGL::bindTransformationProjectionBuffer(): the shader was not created with uniform buffers enabled", *this);
buffer.bind(GL::Buffer::Target::Uniform, TransformationProjectionBufferBinding);
buffer.bind(
#ifndef MAGNUM_TARGET_WEBGL
_flags >= Flag::ShaderStorageBuffers ? GL::Buffer::Target::ShaderStorage :
#endif
GL::Buffer::Target::Uniform, TransformationProjectionBufferBinding);
return *this;
}
template<UnsignedInt dimensions> FlatGL<dimensions>& FlatGL<dimensions>::bindTransformationProjectionBuffer(GL::Buffer& buffer, const GLintptr offset, const GLsizeiptr size) {
CORRADE_ASSERT(_flags >= Flag::UniformBuffers,
"Shaders::FlatGL::bindTransformationProjectionBuffer(): the shader was not created with uniform buffers enabled", *this);
buffer.bind(GL::Buffer::Target::Uniform, TransformationProjectionBufferBinding, offset, size);
buffer.bind(
#ifndef MAGNUM_TARGET_WEBGL
_flags >= Flag::ShaderStorageBuffers ? GL::Buffer::Target::ShaderStorage :
#endif
GL::Buffer::Target::Uniform, TransformationProjectionBufferBinding, offset, size);
return *this;
}
template<UnsignedInt dimensions> FlatGL<dimensions>& FlatGL<dimensions>::bindDrawBuffer(GL::Buffer& buffer) {
CORRADE_ASSERT(_flags >= Flag::UniformBuffers,
"Shaders::FlatGL::bindDrawBuffer(): the shader was not created with uniform buffers enabled", *this);
buffer.bind(GL::Buffer::Target::Uniform, DrawBufferBinding);
buffer.bind(
#ifndef MAGNUM_TARGET_WEBGL
_flags >= Flag::ShaderStorageBuffers ? GL::Buffer::Target::ShaderStorage :
#endif
GL::Buffer::Target::Uniform, DrawBufferBinding);
return *this;
}
template<UnsignedInt dimensions> FlatGL<dimensions>& FlatGL<dimensions>::bindDrawBuffer(GL::Buffer& buffer, const GLintptr offset, const GLsizeiptr size) {
CORRADE_ASSERT(_flags >= Flag::UniformBuffers,
"Shaders::FlatGL::bindDrawBuffer(): the shader was not created with uniform buffers enabled", *this);
buffer.bind(GL::Buffer::Target::Uniform, DrawBufferBinding, offset, size);
buffer.bind(
#ifndef MAGNUM_TARGET_WEBGL
_flags >= Flag::ShaderStorageBuffers ? GL::Buffer::Target::ShaderStorage :
#endif
GL::Buffer::Target::Uniform, DrawBufferBinding, offset, size);
return *this;
}
@ -610,7 +688,11 @@ template<UnsignedInt dimensions> FlatGL<dimensions>& FlatGL<dimensions>::bindTex
"Shaders::FlatGL::bindTextureTransformationBuffer(): the shader was not created with uniform buffers enabled", *this);
CORRADE_ASSERT(_flags & Flag::TextureTransformation,
"Shaders::FlatGL::bindTextureTransformationBuffer(): the shader was not created with texture transformation enabled", *this);
buffer.bind(GL::Buffer::Target::Uniform, TextureTransformationBufferBinding);
buffer.bind(
#ifndef MAGNUM_TARGET_WEBGL
_flags >= Flag::ShaderStorageBuffers ? GL::Buffer::Target::ShaderStorage :
#endif
GL::Buffer::Target::Uniform, TextureTransformationBufferBinding);
return *this;
}
@ -619,35 +701,55 @@ template<UnsignedInt dimensions> FlatGL<dimensions>& FlatGL<dimensions>::bindTex
"Shaders::FlatGL::bindTextureTransformationBuffer(): the shader was not created with uniform buffers enabled", *this);
CORRADE_ASSERT(_flags & Flag::TextureTransformation,
"Shaders::FlatGL::bindTextureTransformationBuffer(): the shader was not created with texture transformation enabled", *this);
buffer.bind(GL::Buffer::Target::Uniform, TextureTransformationBufferBinding, offset, size);
buffer.bind(
#ifndef MAGNUM_TARGET_WEBGL
_flags >= Flag::ShaderStorageBuffers ? GL::Buffer::Target::ShaderStorage :
#endif
GL::Buffer::Target::Uniform, TextureTransformationBufferBinding, offset, size);
return *this;
}
template<UnsignedInt dimensions> FlatGL<dimensions>& FlatGL<dimensions>::bindMaterialBuffer(GL::Buffer& buffer) {
CORRADE_ASSERT(_flags >= Flag::UniformBuffers,
"Shaders::FlatGL::bindMaterialBuffer(): the shader was not created with uniform buffers enabled", *this);
buffer.bind(GL::Buffer::Target::Uniform, MaterialBufferBinding);
buffer.bind(
#ifndef MAGNUM_TARGET_WEBGL
_flags >= Flag::ShaderStorageBuffers ? GL::Buffer::Target::ShaderStorage :
#endif
GL::Buffer::Target::Uniform, MaterialBufferBinding);
return *this;
}
template<UnsignedInt dimensions> FlatGL<dimensions>& FlatGL<dimensions>::bindMaterialBuffer(GL::Buffer& buffer, const GLintptr offset, const GLsizeiptr size) {
CORRADE_ASSERT(_flags >= Flag::UniformBuffers,
"Shaders::FlatGL::bindMaterialBuffer(): the shader was not created with uniform buffers enabled", *this);
buffer.bind(GL::Buffer::Target::Uniform, MaterialBufferBinding, offset, size);
buffer.bind(
#ifndef MAGNUM_TARGET_WEBGL
_flags >= Flag::ShaderStorageBuffers ? GL::Buffer::Target::ShaderStorage :
#endif
GL::Buffer::Target::Uniform, MaterialBufferBinding, offset, size);
return *this;
}
template<UnsignedInt dimensions> FlatGL<dimensions>& FlatGL<dimensions>::bindJointBuffer(GL::Buffer& buffer) {
CORRADE_ASSERT(_flags >= Flag::UniformBuffers,
"Shaders::FlatGL::bindJointBuffer(): the shader was not created with uniform buffers enabled", *this);
buffer.bind(GL::Buffer::Target::Uniform, JointBufferBinding);
buffer.bind(
#ifndef MAGNUM_TARGET_WEBGL
_flags >= Flag::ShaderStorageBuffers ? GL::Buffer::Target::ShaderStorage :
#endif
GL::Buffer::Target::Uniform, JointBufferBinding);
return *this;
}
template<UnsignedInt dimensions> FlatGL<dimensions>& FlatGL<dimensions>::bindJointBuffer(GL::Buffer& buffer, const GLintptr offset, const GLsizeiptr size) {
CORRADE_ASSERT(_flags >= Flag::UniformBuffers,
"Shaders::FlatGL::bindJointBuffer(): the shader was not created with uniform buffers enabled", *this);
buffer.bind(GL::Buffer::Target::Uniform, JointBufferBinding, offset, size);
buffer.bind(
#ifndef MAGNUM_TARGET_WEBGL
_flags >= Flag::ShaderStorageBuffers ? GL::Buffer::Target::ShaderStorage :
#endif
GL::Buffer::Target::Uniform, JointBufferBinding, offset, size);
return *this;
}
#endif
@ -702,8 +804,8 @@ template<UnsignedInt dimensions> typename FlatGL<dimensions>::Configuration& Fla
"Shaders::FlatGL::Configuration::setJointCount(): expected at most 4 per-vertex joints, got" << perVertexCount, *this);
CORRADE_ASSERT(secondaryPerVertexCount <= 4,
"Shaders::FlatGL::Configuration::setJointCount(): expected at most 4 secondary per-vertex joints, got" << secondaryPerVertexCount, *this);
CORRADE_ASSERT(!count == (!perVertexCount && !secondaryPerVertexCount),
"Shaders::FlatGL::Configuration::setJointCount(): count has to be non-zero iff (secondary) per-vertex joint count is non-zero", *this);
CORRADE_ASSERT(perVertexCount || secondaryPerVertexCount || !count,
"Shaders::FlatGL::Configuration::setJointCount(): count has to be zero if per-vertex joint count is zero", *this);
_jointCount = count;
_perVertexJointCount = perVertexCount;
_secondaryPerVertexJointCount = secondaryPerVertexCount;
@ -723,6 +825,11 @@ Debug& operator<<(Debug& debug, const FlatGLFlag value) {
`Flag::InstancedObjectId|Flag(0x800)` in the output. */
if(value == FlatGLFlag(UnsignedShort(FlatGLFlag::InstancedObjectId|FlatGLFlag::ObjectIdTexture)))
return debug << FlatGLFlag::InstancedObjectId << Debug::nospace << "|" << Debug::nospace << FlatGLFlag::ObjectIdTexture;
#ifndef MAGNUM_TARGET_WEBGL
/* Similarly here, both are a superset of UniformBuffers */
if(value == FlatGLFlag(UnsignedShort(FlatGLFlag::MultiDraw|FlatGLFlag::ShaderStorageBuffers)))
return debug << FlatGLFlag::MultiDraw << Debug::nospace << "|" << Debug::nospace << FlatGLFlag::ShaderStorageBuffers;
#endif
#endif
debug << "Shaders::FlatGL::Flag" << Debug::nospace;
@ -743,6 +850,9 @@ Debug& operator<<(Debug& debug, const FlatGLFlag value) {
_c(InstancedTextureOffset)
#ifndef MAGNUM_TARGET_GLES2
_c(UniformBuffers)
#ifndef MAGNUM_TARGET_WEBGL
_c(ShaderStorageBuffers)
#endif
_c(MultiDraw)
_c(TextureArrays)
_c(DynamicPerVertexJointCount)
@ -772,7 +882,15 @@ Debug& operator<<(Debug& debug, const FlatGLFlags value) {
#endif
FlatGLFlag::InstancedTransformation,
#ifndef MAGNUM_TARGET_GLES2
#ifndef MAGNUM_TARGET_WEBGL
/* Both are a superset of UniformBuffers; similarly to ObjectId above
letting the Flag printer deal with that */
FlatGLFlag(UnsignedShort(FlatGLFlag::MultiDraw|FlatGLFlag::ShaderStorageBuffers)),
#endif
FlatGLFlag::MultiDraw, /* Superset of UniformBuffers */
#ifndef MAGNUM_TARGET_WEBGL
FlatGLFlag::ShaderStorageBuffers, /* Superset of UniformBuffers */
#endif
FlatGLFlag::UniformBuffers,
FlatGLFlag::TextureArrays,
FlatGLFlag::DynamicPerVertexJointCount,

71
src/Magnum/Shaders/FlatGL.h

@ -60,6 +60,9 @@ namespace Implementation {
InstancedTextureOffset = (1 << 7)|TextureTransformation,
#ifndef MAGNUM_TARGET_GLES2
UniformBuffers = 1 << 8,
#ifndef MAGNUM_TARGET_WEBGL
ShaderStorageBuffers = UniformBuffers|(1 << 13),
#endif
MultiDraw = UniformBuffers|(1 << 9),
TextureArrays = 1 << 10,
DynamicPerVertexJointCount = 1 << 12
@ -597,6 +600,7 @@ template<UnsignedInt dimensions> class MAGNUM_SHADERS_EXPORT FlatGL: public GL::
* @ref bindTransformationProjectionBuffer(),
* @ref bindDrawBuffer(), @ref bindTextureTransformationBuffer()
* and @ref bindMaterialBuffer() instead of direct uniform setters.
* @see @ref Flag::ShaderStorageBuffers
* @requires_gl31 Extension @gl_extension{ARB,uniform_buffer_object}
* @requires_gles30 Uniform buffers are not available in OpenGL ES
* 2.0.
@ -606,6 +610,24 @@ template<UnsignedInt dimensions> class MAGNUM_SHADERS_EXPORT FlatGL: public GL::
*/
UniformBuffers = 1 << 8,
#ifndef MAGNUM_TARGET_WEBGL
/**
* Use shader storage buffers. Superset of functionality provided
* by @ref Flag::UniformBuffers, compared to it doesn't have any
* size limits on @ref Configuration::setJointCount(),
* @relativeref{Configuration,setMaterialCount()} and
* @relativeref{Configuration,setDrawCount()} in exchange for
* potentially more costly access and narrower platform support.
* @requires_gl43 Extension @gl_extension{ARB,shader_storage_buffer_object}
* @requires_gles31 Shader storage buffers are not available in
* OpenGL ES 3.0 and older.
* @requires_gles Shader storage buffers are not available in
* WebGL.
* @m_since_latest
*/
ShaderStorageBuffers = UniformBuffers|(1 << 13),
#endif
/**
* Enable multidraw functionality. Implies @ref Flag::UniformBuffers
* and adds the value from @ref setDrawOffset() with the
@ -804,7 +826,8 @@ template<UnsignedInt dimensions> class MAGNUM_SHADERS_EXPORT FlatGL: public GL::
* If @ref Flag::UniformBuffers is set, this is the statically defined
* size of the @ref TransformationUniform2D /
* @ref TransformationUniform3D uniform buffer bound with
* @ref bindJointBuffer().
* @ref bindJointBuffer(). Has no use if @ref Flag::ShaderStorageBuffers
* is set.
* @see @ref Configuration::setJointCount()
* @requires_gles30 Not defined on OpenGL ES 2.0 builds.
* @requires_webgl20 Not defined on WebGL 1.0 builds.
@ -843,7 +866,8 @@ template<UnsignedInt dimensions> class MAGNUM_SHADERS_EXPORT FlatGL: public GL::
*
* Statically defined size of the @ref FlatMaterialUniform uniform
* buffer bound with @ref bindMaterialBuffer(). Has use only if
* @ref Flag::UniformBuffers is set.
* @ref Flag::UniformBuffers is set and @ref Flag::ShaderStorageBuffers
* is not set.
* @see @ref Configuration::setMaterialCount()
* @requires_gles30 Not defined on OpenGL ES 2.0 builds.
* @requires_webgl20 Not defined on WebGL 1.0 builds.
@ -860,7 +884,8 @@ template<UnsignedInt dimensions> class MAGNUM_SHADERS_EXPORT FlatGL: public GL::
* @ref TextureTransformationUniform uniform buffers bound with
* @ref bindTransformationProjectionBuffer(), @ref bindDrawBuffer() and
* @ref bindTextureTransformationBuffer(). Has use only if
* @ref Flag::UniformBuffers is set.
* @ref Flag::UniformBuffers is set and @ref Flag::ShaderStorageBuffers
* is not set.
* @see @ref Configuration::setDrawCount()
* @requires_gles30 Not defined on OpenGL ES 2.0 builds.
* @requires_webgl20 Not defined on WebGL 1.0 builds.
@ -1097,7 +1122,7 @@ template<UnsignedInt dimensions> class MAGNUM_SHADERS_EXPORT FlatGL: public GL::
#ifndef MAGNUM_TARGET_GLES2
/** @{
* @name Uniform buffer binding and related uniform setters
* @name Uniform / shader storage buffer binding and related uniform setters
*
* Used if @ref Flag::UniformBuffers is set.
*/
@ -1128,7 +1153,7 @@ template<UnsignedInt dimensions> class MAGNUM_SHADERS_EXPORT FlatGL: public GL::
FlatGL<dimensions>& setDrawOffset(UnsignedInt offset);
/**
* @brief Bind a transformation and projection uniform buffer
* @brief Bind a transformation and projection uniform / shader storage buffer
* @return Reference to self (for method chaining)
* @m_since_latest
*
@ -1149,7 +1174,7 @@ template<UnsignedInt dimensions> class MAGNUM_SHADERS_EXPORT FlatGL: public GL::
FlatGL<dimensions>& bindTransformationProjectionBuffer(GL::Buffer& buffer, GLintptr offset, GLsizeiptr size);
/**
* @brief Bind a draw uniform buffer
* @brief Bind a draw uniform / shader storage buffer
* @return Reference to self (for method chaining)
* @m_since_latest
*
@ -1170,7 +1195,7 @@ template<UnsignedInt dimensions> class MAGNUM_SHADERS_EXPORT FlatGL: public GL::
FlatGL<dimensions>& bindDrawBuffer(GL::Buffer& buffer, GLintptr offset, GLsizeiptr size);
/**
* @brief Bind a texture transformation uniform buffer
* @brief Bind a texture transformation uniform / shader storage buffer
* @return Reference to self (for method chaining)
* @m_since_latest
*
@ -1190,7 +1215,7 @@ template<UnsignedInt dimensions> class MAGNUM_SHADERS_EXPORT FlatGL: public GL::
FlatGL<dimensions>& bindTextureTransformationBuffer(GL::Buffer& buffer, GLintptr offset, GLsizeiptr size);
/**
* @brief Bind a material uniform buffer
* @brief Bind a material uniform / shader storage buffer
* @return Reference to self (for method chaining)
* @m_since_latest
*
@ -1210,7 +1235,7 @@ template<UnsignedInt dimensions> class MAGNUM_SHADERS_EXPORT FlatGL: public GL::
FlatGL<dimensions>& bindMaterialBuffer(GL::Buffer& buffer, GLintptr offset, GLsizeiptr size);
/**
* @brief Bind a joint matrix uniform buffer
* @brief Bind a joint matrix uniform / shader storage buffer
* @return Reference to self (for method chaining)
* @m_since_latest
*
@ -1413,9 +1438,10 @@ template<UnsignedInt dimensions> class MAGNUM_SHADERS_EXPORT FlatGL<dimensions>:
* bound with @ref bindJointBuffer(). Uniform buffers have a statically
* defined size and @cpp count*sizeof(TransformationUniform2D) @ce /
* @cpp count*sizeof(TransformationUniform3D) @ce has to be within
* @ref GL::AbstractShaderProgram::maxUniformBlockSize(). The
* per-vertex joints then index into the array offset by
* @ref FlatDrawUniform::jointOffset.
* @ref GL::AbstractShaderProgram::maxUniformBlockSize(), if
* @ref Flag::ShaderStorageBuffers is set as well, the buffer is
* unbounded and @p count is ignored. The per-vertex joints index into
* the array offset by @ref FlatDrawUniform::jointOffset.
*
* The @p perVertexCount and @p secondaryPerVertexCount parameters
* describe how many components are taken from @ref JointIds /
@ -1424,8 +1450,8 @@ template<UnsignedInt dimensions> class MAGNUM_SHADERS_EXPORT FlatGL<dimensions>:
* @cpp 4 @ce, setting either of these to @cpp 0 @ce means given
* attribute is not used at all. If both @p perVertexCount and
* @p secondaryPerVertexCount are set to @cpp 0 @ce, skinning is not
* performed; if either of them is non-zero, @p count is expected to be
* non-zero as well.
* performed. Unless @ref Flag::ShaderStorageBuffers is set, if either
* of them is non-zero, @p count is expected to be non-zero as well.
*
* Default value for all three is @cpp 0 @ce.
* @see @ref FlatGL::jointCount(), @ref FlatGL::perVertexJointCount(),
@ -1455,10 +1481,11 @@ template<UnsignedInt dimensions> class MAGNUM_SHADERS_EXPORT FlatGL<dimensions>:
* @ref FlatMaterialUniform buffer bound with
* @ref bindMaterialBuffer(). Uniform buffers have a statically defined
* size and @cpp count*sizeof(FlatMaterialUniform) @ce has to be within
* @ref GL::AbstractShaderProgram::maxUniformBlockSize().
*
* The per-draw materials are then specified via
* @ref FlatDrawUniform::materialId. Default value is @cpp 1 @ce.
* @ref GL::AbstractShaderProgram::maxUniformBlockSize(), if
* @ref Flag::ShaderStorageBuffers is set as well, the buffer is
* unbounded and @p count is ignored. The per-draw materials are
* specified via @ref FlatDrawUniform::materialId. Default value is
* @cpp 1 @ce.
*
* If @ref Flag::UniformBuffers isn't set, this value is ignored.
* @see @ref setFlags(), @ref setDrawCount(),
@ -1494,10 +1521,10 @@ template<UnsignedInt dimensions> class MAGNUM_SHADERS_EXPORT FlatGL<dimensions>:
* @cpp count*sizeof(TransformationProjectionUniform3D) @ce,
* @cpp count*sizeof(FlatDrawUniform) @ce and
* @cpp count*sizeof(TextureTransformationUniform) @ce has to be within
* @ref GL::AbstractShaderProgram::maxUniformBlockSize().
*
* The draw offset is then set via @ref setDrawOffset(). Default value
* is @cpp 1 @ce.
* @ref GL::AbstractShaderProgram::maxUniformBlockSize(), if
* @ref Flag::ShaderStorageBuffers is set as well, the buffers are
* unbounded and @p count is ignored. The draw offset is set via
* @ref setDrawOffset(). Default value is @cpp 1 @ce.
*
* If @ref Flag::UniformBuffers isn't set, this value is ignored.
* @see @ref setFlags(), @ref setMaterialCount(),

37
src/Magnum/Shaders/Line.frag

@ -27,6 +27,10 @@
#extension GL_EXT_gpu_shader4: require
#endif
#if defined(SHADER_STORAGE_BUFFERS) && !defined(GL_ES)
#extension GL_ARB_shader_storage_buffer_object: require
#endif
/* See the corresponding block in Line.vert for more information */
#ifndef GL_ES
#define CAN_USE_NOPERSPECTIVE
@ -91,11 +95,24 @@ layout(location = 7)
uniform highp uint objectId; /* defaults to zero */
#endif
/* Uniform buffers */
/* Uniform / shader storage buffers */
#else
/* For SSBOs, the per-draw and material arrays are unbounded */
#ifdef SHADER_STORAGE_BUFFERS
#define DRAW_COUNT
#define MATERIAL_COUNT
#define BUFFER_OR_UNIFORM buffer
#define BUFFER_READONLY readonly
#else
#define BUFFER_OR_UNIFORM uniform
#define BUFFER_READONLY
#endif
#ifndef MULTI_DRAW
#if DRAW_COUNT > 1
/* With SSBOs DRAW_COUNT is defined to be empty, +0 makes the condition not
cause a compile error */
#if defined(SHADER_STORAGE_BUFFERS) || DRAW_COUNT+0 > 1
#ifdef EXPLICIT_UNIFORM_LOCATION
layout(location = 1)
#endif
@ -117,11 +134,11 @@ struct DrawUniform {
};
layout(std140
#ifdef EXPLICIT_BINDING
#if defined(EXPLICIT_BINDING) || defined(SHADER_STORAGE_BUFFERS)
, binding = 2
#endif
) uniform Draw {
DrawUniform draws[DRAW_COUNT];
) BUFFER_OR_UNIFORM Draw {
BUFFER_READONLY DrawUniform draws[DRAW_COUNT];
};
struct MaterialUniform {
@ -134,11 +151,11 @@ struct MaterialUniform {
};
layout(std140
#ifdef EXPLICIT_BINDING
#if defined(EXPLICIT_BINDING) || defined(SHADER_STORAGE_BUFFERS)
, binding = 3
#endif
) uniform Material {
MaterialUniform materials[MATERIAL_COUNT];
) BUFFER_OR_UNIFORM Material {
BUFFER_READONLY MaterialUniform materials[MATERIAL_COUNT];
};
#endif
@ -187,7 +204,9 @@ void main() {
#ifdef OBJECT_ID
highp const uint objectId = draws[drawId].draw_objectId;
#endif
#if MATERIAL_COUNT > 1
/* With SSBOs MATERIAL_COUNT is defined to be empty, +0 makes the condition
not cause a compile error */
#if defined(SHADER_STORAGE_BUFFERS) || MATERIAL_COUNT+0 > 1
mediump const uint materialId = draws[drawId].draw_materialIdReserved & 0xffffu;
#else
#define materialId 0u

43
src/Magnum/Shaders/Line.vert

@ -27,6 +27,10 @@
#extension GL_EXT_gpu_shader4: require
#endif
#if defined(SHADER_STORAGE_BUFFERS) && !defined(GL_ES)
#extension GL_ARB_shader_storage_buffer_object: require
#endif
/* Use the noperspective keyword to avoid artifacts in screen-space
interpolation if perspective projection is used in 3D. If not available,
it's worked around by dividing gl_Position with gl_Position.w (which is
@ -112,10 +116,23 @@ uniform mediump float miterLimit
#endif
;
/* Uniform buffers */
/* Uniform / shader storage buffers */
#else
#if DRAW_COUNT > 1
/* For SSBOs, the per-draw and material arrays are unbounded */
#ifdef SHADER_STORAGE_BUFFERS
#define DRAW_COUNT
#define MATERIAL_COUNT
#define BUFFER_OR_UNIFORM buffer
#define BUFFER_READONLY readonly
#else
#define BUFFER_OR_UNIFORM uniform
#define BUFFER_READONLY
#endif
/* With SSBOs DRAW_COUNT is defined to be empty, +0 makes the condition not
cause a compile error */
#if defined(SHADER_STORAGE_BUFFERS) || DRAW_COUNT+0 > 1
#ifdef EXPLICIT_UNIFORM_LOCATION
layout(location = 1)
#endif
@ -129,11 +146,11 @@ uniform highp uint drawOffset
#endif
layout(std140
#ifdef EXPLICIT_BINDING
#if defined(EXPLICIT_BINDING) || defined(SHADER_STORAGE_BUFFERS)
, binding = 1
#endif
) uniform TransformationProjection {
highp
) BUFFER_OR_UNIFORM TransformationProjection {
BUFFER_READONLY highp
#ifdef TWO_DIMENSIONS
/* Can't be a mat3 because of ANGLE, see DrawUniform in Phong.vert for
details */
@ -153,11 +170,11 @@ struct DrawUniform {
};
layout(std140
#ifdef EXPLICIT_BINDING
#if defined(EXPLICIT_BINDING) || defined(SHADER_STORAGE_BUFFERS)
, binding = 2
#endif
) uniform Draw {
DrawUniform draws[DRAW_COUNT];
) BUFFER_OR_UNIFORM Draw {
BUFFER_READONLY DrawUniform draws[DRAW_COUNT];
};
struct MaterialUniform {
@ -170,11 +187,11 @@ struct MaterialUniform {
};
layout(std140
#ifdef EXPLICIT_BINDING
#if defined(EXPLICIT_BINDING) || defined(SHADER_STORAGE_BUFFERS)
, binding = 3
#endif
) uniform Material {
MaterialUniform materials[MATERIAL_COUNT];
) BUFFER_OR_UNIFORM Material {
BUFFER_READONLY MaterialUniform materials[MATERIAL_COUNT];
};
#endif
@ -300,7 +317,9 @@ void main() {
#else
#error
#endif
#if MATERIAL_COUNT > 1
/* With SSBOs MATERIAL_COUNT is defined to be empty, +0 makes the condition
not cause a compile error */
#if defined(SHADER_STORAGE_BUFFERS) || MATERIAL_COUNT+0 > 1
mediump const uint materialId = draws[drawId].draw_materialIdReserved & 0xffffu;
#else
#define materialId 0u

151
src/Magnum/Shaders/LineGL.cpp

@ -65,16 +65,32 @@ namespace {
}
template<UnsignedInt dimensions> typename LineGL<dimensions>::CompileState LineGL<dimensions>::compile(const Configuration& configuration) {
CORRADE_ASSERT(!(configuration.flags() >= Flag::UniformBuffers) || configuration.materialCount(),
"Shaders::LineGL: material count can't be zero", CompileState{NoCreate});
CORRADE_ASSERT(!(configuration.flags() >= Flag::UniformBuffers) || configuration.drawCount(),
"Shaders::LineGL: draw count can't be zero", CompileState{NoCreate});
#ifndef CORRADE_NO_ASSERT
#ifndef MAGNUM_TARGET_WEBGL
if(!(configuration.flags() >= Flag::ShaderStorageBuffers))
#endif
{
CORRADE_ASSERT(!(configuration.flags() >= Flag::UniformBuffers) || configuration.materialCount(),
"Shaders::LineGL: material count can't be zero", CompileState{NoCreate});
CORRADE_ASSERT(!(configuration.flags() >= Flag::UniformBuffers) || configuration.drawCount(),
"Shaders::LineGL: draw count can't be zero", CompileState{NoCreate});
}
#endif
#ifndef MAGNUM_TARGET_GLES
MAGNUM_ASSERT_GL_EXTENSION_SUPPORTED(GL::Extensions::EXT::gpu_shader4);
if(configuration.flags() >= Flag::UniformBuffers)
MAGNUM_ASSERT_GL_EXTENSION_SUPPORTED(GL::Extensions::ARB::uniform_buffer_object);
#endif
#ifndef MAGNUM_TARGET_WEBGL
if(configuration.flags() >= Flag::ShaderStorageBuffers) {
#ifndef MAGNUM_TARGET_GLES
MAGNUM_ASSERT_GL_EXTENSION_SUPPORTED(GL::Extensions::ARB::shader_storage_buffer_object);
#else
MAGNUM_ASSERT_GL_VERSION_SUPPORTED(GL::Version::GLES310);
#endif
}
#endif
if(configuration.flags() >= Flag::MultiDraw) {
#ifndef MAGNUM_TARGET_GLES
MAGNUM_ASSERT_GL_EXTENSION_SUPPORTED(GL::Extensions::ARB::shader_draw_parameters);
@ -137,12 +153,23 @@ template<UnsignedInt dimensions> typename LineGL<dimensions>::CompileState LineG
.addSource(configuration.flags() >= Flag::InstancedObjectId ? "#define INSTANCED_OBJECT_ID\n"_s : ""_s)
.addSource(configuration.flags() & Flag::InstancedTransformation ? "#define INSTANCED_TRANSFORMATION\n"_s : ""_s);
if(configuration.flags() >= Flag::UniformBuffers) {
vert.addSource(Utility::format(
"#define UNIFORM_BUFFERS\n"
"#define DRAW_COUNT {}\n"
"#define MATERIAL_COUNT {}\n",
configuration.drawCount(),
configuration.materialCount()));
#ifndef MAGNUM_TARGET_WEBGL
/* SSBOs have unbounded per-draw arrays so just a plain string can be
passed */
if(configuration.flags() >= Flag::ShaderStorageBuffers) {
vert.addSource(
"#define UNIFORM_BUFFERS\n"
"#define SHADER_STORAGE_BUFFERS\n"_s);
} else
#endif
{
vert.addSource(Utility::format(
"#define UNIFORM_BUFFERS\n"
"#define DRAW_COUNT {}\n"
"#define MATERIAL_COUNT {}\n",
configuration.drawCount(),
configuration.materialCount()));
}
vert.addSource(configuration.flags() >= Flag::MultiDraw ? "#define MULTI_DRAW\n"_s : ""_s);
}
vert.addSource(rs.getString("generic.glsl"_s))
@ -156,12 +183,23 @@ template<UnsignedInt dimensions> typename LineGL<dimensions>::CompileState LineG
.addSource(configuration.flags() & Flag::ObjectId ? "#define OBJECT_ID\n"_s : ""_s)
.addSource(configuration.flags() >= Flag::InstancedObjectId ? "#define INSTANCED_OBJECT_ID\n"_s : ""_s);
if(configuration.flags() >= Flag::UniformBuffers) {
frag.addSource(Utility::format(
"#define UNIFORM_BUFFERS\n"
"#define DRAW_COUNT {}\n"
"#define MATERIAL_COUNT {}\n",
configuration.drawCount(),
configuration.materialCount()));
#ifndef MAGNUM_TARGET_WEBGL
/* SSBOs have unbounded per-draw arrays so just a plain string can be
passed */
if(configuration.flags() >= Flag::ShaderStorageBuffers) {
frag.addSource(
"#define UNIFORM_BUFFERS\n"
"#define SHADER_STORAGE_BUFFERS\n"_s);
} else
#endif
{
frag.addSource(Utility::format(
"#define UNIFORM_BUFFERS\n"
"#define DRAW_COUNT {}\n"
"#define MATERIAL_COUNT {}\n",
configuration.drawCount(),
configuration.materialCount()));
}
frag.addSource(configuration.flags() >= Flag::MultiDraw ? "#define MULTI_DRAW\n"_s : ""_s);
}
frag.addSource(rs.getString("generic.glsl"_s))
@ -225,8 +263,11 @@ template<UnsignedInt dimensions> LineGL<dimensions>::LineGL(CompileState&& state
{
_viewportSizeUniform = uniformLocation("viewportSize"_s);
if(_flags >= Flag::UniformBuffers) {
if(_drawCount > 1)
_drawOffsetUniform = uniformLocation("drawOffset"_s);
if(_drawCount > 1
#ifndef MAGNUM_TARGET_WEBGL
|| flags() >= Flag::ShaderStorageBuffers
#endif
) _drawOffsetUniform = uniformLocation("drawOffset"_s);
} else {
_transformationProjectionMatrixUniform = uniformLocation("transformationProjectionMatrix"_s);
_widthUniform = uniformLocation("width"_s);
@ -246,7 +287,12 @@ template<UnsignedInt dimensions> LineGL<dimensions>::LineGL(CompileState&& state
if(state._version < GL::Version::GLES310)
#endif
{
if(_flags >= Flag::UniformBuffers) {
/* SSBOs have bindings defined in the source always */
if(_flags >= Flag::UniformBuffers
#ifndef MAGNUM_TARGET_WEBGL
&& !(_flags >= Flag::ShaderStorageBuffers)
#endif
) {
setUniformBlockBinding(uniformBlockIndex("TransformationProjection"_s), TransformationProjectionBufferBinding);
setUniformBlockBinding(uniformBlockIndex("Draw"_s), DrawBufferBinding);
setUniformBlockBinding(uniformBlockIndex("Material"_s), MaterialBufferBinding);
@ -343,51 +389,84 @@ template<UnsignedInt dimensions> LineGL<dimensions>& LineGL<dimensions>::setObje
template<UnsignedInt dimensions> LineGL<dimensions>& LineGL<dimensions>::setDrawOffset(const UnsignedInt offset) {
CORRADE_ASSERT(_flags >= Flag::UniformBuffers,
"Shaders::LineGL::setDrawOffset(): the shader was not created with uniform buffers enabled", *this);
#ifndef MAGNUM_TARGET_WEBGL
CORRADE_ASSERT(_flags >= Flag::ShaderStorageBuffers || offset < _drawCount,
"Shaders::LineGL::setDrawOffset(): draw offset" << offset << "is out of bounds for" << _drawCount << "draws", *this);
#else
CORRADE_ASSERT(offset < _drawCount,
"Shaders::LineGL::setDrawOffset(): draw offset" << offset << "is out of bounds for" << _drawCount << "draws", *this);
if(_drawCount > 1) setUniform(_drawOffsetUniform, offset);
#endif
if(_drawCount > 1
#ifndef MAGNUM_TARGET_WEBGL
|| _flags >= Flag::ShaderStorageBuffers
#endif
) setUniform(_drawOffsetUniform, offset);
return *this;
}
template<UnsignedInt dimensions> LineGL<dimensions>& LineGL<dimensions>::bindTransformationProjectionBuffer(GL::Buffer& buffer) {
CORRADE_ASSERT(_flags >= Flag::UniformBuffers,
"Shaders::LineGL::bindTransformationProjectionBuffer(): the shader was not created with uniform buffers enabled", *this);
buffer.bind(GL::Buffer::Target::Uniform, TransformationProjectionBufferBinding);
buffer.bind(
#ifndef MAGNUM_TARGET_WEBGL
_flags >= Flag::ShaderStorageBuffers ? GL::Buffer::Target::ShaderStorage :
#endif
GL::Buffer::Target::Uniform, TransformationProjectionBufferBinding);
return *this;
}
template<UnsignedInt dimensions> LineGL<dimensions>& LineGL<dimensions>::bindTransformationProjectionBuffer(GL::Buffer& buffer, const GLintptr offset, const GLsizeiptr size) {
CORRADE_ASSERT(_flags >= Flag::UniformBuffers,
"Shaders::LineGL::bindTransformationProjectionBuffer(): the shader was not created with uniform buffers enabled", *this);
buffer.bind(GL::Buffer::Target::Uniform, TransformationProjectionBufferBinding, offset, size);
buffer.bind(
#ifndef MAGNUM_TARGET_WEBGL
_flags >= Flag::ShaderStorageBuffers ? GL::Buffer::Target::ShaderStorage :
#endif
GL::Buffer::Target::Uniform, TransformationProjectionBufferBinding, offset, size);
return *this;
}
template<UnsignedInt dimensions> LineGL<dimensions>& LineGL<dimensions>::bindDrawBuffer(GL::Buffer& buffer) {
CORRADE_ASSERT(_flags >= Flag::UniformBuffers,
"Shaders::LineGL::bindDrawBuffer(): the shader was not created with uniform buffers enabled", *this);
buffer.bind(GL::Buffer::Target::Uniform, DrawBufferBinding);
buffer.bind(
#ifndef MAGNUM_TARGET_WEBGL
_flags >= Flag::ShaderStorageBuffers ? GL::Buffer::Target::ShaderStorage :
#endif
GL::Buffer::Target::Uniform, DrawBufferBinding);
return *this;
}
template<UnsignedInt dimensions> LineGL<dimensions>& LineGL<dimensions>::bindDrawBuffer(GL::Buffer& buffer, const GLintptr offset, const GLsizeiptr size) {
CORRADE_ASSERT(_flags >= Flag::UniformBuffers,
"Shaders::LineGL::bindDrawBuffer(): the shader was not created with uniform buffers enabled", *this);
buffer.bind(GL::Buffer::Target::Uniform, DrawBufferBinding, offset, size);
buffer.bind(
#ifndef MAGNUM_TARGET_WEBGL
_flags >= Flag::ShaderStorageBuffers ? GL::Buffer::Target::ShaderStorage :
#endif
GL::Buffer::Target::Uniform, DrawBufferBinding, offset, size);
return *this;
}
template<UnsignedInt dimensions> LineGL<dimensions>& LineGL<dimensions>::bindMaterialBuffer(GL::Buffer& buffer) {
CORRADE_ASSERT(_flags >= Flag::UniformBuffers,
"Shaders::LineGL::bindMaterialBuffer(): the shader was not created with uniform buffers enabled", *this);
buffer.bind(GL::Buffer::Target::Uniform, MaterialBufferBinding);
buffer.bind(
#ifndef MAGNUM_TARGET_WEBGL
_flags >= Flag::ShaderStorageBuffers ? GL::Buffer::Target::ShaderStorage :
#endif
GL::Buffer::Target::Uniform, MaterialBufferBinding);
return *this;
}
template<UnsignedInt dimensions> LineGL<dimensions>& LineGL<dimensions>::bindMaterialBuffer(GL::Buffer& buffer, const GLintptr offset, const GLsizeiptr size) {
CORRADE_ASSERT(_flags >= Flag::UniformBuffers,
"Shaders::LineGL::bindMaterialBuffer(): the shader was not created with uniform buffers enabled", *this);
buffer.bind(GL::Buffer::Target::Uniform, MaterialBufferBinding, offset, size);
buffer.bind(
#ifndef MAGNUM_TARGET_WEBGL
_flags >= Flag::ShaderStorageBuffers ? GL::Buffer::Target::ShaderStorage :
#endif
GL::Buffer::Target::Uniform, MaterialBufferBinding, offset, size);
return *this;
}
@ -399,6 +478,14 @@ template class MAGNUM_SHADERS_EXPORT LineGL<3>;
namespace Implementation {
Debug& operator<<(Debug& debug, const LineGLFlag value) {
#ifndef MAGNUM_TARGET_WEBGL
/* Special case coming from the Flags printer. As both flags are a superset
of UniformBuffers, printing just one would result in
`Flag::MultiDraw|Flag(0x40)` in the output. */
if(value == LineGLFlag(UnsignedShort(LineGLFlag::MultiDraw|LineGLFlag::ShaderStorageBuffers)))
return debug << LineGLFlag::MultiDraw << Debug::nospace << "|" << Debug::nospace << LineGLFlag::ShaderStorageBuffers;
#endif
debug << "Shaders::LineGL::Flag" << Debug::nospace;
switch(value) {
@ -409,6 +496,9 @@ Debug& operator<<(Debug& debug, const LineGLFlag value) {
_c(InstancedObjectId)
_c(InstancedTransformation)
_c(UniformBuffers)
#ifndef MAGNUM_TARGET_WEBGL
_c(ShaderStorageBuffers)
#endif
_c(MultiDraw)
#undef _c
/* LCOV_EXCL_STOP */
@ -423,7 +513,16 @@ Debug& operator<<(Debug& debug, const LineGLFlags value) {
LineGLFlag::InstancedObjectId, /* Superset of ObjectId */
LineGLFlag::ObjectId,
LineGLFlag::InstancedTransformation,
#ifndef MAGNUM_TARGET_WEBGL
/* Both are a superset of UniformBuffers, meaning printing just one
would result in `Flag::MultiDraw|Flag(0x40)` in the output. So we
pass both and let the Flag printer deal with that. */
LineGLFlag(UnsignedShort(LineGLFlag::MultiDraw|LineGLFlag::ShaderStorageBuffers)),
#endif
LineGLFlag::MultiDraw, /* Superset of UniformBuffers */
#ifndef MAGNUM_TARGET_WEBGL
LineGLFlag::ShaderStorageBuffers, /* Superset of UniformBuffers */
#endif
LineGLFlag::UniformBuffers
});
}

55
src/Magnum/Shaders/LineGL.h

@ -46,15 +46,14 @@ namespace Magnum { namespace Shaders {
namespace Implementation {
enum class LineGLFlag: UnsignedShort {
VertexColor = 1 << 0,
#ifndef MAGNUM_TARGET_GLES2
ObjectId = 1 << 1,
InstancedObjectId = (1 << 2)|ObjectId,
#endif
InstancedTransformation = 1 << 3,
#ifndef MAGNUM_TARGET_GLES2
UniformBuffers = 1 << 4,
MultiDraw = UniformBuffers|(1 << 5)
#ifndef MAGNUM_TARGET_WEBGL
ShaderStorageBuffers = UniformBuffers|(1 << 6),
#endif
MultiDraw = UniformBuffers|(1 << 5)
};
typedef Containers::EnumSet<LineGLFlag> LineGLFlags;
CORRADE_ENUMSET_OPERATORS(LineGLFlags)
@ -572,10 +571,28 @@ template<UnsignedInt dimensions> class MAGNUM_SHADERS_EXPORT LineGL: public GL::
* @ref bindTransformationProjectionBuffer(),
* @ref bindDrawBuffer() and @ref bindMaterialBuffer() instead of
* direct uniform setters.
* @see @ref Flag::ShaderStorageBuffers
* @requires_gl31 Extension @gl_extension{ARB,uniform_buffer_object}
*/
UniformBuffers = 1 << 4,
#ifndef MAGNUM_TARGET_WEBGL
/**
* Use shader storage buffers. Superset of functionality provided
* by @ref Flag::UniformBuffers, compared to it doesn't have any
* size limits on @ref Configuration::setMaterialCount() and
* @relativeref{Configuration,setDrawCount()} in exchange for
* potentially more costly access and narrower platform support.
* @requires_gl43 Extension @gl_extension{ARB,shader_storage_buffer_object}
* @requires_gles31 Shader storage buffers are not available in
* OpenGL ES 3.0 and older.
* @requires_gles Shader storage buffers are not available in
* WebGL.
* @m_since_latest
*/
ShaderStorageBuffers = UniformBuffers|(1 << 6),
#endif
/**
* Enable multidraw functionality. Implies @ref Flag::UniformBuffers
* and adds the value from @ref setDrawOffset() with the
@ -693,7 +710,8 @@ template<UnsignedInt dimensions> class MAGNUM_SHADERS_EXPORT LineGL: public GL::
*
* Statically defined size of the @ref LineMaterialUniform uniform
* buffer bound with @ref bindMaterialBuffer(). Has use only if
* @ref Flag::UniformBuffers is set.
* @ref Flag::UniformBuffers is set and @ref Flag::ShaderStorageBuffers
* is not set.
* @see @ref Configuration::setMaterialCount()
*/
UnsignedInt materialCount() const { return _materialCount; }
@ -706,7 +724,7 @@ template<UnsignedInt dimensions> class MAGNUM_SHADERS_EXPORT LineGL: public GL::
* @ref TransformationProjectionUniform3D and @ref LineDrawUniform
* uniform buffers bound with @ref bindTransformationProjectionBuffer()
* and @ref bindDrawBuffer(). Has use only if @ref Flag::UniformBuffers
* is set.
* is set and @ref Flag::ShaderStorageBuffers is not set.
* @see @ref Configuration::setDrawCount()
*/
UnsignedInt drawCount() const { return _drawCount; }
@ -877,7 +895,7 @@ template<UnsignedInt dimensions> class MAGNUM_SHADERS_EXPORT LineGL: public GL::
*/
/** @{
* @name Uniform buffer binding and related uniform setters
* @name Uniform / shader storage buffer binding and related uniform setters
*
* Used if @ref Flag::UniformBuffers is set.
*/
@ -906,7 +924,7 @@ template<UnsignedInt dimensions> class MAGNUM_SHADERS_EXPORT LineGL: public GL::
LineGL<dimensions>& setDrawOffset(UnsignedInt offset);
/**
* @brief Bind a transformation and projection uniform buffer
* @brief Bind a transformation and projection uniform / shader storage buffer
* @return Reference to self (for method chaining)
*
* Expects that @ref Flag::UniformBuffers is set. The buffer is
@ -920,7 +938,7 @@ template<UnsignedInt dimensions> class MAGNUM_SHADERS_EXPORT LineGL: public GL::
LineGL<dimensions>& bindTransformationProjectionBuffer(GL::Buffer& buffer, GLintptr offset, GLsizeiptr size); /**< @overload */
/**
* @brief Bind a draw uniform buffer
* @brief Bind a draw uniform / shader storage buffer
* @return Reference to self (for method chaining)
*
* Expects that @ref Flag::UniformBuffers is set. The buffer is
@ -934,7 +952,7 @@ template<UnsignedInt dimensions> class MAGNUM_SHADERS_EXPORT LineGL: public GL::
LineGL<dimensions>& bindDrawBuffer(GL::Buffer& buffer, GLintptr offset, GLsizeiptr size); /**< @overload */
/**
* @brief Bind a material uniform buffer
* @brief Bind a material uniform / shader storage buffer
* @return Reference to self (for method chaining)
*
* Expects that @ref Flag::UniformBuffers is set. The buffer is
@ -1039,10 +1057,11 @@ template<UnsignedInt dimensions> class MAGNUM_SHADERS_EXPORT LineGL<dimensions>:
* @ref LineMaterialUniform buffer bound with
* @ref bindMaterialBuffer(). Uniform buffers have a statically defined
* size and @cpp count*sizeof(LineMaterialUniform) @ce has to be within
* @ref GL::AbstractShaderProgram::maxUniformBlockSize().
*
* The per-draw materials are then specified via
* @ref LineDrawUniform::materialId. Default value is @cpp 1 @ce.
* @ref GL::AbstractShaderProgram::maxUniformBlockSize(), if
* @ref Flag::ShaderStorageBuffers is set as well, the buffer is
* unbounded and @p count is ignored. The per-draw materials are
* specified via @ref LineDrawUniform::materialId. Default value is
* @cpp 1 @ce.
*
* If @ref Flag::UniformBuffers isn't set, this value is ignored.
* @see @ref setFlags(), @ref setDrawCount(),
@ -1069,10 +1088,10 @@ template<UnsignedInt dimensions> class MAGNUM_SHADERS_EXPORT LineGL<dimensions>:
* @cpp count*sizeof(TransformationProjectionUniform2D) @ce /
* @cpp count*sizeof(TransformationProjectionUniform3D) @ce and
* @cpp count*sizeof(LineDrawUniform) @ce has to be within
* @ref GL::AbstractShaderProgram::maxUniformBlockSize().
*
* The draw offset is then set via @ref setDrawOffset(). Default value
* is @cpp 1 @ce.
* @ref GL::AbstractShaderProgram::maxUniformBlockSize(), if
* @ref Flag::ShaderStorageBuffers is set as well, the buffers are
* unbounded and @p count is ignored. The draw offset is set via
* @ref setDrawOffset(). Default value is @cpp 1 @ce.
*
* If @ref Flag::UniformBuffers isn't set, this value is ignored.
* @see @ref setFlags(), @ref setMaterialCount(),

37
src/Magnum/Shaders/MeshVisualizer.frag

@ -32,6 +32,10 @@
#define const
#endif
#if defined(SHADER_STORAGE_BUFFERS) && !defined(GL_ES)
#extension GL_ARB_shader_storage_buffer_object: require
#endif
#if defined(WIREFRAME_RENDERING) && defined(GL_ES) && __VERSION__ < 300
#extension GL_OES_standard_derivatives : enable
#endif
@ -115,11 +119,24 @@ layout(location = 6)
uniform highp uint objectId; /* defaults to zero */
#endif
/* Uniform buffers */
/* Uniform / shader storage buffers */
#else
/* For SSBOs, the per-draw and material arrays are unbounded */
#ifdef SHADER_STORAGE_BUFFERS
#define DRAW_COUNT
#define MATERIAL_COUNT
#define BUFFER_OR_UNIFORM buffer
#define BUFFER_READONLY readonly
#else
#define BUFFER_OR_UNIFORM uniform
#define BUFFER_READONLY
#endif
#ifndef MULTI_DRAW
#if DRAW_COUNT > 1
/* With SSBOs DRAW_COUNT is defined to be empty, +0 makes the condition not
cause a compile error */
#if defined(SHADER_STORAGE_BUFFERS) || DRAW_COUNT+0 > 1
#ifdef EXPLICIT_UNIFORM_LOCATION
layout(location = 1)
#endif
@ -151,11 +168,11 @@ struct DrawUniform {
};
layout(std140
#ifdef EXPLICIT_BINDING
#if defined(EXPLICIT_BINDING) || defined(SHADER_STORAGE_BUFFERS)
, binding = 2
#endif
) uniform Draw {
DrawUniform draws[DRAW_COUNT];
) BUFFER_OR_UNIFORM Draw {
BUFFER_READONLY DrawUniform draws[DRAW_COUNT];
};
/* Keep in sync with MeshVisualizer.vert and MeshVisualizer.geom. Can't
@ -175,11 +192,11 @@ struct MaterialUniform {
};
layout(std140
#ifdef EXPLICIT_BINDING
#if defined(EXPLICIT_BINDING) || defined(SHADER_STORAGE_BUFFERS)
, binding = 4
#endif
) uniform Material {
MaterialUniform materials[MATERIAL_COUNT];
) BUFFER_OR_UNIFORM Material {
BUFFER_READONLY MaterialUniform materials[MATERIAL_COUNT];
};
#endif
@ -261,7 +278,9 @@ void main() {
#ifdef OBJECT_ID
highp const uint objectId = draws[drawId].draw_objectId;
#endif
#if MATERIAL_COUNT > 1
/* With SSBOs MATERIAL_COUNT is defined to be empty, +0 makes the condition
not cause a compile error */
#if defined(SHADER_STORAGE_BUFFERS) || MATERIAL_COUNT+0 > 1
mediump const uint materialId = draws[drawId].draw_materialIdReserved & 0xffffu;
#else
#define materialId 0u

33
src/Magnum/Shaders/MeshVisualizer.geom

@ -27,6 +27,10 @@
#define const
#endif
#if defined(SHADER_STORAGE_BUFFERS) && !defined(GL_ES)
#extension GL_ARB_shader_storage_buffer_object: require
#endif
#ifdef GL_ES
#extension GL_EXT_geometry_shader: require
#ifdef GL_NV_shader_noperspective_interpolation
@ -84,9 +88,20 @@ uniform lowp float smoothness
;
#endif
/* Uniform buffers */
/* Uniform / shader storage buffers */
#else
/* For SSBOs, the per-draw and material arrays are unbounded */
#ifdef SHADER_STORAGE_BUFFERS
#define DRAW_COUNT
#define MATERIAL_COUNT
#define BUFFER_OR_UNIFORM buffer
#define BUFFER_READONLY readonly
#else
#define BUFFER_OR_UNIFORM uniform
#define BUFFER_READONLY
#endif
#ifndef MULTI_DRAW
#ifdef EXPLICIT_UNIFORM_LOCATION
layout(location = 1)
@ -115,11 +130,11 @@ struct DrawUniform {
};
layout(std140
#ifdef EXPLICIT_BINDING
#if defined(EXPLICIT_BINDING) || defined(SHADER_STORAGE_BUFFERS)
, binding = 2
#endif
) uniform Draw {
DrawUniform draws[DRAW_COUNT];
) BUFFER_OR_UNIFORM Draw {
BUFFER_READONLY DrawUniform draws[DRAW_COUNT];
};
/* Keep in sync with MeshVisualizer.vert and MeshVisualizer.frag. Can't
@ -139,11 +154,11 @@ struct MaterialUniform {
};
layout(std140
#ifdef EXPLICIT_BINDING
#if defined(EXPLICIT_BINDING) || defined(SHADER_STORAGE_BUFFERS)
, binding = 4
#endif
) uniform Material {
MaterialUniform materials[MATERIAL_COUNT];
) BUFFER_OR_UNIFORM Material {
BUFFER_READONLY MaterialUniform materials[MATERIAL_COUNT];
};
#endif
@ -292,7 +307,9 @@ void main() {
#define drawId drawOffset
#endif
#if MATERIAL_COUNT > 1
/* With SSBOs MATERIAL_COUNT is defined to be empty, +0 makes the condition
not cause a compile error */
#if defined(SHADER_STORAGE_BUFFERS) || MATERIAL_COUNT+0 > 1
mediump const uint materialId = draws[drawId].draw_materialIdReserved & 0xffffu;
#else
#define materialId 0u

72
src/Magnum/Shaders/MeshVisualizer.vert

@ -31,6 +31,10 @@
#extension GL_ARB_shader_bit_encoding: require
#endif
#if defined(SHADER_STORAGE_BUFFERS) && !defined(GL_ES)
#extension GL_ARB_shader_storage_buffer_object: require
#endif
#ifdef MULTI_DRAW
#ifndef GL_ES
#extension GL_ARB_shader_draw_parameters: require
@ -172,10 +176,28 @@ layout(location = PER_INSTANCE_JOINT_COUNT_LOCATION)
uniform uint perInstanceJointCount; /* defaults to zero */
#endif
/* Uniform buffers */
/* Uniform / shader storage buffers */
#else
#if DRAW_COUNT > 1
/* For SSBOs, the per-draw, material and joint arrays are unbounded */
#ifdef SHADER_STORAGE_BUFFERS
#define DRAW_COUNT
#define MATERIAL_COUNT
/* Define JOINT_COUNT only if there are any per-vertex attributes, otherwise
the buffer would be useless */
#if defined(PER_VERTEX_JOINT_COUNT) || defined(SECONDARY_PER_VERTEX_JOINT_COUNT)
#define JOINT_COUNT
#endif
#define BUFFER_OR_UNIFORM buffer
#define BUFFER_READONLY readonly
#else
#define BUFFER_OR_UNIFORM uniform
#define BUFFER_READONLY
#endif
/* With SSBOs DRAW_COUNT is defined to be empty, +0 makes the condition not
cause a compile error */
#if defined(SHADER_STORAGE_BUFFERS) || DRAW_COUNT+0 > 1
#ifdef EXPLICIT_UNIFORM_LOCATION
layout(location = 1)
#endif
@ -190,29 +212,29 @@ uniform highp uint drawOffset
#ifdef TWO_DIMENSIONS
layout(std140
#ifdef EXPLICIT_BINDING
#if defined(EXPLICIT_BINDING) || defined(SHADER_STORAGE_BUFFERS)
, binding = 1
#endif
) uniform TransformationProjection {
) BUFFER_OR_UNIFORM TransformationProjection {
/* Can't be a mat3 because of ANGLE, see DrawUniform in Phong.vert for
details */
highp mat3x4 transformationProjectionMatrices[DRAW_COUNT];
BUFFER_READONLY highp mat3x4 transformationProjectionMatrices[DRAW_COUNT];
};
#elif defined(THREE_DIMENSIONS)
layout(std140
#ifdef EXPLICIT_BINDING
#if defined(EXPLICIT_BINDING) || defined(SHADER_STORAGE_BUFFERS)
, binding = 0
#endif
) uniform Projection {
highp mat4 projectionMatrix;
) BUFFER_OR_UNIFORM Projection {
BUFFER_READONLY highp mat4 projectionMatrix;
};
layout(std140
#ifdef EXPLICIT_BINDING
#if defined(EXPLICIT_BINDING) || defined(SHADER_STORAGE_BUFFERS)
, binding = 1
#endif
) uniform Transformation {
highp mat4 transformationMatrices[DRAW_COUNT];
) BUFFER_OR_UNIFORM Transformation {
BUFFER_READONLY highp mat4 transformationMatrices[DRAW_COUNT];
};
#else
#error
@ -227,11 +249,11 @@ struct TextureTransformationUniform {
};
layout(std140
#ifdef EXPLICIT_BINDING
#if defined(EXPLICIT_BINDING) || defined(SHADER_STORAGE_BUFFERS)
, binding = 3
#endif
) uniform TextureTransformation {
TextureTransformationUniform textureTransformations[DRAW_COUNT];
) BUFFER_OR_UNIFORM TextureTransformation {
BUFFER_READONLY TextureTransformationUniform textureTransformations[DRAW_COUNT];
};
#endif
@ -252,11 +274,11 @@ struct DrawUniform {
};
layout(std140
#ifdef EXPLICIT_BINDING
#if defined(EXPLICIT_BINDING) || defined(SHADER_STORAGE_BUFFERS)
, binding = 2
#endif
) uniform Draw {
DrawUniform draws[DRAW_COUNT];
) BUFFER_OR_UNIFORM Draw {
BUFFER_READONLY DrawUniform draws[DRAW_COUNT];
};
/* Keep in sync with MeshVisualizer.geom and MeshVisualizer.frag. Can't
@ -276,20 +298,20 @@ struct MaterialUniform {
};
layout(std140
#ifdef EXPLICIT_BINDING
#if defined(EXPLICIT_BINDING) || defined(SHADER_STORAGE_BUFFERS)
, binding = 4
#endif
) uniform Material {
MaterialUniform materials[MATERIAL_COUNT];
) BUFFER_OR_UNIFORM Material {
BUFFER_READONLY MaterialUniform materials[MATERIAL_COUNT];
};
#ifdef JOINT_COUNT
layout(std140
#ifdef EXPLICIT_BINDING
#if defined(EXPLICIT_BINDING) || defined(SHADER_STORAGE_BUFFERS)
, binding = 6
#endif
) uniform Joint {
highp
) BUFFER_OR_UNIFORM Joint {
BUFFER_READONLY highp
#ifdef TWO_DIMENSIONS
/* Can't be a mat3 because of ANGLE, see DrawUniform in Phong.vert for
details */
@ -516,7 +538,9 @@ void main() {
#if defined(TANGENT_DIRECTION) || defined(BITANGENT_DIRECTION) || defined(BITANGENT_FROM_TANGENT_DIRECTION) || defined(NORMAL_DIRECTION)
mediump const mat3 normalMatrix = mat3(draws[drawId].normalMatrix);
#endif
#if MATERIAL_COUNT > 1
/* With SSBOs MATERIAL_COUNT is defined to be empty, +0 makes the condition
not cause a compile error */
#if defined(SHADER_STORAGE_BUFFERS) || MATERIAL_COUNT+0 > 1
mediump const uint materialId = draws[drawId].draw_materialIdReserved & 0xffffu;
#else
#define materialId 0u

325
src/Magnum/Shaders/MeshVisualizerGL.cpp

@ -108,6 +108,15 @@ void MeshVisualizerGLBase::assertExtensions(const FlagsBase flags) {
if(flags >= FlagBase::UniformBuffers)
MAGNUM_ASSERT_GL_EXTENSION_SUPPORTED(GL::Extensions::ARB::uniform_buffer_object);
#endif
#if !defined(MAGNUM_TARGET_GLES2) && !defined(MAGNUM_TARGET_WEBGL)
if(flags >= FlagBase::ShaderStorageBuffers) {
#ifndef MAGNUM_TARGET_GLES
MAGNUM_ASSERT_GL_EXTENSION_SUPPORTED(GL::Extensions::ARB::shader_storage_buffer_object);
#else
MAGNUM_ASSERT_GL_VERSION_SUPPORTED(GL::Version::GLES310);
#endif
}
#endif
#ifndef MAGNUM_TARGET_GLES2
if(flags >= FlagBase::MultiDraw) {
#ifndef MAGNUM_TARGET_GLES
@ -228,9 +237,15 @@ GL::Version MeshVisualizerGLBase::setupShaders(GL::Shader& vert, GL::Shader& fra
#endif
{
vert.addSource(Utility::format(
"#define JOINT_COUNT {}\n"
"#define PER_VERTEX_JOINT_COUNT {}u\n"
"#define SECONDARY_PER_VERTEX_JOINT_COUNT {}u\n",
/* SSBOs have an unbounded joints array */
#ifndef MAGNUM_TARGET_WEBGL
flags >= FlagBase::ShaderStorageBuffers ?
"#define PER_VERTEX_JOINT_COUNT {1}u\n"
"#define SECONDARY_PER_VERTEX_JOINT_COUNT {2}u\n" :
#endif
"#define JOINT_COUNT {}\n"
"#define PER_VERTEX_JOINT_COUNT {}u\n"
"#define SECONDARY_PER_VERTEX_JOINT_COUNT {}u\n",
jointCount,
perVertexJointCount,
secondaryPerVertexJointCount));
@ -240,7 +255,7 @@ GL::Version MeshVisualizerGLBase::setupShaders(GL::Shader& vert, GL::Shader& fra
#ifndef MAGNUM_TARGET_WEBGL
/* The _LOCATION is needed only if explicit uniform location (desktop /
ES3.1) is supported, a plain string can be added otherwise. This is
an immediate uniform also in the UBO case. */
an immediate uniform also in the UBO / SSBO case. */
#ifndef MAGNUM_TARGET_GLES
if(context.isExtensionSupported<GL::Extensions::ARB::explicit_uniform_location>(version))
#else
@ -260,12 +275,23 @@ GL::Version MeshVisualizerGLBase::setupShaders(GL::Shader& vert, GL::Shader& fra
#endif
#ifndef MAGNUM_TARGET_GLES2
if(flags >= FlagBase::UniformBuffers) {
vert.addSource(Utility::format(
"#define UNIFORM_BUFFERS\n"
"#define DRAW_COUNT {}\n"
"#define MATERIAL_COUNT {}\n",
drawCount,
materialCount));
#ifndef MAGNUM_TARGET_WEBGL
/* SSBOs have unbounded per-draw arrays so just a plain string can be
passed */
if(flags >= FlagBase::ShaderStorageBuffers) {
vert.addSource(
"#define UNIFORM_BUFFERS\n"
"#define SHADER_STORAGE_BUFFERS\n"_s);
} else
#endif
{
vert.addSource(Utility::format(
"#define UNIFORM_BUFFERS\n"
"#define DRAW_COUNT {}\n"
"#define MATERIAL_COUNT {}\n",
drawCount,
materialCount));
}
vert.addSource(flags >= FlagBase::MultiDraw ? "#define MULTI_DRAW\n"_s : ""_s);
}
#endif
@ -286,12 +312,23 @@ GL::Version MeshVisualizerGLBase::setupShaders(GL::Shader& vert, GL::Shader& fra
;
#ifndef MAGNUM_TARGET_GLES2
if(flags >= FlagBase::UniformBuffers) {
frag.addSource(Utility::format(
"#define UNIFORM_BUFFERS\n"
"#define DRAW_COUNT {}\n"
"#define MATERIAL_COUNT {}\n",
drawCount,
materialCount));
#ifndef MAGNUM_TARGET_WEBGL
/* SSBOs have unbounded per-draw arrays so just a plain string can be
passed */
if(flags >= FlagBase::ShaderStorageBuffers) {
frag.addSource(
"#define UNIFORM_BUFFERS\n"
"#define SHADER_STORAGE_BUFFERS\n"_s);
} else
#endif
{
frag.addSource(Utility::format(
"#define UNIFORM_BUFFERS\n"
"#define DRAW_COUNT {}\n"
"#define MATERIAL_COUNT {}\n",
drawCount,
materialCount));
}
frag.addSource(flags >= FlagBase::MultiDraw ? "#define MULTI_DRAW\n"_s : ""_s);
}
#endif
@ -403,9 +440,18 @@ MeshVisualizerGLBase& MeshVisualizerGLBase::setPerInstanceJointCount(const Unsig
MeshVisualizerGLBase& MeshVisualizerGLBase::setDrawOffset(const UnsignedInt offset) {
CORRADE_ASSERT(_flags >= FlagBase::UniformBuffers,
"Shaders::MeshVisualizerGL::setDrawOffset(): the shader was not created with uniform buffers enabled", *this);
#ifndef MAGNUM_TARGET_WEBGL
CORRADE_ASSERT(_flags >= FlagBase::ShaderStorageBuffers || offset < _drawCount,
"Shaders::MeshVisualizerGL::setDrawOffset(): draw offset" << offset << "is out of bounds for" << _drawCount << "draws", *this);
#else
CORRADE_ASSERT(offset < _drawCount,
"Shaders::MeshVisualizerGL::setDrawOffset(): draw offset" << offset << "is out of bounds for" << _drawCount << "draws", *this);
if(_drawCount > 1) setUniform(_drawOffsetUniform, offset);
#endif
if(_drawCount > 1
#ifndef MAGNUM_TARGET_WEBGL
|| _flags >= FlagBase::ShaderStorageBuffers
#endif
) setUniform(_drawOffsetUniform, offset);
return *this;
}
@ -414,7 +460,11 @@ MeshVisualizerGLBase& MeshVisualizerGLBase::bindTextureTransformationBuffer(GL::
"Shaders::MeshVisualizerGL::bindTextureTransformationBuffer(): the shader was not created with uniform buffers enabled", *this);
CORRADE_ASSERT(_flags & FlagBase::TextureTransformation,
"Shaders::MeshVisualizerGL::bindTextureTransformationBuffer(): the shader was not created with texture transformation enabled", *this);
buffer.bind(GL::Buffer::Target::Uniform, TextureTransformationBufferBinding);
buffer.bind(
#ifndef MAGNUM_TARGET_WEBGL
_flags >= FlagBase::ShaderStorageBuffers ? GL::Buffer::Target::ShaderStorage :
#endif
GL::Buffer::Target::Uniform, TextureTransformationBufferBinding);
return *this;
}
@ -423,35 +473,55 @@ MeshVisualizerGLBase& MeshVisualizerGLBase::bindTextureTransformationBuffer(GL::
"Shaders::MeshVisualizerGL::bindTextureTransformationBuffer(): the shader was not created with uniform buffers enabled", *this);
CORRADE_ASSERT(_flags & FlagBase::TextureTransformation,
"Shaders::MeshVisualizerGL::bindTextureTransformationBuffer(): the shader was not created with texture transformation enabled", *this);
buffer.bind(GL::Buffer::Target::Uniform, TextureTransformationBufferBinding, offset, size);
buffer.bind(
#ifndef MAGNUM_TARGET_WEBGL
_flags >= FlagBase::ShaderStorageBuffers ? GL::Buffer::Target::ShaderStorage :
#endif
GL::Buffer::Target::Uniform, TextureTransformationBufferBinding, offset, size);
return *this;
}
MeshVisualizerGLBase& MeshVisualizerGLBase::bindMaterialBuffer(GL::Buffer& buffer) {
CORRADE_ASSERT(_flags >= FlagBase::UniformBuffers,
"Shaders::MeshVisualizerGL::bindMaterialBuffer(): the shader was not created with uniform buffers enabled", *this);
buffer.bind(GL::Buffer::Target::Uniform, MaterialBufferBinding);
buffer.bind(
#ifndef MAGNUM_TARGET_WEBGL
_flags >= FlagBase::ShaderStorageBuffers ? GL::Buffer::Target::ShaderStorage :
#endif
GL::Buffer::Target::Uniform, MaterialBufferBinding);
return *this;
}
MeshVisualizerGLBase& MeshVisualizerGLBase::bindMaterialBuffer(GL::Buffer& buffer, const GLintptr offset, const GLsizeiptr size) {
CORRADE_ASSERT(_flags >= FlagBase::UniformBuffers,
"Shaders::MeshVisualizerGL::bindMaterialBuffer(): the shader was not created with uniform buffers enabled", *this);
buffer.bind(GL::Buffer::Target::Uniform, MaterialBufferBinding, offset, size);
buffer.bind(
#ifndef MAGNUM_TARGET_WEBGL
_flags >= FlagBase::ShaderStorageBuffers ? GL::Buffer::Target::ShaderStorage :
#endif
GL::Buffer::Target::Uniform, MaterialBufferBinding, offset, size);
return *this;
}
MeshVisualizerGLBase& MeshVisualizerGLBase::bindJointBuffer(GL::Buffer& buffer) {
CORRADE_ASSERT(_flags >= FlagBase::UniformBuffers,
"Shaders::MeshVisualizerGL::bindJointBuffer(): the shader was not created with uniform buffers enabled", *this);
buffer.bind(GL::Buffer::Target::Uniform, JointBufferBinding);
buffer.bind(
#ifndef MAGNUM_TARGET_WEBGL
_flags >= FlagBase::ShaderStorageBuffers ? GL::Buffer::Target::ShaderStorage :
#endif
GL::Buffer::Target::Uniform, JointBufferBinding);
return *this;
}
MeshVisualizerGLBase& MeshVisualizerGLBase::bindJointBuffer(GL::Buffer& buffer, const GLintptr offset, const GLsizeiptr size) {
CORRADE_ASSERT(_flags >= FlagBase::UniformBuffers,
"Shaders::MeshVisualizerGL::bindJointBuffer(): the shader was not created with uniform buffers enabled", *this);
buffer.bind(GL::Buffer::Target::Uniform, JointBufferBinding, offset, size);
buffer.bind(
#ifndef MAGNUM_TARGET_WEBGL
_flags >= FlagBase::ShaderStorageBuffers ? GL::Buffer::Target::ShaderStorage :
#endif
GL::Buffer::Target::Uniform, JointBufferBinding, offset, size);
return *this;
}
#endif
@ -502,11 +572,18 @@ MeshVisualizerGL2D::CompileState MeshVisualizerGL2D::compile(const Configuration
/* Has to be here and not in the base class in order to have it exit the
constructor when testing for asserts -- GLSL compilation would fail
otherwise */
#ifndef MAGNUM_TARGET_GLES2
CORRADE_ASSERT(!(configuration.flags() >= Flag::UniformBuffers) || configuration.materialCount(),
"Shaders::MeshVisualizerGL2D: material count can't be zero", CompileState{NoCreate});
CORRADE_ASSERT(!(configuration.flags() >= Flag::UniformBuffers) || configuration.drawCount(),
"Shaders::MeshVisualizerGL2D: draw count can't be zero", CompileState{NoCreate});
#if !defined(MAGNUM_TARGET_GLES2) && !defined(CORRADE_NO_ASSERT)
#ifndef MAGNUM_TARGET_WEBGL
if(!(configuration.flags() >= Flag::ShaderStorageBuffers))
#endif
{
CORRADE_ASSERT(!configuration.jointCount() == (!configuration.perVertexJointCount() && !configuration.secondaryPerVertexJointCount()),
"Shaders::MeshVisualizerGL2D: joint count can't be zero if per-vertex joint count is non-zero", CompileState{NoCreate});
CORRADE_ASSERT(!(configuration.flags() >= Flag::UniformBuffers) || configuration.materialCount(),
"Shaders::MeshVisualizerGL2D: material count can't be zero", CompileState{NoCreate});
CORRADE_ASSERT(!(configuration.flags() >= Flag::UniformBuffers) || configuration.drawCount(),
"Shaders::MeshVisualizerGL2D: draw count can't be zero", CompileState{NoCreate});
}
#endif
/* Has to be here and not in the base class in order to have it exit the
@ -585,13 +662,22 @@ MeshVisualizerGL2D::CompileState MeshVisualizerGL2D::compile(const Configuration
"#define PRIMITIVE_ID\n"_s) : ""_s);
#ifndef MAGNUM_TARGET_GLES2
if(configuration.flags() >= Flag::UniformBuffers) {
geom->addSource(Utility::format(
"#define TWO_DIMENSIONS\n"
"#define UNIFORM_BUFFERS\n"
"#define DRAW_COUNT {}\n"
"#define MATERIAL_COUNT {}\n",
configuration.drawCount(),
configuration.materialCount()));
/* SSBOs have unbounded per-draw arrays so just a plain string can
be passed */
if(configuration.flags() >= Flag::ShaderStorageBuffers) {
vert.addSource(
"#define TWO_DIMENSIONS\n"
"#define UNIFORM_BUFFERS\n"
"#define SHADER_STORAGE_BUFFERS\n"_s);
} else {
geom->addSource(Utility::format(
"#define TWO_DIMENSIONS\n"
"#define UNIFORM_BUFFERS\n"
"#define DRAW_COUNT {}\n"
"#define MATERIAL_COUNT {}\n",
configuration.drawCount(),
configuration.materialCount()));
}
geom->addSource(configuration.flags() >= Flag::MultiDraw ? "#define MULTI_DRAW\n"_s : ""_s);
}
#endif
@ -710,7 +796,11 @@ MeshVisualizerGL2D::MeshVisualizerGL2D(CompileState&& state): MeshVisualizerGL2D
if(flags() >= Flag::DynamicPerVertexJointCount)
_perVertexJointCountUniform = uniformLocation("perVertexJointCount"_s);
if(flags() >= Flag::UniformBuffers) {
if(_drawCount > 1) _drawOffsetUniform = uniformLocation("drawOffset"_s);
if(_drawCount > 1
#ifndef MAGNUM_TARGET_WEBGL
|| flags() >= Flag::ShaderStorageBuffers
#endif
) _drawOffsetUniform = uniformLocation("drawOffset"_s);
} else
#endif
{
@ -761,7 +851,12 @@ MeshVisualizerGL2D::MeshVisualizerGL2D(CompileState&& state): MeshVisualizerGL2D
#ifndef MAGNUM_TARGET_GLES2
if(flags() >= Flag::ObjectIdTexture)
setUniform(uniformLocation("objectIdTextureData"_s), ObjectIdTextureUnit);
if(flags() >= Flag::UniformBuffers) {
/* SSBOs have bindings defined in the source always */
if(flags() >= Flag::UniformBuffers
#ifndef MAGNUM_TARGET_WEBGL
&& !(flags() >= Flag::ShaderStorageBuffers)
#endif
) {
setUniformBlockBinding(uniformBlockIndex("TransformationProjection"_s), TransformationProjectionBufferBinding);
setUniformBlockBinding(uniformBlockIndex("Draw"_s), DrawBufferBinding);
setUniformBlockBinding(uniformBlockIndex("Material"_s), MaterialBufferBinding);
@ -886,28 +981,44 @@ MeshVisualizerGL2D& MeshVisualizerGL2D::setJointMatrix(const UnsignedInt id, con
MeshVisualizerGL2D& MeshVisualizerGL2D::bindTransformationProjectionBuffer(GL::Buffer& buffer) {
CORRADE_ASSERT(flags() >= Flag::UniformBuffers,
"Shaders::MeshVisualizerGL2D::bindTransformationProjectionBuffer(): the shader was not created with uniform buffers enabled", *this);
buffer.bind(GL::Buffer::Target::Uniform, TransformationProjectionBufferBinding);
buffer.bind(
#ifndef MAGNUM_TARGET_WEBGL
flags() >= Flag::ShaderStorageBuffers ? GL::Buffer::Target::ShaderStorage :
#endif
GL::Buffer::Target::Uniform, TransformationProjectionBufferBinding);
return *this;
}
MeshVisualizerGL2D& MeshVisualizerGL2D::bindTransformationProjectionBuffer(GL::Buffer& buffer, const GLintptr offset, const GLsizeiptr size) {
CORRADE_ASSERT(flags() >= Flag::UniformBuffers,
"Shaders::MeshVisualizerGL2D::bindTransformationProjectionBuffer(): the shader was not created with uniform buffers enabled", *this);
buffer.bind(GL::Buffer::Target::Uniform, TransformationProjectionBufferBinding, offset, size);
buffer.bind(
#ifndef MAGNUM_TARGET_WEBGL
flags() >= Flag::ShaderStorageBuffers ? GL::Buffer::Target::ShaderStorage :
#endif
GL::Buffer::Target::Uniform, TransformationProjectionBufferBinding, offset, size);
return *this;
}
MeshVisualizerGL2D& MeshVisualizerGL2D::bindDrawBuffer(GL::Buffer& buffer) {
CORRADE_ASSERT(flags() >= Flag::UniformBuffers,
"Shaders::MeshVisualizerGL2D::bindDrawBuffer(): the shader was not created with uniform buffers enabled", *this);
buffer.bind(GL::Buffer::Target::Uniform, DrawBufferBinding);
buffer.bind(
#ifndef MAGNUM_TARGET_WEBGL
flags() >= Flag::ShaderStorageBuffers ? GL::Buffer::Target::ShaderStorage :
#endif
GL::Buffer::Target::Uniform, DrawBufferBinding);
return *this;
}
MeshVisualizerGL2D& MeshVisualizerGL2D::bindDrawBuffer(GL::Buffer& buffer, const GLintptr offset, const GLsizeiptr size) {
CORRADE_ASSERT(flags() >= Flag::UniformBuffers,
"Shaders::MeshVisualizerGL2D::bindDrawBuffer(): the shader was not created with uniform buffers enabled", *this);
buffer.bind(GL::Buffer::Target::Uniform, DrawBufferBinding, offset, size);
buffer.bind(
#ifndef MAGNUM_TARGET_WEBGL
flags() >= Flag::ShaderStorageBuffers ? GL::Buffer::Target::ShaderStorage :
#endif
GL::Buffer::Target::Uniform, DrawBufferBinding, offset, size);
return *this;
}
#endif
@ -918,8 +1029,8 @@ MeshVisualizerGL2D::Configuration& MeshVisualizerGL2D::Configuration::setJointCo
"Shaders::MeshVisualizerGL2D::Configuration::setJointCount(): expected at most 4 per-vertex joints, got" << perVertexCount, *this);
CORRADE_ASSERT(secondaryPerVertexCount <= 4,
"Shaders::MeshVisualizerGL2D::Configuration::setJointCount(): expected at most 4 secondary per-vertex joints, got" << secondaryPerVertexCount, *this);
CORRADE_ASSERT(!count == (!perVertexCount && !secondaryPerVertexCount),
"Shaders::MeshVisualizerGL2D::Configuration::setJointCount(): count has to be non-zero iff (secondary) per-vertex joint count is non-zero", *this);
CORRADE_ASSERT(perVertexCount || secondaryPerVertexCount || !count,
"Shaders::MeshVisualizerGL2D::Configuration::setJointCount(): count has to be zero if per-vertex joint count is zero", *this);
_jointCount = count;
_perVertexJointCount = perVertexCount;
_secondaryPerVertexJointCount = secondaryPerVertexCount;
@ -954,11 +1065,21 @@ MeshVisualizerGL3D::CompileState MeshVisualizerGL3D::compile(const Configuration
/* Has to be here and not in the base class in order to have it exit the
constructor when testing for asserts -- GLSL compilation would fail
otherwise */
#ifndef MAGNUM_TARGET_GLES2
CORRADE_ASSERT(!(configuration.flags() >= Flag::UniformBuffers) || configuration.materialCount(),
"Shaders::MeshVisualizerGL3D: material count can't be zero", CompileState{NoCreate});
CORRADE_ASSERT(!(configuration.flags() >= Flag::UniformBuffers) || configuration.drawCount(),
"Shaders::MeshVisualizerGL3D: draw count can't be zero", CompileState{NoCreate});
/* Has to be here and not in the base class in order to have it exit the
constructor when testing for asserts -- GLSL compilation would fail
otherwise */
#if !defined(MAGNUM_TARGET_GLES2) && !defined(CORRADE_NO_ASSERT)
#ifndef MAGNUM_TARGET_WEBGL
if(!(configuration.flags() >= Flag::ShaderStorageBuffers))
#endif
{
CORRADE_ASSERT(!configuration.jointCount() == (!configuration.perVertexJointCount() && !configuration.secondaryPerVertexJointCount()),
"Shaders::MeshVisualizerGL3D: joint count can't be zero if per-vertex joint count is non-zero", CompileState{NoCreate});
CORRADE_ASSERT(!(configuration.flags() >= Flag::UniformBuffers) || configuration.materialCount(),
"Shaders::MeshVisualizerGL3D: material count can't be zero", CompileState{NoCreate});
CORRADE_ASSERT(!(configuration.flags() >= Flag::UniformBuffers) || configuration.drawCount(),
"Shaders::MeshVisualizerGL3D: draw count can't be zero", CompileState{NoCreate});
}
#endif
/* Has to be here and not in the base class in order to have it exit the
@ -1069,13 +1190,22 @@ MeshVisualizerGL3D::CompileState MeshVisualizerGL3D::compile(const Configuration
.addSource(configuration.flags() & Flag::NormalDirection ? "#define NORMAL_DIRECTION\n"_s : ""_s);
#ifndef MAGNUM_TARGET_GLES2
if(configuration.flags() >= Flag::UniformBuffers) {
geom->addSource(Utility::format(
"#define THREE_DIMENSIONS\n"
"#define UNIFORM_BUFFERS\n"
"#define DRAW_COUNT {}\n"
"#define MATERIAL_COUNT {}\n",
configuration.drawCount(),
configuration.materialCount()));
/* SSBOs have unbounded per-draw arrays so just a plain string can
be passed */
if(configuration.flags() >= Flag::ShaderStorageBuffers) {
geom->addSource(
"#define THREE_DIMENSIONS\n"
"#define UNIFORM_BUFFERS\n"
"#define SHADER_STORAGE_BUFFERS\n"_s);
} else {
geom->addSource(Utility::format(
"#define THREE_DIMENSIONS\n"
"#define UNIFORM_BUFFERS\n"
"#define DRAW_COUNT {}\n"
"#define MATERIAL_COUNT {}\n",
configuration.drawCount(),
configuration.materialCount()));
}
geom->addSource(configuration.flags() >= Flag::MultiDraw ? "#define MULTI_DRAW\n"_s : ""_s);
}
#endif
@ -1215,7 +1345,11 @@ MeshVisualizerGL3D::MeshVisualizerGL3D(CompileState&& state): MeshVisualizerGL3D
if(flags() >= Flag::DynamicPerVertexJointCount)
_perVertexJointCountUniform = uniformLocation("perVertexJointCount"_s);
if(flags() >= Flag::UniformBuffers) {
if(_drawCount > 1) _drawOffsetUniform = uniformLocation("drawOffset"_s);
if(_drawCount > 1
#ifndef MAGNUM_TARGET_WEBGL
|| flags() >= Flag::ShaderStorageBuffers
#endif
) _drawOffsetUniform = uniformLocation("drawOffset"_s);
} else
#endif
{
@ -1280,7 +1414,12 @@ MeshVisualizerGL3D::MeshVisualizerGL3D(CompileState&& state): MeshVisualizerGL3D
#ifndef MAGNUM_TARGET_GLES2
if(flags() >= Flag::ObjectIdTexture)
setUniform(uniformLocation("objectIdTextureData"_s), ObjectIdTextureUnit);
if(flags() >= Flag::UniformBuffers) {
/* SSBOs have bindings defined in the source always */
if(flags() >= Flag::UniformBuffers
#ifndef MAGNUM_TARGET_WEBGL
&& !(flags() >= Flag::ShaderStorageBuffers)
#endif
) {
setUniformBlockBinding(uniformBlockIndex("Projection"_s), ProjectionBufferBinding);
setUniformBlockBinding(uniformBlockIndex("Transformation"_s), TransformationBufferBinding);
setUniformBlockBinding(uniformBlockIndex("Draw"_s), DrawBufferBinding);
@ -1473,42 +1612,66 @@ MeshVisualizerGL3D& MeshVisualizerGL3D::setJointMatrix(const UnsignedInt id, con
MeshVisualizerGL3D& MeshVisualizerGL3D::bindProjectionBuffer(GL::Buffer& buffer) {
CORRADE_ASSERT(flags() >= Flag::UniformBuffers,
"Shaders::MeshVisualizerGL3D::bindProjectionBuffer(): the shader was not created with uniform buffers enabled", *this);
buffer.bind(GL::Buffer::Target::Uniform, ProjectionBufferBinding);
buffer.bind(
#ifndef MAGNUM_TARGET_WEBGL
flags() >= Flag::ShaderStorageBuffers ? GL::Buffer::Target::ShaderStorage :
#endif
GL::Buffer::Target::Uniform, ProjectionBufferBinding);
return *this;
}
MeshVisualizerGL3D& MeshVisualizerGL3D::bindProjectionBuffer(GL::Buffer& buffer, const GLintptr offset, const GLsizeiptr size) {
CORRADE_ASSERT(flags() >= Flag::UniformBuffers,
"Shaders::MeshVisualizerGL3D::bindProjectionBuffer(): the shader was not created with uniform buffers enabled", *this);
buffer.bind(GL::Buffer::Target::Uniform, ProjectionBufferBinding, offset, size);
buffer.bind(
#ifndef MAGNUM_TARGET_WEBGL
flags() >= Flag::ShaderStorageBuffers ? GL::Buffer::Target::ShaderStorage :
#endif
GL::Buffer::Target::Uniform, ProjectionBufferBinding, offset, size);
return *this;
}
MeshVisualizerGL3D& MeshVisualizerGL3D::bindTransformationBuffer(GL::Buffer& buffer) {
CORRADE_ASSERT(flags() >= Flag::UniformBuffers,
"Shaders::MeshVisualizerGL3D::bindTransformationBuffer(): the shader was not created with uniform buffers enabled", *this);
buffer.bind(GL::Buffer::Target::Uniform, TransformationBufferBinding);
buffer.bind(
#ifndef MAGNUM_TARGET_WEBGL
flags() >= Flag::ShaderStorageBuffers ? GL::Buffer::Target::ShaderStorage :
#endif
GL::Buffer::Target::Uniform, TransformationBufferBinding);
return *this;
}
MeshVisualizerGL3D& MeshVisualizerGL3D::bindTransformationBuffer(GL::Buffer& buffer, const GLintptr offset, const GLsizeiptr size) {
CORRADE_ASSERT(flags() >= Flag::UniformBuffers,
"Shaders::MeshVisualizerGL3D::bindTransformationBuffer(): the shader was not created with uniform buffers enabled", *this);
buffer.bind(GL::Buffer::Target::Uniform, TransformationBufferBinding, offset, size);
buffer.bind(
#ifndef MAGNUM_TARGET_WEBGL
flags() >= Flag::ShaderStorageBuffers ? GL::Buffer::Target::ShaderStorage :
#endif
GL::Buffer::Target::Uniform, TransformationBufferBinding, offset, size);
return *this;
}
MeshVisualizerGL3D& MeshVisualizerGL3D::bindDrawBuffer(GL::Buffer& buffer) {
CORRADE_ASSERT(flags() >= Flag::UniformBuffers,
"Shaders::MeshVisualizerGL3D::bindDrawBuffer(): the shader was not created with uniform buffers enabled", *this);
buffer.bind(GL::Buffer::Target::Uniform, DrawBufferBinding);
buffer.bind(
#ifndef MAGNUM_TARGET_WEBGL
flags() >= Flag::ShaderStorageBuffers ? GL::Buffer::Target::ShaderStorage :
#endif
GL::Buffer::Target::Uniform, DrawBufferBinding);
return *this;
}
MeshVisualizerGL3D& MeshVisualizerGL3D::bindDrawBuffer(GL::Buffer& buffer, const GLintptr offset, const GLsizeiptr size) {
CORRADE_ASSERT(flags() >= Flag::UniformBuffers,
"Shaders::MeshVisualizerGL3D::bindDrawBuffer(): the shader was not created with uniform buffers enabled", *this);
buffer.bind(GL::Buffer::Target::Uniform, DrawBufferBinding, offset, size);
buffer.bind(
#ifndef MAGNUM_TARGET_WEBGL
flags() >= Flag::ShaderStorageBuffers ? GL::Buffer::Target::ShaderStorage :
#endif
GL::Buffer::Target::Uniform, DrawBufferBinding, offset, size);
return *this;
}
#endif
@ -1519,8 +1682,8 @@ MeshVisualizerGL3D::Configuration& MeshVisualizerGL3D::Configuration::setJointCo
"Shaders::MeshVisualizerGL3D::Configuration::setJointCount(): expected at most 4 per-vertex joints, got" << perVertexCount, *this);
CORRADE_ASSERT(secondaryPerVertexCount <= 4,
"Shaders::MeshVisualizerGL3D::Configuration::setJointCount(): expected at most 4 secondary per-vertex joints, got" << secondaryPerVertexCount, *this);
CORRADE_ASSERT(!count == (!perVertexCount && !secondaryPerVertexCount),
"Shaders::MeshVisualizerGL3D::Configuration::setJointCount(): count has to be non-zero iff (secondary) per-vertex joint count is non-zero", *this);
CORRADE_ASSERT(perVertexCount || secondaryPerVertexCount || !count,
"Shaders::MeshVisualizerGL3D::Configuration::setJointCount(): count has to be zero if per-vertex joint count is zero", *this);
_jointCount = count;
_perVertexJointCount = perVertexCount;
_secondaryPerVertexJointCount = secondaryPerVertexCount;
@ -1535,6 +1698,11 @@ Debug& operator<<(Debug& debug, const MeshVisualizerGL2D::Flag value) {
`Flag::InstancedObjectId|Flag(0x4000)` in the output. */
if(value == MeshVisualizerGL2D::Flag(UnsignedInt(MeshVisualizerGL2D::Flag::InstancedObjectId|MeshVisualizerGL2D::Flag::ObjectIdTexture)))
return debug << MeshVisualizerGL2D::Flag::InstancedObjectId << Debug::nospace << "|" << Debug::nospace << MeshVisualizerGL2D::Flag::ObjectIdTexture;
#ifndef MAGNUM_TARGET_WEBGL
/* Similarly here, both are a superset of UniformBuffers */
if(value == MeshVisualizerGL2D::Flag(UnsignedInt(MeshVisualizerGL2D::Flag::MultiDraw|MeshVisualizerGL2D::Flag::ShaderStorageBuffers)))
return debug << MeshVisualizerGL2D::Flag::MultiDraw << Debug::nospace << "|" << Debug::nospace << MeshVisualizerGL2D::Flag::ShaderStorageBuffers;
#endif
#endif
debug << "Shaders::MeshVisualizerGL2D::Flag" << Debug::nospace;
@ -1561,6 +1729,9 @@ Debug& operator<<(Debug& debug, const MeshVisualizerGL2D::Flag value) {
#endif
#ifndef MAGNUM_TARGET_GLES2
_c(UniformBuffers)
#ifndef MAGNUM_TARGET_WEBGL
_c(ShaderStorageBuffers)
#endif
_c(MultiDraw)
_c(TextureArrays)
_c(DynamicPerVertexJointCount)
@ -1579,6 +1750,11 @@ Debug& operator<<(Debug& debug, const MeshVisualizerGL3D::Flag value) {
`Flag::InstancedObjectId|Flag(0x4000)` in the output. */
if(value == MeshVisualizerGL3D::Flag(UnsignedInt(MeshVisualizerGL3D::Flag::InstancedObjectId|MeshVisualizerGL3D::Flag::ObjectIdTexture)))
return debug << MeshVisualizerGL3D::Flag::InstancedObjectId << Debug::nospace << "|" << Debug::nospace << MeshVisualizerGL3D::Flag::ObjectIdTexture;
#ifndef MAGNUM_TARGET_WEBGL
/* Similarly here, both are a superset of UniformBuffers */
if(value == MeshVisualizerGL3D::Flag(UnsignedInt(MeshVisualizerGL3D::Flag::MultiDraw|MeshVisualizerGL3D::Flag::ShaderStorageBuffers)))
return debug << MeshVisualizerGL3D::Flag::MultiDraw << Debug::nospace << "|" << Debug::nospace << MeshVisualizerGL3D::Flag::ShaderStorageBuffers;
#endif
#endif
debug << "Shaders::MeshVisualizerGL3D::Flag" << Debug::nospace;
@ -1611,6 +1787,9 @@ Debug& operator<<(Debug& debug, const MeshVisualizerGL3D::Flag value) {
#endif
#ifndef MAGNUM_TARGET_GLES2
_c(UniformBuffers)
#ifndef MAGNUM_TARGET_WEBGL
_c(ShaderStorageBuffers)
#endif
_c(MultiDraw)
_c(TextureArrays)
_c(DynamicPerVertexJointCount)
@ -1647,7 +1826,15 @@ Debug& operator<<(Debug& debug, const MeshVisualizerGL2D::Flags value) {
MeshVisualizerGL2D::Flag::PrimitiveId,
#endif
#ifndef MAGNUM_TARGET_GLES2
#ifndef MAGNUM_TARGET_WEBGL
/* Both are a superset of UniformBuffers; similarly to ObjectId above
letting the Flag printer deal with that */
MeshVisualizerGL2D::Flag(UnsignedInt(MeshVisualizerGL2D::Flag::MultiDraw|MeshVisualizerGL2D::Flag::ShaderStorageBuffers)),
#endif
MeshVisualizerGL2D::Flag::MultiDraw, /* Superset of UniformBuffers */
#ifndef MAGNUM_TARGET_WEBGL
MeshVisualizerGL2D::Flag::ShaderStorageBuffers, /* Superset of UniformBuffers */
#endif
MeshVisualizerGL2D::Flag::UniformBuffers,
MeshVisualizerGL2D::Flag::TextureArrays,
MeshVisualizerGL2D::Flag::DynamicPerVertexJointCount,
@ -1687,7 +1874,15 @@ Debug& operator<<(Debug& debug, const MeshVisualizerGL3D::Flags value) {
MeshVisualizerGL3D::Flag::PrimitiveId,
#endif
#ifndef MAGNUM_TARGET_GLES2
#ifndef MAGNUM_TARGET_WEBGL
/* Both are a superset of UniformBuffers; similarly to ObjectId above
letting the Flag printer deal with that */
MeshVisualizerGL3D::Flag(UnsignedInt(MeshVisualizerGL3D::Flag::MultiDraw|MeshVisualizerGL3D::Flag::ShaderStorageBuffers)),
#endif
MeshVisualizerGL3D::Flag::MultiDraw, /* Superset of UniformBuffers */
#ifndef MAGNUM_TARGET_WEBGL
MeshVisualizerGL3D::Flag::ShaderStorageBuffers, /* Superset of UniformBuffers */
#endif
MeshVisualizerGL3D::Flag::UniformBuffers,
MeshVisualizerGL3D::Flag::TextureArrays,
MeshVisualizerGL3D::Flag::DynamicPerVertexJointCount,

139
src/Magnum/Shaders/MeshVisualizerGL.h

@ -68,6 +68,7 @@ class MAGNUM_SHADERS_EXPORT MeshVisualizerGLBase: public GL::AbstractShaderProgr
PrimitiveIdFromVertexId = (1 << 5)|PrimitiveId,
/* bit 6, 7, 8, 9 used by 3D-specific TBN visualization */
UniformBuffers = 1 << 10,
ShaderStorageBuffers = UniformBuffers|(1 << 19),
MultiDraw = UniformBuffers|(1 << 11),
TextureArrays = 1 << 17,
DynamicPerVertexJointCount = 1 << 18
@ -490,6 +491,7 @@ class MAGNUM_SHADERS_EXPORT MeshVisualizerGL2D: public Implementation::MeshVisua
* Use uniform buffers. Expects that uniform data are supplied via
* @ref bindTransformationProjectionBuffer(), @ref bindDrawBuffer()
* and @ref bindMaterialBuffer() instead of direct uniform setters.
* @see @ref Flag::ShaderStorageBuffers
* @requires_gl31 Extension @gl_extension{ARB,uniform_buffer_object}
* @requires_gles30 Uniform buffers are not available in OpenGL ES
* 2.0.
@ -499,6 +501,24 @@ class MAGNUM_SHADERS_EXPORT MeshVisualizerGL2D: public Implementation::MeshVisua
*/
UniformBuffers = 1 << 10,
#ifndef MAGNUM_TARGET_WEBGL
/**
* Use shader storage buffers. Superset of functionality provided
* by @ref Flag::UniformBuffers, compared to it doesn't have any
* size limits on @ref Configuration::setJointCount(),
* @relativeref{Configuration,setMaterialCount()} and
* @relativeref{Configuration,setDrawCount()} in exchange for
* potentially more costly access and narrower platform support.
* @requires_gl43 Extension @gl_extension{ARB,shader_storage_buffer_object}
* @requires_gles31 Shader storage buffers are not available in
* OpenGL ES 3.0 and older.
* @requires_gles Shader storage buffers are not available in
* WebGL.
* @m_since_latest
*/
ShaderStorageBuffers = UniformBuffers|(1 << 19),
#endif
/**
* Enable multidraw functionality. Implies @ref Flag::UniformBuffers
* and combines the value from @ref setDrawOffset() with the
@ -675,7 +695,8 @@ class MAGNUM_SHADERS_EXPORT MeshVisualizerGL2D: public Implementation::MeshVisua
* matrices accepted by @ref setJointMatrices() / @ref setJointMatrix().
* If @ref Flag::UniformBuffers is set, this is the statically defined
* size of the @ref TransformationUniform2D uniform buffer bound with
* @ref bindJointBuffer().
* @ref bindJointBuffer(). Has no use if @ref Flag::ShaderStorageBuffers
* is set.
* @see @ref Configuration::setJointCount()
* @requires_gles30 Not defined on OpenGL ES 2.0 builds.
* @requires_webgl20 Not defined on WebGL 1.0 builds.
@ -714,7 +735,8 @@ class MAGNUM_SHADERS_EXPORT MeshVisualizerGL2D: public Implementation::MeshVisua
*
* Statically defined size of the @ref MeshVisualizerMaterialUniform
* uniform buffer bound with @ref bindMaterialBuffer(). Has use only if
* @ref Flag::UniformBuffers is set.
* @ref Flag::UniformBuffers is set and @ref Flag::ShaderStorageBuffers
* is not set.
* @see @ref Configuration::setMaterialCount()
* @requires_gles30 Not defined on OpenGL ES 2.0 builds.
* @requires_webgl20 Not defined on WebGL 1.0 builds.
@ -729,7 +751,8 @@ class MAGNUM_SHADERS_EXPORT MeshVisualizerGL2D: public Implementation::MeshVisua
* @ref TransformationProjectionUniform2D and
* @ref MeshVisualizerDrawUniform2D uniform buffers bound with
* @ref bindTransformationProjectionBuffer() and @ref bindDrawBuffer().
* Has use only if @ref Flag::UniformBuffers is set.
* Has use only if @ref Flag::UniformBuffers is set and
* @ref Flag::ShaderStorageBuffers is not set.
* @see @ref Configuration::setDrawCount()
* @requires_gles30 Not defined on OpenGL ES 2.0 builds.
* @requires_webgl20 Not defined on WebGL 1.0 builds.
@ -983,7 +1006,7 @@ class MAGNUM_SHADERS_EXPORT MeshVisualizerGL2D: public Implementation::MeshVisua
#ifndef MAGNUM_TARGET_GLES2
/** @{
* @name Uniform buffer binding and related uniform setters
* @name Uniform / shader storage buffer binding and related uniform setters
*
* Used if @ref Flag::UniformBuffers is set.
*/
@ -1015,7 +1038,7 @@ class MAGNUM_SHADERS_EXPORT MeshVisualizerGL2D: public Implementation::MeshVisua
}
/**
* @brief Bind a transformation and projection uniform buffer
* @brief Bind a transformation and projection uniform / shader storage buffer
* @return Reference to self (for method chaining)
* @m_since_latest
*
@ -1035,7 +1058,7 @@ class MAGNUM_SHADERS_EXPORT MeshVisualizerGL2D: public Implementation::MeshVisua
MeshVisualizerGL2D& bindTransformationProjectionBuffer(GL::Buffer& buffer, GLintptr offset, GLsizeiptr size);
/**
* @brief Bind a draw uniform buffer
* @brief Bind a draw uniform / shader storage buffer
* @return Reference to self (for method chaining)
* @m_since_latest
*
@ -1065,7 +1088,7 @@ class MAGNUM_SHADERS_EXPORT MeshVisualizerGL2D: public Implementation::MeshVisua
}
/**
* @brief Bind a material uniform buffer
* @brief Bind a material uniform / shader storage buffer
* @return Reference to self (for method chaining)
* @m_since_latest
*
@ -1090,7 +1113,7 @@ class MAGNUM_SHADERS_EXPORT MeshVisualizerGL2D: public Implementation::MeshVisua
}
/**
* @brief Bind a joint matrix uniform buffer
* @brief Bind a joint matrix uniform / shader storage buffer
* @return Reference to self (for method chaining)
* @m_since_latest
*
@ -1216,9 +1239,10 @@ class MAGNUM_SHADERS_EXPORT MeshVisualizerGL2D::Configuration {
* @ref TransformationUniform2D buffer bound with
* @ref bindJointBuffer(). Uniform buffers have a statically defined
* size and @cpp count*sizeof(TransformationUniform2D) @ce has to be
* within @ref GL::AbstractShaderProgram::maxUniformBlockSize(). The
* per-vertex joints then index into the array offset by
* @ref MeshVisualizerDrawUniform2D::jointOffset.
* within @ref GL::AbstractShaderProgram::maxUniformBlockSize(), if
* @ref Flag::ShaderStorageBuffers is set as well, the buffer is
* unbounded and @p count is ignored. The per-vertex joints index into
* the array offset by @ref MeshVisualizerDrawUniform2D::jointOffset.
*
* The @p perVertexCount and @p secondaryPerVertexCount parameters
* describe how many components are taken from @ref JointIds /
@ -1227,8 +1251,8 @@ class MAGNUM_SHADERS_EXPORT MeshVisualizerGL2D::Configuration {
* @cpp 4 @ce, setting either of these to @cpp 0 @ce means given
* attribute is not used at all. If both @p perVertexCount and
* @p secondaryPerVertexCount are set to @cpp 0 @ce, skinning is not
* performed; if either of them is non-zero, @p count is expected to be
* non-zero as well.
* performed. Unless @ref Flag::ShaderStorageBuffers is set, if either
* of them is non-zero, @p count is expected to be non-zero as well.
*
* Default value for all three is @cpp 0 @ce.
* @see @ref MeshVisualizerGL2D::jointCount(),
@ -1259,11 +1283,11 @@ class MAGNUM_SHADERS_EXPORT MeshVisualizerGL2D::Configuration {
* @ref MeshVisualizerMaterialUniform buffer bound with
* @ref bindMaterialBuffer(). Uniform buffers have a statically defined
* size and @cpp count*sizeof(MeshVisualizerMaterialUniform) @ce has to
* be within @ref GL::AbstractShaderProgram::maxUniformBlockSize().
*
* The per-draw materials are then specified via
* @ref MeshVisualizerDrawUniform2D::materialId. Default value is
* @cpp 1 @ce.
* be within @ref GL::AbstractShaderProgram::maxUniformBlockSize(), if
* @ref Flag::ShaderStorageBuffers is set as well, the buffer is
* unbounded and @p count is ignored. The per-draw materials are
* specified via @ref MeshVisualizerDrawUniform2D::materialId. Default
* value is @cpp 1 @ce.
*
* If @ref Flag::UniformBuffers isn't set, this value is ignored.
* @see @ref setFlags(), @ref setDrawCount(),
@ -1297,10 +1321,10 @@ class MAGNUM_SHADERS_EXPORT MeshVisualizerGL2D::Configuration {
* @cpp count*sizeof(TransformationProjectionUniform2D) @ce,
* @cpp count*sizeof(MeshVisualizerDrawUniform2D) @ce and
* @cpp count*sizeof(TextureTransformationUniform) @ce has to be within
* @ref GL::AbstractShaderProgram::maxUniformBlockSize().
*
* The draw offset is then set via @ref setDrawOffset(). Default value
* is @cpp 1 @ce.
* @ref GL::AbstractShaderProgram::maxUniformBlockSize(), if
* @ref Flag::ShaderStorageBuffers is set as well, the buffers are
* unbounded and @p count is ignored. The draw offset is set via
* @ref setDrawOffset(). Default value is @cpp 1 @ce.
*
* If @ref Flag::UniformBuffers isn't set, this value is ignored.
* @see @ref setFlags(), @ref setMaterialCount(),
@ -2175,6 +2199,7 @@ class MAGNUM_SHADERS_EXPORT MeshVisualizerGL3D: public Implementation::MeshVisua
* @ref bindProjectionBuffer(), @ref bindTransformationBuffer(),
* @ref bindDrawBuffer() and @ref bindMaterialBuffer() instead of
* direct uniform setters.
* @see @ref Flag::ShaderStorageBuffers
* @requires_gl31 Extension @gl_extension{ARB,uniform_buffer_object}
* @requires_gles30 Uniform buffers are not available in OpenGL ES
* 2.0.
@ -2184,6 +2209,24 @@ class MAGNUM_SHADERS_EXPORT MeshVisualizerGL3D: public Implementation::MeshVisua
*/
UniformBuffers = 1 << 10,
#ifndef MAGNUM_TARGET_WEBGL
/**
* Use shader storage buffers. Superset of functionality provided
* by @ref Flag::UniformBuffers, compared to it doesn't have any
* size limits on @ref Configuration::setJointCount(),
* @relativeref{Configuration,setMaterialCount()} and
* @relativeref{Configuration,setDrawCount()} in exchange for
* potentially more costly access and narrower platform support.
* @requires_gl43 Extension @gl_extension{ARB,shader_storage_buffer_object}
* @requires_gles31 Shader storage buffers are not available in
* OpenGL ES 3.0 and older.
* @requires_gles Shader storage buffers are not available in
* WebGL.
* @m_since_latest
*/
ShaderStorageBuffers = UniformBuffers|(1 << 19),
#endif
/**
* Enable multidraw functionality. Implies @ref Flag::UniformBuffers
* and combines the value from @ref setDrawOffset() with the
@ -2388,7 +2431,8 @@ class MAGNUM_SHADERS_EXPORT MeshVisualizerGL3D: public Implementation::MeshVisua
* matrices accepted by @ref setJointMatrices() / @ref setJointMatrix().
* If @ref Flag::UniformBuffers is set, this is the statically defined
* size of the @ref TransformationUniform3D uniform buffer bound with
* @ref bindJointBuffer().
* @ref bindJointBuffer(). Has no use if @ref Flag::ShaderStorageBuffers
* is set.
* @see @ref Configuration::setJointCount()
* @requires_gles30 Not defined on OpenGL ES 2.0 builds.
* @requires_webgl20 Not defined on WebGL 1.0 builds.
@ -2427,7 +2471,8 @@ class MAGNUM_SHADERS_EXPORT MeshVisualizerGL3D: public Implementation::MeshVisua
*
* Statically defined size of the @ref MeshVisualizerMaterialUniform
* uniform buffer bound with @ref bindMaterialBuffer(). Has use only if
* @ref Flag::UniformBuffers is set.
* @ref Flag::UniformBuffers is set and @ref Flag::ShaderStorageBuffers
* is not set.
* @see @ref Configuration::setMaterialCount()
* @requires_gles30 Not defined on OpenGL ES 2.0 builds.
* @requires_webgl20 Not defined on WebGL 1.0 builds.
@ -2442,7 +2487,8 @@ class MAGNUM_SHADERS_EXPORT MeshVisualizerGL3D: public Implementation::MeshVisua
* @ref TransformationUniform3D and
* @ref MeshVisualizerDrawUniform3D uniform buffers, bound with
* @ref bindTransformationBuffer() and @ref bindDrawBuffer(). Has use
* only if @ref Flag::UniformBuffers is set.
* only if @ref Flag::UniformBuffers is set and
* @ref Flag::ShaderStorageBuffers is not set.
* @see @ref Configuration::setDrawCount()
* @requires_gles30 Not defined on OpenGL ES 2.0 builds.
* @requires_webgl20 Not defined on WebGL 1.0 builds.
@ -2875,7 +2921,7 @@ class MAGNUM_SHADERS_EXPORT MeshVisualizerGL3D: public Implementation::MeshVisua
#ifndef MAGNUM_TARGET_GLES2
/** @{
* @name Uniform buffer binding and related uniform setters
* @name Uniform / shader storage buffer binding and related uniform setters
*
* Used if @ref Flag::UniformBuffers is set.
*/
@ -2906,7 +2952,7 @@ class MAGNUM_SHADERS_EXPORT MeshVisualizerGL3D: public Implementation::MeshVisua
}
/**
* @brief Bind a projection uniform buffer
* @brief Bind a projection uniform / shader storage buffer
* @return Reference to self (for method chaining)
* @m_since_latest
*
@ -2927,7 +2973,7 @@ class MAGNUM_SHADERS_EXPORT MeshVisualizerGL3D: public Implementation::MeshVisua
MeshVisualizerGL3D& bindProjectionBuffer(GL::Buffer& buffer, GLintptr offset, GLsizeiptr size);
/**
* @brief Bind a transformation uniform buffer
* @brief Bind a transformation uniform / shader storage buffer
* @return Reference to self (for method chaining)
* @m_since_latest
*
@ -2947,7 +2993,7 @@ class MAGNUM_SHADERS_EXPORT MeshVisualizerGL3D: public Implementation::MeshVisua
MeshVisualizerGL3D& bindTransformationBuffer(GL::Buffer& buffer, GLintptr offset, GLsizeiptr size);
/**
* @brief Bind a draw uniform buffer
* @brief Bind a draw uniform / shader storage buffer
* @return Reference to self (for method chaining)
* @m_since_latest
*
@ -2968,7 +3014,7 @@ class MAGNUM_SHADERS_EXPORT MeshVisualizerGL3D: public Implementation::MeshVisua
MeshVisualizerGL3D& bindDrawBuffer(GL::Buffer& buffer, GLintptr offset, GLsizeiptr size);
/**
* @brief Bind a texture transformation uniform buffer for an object ID texture
* @brief Bind a texture transformation uniform / shader storage buffer for an object ID texture
* @return Reference to self (for method chaining)
* @m_since_latest
*
@ -2996,7 +3042,7 @@ class MAGNUM_SHADERS_EXPORT MeshVisualizerGL3D: public Implementation::MeshVisua
}
/**
* @brief Bind a material uniform buffer
* @brief Bind a material uniform / shader storage buffer
* @return Reference to self (for method chaining)
* @m_since_latest
*
@ -3021,7 +3067,7 @@ class MAGNUM_SHADERS_EXPORT MeshVisualizerGL3D: public Implementation::MeshVisua
}
/**
* @brief Bind a joint matrix uniform buffer
* @brief Bind a joint matrix uniform / shader storage buffer
* @return Reference to self (for method chaining)
* @m_since_latest
*
@ -3208,9 +3254,10 @@ class MeshVisualizerGL3D::Configuration {
* @ref TransformationUniform3D buffer bound with
* @ref bindJointBuffer(). Uniform buffers have a statically defined
* size and @cpp count*sizeof(TransformationUniform3D) @ce has to be
* within @ref GL::AbstractShaderProgram::maxUniformBlockSize(). The
* per-vertex joints then index into the array offset by
* @ref MeshVisualizerDrawUniform3D::jointOffset.
* within @ref GL::AbstractShaderProgram::maxUniformBlockSize(), if
* @ref Flag::ShaderStorageBuffers is set as well, the buffer is
* unbounded and @p count is ignored. The per-vertex joints index into
* the array offset by @ref MeshVisualizerDrawUniform3D::jointOffset.
*
* The @p perVertexCount and @p secondaryPerVertexCount parameters
* describe how many components are taken from @ref JointIds /
@ -3219,8 +3266,8 @@ class MeshVisualizerGL3D::Configuration {
* @cpp 4 @ce, setting either of these to @cpp 0 @ce means given
* attribute is not used at all. If both @p perVertexCount and
* @p secondaryPerVertexCount are set to @cpp 0 @ce, skinning is not
* performed; if either of them is non-zero, @p count is expected to be
* non-zero as well.
* performed. Unless @ref Flag::ShaderStorageBuffers is set, if either
* of them is non-zero, @p count is expected to be non-zero as well.
*
* Default value for all three is @cpp 0 @ce.
* @see @ref MeshVisualizerGL2D::jointCount(),
@ -3251,11 +3298,11 @@ class MeshVisualizerGL3D::Configuration {
* @ref MeshVisualizerMaterialUniform buffer bound with
* @ref bindMaterialBuffer(). Uniform buffers have a statically defined
* size and @cpp count*sizeof(MeshVisualizerMaterialUniform) @ce has to
* be within @ref GL::AbstractShaderProgram::maxUniformBlockSize().
*
* The per-draw materials are then specified via
* @ref MeshVisualizerDrawUniform3D::materialId. Default value is
* @cpp 1 @ce.
* be within @ref GL::AbstractShaderProgram::maxUniformBlockSize(), if
* @ref Flag::ShaderStorageBuffers is set as well, the buffer is
* unbounded and @p count is ignored. The per-draw materials are
* specified via @ref MeshVisualizerDrawUniform3D::materialId. Default
* value is @cpp 1 @ce.
*
* If @ref Flag::UniformBuffers isn't set, this value is ignored.
* @see @ref setFlags(), @ref setDrawCount(),
@ -3289,10 +3336,10 @@ class MeshVisualizerGL3D::Configuration {
* @cpp count*sizeof(TransformationUniform3D) @ce,
* @cpp count*sizeof(MeshVisualizerDrawUniform3D) @ce and
* @cpp count*sizeof(TextureTransformationUniform) @ce has to be within
* @ref GL::AbstractShaderProgram::maxUniformBlockSize().
*
* The draw offset is then set via @ref setDrawOffset(). Default value
* is @cpp 1 @ce.
* @ref GL::AbstractShaderProgram::maxUniformBlockSize(), if
* @ref Flag::ShaderStorageBuffers is set as well, the buffers are
* unbounded and @p count is ignored. The draw offset is set via
* @ref setDrawOffset(). Default value is @cpp 1 @ce.
*
* If @ref Flag::UniformBuffers isn't set, this value is ignored.
* @see @ref setFlags(), @ref setMaterialCount(),

48
src/Magnum/Shaders/Phong.frag

@ -27,6 +27,10 @@
#extension GL_EXT_gpu_shader4: require
#endif
#if defined(SHADER_STORAGE_BUFFERS) && !defined(GL_ES)
#extension GL_ARB_shader_storage_buffer_object: require
#endif
#ifndef NEW_GLSL
#define in varying
#define fragmentColor gl_FragColor
@ -159,11 +163,25 @@ uniform lowp float lightRanges[LIGHT_COUNT]
;
#endif
/* Uniform buffers */
/* Uniform / shader storage buffers */
#else
/* For SSBOs, the per-draw, material and light arrays are unbounded */
#ifdef SHADER_STORAGE_BUFFERS
#define DRAW_COUNT
#define MATERIAL_COUNT
#define LIGHT_COUNT
#define BUFFER_OR_UNIFORM buffer
#define BUFFER_READONLY readonly
#else
#define BUFFER_OR_UNIFORM uniform
#define BUFFER_READONLY
#endif
#ifndef MULTI_DRAW
#if DRAW_COUNT > 1
/* With SSBOs DRAW_COUNT is defined to be empty, +0 makes the condition not
cause a compile error */
#if defined(SHADER_STORAGE_BUFFERS) || DRAW_COUNT+0 > 1
#ifdef EXPLICIT_UNIFORM_LOCATION
layout(location = 0)
#endif
@ -191,11 +209,11 @@ struct DrawUniform {
};
layout(std140
#ifdef EXPLICIT_BINDING
#if defined(EXPLICIT_BINDING) || defined(SHADER_STORAGE_BUFFERS)
, binding = 2
#endif
) uniform Draw {
DrawUniform draws[DRAW_COUNT];
) BUFFER_OR_UNIFORM Draw {
BUFFER_READONLY DrawUniform draws[DRAW_COUNT];
};
struct MaterialUniform {
@ -209,14 +227,16 @@ struct MaterialUniform {
};
layout(std140
#ifdef EXPLICIT_BINDING
#if defined(EXPLICIT_BINDING) || defined(SHADER_STORAGE_BUFFERS)
, binding = 4
#endif
) uniform Material {
MaterialUniform materials[MATERIAL_COUNT];
) BUFFER_OR_UNIFORM Material {
BUFFER_READONLY MaterialUniform materials[MATERIAL_COUNT];
};
#if LIGHT_COUNT
/* With SSBOs LIGHT_COUNT is defined to be empty, +0 makes the condition not
cause a compile error */
#if defined(SHADER_STORAGE_BUFFERS) || LIGHT_COUNT+0
struct LightUniform {
highp vec4 position;
lowp vec3 colorReserved;
@ -228,11 +248,11 @@ struct LightUniform {
};
layout(std140
#ifdef EXPLICIT_BINDING
#if defined(EXPLICIT_BINDING) || defined(SHADER_STORAGE_BUFFERS)
, binding = 5
#endif
) uniform Light {
LightUniform lights[LIGHT_COUNT];
) BUFFER_OR_UNIFORM Light {
BUFFER_READONLY LightUniform lights[LIGHT_COUNT];
};
#endif
#endif
@ -364,7 +384,9 @@ void main() {
#ifdef OBJECT_ID
highp const uint objectId = draws[drawId].draw_objectId;
#endif
#if MATERIAL_COUNT > 1
/* With SSBOs MATERIAL_COUNT is defined to be empty, +0 makes the condition
not cause a compile error */
#if defined(SHADER_STORAGE_BUFFERS) || MATERIAL_COUNT+0 > 1
mediump const uint materialId = draws[drawId].draw_materialIdReserved & 0xffffu;
#else
#define materialId 0u

55
src/Magnum/Shaders/Phong.vert

@ -31,6 +31,10 @@
#extension GL_ARB_shader_bit_encoding: require
#endif
#if defined(SHADER_STORAGE_BUFFERS) && !defined(GL_ES)
#extension GL_ARB_shader_storage_buffer_object: require
#endif
#ifdef MULTI_DRAW
#ifndef GL_ES
#extension GL_ARB_shader_draw_parameters: require
@ -128,10 +132,27 @@ layout(location = PER_INSTANCE_JOINT_COUNT_LOCATION)
uniform uint perInstanceJointCount; /* defaults to zero */
#endif
/* Uniform buffers */
/* Uniform / shader storage buffers */
#else
#if DRAW_COUNT > 1
/* For SSBOs, the per-draw and joint arrays are unbounded */
#ifdef SHADER_STORAGE_BUFFERS
#define DRAW_COUNT
/* Define JOINT_COUNT only if there are any per-vertex attributes, otherwise
the buffer would be useless */
#if defined(PER_VERTEX_JOINT_COUNT) || defined(SECONDARY_PER_VERTEX_JOINT_COUNT)
#define JOINT_COUNT
#endif
#define BUFFER_OR_UNIFORM buffer
#define BUFFER_READONLY readonly
#else
#define BUFFER_OR_UNIFORM uniform
#define BUFFER_READONLY
#endif
/* With SSBOs DRAW_COUNT is defined to be empty, +0 makes the condition not
cause a compile error */
#if defined(SHADER_STORAGE_BUFFERS) || DRAW_COUNT+0 > 1
#ifdef EXPLICIT_UNIFORM_LOCATION
layout(location = 0)
#endif
@ -169,36 +190,36 @@ struct DrawUniform {
};
layout(std140
#ifdef EXPLICIT_BINDING
#if defined(EXPLICIT_BINDING) || defined(SHADER_STORAGE_BUFFERS)
, binding = 2
#endif
) uniform Draw {
DrawUniform draws[DRAW_COUNT];
) BUFFER_OR_UNIFORM Draw {
BUFFER_READONLY DrawUniform draws[DRAW_COUNT];
};
layout(std140
#ifdef EXPLICIT_BINDING
#if defined(EXPLICIT_BINDING) || defined(SHADER_STORAGE_BUFFERS)
, binding = 0
#endif
) uniform Projection {
highp mat4 projectionMatrix;
) BUFFER_OR_UNIFORM Projection {
BUFFER_READONLY highp mat4 projectionMatrix;
};
layout(std140
#ifdef EXPLICIT_BINDING
#if defined(EXPLICIT_BINDING) || defined(SHADER_STORAGE_BUFFERS)
, binding = 1
#endif
) uniform Transformation {
highp mat4 transformationMatrices[DRAW_COUNT];
) BUFFER_OR_UNIFORM Transformation {
BUFFER_READONLY highp mat4 transformationMatrices[DRAW_COUNT];
};
#ifdef JOINT_COUNT
layout(std140
#ifdef EXPLICIT_BINDING
#if defined(EXPLICIT_BINDING) || defined(SHADER_STORAGE_BUFFERS)
, binding = 6
#endif
) uniform Joint {
highp mat4 jointMatrices[JOINT_COUNT];
) BUFFER_OR_UNIFORM Joint {
BUFFER_READONLY highp mat4 jointMatrices[JOINT_COUNT];
};
#endif
@ -211,11 +232,11 @@ struct TextureTransformationUniform {
};
layout(std140
#ifdef EXPLICIT_BINDING
#if defined(EXPLICIT_BINDING) || defined(SHADER_STORAGE_BUFFERS)
, binding = 3
#endif
) uniform TextureTransformation {
TextureTransformationUniform textureTransformations[DRAW_COUNT];
) BUFFER_OR_UNIFORM TextureTransformation {
BUFFER_READONLY TextureTransformationUniform textureTransformations[DRAW_COUNT];
};
#endif
#endif

222
src/Magnum/Shaders/PhongGL.cpp

@ -99,11 +99,22 @@ PhongGL::CompileState PhongGL::compile(const Configuration& configuration) {
"Shaders::PhongGL: Bitangent attribute binding conflicts with the ObjectId attribute, use a Tangent4 attribute with instanced object ID rendering instead", CompileState{NoCreate});
#endif
#ifndef MAGNUM_TARGET_GLES2
CORRADE_ASSERT(!(configuration.flags() >= Flag::UniformBuffers) || configuration.materialCount(),
"Shaders::PhongGL: material count can't be zero", CompileState{NoCreate});
CORRADE_ASSERT(!(configuration.flags() >= Flag::UniformBuffers) || configuration.drawCount(),
"Shaders::PhongGL: draw count can't be zero", CompileState{NoCreate});
#ifndef CORRADE_NO_ASSERT
#if !defined(MAGNUM_TARGET_GLES2) && !defined(MAGNUM_TARGET_WEBGL)
if(!(configuration.flags() >= Flag::ShaderStorageBuffers))
#endif
{
CORRADE_ASSERT(configuration.perDrawLightCount() <= configuration.lightCount(),
"Shaders::PhongGL: per-draw light count expected to not be larger than total count of" << configuration.lightCount() << Debug::nospace << ", got" << configuration.perDrawLightCount(), CompileState{NoCreate});
#ifndef MAGNUM_TARGET_GLES2
CORRADE_ASSERT(!configuration.jointCount() == (!configuration.perVertexJointCount() && !configuration.secondaryPerVertexJointCount()),
"Shaders::PhongGL: joint count can't be zero if per-vertex joint count is non-zero", CompileState{NoCreate});
CORRADE_ASSERT(!(configuration.flags() >= Flag::UniformBuffers) || configuration.materialCount(),
"Shaders::PhongGL: material count can't be zero", CompileState{NoCreate});
CORRADE_ASSERT(!(configuration.flags() >= Flag::UniformBuffers) || configuration.drawCount(),
"Shaders::PhongGL: draw count can't be zero", CompileState{NoCreate});
#endif
}
#endif
#ifndef MAGNUM_TARGET_GLES2
@ -131,6 +142,15 @@ PhongGL::CompileState PhongGL::compile(const Configuration& configuration) {
if(configuration.flags() >= Flag::UniformBuffers)
MAGNUM_ASSERT_GL_EXTENSION_SUPPORTED(GL::Extensions::ARB::uniform_buffer_object);
#endif
#if !defined(MAGNUM_TARGET_GLES2) && !defined(MAGNUM_TARGET_WEBGL)
if(configuration.flags() >= Flag::ShaderStorageBuffers) {
#ifndef MAGNUM_TARGET_GLES
MAGNUM_ASSERT_GL_EXTENSION_SUPPORTED(GL::Extensions::ARB::shader_storage_buffer_object);
#else
MAGNUM_ASSERT_GL_VERSION_SUPPORTED(GL::Version::GLES310);
#endif
}
#endif
#ifndef MAGNUM_TARGET_GLES2
if(configuration.flags() >= Flag::MultiDraw) {
#ifndef MAGNUM_TARGET_GLES
@ -252,9 +272,15 @@ PhongGL::CompileState PhongGL::compile(const Configuration& configuration) {
#endif
{
vert.addSource(Utility::format(
"#define JOINT_COUNT {}\n"
"#define PER_VERTEX_JOINT_COUNT {}u\n"
"#define SECONDARY_PER_VERTEX_JOINT_COUNT {}u\n",
/* SSBOs have an unbounded joints array */
#ifndef MAGNUM_TARGET_WEBGL
configuration.flags() >= Flag::ShaderStorageBuffers ?
"#define PER_VERTEX_JOINT_COUNT {1}u\n"
"#define SECONDARY_PER_VERTEX_JOINT_COUNT {2}u\n" :
#endif
"#define JOINT_COUNT {}\n"
"#define PER_VERTEX_JOINT_COUNT {1}u\n"
"#define SECONDARY_PER_VERTEX_JOINT_COUNT {2}u\n",
configuration.jointCount(),
configuration.perVertexJointCount(),
configuration.secondaryPerVertexJointCount()));
@ -264,7 +290,7 @@ PhongGL::CompileState PhongGL::compile(const Configuration& configuration) {
#ifndef MAGNUM_TARGET_WEBGL
/* The _LOCATION is needed only if explicit uniform location (desktop /
ES3.1) is supported, a plain string can be added otherwise. This is
an immediate uniform also in the UBO case. */
an immediate uniform also in the UBO / SSBO case. */
#ifndef MAGNUM_TARGET_GLES
if(context.isExtensionSupported<GL::Extensions::ARB::explicit_uniform_location>(version))
#else
@ -284,10 +310,21 @@ PhongGL::CompileState PhongGL::compile(const Configuration& configuration) {
#endif
#ifndef MAGNUM_TARGET_GLES2
if(configuration.flags() >= Flag::UniformBuffers) {
vert.addSource(Utility::format(
"#define UNIFORM_BUFFERS\n"
"#define DRAW_COUNT {}\n",
configuration.drawCount()));
#ifndef MAGNUM_TARGET_WEBGL
/* SSBOs have unbounded per-draw arrays so just a plain string can be
passed */
if(configuration.flags() >= Flag::ShaderStorageBuffers) {
vert.addSource(
"#define UNIFORM_BUFFERS\n"
"#define SHADER_STORAGE_BUFFERS\n"_s);
} else
#endif
{
vert.addSource(Utility::format(
"#define UNIFORM_BUFFERS\n"
"#define DRAW_COUNT {}\n",
configuration.drawCount()));
}
vert.addSource(configuration.flags() >= Flag::MultiDraw ? "#define MULTI_DRAW\n"_s : ""_s);
}
#endif
@ -316,15 +353,22 @@ PhongGL::CompileState PhongGL::compile(const Configuration& configuration) {
#ifndef MAGNUM_TARGET_GLES2
if(configuration.flags() >= Flag::UniformBuffers) {
frag.addSource(Utility::format(
"#define UNIFORM_BUFFERS\n"
"#define DRAW_COUNT {}\n"
"#define MATERIAL_COUNT {}\n"
"#define LIGHT_COUNT {}\n"
"#define PER_DRAW_LIGHT_COUNT {}\n",
configuration.drawCount(),
configuration.materialCount(),
configuration.lightCount(),
configuration.perDrawLightCount()));
#ifndef MAGNUM_TARGET_WEBGL
/* SSBOs have unbounded per-draw, material and light arrays */
configuration.flags() >= Flag::ShaderStorageBuffers ?
"#define UNIFORM_BUFFERS\n"
"#define SHADER_STORAGE_BUFFERS\n"
"#define PER_DRAW_LIGHT_COUNT {3}\n" :
#endif
"#define UNIFORM_BUFFERS\n"
"#define DRAW_COUNT {0}\n"
"#define MATERIAL_COUNT {1}\n"
"#define LIGHT_COUNT {2}\n"
"#define PER_DRAW_LIGHT_COUNT {3}\n",
configuration.drawCount(),
configuration.materialCount(),
configuration.lightCount(),
configuration.perDrawLightCount()));
frag.addSource(configuration.flags() >= Flag::MultiDraw ? "#define MULTI_DRAW\n"_s : ""_s)
.addSource(configuration.flags() >= Flag::LightCulling ? "#define LIGHT_CULLING\n"_s : ""_s);
} else
@ -469,7 +513,11 @@ PhongGL::PhongGL(CompileState&& state): PhongGL{static_cast<PhongGL&&>(std::move
if(_flags >= Flag::DynamicPerVertexJointCount)
_perVertexJointCountUniform = uniformLocation("perVertexJointCount"_s);
if(_flags >= Flag::UniformBuffers) {
if(_drawCount > 1) _drawOffsetUniform = uniformLocation("drawOffset"_s);
if(_drawCount > 1
#ifndef MAGNUM_TARGET_WEBGL
|| flags() >= Flag::ShaderStorageBuffers
#endif
) _drawOffsetUniform = uniformLocation("drawOffset"_s);
} else
#endif
{
@ -524,7 +572,12 @@ PhongGL::PhongGL(CompileState&& state): PhongGL{static_cast<PhongGL&&>(std::move
}
#ifndef MAGNUM_TARGET_GLES2
if(_flags >= Flag::ObjectIdTexture) setUniform(uniformLocation("objectIdTextureData"_s), ObjectIdTextureUnit);
if(_flags >= Flag::UniformBuffers) {
/* SSBOs have bindings defined in the source always */
if(_flags >= Flag::UniformBuffers
#ifndef MAGNUM_TARGET_WEBGL
&& !(_flags >= Flag::ShaderStorageBuffers)
#endif
) {
setUniformBlockBinding(uniformBlockIndex("Projection"_s), ProjectionBufferBinding);
setUniformBlockBinding(uniformBlockIndex("Transformation"_s), TransformationBufferBinding);
setUniformBlockBinding(uniformBlockIndex("Draw"_s), DrawBufferBinding);
@ -940,51 +993,84 @@ PhongGL& PhongGL::setPerInstanceJointCount(const UnsignedInt count) {
PhongGL& PhongGL::setDrawOffset(const UnsignedInt offset) {
CORRADE_ASSERT(_flags >= Flag::UniformBuffers,
"Shaders::PhongGL::setDrawOffset(): the shader was not created with uniform buffers enabled", *this);
#ifndef MAGNUM_TARGET_WEBGL
CORRADE_ASSERT(_flags >= Flag::ShaderStorageBuffers || offset < _drawCount,
"Shaders::PhongGL::setDrawOffset(): draw offset" << offset << "is out of bounds for" << _drawCount << "draws", *this);
#else
CORRADE_ASSERT(offset < _drawCount,
"Shaders::PhongGL::setDrawOffset(): draw offset" << offset << "is out of bounds for" << _drawCount << "draws", *this);
if(_drawCount > 1) setUniform(_drawOffsetUniform, offset);
#endif
if(_drawCount > 1
#ifndef MAGNUM_TARGET_WEBGL
|| _flags >= Flag::ShaderStorageBuffers
#endif
) setUniform(_drawOffsetUniform, offset);
return *this;
}
PhongGL& PhongGL::bindProjectionBuffer(GL::Buffer& buffer) {
CORRADE_ASSERT(_flags >= Flag::UniformBuffers,
"Shaders::PhongGL::bindProjectionBuffer(): the shader was not created with uniform buffers enabled", *this);
buffer.bind(GL::Buffer::Target::Uniform, ProjectionBufferBinding);
buffer.bind(
#ifndef MAGNUM_TARGET_WEBGL
_flags >= Flag::ShaderStorageBuffers ? GL::Buffer::Target::ShaderStorage :
#endif
GL::Buffer::Target::Uniform, ProjectionBufferBinding);
return *this;
}
PhongGL& PhongGL::bindProjectionBuffer(GL::Buffer& buffer, const GLintptr offset, const GLsizeiptr size) {
CORRADE_ASSERT(_flags >= Flag::UniformBuffers,
"Shaders::PhongGL::bindProjectionBuffer(): the shader was not created with uniform buffers enabled", *this);
buffer.bind(GL::Buffer::Target::Uniform, ProjectionBufferBinding, offset, size);
buffer.bind(
#ifndef MAGNUM_TARGET_WEBGL
_flags >= Flag::ShaderStorageBuffers ? GL::Buffer::Target::ShaderStorage :
#endif
GL::Buffer::Target::Uniform, ProjectionBufferBinding, offset, size);
return *this;
}
PhongGL& PhongGL::bindTransformationBuffer(GL::Buffer& buffer) {
CORRADE_ASSERT(_flags >= Flag::UniformBuffers,
"Shaders::PhongGL::bindTransformationBuffer(): the shader was not created with uniform buffers enabled", *this);
buffer.bind(GL::Buffer::Target::Uniform, TransformationBufferBinding);
buffer.bind(
#ifndef MAGNUM_TARGET_WEBGL
_flags >= Flag::ShaderStorageBuffers ? GL::Buffer::Target::ShaderStorage :
#endif
GL::Buffer::Target::Uniform, TransformationBufferBinding);
return *this;
}
PhongGL& PhongGL::bindTransformationBuffer(GL::Buffer& buffer, const GLintptr offset, const GLsizeiptr size) {
CORRADE_ASSERT(_flags >= Flag::UniformBuffers,
"Shaders::PhongGL::bindTransformationBuffer(): the shader was not created with uniform buffers enabled", *this);
buffer.bind(GL::Buffer::Target::Uniform, TransformationBufferBinding, offset, size);
buffer.bind(
#ifndef MAGNUM_TARGET_WEBGL
_flags >= Flag::ShaderStorageBuffers ? GL::Buffer::Target::ShaderStorage :
#endif
GL::Buffer::Target::Uniform, TransformationBufferBinding, offset, size);
return *this;
}
PhongGL& PhongGL::bindDrawBuffer(GL::Buffer& buffer) {
CORRADE_ASSERT(_flags >= Flag::UniformBuffers,
"Shaders::PhongGL::bindDrawBuffer(): the shader was not created with uniform buffers enabled", *this);
buffer.bind(GL::Buffer::Target::Uniform, DrawBufferBinding);
buffer.bind(
#ifndef MAGNUM_TARGET_WEBGL
_flags >= Flag::ShaderStorageBuffers ? GL::Buffer::Target::ShaderStorage :
#endif
GL::Buffer::Target::Uniform, DrawBufferBinding);
return *this;
}
PhongGL& PhongGL::bindDrawBuffer(GL::Buffer& buffer, const GLintptr offset, const GLsizeiptr size) {
CORRADE_ASSERT(_flags >= Flag::UniformBuffers,
"Shaders::PhongGL::bindDrawBuffer(): the shader was not created with uniform buffers enabled", *this);
buffer.bind(GL::Buffer::Target::Uniform, DrawBufferBinding, offset, size);
buffer.bind(
#ifndef MAGNUM_TARGET_WEBGL
_flags >= Flag::ShaderStorageBuffers ? GL::Buffer::Target::ShaderStorage :
#endif
GL::Buffer::Target::Uniform, DrawBufferBinding, offset, size);
return *this;
}
@ -993,7 +1079,11 @@ PhongGL& PhongGL::bindTextureTransformationBuffer(GL::Buffer& buffer) {
"Shaders::PhongGL::bindTextureTransformationBuffer(): the shader was not created with uniform buffers enabled", *this);
CORRADE_ASSERT(_flags & Flag::TextureTransformation,
"Shaders::PhongGL::bindTextureTransformationBuffer(): the shader was not created with texture transformation enabled", *this);
buffer.bind(GL::Buffer::Target::Uniform, TextureTransformationBufferBinding);
buffer.bind(
#ifndef MAGNUM_TARGET_WEBGL
_flags >= Flag::ShaderStorageBuffers ? GL::Buffer::Target::ShaderStorage :
#endif
GL::Buffer::Target::Uniform, TextureTransformationBufferBinding);
return *this;
}
@ -1002,49 +1092,77 @@ PhongGL& PhongGL::bindTextureTransformationBuffer(GL::Buffer& buffer, const GLin
"Shaders::PhongGL::bindTextureTransformationBuffer(): the shader was not created with uniform buffers enabled", *this);
CORRADE_ASSERT(_flags & Flag::TextureTransformation,
"Shaders::PhongGL::bindTextureTransformationBuffer(): the shader was not created with texture transformation enabled", *this);
buffer.bind(GL::Buffer::Target::Uniform, TextureTransformationBufferBinding, offset, size);
buffer.bind(
#ifndef MAGNUM_TARGET_WEBGL
_flags >= Flag::ShaderStorageBuffers ? GL::Buffer::Target::ShaderStorage :
#endif
GL::Buffer::Target::Uniform, TextureTransformationBufferBinding, offset, size);
return *this;
}
PhongGL& PhongGL::bindMaterialBuffer(GL::Buffer& buffer) {
CORRADE_ASSERT(_flags >= Flag::UniformBuffers,
"Shaders::PhongGL::bindMaterialBuffer(): the shader was not created with uniform buffers enabled", *this);
buffer.bind(GL::Buffer::Target::Uniform, MaterialBufferBinding);
buffer.bind(
#ifndef MAGNUM_TARGET_WEBGL
_flags >= Flag::ShaderStorageBuffers ? GL::Buffer::Target::ShaderStorage :
#endif
GL::Buffer::Target::Uniform, MaterialBufferBinding);
return *this;
}
PhongGL& PhongGL::bindMaterialBuffer(GL::Buffer& buffer, const GLintptr offset, const GLsizeiptr size) {
CORRADE_ASSERT(_flags >= Flag::UniformBuffers,
"Shaders::PhongGL::bindMaterialBuffer(): the shader was not created with uniform buffers enabled", *this);
buffer.bind(GL::Buffer::Target::Uniform, MaterialBufferBinding, offset, size);
buffer.bind(
#ifndef MAGNUM_TARGET_WEBGL
_flags >= Flag::ShaderStorageBuffers ? GL::Buffer::Target::ShaderStorage :
#endif
GL::Buffer::Target::Uniform, MaterialBufferBinding, offset, size);
return *this;
}
PhongGL& PhongGL::bindLightBuffer(GL::Buffer& buffer) {
CORRADE_ASSERT(_flags >= Flag::UniformBuffers,
"Shaders::PhongGL::bindLightBuffer(): the shader was not created with uniform buffers enabled", *this);
buffer.bind(GL::Buffer::Target::Uniform, LightBufferBinding);
buffer.bind(
#ifndef MAGNUM_TARGET_WEBGL
_flags >= Flag::ShaderStorageBuffers ? GL::Buffer::Target::ShaderStorage :
#endif
GL::Buffer::Target::Uniform, LightBufferBinding);
return *this;
}
PhongGL& PhongGL::bindLightBuffer(GL::Buffer& buffer, const GLintptr offset, const GLsizeiptr size) {
CORRADE_ASSERT(_flags >= Flag::UniformBuffers,
"Shaders::PhongGL::bindLightBuffer(): the shader was not created with uniform buffers enabled", *this);
buffer.bind(GL::Buffer::Target::Uniform, LightBufferBinding, offset, size);
buffer.bind(
#ifndef MAGNUM_TARGET_WEBGL
_flags >= Flag::ShaderStorageBuffers ? GL::Buffer::Target::ShaderStorage :
#endif
GL::Buffer::Target::Uniform, LightBufferBinding, offset, size);
return *this;
}
PhongGL& PhongGL::bindJointBuffer(GL::Buffer& buffer) {
CORRADE_ASSERT(_flags >= Flag::UniformBuffers,
"Shaders::PhongGL::bindJointBuffer(): the shader was not created with uniform buffers enabled", *this);
buffer.bind(GL::Buffer::Target::Uniform, JointBufferBinding);
buffer.bind(
#ifndef MAGNUM_TARGET_WEBGL
_flags >= Flag::ShaderStorageBuffers ? GL::Buffer::Target::ShaderStorage :
#endif
GL::Buffer::Target::Uniform, JointBufferBinding);
return *this;
}
PhongGL& PhongGL::bindJointBuffer(GL::Buffer& buffer, const GLintptr offset, const GLsizeiptr size) {
CORRADE_ASSERT(_flags >= Flag::UniformBuffers,
"Shaders::PhongGL::bindJointBuffer(): the shader was not created with uniform buffers enabled", *this);
buffer.bind(GL::Buffer::Target::Uniform, JointBufferBinding, offset, size);
buffer.bind(
#ifndef MAGNUM_TARGET_WEBGL
_flags >= Flag::ShaderStorageBuffers ? GL::Buffer::Target::ShaderStorage :
#endif
GL::Buffer::Target::Uniform, JointBufferBinding, offset, size);
return *this;
}
#endif
@ -1171,10 +1289,8 @@ PhongGL& PhongGL::bindTextures(GL::Texture2D* ambient, GL::Texture2D* diffuse, G
}
PhongGL::Configuration& PhongGL::Configuration::setLightCount(const UnsignedInt count, const UnsignedInt perDrawCount) {
CORRADE_ASSERT(!count == !perDrawCount,
"Shaders::PhongGL::Configuration::setLightCount(): count has to be non-zero iff per-draw count is non-zero", *this);
CORRADE_ASSERT(perDrawCount <= count,
"Shaders::PhongGL::Configuration::setLightCount(): per-draw light count expected to be not larger than total count of" << count << Debug::nospace << ", got" << perDrawCount, *this);
CORRADE_ASSERT(perDrawCount || !count,
"Shaders::PhongGL::Configuration::setLightCount(): count has to be zero if per-draw count is zero", *this);
_lightCount = count;
_perDrawLightCount = perDrawCount;
return *this;
@ -1186,8 +1302,8 @@ PhongGL::Configuration& PhongGL::Configuration::setJointCount(UnsignedInt count,
"Shaders::PhongGL::Configuration::setJointCount(): expected at most 4 per-vertex joints, got" << perVertexCount, *this);
CORRADE_ASSERT(secondaryPerVertexCount <= 4,
"Shaders::PhongGL::Configuration::setJointCount(): expected at most 4 secondary per-vertex joints, got" << secondaryPerVertexCount, *this);
CORRADE_ASSERT(!count == (!perVertexCount && !secondaryPerVertexCount),
"Shaders::PhongGL::Configuration::setJointCount(): count has to be non-zero iff (secondary) per-vertex joint count is non-zero", *this);
CORRADE_ASSERT(perVertexCount || secondaryPerVertexCount || !count,
"Shaders::PhongGL::Configuration::setJointCount(): count has to be zero if per-vertex joint count is zero", *this);
_jointCount = count;
_perVertexJointCount = perVertexCount;
_secondaryPerVertexJointCount = secondaryPerVertexCount;
@ -1202,6 +1318,11 @@ Debug& operator<<(Debug& debug, const PhongGL::Flag value) {
`Flag::InstancedObjectId|Flag(0x20000)` in the output. */
if(value == PhongGL::Flag(UnsignedInt(PhongGL::Flag::InstancedObjectId|PhongGL::Flag::ObjectIdTexture)))
return debug << PhongGL::Flag::InstancedObjectId << Debug::nospace << "|" << Debug::nospace << PhongGL::Flag::ObjectIdTexture;
#ifndef MAGNUM_TARGET_WEBGL
/* Similarly here, both are a superset of UniformBuffers */
if(value == PhongGL::Flag(UnsignedInt(PhongGL::Flag::MultiDraw|PhongGL::Flag::ShaderStorageBuffers)))
return debug << PhongGL::Flag::MultiDraw << Debug::nospace << "|" << Debug::nospace << PhongGL::Flag::ShaderStorageBuffers;
#endif
#endif
debug << "Shaders::PhongGL::Flag" << Debug::nospace;
@ -1226,6 +1347,9 @@ Debug& operator<<(Debug& debug, const PhongGL::Flag value) {
_c(InstancedTextureOffset)
#ifndef MAGNUM_TARGET_GLES2
_c(UniformBuffers)
#ifndef MAGNUM_TARGET_WEBGL
_c(ShaderStorageBuffers)
#endif
_c(MultiDraw)
_c(TextureArrays)
_c(LightCulling)
@ -1263,7 +1387,15 @@ Debug& operator<<(Debug& debug, const PhongGL::Flags value) {
#endif
PhongGL::Flag::InstancedTransformation,
#ifndef MAGNUM_TARGET_GLES2
#ifndef MAGNUM_TARGET_WEBGL
/* Both are a superset of UniformBuffers; similarly to ObjectId above
letting the Flag printer deal with that */
PhongGL::Flag(UnsignedInt(PhongGL::Flag::MultiDraw|PhongGL::Flag::ShaderStorageBuffers)),
#endif
PhongGL::Flag::MultiDraw, /* Superset of UniformBuffers */
#ifndef MAGNUM_TARGET_WEBGL
PhongGL::Flag::ShaderStorageBuffers, /* Superset of UniformBuffers */
#endif
PhongGL::Flag::UniformBuffers,
PhongGL::Flag::TextureArrays,
PhongGL::Flag::LightCulling,

85
src/Magnum/Shaders/PhongGL.h

@ -789,6 +789,7 @@ class MAGNUM_SHADERS_EXPORT PhongGL: public GL::AbstractShaderProgram {
* @ref bindDrawBuffer(), @ref bindTextureTransformationBuffer(),
* @ref bindMaterialBuffer() and @ref bindLightBuffer() instead of
* direct uniform setters.
* @see @ref Flag::ShaderStorageBuffers
* @requires_gl31 Extension @gl_extension{ARB,uniform_buffer_object}
* @requires_gles30 Uniform buffers are not available in OpenGL ES
* 2.0.
@ -798,6 +799,25 @@ class MAGNUM_SHADERS_EXPORT PhongGL: public GL::AbstractShaderProgram {
*/
UniformBuffers = 1 << 12,
#ifndef MAGNUM_TARGET_WEBGL
/**
* Use shader storage buffers. Superset of functionality provided
* by @ref Flag::UniformBuffers, compared to it doesn't have any
* size limits on @ref Configuration::setLightCount(),
* @relativeref{Configuration,setJointCount()},
* @relativeref{Configuration,setMaterialCount()} and
* @relativeref{Configuration,setDrawCount()} in exchange for
* potentially more costly access and narrower platform support.
* @requires_gl43 Extension @gl_extension{ARB,shader_storage_buffer_object}
* @requires_gles31 Shader storage buffers are not available in
* OpenGL ES 3.0 and older.
* @requires_gles Shader storage buffers are not available in
* WebGL.
* @m_since_latest
*/
ShaderStorageBuffers = UniformBuffers|(1 << 19),
#endif
/**
* Enable multidraw functionality. Implies @ref Flag::UniformBuffers
* and adds the value from @ref setDrawOffset() with the
@ -1032,7 +1052,8 @@ class MAGNUM_SHADERS_EXPORT PhongGL: public GL::AbstractShaderProgram {
*
* If @ref Flag::UniformBuffers is set, this is the statically defined
* size of the @ref PhongLightUniform uniform buffer bound with
* @ref bindLightBuffer().
* @ref bindLightBuffer(). Has no use if @ref Flag::ShaderStorageBuffers
* is set.
* @see @ref perDrawLightCount(), @ref Configuration::setLightCount()
*/
UnsignedInt lightCount() const { return _lightCount; }
@ -1060,7 +1081,8 @@ class MAGNUM_SHADERS_EXPORT PhongGL: public GL::AbstractShaderProgram {
* matrices accepted by @ref setJointMatrices() / @ref setJointMatrix().
* If @ref Flag::UniformBuffers is set, this is the statically defined
* size of the @ref TransformationUniform3D uniform buffer bound with
* @ref bindJointBuffer().
* @ref bindJointBuffer(). Has no use if @ref Flag::ShaderStorageBuffers
* is set.
* @see @ref Configuration::setJointCount()
* @requires_gles30 Not defined on OpenGL ES 2.0 builds.
* @requires_webgl20 Not defined on WebGL 1.0 builds.
@ -1099,7 +1121,8 @@ class MAGNUM_SHADERS_EXPORT PhongGL: public GL::AbstractShaderProgram {
*
* Statically defined size of the @ref PhongMaterialUniform uniform
* buffer bound with @ref bindMaterialBuffer(). Has use only if
* @ref Flag::UniformBuffers is set.
* @ref Flag::UniformBuffers is set and @ref Flag::ShaderStorageBuffers
* is not set.
* @see @ref Configuration::setMaterialCount()
* @requires_gles30 Not defined on OpenGL ES 2.0 builds.
* @requires_webgl20 Not defined on WebGL 1.0 builds.
@ -1114,7 +1137,8 @@ class MAGNUM_SHADERS_EXPORT PhongGL: public GL::AbstractShaderProgram {
* @ref PhongDrawUniform and @ref TextureTransformationUniform uniform
* buffers bound with @ref bindTransformationBuffer(),
* @ref bindDrawBuffer() and @ref bindTextureTransformationBuffer().
* Has use only if @ref Flag::UniformBuffers is set.
* Has use only if @ref Flag::UniformBuffers is set and
* @ref Flag::ShaderStorageBuffers is not set.
* @see @ref Configuration::setDrawCount()
* @requires_gles30 Not defined on OpenGL ES 2.0 builds.
* @requires_webgl20 Not defined on WebGL 1.0 builds.
@ -1691,7 +1715,7 @@ class MAGNUM_SHADERS_EXPORT PhongGL: public GL::AbstractShaderProgram {
#ifndef MAGNUM_TARGET_GLES2
/** @{
* @name Uniform buffer binding and related uniform setters
* @name Uniform / shader storage buffer binding and related uniform setters
*
* Used if @ref Flag::UniformBuffers is set.
*/
@ -1721,7 +1745,7 @@ class MAGNUM_SHADERS_EXPORT PhongGL: public GL::AbstractShaderProgram {
PhongGL& setDrawOffset(UnsignedInt offset);
/**
* @brief Bind a projection uniform buffer
* @brief Bind a projection uniform / shader storage buffer
* @return Reference to self (for method chaining)
* @m_since_latest
*
@ -1742,7 +1766,7 @@ class MAGNUM_SHADERS_EXPORT PhongGL: public GL::AbstractShaderProgram {
PhongGL& bindProjectionBuffer(GL::Buffer& buffer, GLintptr offset, GLsizeiptr size);
/**
* @brief Bind a transformation uniform buffer
* @brief Bind a transformation uniform / shader storage buffer
* @return Reference to self (for method chaining)
* @m_since_latest
*
@ -1763,7 +1787,7 @@ class MAGNUM_SHADERS_EXPORT PhongGL: public GL::AbstractShaderProgram {
PhongGL& bindTransformationBuffer(GL::Buffer& buffer, GLintptr offset, GLsizeiptr size);
/**
* @brief Bind a draw uniform buffer
* @brief Bind a draw uniform / shader storage buffer
* @return Reference to self (for method chaining)
* @m_since_latest
*
@ -1784,7 +1808,7 @@ class MAGNUM_SHADERS_EXPORT PhongGL: public GL::AbstractShaderProgram {
PhongGL& bindDrawBuffer(GL::Buffer& buffer, GLintptr offset, GLsizeiptr size);
/**
* @brief Bind a texture transformation uniform buffer
* @brief Bind a texture transformation uniform / shader storage buffer
* @return Reference to self (for method chaining)
* @m_since_latest
*
@ -1804,7 +1828,7 @@ class MAGNUM_SHADERS_EXPORT PhongGL: public GL::AbstractShaderProgram {
PhongGL& bindTextureTransformationBuffer(GL::Buffer& buffer, GLintptr offset, GLsizeiptr size);
/**
* @brief Bind a material uniform buffer
* @brief Bind a material uniform / shader storage buffer
* @return Reference to self (for method chaining)
* @m_since_latest
*
@ -1825,7 +1849,7 @@ class MAGNUM_SHADERS_EXPORT PhongGL: public GL::AbstractShaderProgram {
PhongGL& bindMaterialBuffer(GL::Buffer& buffer, GLintptr offset, GLsizeiptr size);
/**
* @brief Bind a light uniform buffer
* @brief Bind a light uniform / shader storage buffer
* @return Reference to self (for method chaining)
* @m_since_latest
*
@ -1844,7 +1868,7 @@ class MAGNUM_SHADERS_EXPORT PhongGL: public GL::AbstractShaderProgram {
PhongGL& bindLightBuffer(GL::Buffer& buffer, GLintptr offset, GLsizeiptr size);
/**
* @brief Bind a joint matrix uniform buffer
* @brief Bind a joint matrix uniform / shader storage buffer
* @return Reference to self (for method chaining)
* @m_since_latest
*
@ -2169,15 +2193,18 @@ class MAGNUM_SHADERS_EXPORT PhongGL::Configuration {
* @ref PhongLightUniform buffer bound with @ref bindLightBuffer().
* Uniform buffers have a statically defined size and
* @cpp count*sizeof(PhongLightUniform) @ce has to be within
* @ref GL::AbstractShaderProgram::maxUniformBlockSize(). The per-draw
* lights are then specified via @ref PhongDrawUniform::lightOffset and
* @ref GL::AbstractShaderProgram::maxUniformBlockSize(), if
* @ref Flag::ShaderStorageBuffers is set as well, the buffer is
* unbounded and @p count is ignored. The per-draw lights are specified
* via @ref PhongDrawUniform::lightOffset and
* @ref PhongDrawUniform::lightCount.
*
* The @p perDrawCount parameter describes how many lights out of
* @p count get applied to each draw. Useful mainly in combination with
* @ref Flag::LightCulling, without it can be used for conveniently
* reducing the light count without having to reduce sizes of the light
* arrays as well. It's expected to not be larger than @p count. If set
* arrays as well. Unless @ref Flag::ShaderStorageBuffers is set,
* @p perDrawCount is expected to not be larger than @p count. If set
* to @cpp 0 @ce, no lighting calculations are performed and only the
* ambient contribution to the color is used. If @p perDrawCount is
* @cpp 0 @ce, @p count is expected to be zero as well.
@ -2234,9 +2261,10 @@ class MAGNUM_SHADERS_EXPORT PhongGL::Configuration {
* @ref TransformationUniform3D buffer bound with
* @ref bindJointBuffer(). Uniform buffers have a statically defined
* size and @cpp count*sizeof(TransformationUniform3D) @ce has to be
* within @ref GL::AbstractShaderProgram::maxUniformBlockSize(). The
* per-vertex joints then index into the array offset by
* @ref PhongDrawUniform::jointOffset.
* within @ref GL::AbstractShaderProgram::maxUniformBlockSize(), if
* @ref Flag::ShaderStorageBuffers is set as well, the buffer is
* unbounded and @p count is ignored. The per-vertex joints index into
* the array offset by @ref PhongDrawUniform::jointOffset.
*
* The @p perVertexCount and @p secondaryPerVertexCount parameters
* describe how many components are taken from @ref JointIds /
@ -2245,8 +2273,8 @@ class MAGNUM_SHADERS_EXPORT PhongGL::Configuration {
* @cpp 4 @ce, setting either of these to @cpp 0 @ce means given
* attribute is not used at all. If both @p perVertexCount and
* @p secondaryPerVertexCount are set to @cpp 0 @ce, skinning is not
* performed; if either of them is non-zero, @p count is expected to be
* non-zero as well.
* performed. Unless @ref Flag::ShaderStorageBuffers is set, if either
* of them is non-zero, @p count is expected to be non-zero as well.
*
* Default value for all three is @cpp 0 @ce.
* @see @ref PhongGL::jointCount(), @ref PhongGL::perVertexJointCount(),
@ -2276,10 +2304,11 @@ class MAGNUM_SHADERS_EXPORT PhongGL::Configuration {
* @ref PhongMaterialUniform buffer bound with
* @ref bindMaterialBuffer(). Uniform buffers have a statically defined
* size and @cpp count*sizeof(PhongMaterialUniform) @ce has to be
* within @ref GL::AbstractShaderProgram::maxUniformBlockSize().
*
* The per-draw materials are then specified via
* @ref PhongDrawUniform::materialId. Default value is @cpp 1 @ce.
* within @ref GL::AbstractShaderProgram::maxUniformBlockSize(), if
* @ref Flag::ShaderStorageBuffers is set as well, the buffer is
* unbounded and @p count is ignored. The per-draw materials are
* specified via @ref PhongDrawUniform::materialId. Default value is
* @cpp 1 @ce.
*
* If @ref Flag::UniformBuffers isn't set, this value is ignored.
* @see @ref setFlags(), @ref setLightCount(), @ref setDrawCount(),
@ -2313,10 +2342,10 @@ class MAGNUM_SHADERS_EXPORT PhongGL::Configuration {
* @cpp count*sizeof(TransformationUniform3D) @ce,
* @cpp count*sizeof(PhongDrawUniform) @ce and
* @cpp count*sizeof(TextureTransformationUniform) @ce has to be within
* @ref GL::AbstractShaderProgram::maxUniformBlockSize().
*
* The draw offset is then set via @ref setDrawOffset(). Default value
* is @cpp 1 @ce.
* @ref GL::AbstractShaderProgram::maxUniformBlockSize(), if
* @ref Flag::ShaderStorageBuffers is set as well, the buffers are
* unbounded and @p count is ignored. The draw offset is set via
* @ref setDrawOffset(). Default value is @cpp 1 @ce.
*
* If @ref Flag::UniformBuffers isn't set, this value is ignored.
* @see @ref setFlags(), @ref setLightCount(), @ref setMaterialCount(),

179
src/Magnum/Shaders/Test/DistanceFieldVectorGLTest.cpp

@ -187,7 +187,10 @@ constexpr struct {
/* SwiftShader has 256 uniform vectors at most, per-draw is 4+1 in 3D case
and 3+1 in 2D, per-material 4 */
{"multiple materials, draws", DistanceFieldVectorGL2D::Flag::UniformBuffers, 16, 48},
{"multidraw with all the things", DistanceFieldVectorGL2D::Flag::MultiDraw|DistanceFieldVectorGL2D::Flag::TextureTransformation, 16, 48}
{"multidraw with all the things", DistanceFieldVectorGL2D::Flag::MultiDraw|DistanceFieldVectorGL2D::Flag::TextureTransformation, 16, 48},
#ifndef MAGNUM_TARGET_WEBGL
{"shader storage + multidraw with all the things", DistanceFieldVectorGL2D::Flag::ShaderStorageBuffers|DistanceFieldVectorGL2D::Flag::MultiDraw|DistanceFieldVectorGL2D::Flag::TextureTransformation, 0, 0}
#endif
};
constexpr struct {
@ -196,6 +199,7 @@ constexpr struct {
UnsignedInt materialCount, drawCount;
const char* message;
} ConstructUniformBuffersInvalidData[]{
/* These two fail for UBOs but not SSBOs */
{"zero draws", DistanceFieldVectorGL2D::Flag::UniformBuffers, 1, 0,
"draw count can't be zero"},
{"zero materials", DistanceFieldVectorGL2D::Flag::UniformBuffers, 0, 1,
@ -232,21 +236,40 @@ constexpr struct {
const char* expected3D;
DistanceFieldVectorGL2D::Flags flags;
UnsignedInt materialCount, drawCount;
bool bindWithOffset;
UnsignedInt uniformIncrement;
Float maxThreshold, meanThreshold;
} RenderMultiData[] {
{"bind with offset", "multidraw2D-distancefield.tga", "multidraw3D-distancefield.tga",
{}, 1, 1, 16,
{}, 1, 1, true, 16,
/* Minor differences on ARM Mali */
1.67f, 0.012f},
#ifndef MAGNUM_TARGET_WEBGL
{"bind with offset, shader storage", "multidraw2D-distancefield.tga", "multidraw3D-distancefield.tga",
DistanceFieldVectorGL2D::Flag::ShaderStorageBuffers, 0, 0, true, 16,
/* Minor differences on ARM Mali */
1.67f, 0.012f},
#endif
{"draw offset", "multidraw2D-distancefield.tga", "multidraw3D-distancefield.tga",
{}, 2, 3, 1,
{}, 2, 3, false, 1,
/* Minor differences on ARM Mali */
1.67f, 0.012f},
#ifndef MAGNUM_TARGET_WEBGL
{"draw offset, shader storage", "multidraw2D-distancefield.tga", "multidraw3D-distancefield.tga",
DistanceFieldVectorGL2D::Flag::ShaderStorageBuffers, 0, 0, false, 1,
/* Minor differences on ARM Mali */
1.67f, 0.012f},
#endif
{"multidraw", "multidraw2D-distancefield.tga", "multidraw3D-distancefield.tga",
DistanceFieldVectorGL2D::Flag::MultiDraw, 2, 3, 1,
DistanceFieldVectorGL2D::Flag::MultiDraw, 2, 3, false, 1,
/* Minor differences on ARM Mali */
1.67f, 0.012f},
#ifndef MAGNUM_TARGET_WEBGL
{"multidraw, shader storage", "multidraw2D-distancefield.tga", "multidraw3D-distancefield.tga",
DistanceFieldVectorGL2D::Flag::ShaderStorageBuffers|DistanceFieldVectorGL2D::Flag::MultiDraw, 0, 0, false, 1,
/* Minor differences on ARM Mali */
1.67f, 0.012f},
#endif
};
#endif
@ -312,10 +335,16 @@ DistanceFieldVectorGLTest::DistanceFieldVectorGLTest() {
&DistanceFieldVectorGLTest::renderDefaults2D,
#ifndef MAGNUM_TARGET_GLES2
&DistanceFieldVectorGLTest::renderDefaults2D<DistanceFieldVectorGL2D::Flag::UniformBuffers>,
#ifndef MAGNUM_TARGET_WEBGL
&DistanceFieldVectorGLTest::renderDefaults2D<DistanceFieldVectorGL2D::Flag::ShaderStorageBuffers>,
#endif
#endif
&DistanceFieldVectorGLTest::renderDefaults3D,
#ifndef MAGNUM_TARGET_GLES2
&DistanceFieldVectorGLTest::renderDefaults3D<DistanceFieldVectorGL3D::Flag::UniformBuffers>,
#ifndef MAGNUM_TARGET_WEBGL
&DistanceFieldVectorGLTest::renderDefaults3D<DistanceFieldVectorGL3D::Flag::ShaderStorageBuffers>,
#endif
#endif
},
&DistanceFieldVectorGLTest::renderSetup,
@ -326,10 +355,16 @@ DistanceFieldVectorGLTest::DistanceFieldVectorGLTest() {
&DistanceFieldVectorGLTest::render2D,
#ifndef MAGNUM_TARGET_GLES2
&DistanceFieldVectorGLTest::render2D<DistanceFieldVectorGL2D::Flag::UniformBuffers>,
#ifndef MAGNUM_TARGET_WEBGL
&DistanceFieldVectorGLTest::render2D<DistanceFieldVectorGL2D::Flag::ShaderStorageBuffers>,
#endif
#endif
&DistanceFieldVectorGLTest::render3D,
#ifndef MAGNUM_TARGET_GLES2
&DistanceFieldVectorGLTest::render3D<DistanceFieldVectorGL3D::Flag::UniformBuffers>,
#ifndef MAGNUM_TARGET_WEBGL
&DistanceFieldVectorGLTest::render3D<DistanceFieldVectorGL3D::Flag::ShaderStorageBuffers>,
#endif
#endif
},
Containers::arraySize(RenderData),
@ -424,6 +459,18 @@ template<UnsignedInt dimensions> void DistanceFieldVectorGLTest::constructUnifor
CORRADE_SKIP(GL::Extensions::ARB::uniform_buffer_object::string() << "is not supported.");
#endif
#ifndef MAGNUM_TARGET_WEBGL
if(data.flags >= DistanceFieldVectorGL2D::Flag::ShaderStorageBuffers) {
#ifndef MAGNUM_TARGET_GLES
if(!GL::Context::current().isExtensionSupported<GL::Extensions::ARB::shader_storage_buffer_object>())
CORRADE_SKIP(GL::Extensions::ARB::shader_storage_buffer_object::string() << "is not supported.");
#else
if(!GL::Context::current().isVersionSupported(GL::Version::GLES310))
CORRADE_SKIP(GL::Version::GLES310 << "is not supported.");
#endif
}
#endif
if(data.flags >= DistanceFieldVectorGL2D::Flag::MultiDraw) {
#ifndef MAGNUM_TARGET_GLES
if(!GL::Context::current().isExtensionSupported<GL::Extensions::ARB::shader_draw_parameters>())
@ -736,6 +783,19 @@ constexpr GL::TextureFormat TextureFormatR =
template<DistanceFieldVectorGL2D::Flag flag> void DistanceFieldVectorGLTest::renderDefaults2D() {
#ifndef MAGNUM_TARGET_GLES2
#ifndef MAGNUM_TARGET_WEBGL
if(flag == DistanceFieldVectorGL2D::Flag::ShaderStorageBuffers) {
setTestCaseTemplateName("Flag::ShaderStorageBuffers");
#ifndef MAGNUM_TARGET_GLES
if(!GL::Context::current().isExtensionSupported<GL::Extensions::ARB::shader_storage_buffer_object>())
CORRADE_SKIP(GL::Extensions::ARB::shader_storage_buffer_object::string() << "is not supported.");
#else
if(!GL::Context::current().isVersionSupported(GL::Version::GLES310))
CORRADE_SKIP(GL::Version::GLES310 << "is not supported.");
#endif
} else
#endif
if(flag == DistanceFieldVectorGL2D::Flag::UniformBuffers) {
setTestCaseTemplateName("Flag::UniformBuffers");
@ -779,7 +839,12 @@ template<DistanceFieldVectorGL2D::Flag flag> void DistanceFieldVectorGLTest::ren
shader.draw(square);
}
#ifndef MAGNUM_TARGET_GLES2
else if(flag == DistanceFieldVectorGL2D::Flag::UniformBuffers) {
else if(flag == DistanceFieldVectorGL2D::Flag::UniformBuffers
#ifndef MAGNUM_TARGET_WEBGL
|| flag == DistanceFieldVectorGL2D::Flag::ShaderStorageBuffers
#endif
) {
/* Target hints matter just on WebGL (which doesn't have SSBOs) */
GL::Buffer transformationProjectionUniform{GL::Buffer::TargetHint::Uniform, {
TransformationProjectionUniform2D{}
}};
@ -825,6 +890,19 @@ template<DistanceFieldVectorGL2D::Flag flag> void DistanceFieldVectorGLTest::ren
template<DistanceFieldVectorGL3D::Flag flag> void DistanceFieldVectorGLTest::renderDefaults3D() {
#ifndef MAGNUM_TARGET_GLES2
#ifndef MAGNUM_TARGET_WEBGL
if(flag == DistanceFieldVectorGL2D::Flag::ShaderStorageBuffers) {
setTestCaseTemplateName("Flag::ShaderStorageBuffers");
#ifndef MAGNUM_TARGET_GLES
if(!GL::Context::current().isExtensionSupported<GL::Extensions::ARB::shader_storage_buffer_object>())
CORRADE_SKIP(GL::Extensions::ARB::shader_storage_buffer_object::string() << "is not supported.");
#else
if(!GL::Context::current().isVersionSupported(GL::Version::GLES310))
CORRADE_SKIP(GL::Version::GLES310 << "is not supported.");
#endif
} else
#endif
if(flag == DistanceFieldVectorGL3D::Flag::UniformBuffers) {
setTestCaseTemplateName("Flag::UniformBuffers");
@ -868,7 +946,12 @@ template<DistanceFieldVectorGL3D::Flag flag> void DistanceFieldVectorGLTest::ren
shader.draw(plane);
}
#ifndef MAGNUM_TARGET_GLES2
else if(flag == DistanceFieldVectorGL3D::Flag::UniformBuffers) {
else if(flag == DistanceFieldVectorGL2D::Flag::UniformBuffers
#ifndef MAGNUM_TARGET_WEBGL
|| flag == DistanceFieldVectorGL2D::Flag::ShaderStorageBuffers
#endif
) {
/* Target hints matter just on WebGL (which doesn't have SSBOs) */
GL::Buffer transformationProjectionUniform{GL::Buffer::TargetHint::Uniform, {
TransformationProjectionUniform3D{}
}};
@ -917,6 +1000,19 @@ template<DistanceFieldVectorGL2D::Flag flag> void DistanceFieldVectorGLTest::ren
setTestCaseDescription(data.name);
#ifndef MAGNUM_TARGET_GLES2
#ifndef MAGNUM_TARGET_WEBGL
if(flag == DistanceFieldVectorGL2D::Flag::ShaderStorageBuffers) {
setTestCaseTemplateName("Flag::ShaderStorageBuffers");
#ifndef MAGNUM_TARGET_GLES
if(!GL::Context::current().isExtensionSupported<GL::Extensions::ARB::shader_storage_buffer_object>())
CORRADE_SKIP(GL::Extensions::ARB::shader_storage_buffer_object::string() << "is not supported.");
#else
if(!GL::Context::current().isVersionSupported(GL::Version::GLES310))
CORRADE_SKIP(GL::Version::GLES310 << "is not supported.");
#endif
} else
#endif
if(flag == DistanceFieldVectorGL2D::Flag::UniformBuffers) {
setTestCaseTemplateName("Flag::UniformBuffers");
@ -968,7 +1064,12 @@ template<DistanceFieldVectorGL2D::Flag flag> void DistanceFieldVectorGLTest::ren
.draw(square);
}
#ifndef MAGNUM_TARGET_GLES2
else if(flag == DistanceFieldVectorGL2D::Flag::UniformBuffers) {
else if(flag == DistanceFieldVectorGL2D::Flag::UniformBuffers
#ifndef MAGNUM_TARGET_WEBGL
|| flag == DistanceFieldVectorGL2D::Flag::ShaderStorageBuffers
#endif
) {
/* Target hints matter just on WebGL (which doesn't have SSBOs) */
GL::Buffer transformationProjectionUniform{GL::Buffer::TargetHint::Uniform, {
TransformationProjectionUniform2D{}
.setTransformationProjectionMatrix(
@ -1026,6 +1127,19 @@ template<DistanceFieldVectorGL3D::Flag flag> void DistanceFieldVectorGLTest::ren
setTestCaseDescription(data.name);
#ifndef MAGNUM_TARGET_GLES2
#ifndef MAGNUM_TARGET_WEBGL
if(flag == DistanceFieldVectorGL2D::Flag::ShaderStorageBuffers) {
setTestCaseTemplateName("Flag::ShaderStorageBuffers");
#ifndef MAGNUM_TARGET_GLES
if(!GL::Context::current().isExtensionSupported<GL::Extensions::ARB::shader_storage_buffer_object>())
CORRADE_SKIP(GL::Extensions::ARB::shader_storage_buffer_object::string() << "is not supported.");
#else
if(!GL::Context::current().isVersionSupported(GL::Version::GLES310))
CORRADE_SKIP(GL::Version::GLES310 << "is not supported.");
#endif
} else
#endif
if(flag == DistanceFieldVectorGL3D::Flag::UniformBuffers) {
setTestCaseTemplateName("Flag::UniformBuffers");
@ -1080,7 +1194,12 @@ template<DistanceFieldVectorGL3D::Flag flag> void DistanceFieldVectorGLTest::ren
.draw(plane);
}
#ifndef MAGNUM_TARGET_GLES2
else if(flag == DistanceFieldVectorGL3D::Flag::UniformBuffers) {
else if(flag == DistanceFieldVectorGL2D::Flag::UniformBuffers
#ifndef MAGNUM_TARGET_WEBGL
|| flag == DistanceFieldVectorGL2D::Flag::ShaderStorageBuffers
#endif
) {
/* Target hints matter just on WebGL (which doesn't have SSBOs) */
GL::Buffer transformationProjectionUniform{GL::Buffer::TargetHint::Uniform, {
TransformationProjectionUniform3D{}
.setTransformationProjectionMatrix(
@ -1146,6 +1265,18 @@ void DistanceFieldVectorGLTest::renderMulti2D() {
CORRADE_SKIP(GL::Extensions::ARB::uniform_buffer_object::string() << "is not supported.");
#endif
#ifndef MAGNUM_TARGET_WEBGL
if(data.flags >= DistanceFieldVectorGL2D::Flag::ShaderStorageBuffers) {
#ifndef MAGNUM_TARGET_GLES
if(!GL::Context::current().isExtensionSupported<GL::Extensions::ARB::shader_storage_buffer_object>())
CORRADE_SKIP(GL::Extensions::ARB::shader_storage_buffer_object::string() << "is not supported.");
#else
if(!GL::Context::current().isVersionSupported(GL::Version::GLES310))
CORRADE_SKIP(GL::Version::GLES310 << "is not supported.");
#endif
}
#endif
if(data.flags >= DistanceFieldVectorGL2D::Flag::MultiDraw) {
#ifndef MAGNUM_TARGET_GLES
if(!GL::Context::current().isExtensionSupported<GL::Extensions::ARB::shader_draw_parameters>())
@ -1252,11 +1383,11 @@ void DistanceFieldVectorGLTest::renderMulti2D() {
/* Material offsets are zero if we have single draw, as those are done with
UBO offset bindings instead. */
drawData[0*data.uniformIncrement] = DistanceFieldVectorDrawUniform{}
.setMaterialId(data.drawCount == 1 ? 0 : 0);
.setMaterialId(data.bindWithOffset ? 0 : 0);
drawData[1*data.uniformIncrement] = DistanceFieldVectorDrawUniform{}
.setMaterialId(data.drawCount == 1 ? 0 : 1);
.setMaterialId(data.bindWithOffset ? 0 : 1);
drawData[2*data.uniformIncrement] = DistanceFieldVectorDrawUniform{}
.setMaterialId(data.drawCount == 1 ? 0 : 0);
.setMaterialId(data.bindWithOffset ? 0 : 0);
GL::Buffer drawUniform{GL::Buffer::TargetHint::Uniform, drawData};
DistanceFieldVectorGL2D shader{DistanceFieldVectorGL2D::Configuration{}
@ -1265,8 +1396,8 @@ void DistanceFieldVectorGLTest::renderMulti2D() {
.setDrawCount(data.drawCount)};
shader.bindVectorTexture(vector);
/* Just one draw, rebinding UBOs each time */
if(data.drawCount == 1) {
/* Rebinding UBOs / SSBOs each time */
if(data.bindWithOffset) {
shader.bindMaterialBuffer(materialUniform,
0*data.uniformIncrement*sizeof(DistanceFieldVectorMaterialUniform),
sizeof(DistanceFieldVectorMaterialUniform));
@ -1350,6 +1481,18 @@ void DistanceFieldVectorGLTest::renderMulti3D() {
CORRADE_SKIP(GL::Extensions::ARB::uniform_buffer_object::string() << "is not supported.");
#endif
#ifndef MAGNUM_TARGET_WEBGL
if(data.flags >= DistanceFieldVectorGL3D::Flag::ShaderStorageBuffers) {
#ifndef MAGNUM_TARGET_GLES
if(!GL::Context::current().isExtensionSupported<GL::Extensions::ARB::shader_storage_buffer_object>())
CORRADE_SKIP(GL::Extensions::ARB::shader_storage_buffer_object::string() << "is not supported.");
#else
if(!GL::Context::current().isVersionSupported(GL::Version::GLES310))
CORRADE_SKIP(GL::Version::GLES310 << "is not supported.");
#endif
}
#endif
if(data.flags >= DistanceFieldVectorGL2D::Flag::MultiDraw) {
#ifndef MAGNUM_TARGET_GLES
if(!GL::Context::current().isExtensionSupported<GL::Extensions::ARB::shader_draw_parameters>())
@ -1461,11 +1604,11 @@ void DistanceFieldVectorGLTest::renderMulti3D() {
/* Material offsets are zero if we have single draw, as those are done with
UBO offset bindings instead. */
drawData[0*data.uniformIncrement] = DistanceFieldVectorDrawUniform{}
.setMaterialId(data.drawCount == 1 ? 0 : 0);
.setMaterialId(data.bindWithOffset ? 0 : 0);
drawData[1*data.uniformIncrement] = DistanceFieldVectorDrawUniform{}
.setMaterialId(data.drawCount == 1 ? 0 : 1);
.setMaterialId(data.bindWithOffset ? 0 : 1);
drawData[2*data.uniformIncrement] = DistanceFieldVectorDrawUniform{}
.setMaterialId(data.drawCount == 1 ? 0 : 0);
.setMaterialId(data.bindWithOffset ? 0 : 0);
GL::Buffer drawUniform{GL::Buffer::TargetHint::Uniform, drawData};
DistanceFieldVectorGL3D shader{DistanceFieldVectorGL3D::Configuration{}
@ -1474,8 +1617,8 @@ void DistanceFieldVectorGLTest::renderMulti3D() {
.setDrawCount(data.drawCount)};
shader.bindVectorTexture(vector);
/* Just one draw, rebinding UBOs each time */
if(data.drawCount == 1) {
/* Rebinding UBOs / SSBOs each time */
if(data.bindWithOffset) {
shader.bindMaterialBuffer(materialUniform,
0*data.uniformIncrement*sizeof(DistanceFieldVectorMaterialUniform),
sizeof(DistanceFieldVectorMaterialUniform));

22
src/Magnum/Shaders/Test/DistanceFieldVectorGL_Test.cpp

@ -99,10 +99,24 @@ void DistanceFieldVectorGL_Test::debugFlags() {
#ifndef MAGNUM_TARGET_GLES2
void DistanceFieldVectorGL_Test::debugFlagsSupersets() {
/* MultiDraw is a superset of UniformBuffers so only one should be printed */
std::ostringstream out;
Debug{&out} << (DistanceFieldVectorGL3D::Flag::MultiDraw|DistanceFieldVectorGL3D::Flag::UniformBuffers);
CORRADE_COMPARE(out.str(), "Shaders::DistanceFieldVectorGL::Flag::MultiDraw\n");
/* MultiDraw and ShaderStorageBuffers are a superset of UniformBuffers so
only one should be printed, but if there are both then both should be */
{
std::ostringstream out;
Debug{&out} << (DistanceFieldVectorGL3D::Flag::MultiDraw|DistanceFieldVectorGL3D::Flag::UniformBuffers);
CORRADE_COMPARE(out.str(), "Shaders::DistanceFieldVectorGL::Flag::MultiDraw\n");
}
#ifndef MAGNUM_TARGET_WEBGL
{
std::ostringstream out;
Debug{&out} << (DistanceFieldVectorGL2D::Flag::ShaderStorageBuffers|DistanceFieldVectorGL2D::Flag::UniformBuffers);
CORRADE_COMPARE(out.str(), "Shaders::DistanceFieldVectorGL::Flag::ShaderStorageBuffers\n");
} {
std::ostringstream out;
Debug{&out} << (DistanceFieldVectorGL3D::Flag::MultiDraw|DistanceFieldVectorGL3D::Flag::ShaderStorageBuffers|DistanceFieldVectorGL3D::Flag::UniformBuffers);
CORRADE_COMPARE(out.str(), "Shaders::DistanceFieldVectorGL::Flag::MultiDraw|Shaders::DistanceFieldVectorGL::Flag::ShaderStorageBuffers\n");
}
#endif
}
#endif

757
src/Magnum/Shaders/Test/FlatGLTest.cpp

File diff suppressed because it is too large Load Diff

25
src/Magnum/Shaders/Test/FlatGL_Test.cpp

@ -64,13 +64,10 @@ const struct {
"expected at most 4 secondary per-vertex joints, got 5"},
{"joint count but no per-vertex joint count",
10, 0, 0,
"count has to be non-zero iff (secondary) per-vertex joint count is non-zero"},
{"per-vertex joint count but no joint count",
0, 2, 0,
"count has to be non-zero iff (secondary) per-vertex joint count is non-zero"},
{"secondary per-vertex joint count but no joint count",
0, 0, 3,
"count has to be non-zero iff (secondary) per-vertex joint count is non-zero"},
"count has to be zero if per-vertex joint count is zero"},
/* The rest depends on flags being set and is thus verified in constructor,
tested in FlatGLTest::constructInvalid() and
constructUniformBuffersInvalid() */
};
#endif
@ -171,12 +168,24 @@ void FlatGL_Test::debugFlagsSupersets() {
}
#ifndef MAGNUM_TARGET_GLES2
/* MultiDraw is a superset of UniformBuffers so only one should be printed */
/* MultiDraw and ShaderStorageBuffers are a superset of UniformBuffers so
only one should be printed, but if there are both then both should be */
{
std::ostringstream out;
Debug{&out} << (FlatGL3D::Flag::MultiDraw|FlatGL3D::Flag::UniformBuffers);
CORRADE_COMPARE(out.str(), "Shaders::FlatGL::Flag::MultiDraw\n");
}
#ifndef MAGNUM_TARGET_WEBGL
{
std::ostringstream out;
Debug{&out} << (FlatGL2D::Flag::ShaderStorageBuffers|FlatGL2D::Flag::UniformBuffers);
CORRADE_COMPARE(out.str(), "Shaders::FlatGL::Flag::ShaderStorageBuffers\n");
} {
std::ostringstream out;
Debug{&out} << (FlatGL3D::Flag::MultiDraw|FlatGL3D::Flag::ShaderStorageBuffers|FlatGL3D::Flag::UniformBuffers);
CORRADE_COMPARE(out.str(), "Shaders::FlatGL::Flag::MultiDraw|Shaders::FlatGL::Flag::ShaderStorageBuffers\n");
}
#endif
#endif
}

358
src/Magnum/Shaders/Test/LineGLTest.cpp

@ -163,7 +163,10 @@ const struct {
{"multiple materials, draws", LineGL2D::Flag::UniformBuffers, {}, {}, 16, 41},
{"object ID", LineGL2D::Flag::UniformBuffers|LineGL2D::Flag::ObjectId, {}, {}, 1, 1},
{"instanced object ID", LineGL2D::Flag::UniformBuffers|LineGL2D::Flag::InstancedObjectId, {}, {}, 1, 1},
{"multidraw with all the things", LineGL2D::Flag::MultiDraw|LineGL2D::Flag::ObjectId|LineGL2D::Flag::InstancedTransformation|LineGL2D::Flag::InstancedObjectId, {}, {}, 16, 41}
{"multidraw with all the things", LineGL2D::Flag::MultiDraw|LineGL2D::Flag::ObjectId|LineGL2D::Flag::InstancedTransformation|LineGL2D::Flag::InstancedObjectId, {}, {}, 16, 41},
#ifndef MAGNUM_TARGET_WEBGL
{"shader storage + multidraw with all the things", LineGL2D::Flag::ShaderStorageBuffers|LineGL2D::Flag::MultiDraw|LineGL2D::Flag::ObjectId|LineGL2D::Flag::InstancedTransformation|LineGL2D::Flag::InstancedObjectId, {}, {}, 0, 0},
#endif
};
const struct {
@ -172,6 +175,7 @@ const struct {
UnsignedInt materialCount, drawCount;
const char* message;
} ConstructUniformBuffersInvalidData[]{
/* These two fail for UBOs but not SSBOs */
{"zero draws", LineGL2D::Flag::UniformBuffers, 1, 0,
"draw count can't be zero"},
{"zero materials", LineGL2D::Flag::UniformBuffers, 0, 1,
@ -333,20 +337,51 @@ const struct {
UnsignedInt expectedId[3];
LineGL2D::Flags flags;
UnsignedInt materialCount, drawCount;
bool bindWithOffset;
UnsignedInt uniformIncrement;
} RenderMultiData[]{
{"bind with offset",
{}, {}, 1, 1, 16},
{},
{},
1, 1, true, 16},
{"bind with offset, object ID",
{1211, 5627, 36363}, LineGL2D::Flag::ObjectId, 1, 1, 16},
{1211, 5627, 36363},
LineGL2D::Flag::ObjectId,
1, 1, true, 16},
#ifndef MAGNUM_TARGET_WEBGL
{"bind with offset, object ID, shader storage",
{1211, 5627, 36363},
LineGL2D::Flag::ShaderStorageBuffers|LineGL2D::Flag::ObjectId,
0, 0, true, 16},
#endif
{"draw offset",
{}, {}, 2, 3, 1},
{},
{},
2, 3, false, 1},
{"draw offset, object ID",
{1211, 5627, 36363}, LineGL2D::Flag::ObjectId, 2, 3, 1},
{1211, 5627, 36363},
LineGL2D::Flag::ObjectId,
2, 3, false, 1},
#ifndef MAGNUM_TARGET_WEBGL
{"draw offset, object ID, shader storage",
{1211, 5627, 36363},
LineGL2D::Flag::ShaderStorageBuffers|LineGL2D::Flag::ObjectId,
0, 0, false, 1},
#endif
{"multidraw",
{}, LineGL2D::Flag::MultiDraw, 2, 3, 1},
{},
LineGL2D::Flag::MultiDraw,
2, 3, false, 1},
{"multidraw, object ID",
{1211, 5627, 36363}, LineGL2D::Flag::MultiDraw|LineGL2D::Flag::ObjectId, 2, 3, 1},
{1211, 5627, 36363},
LineGL2D::Flag::MultiDraw|LineGL2D::Flag::ObjectId,
2, 3, false, 1},
#ifndef MAGNUM_TARGET_WEBGL
{"multidraw, object ID, shader storage",
{1211, 5627, 36363},
LineGL2D::Flag::ShaderStorageBuffers|LineGL2D::Flag::MultiDraw|LineGL2D::Flag::ObjectId,
0, 0, false, 1},
#endif
};
LineGLTest::LineGLTest() {
@ -405,8 +440,15 @@ LineGLTest::LineGLTest() {
addTests<LineGLTest>({
&LineGLTest::renderDefaults2D,
&LineGLTest::renderDefaults2D<LineGL2D::Flag::UniformBuffers>,
#ifndef MAGNUM_TARGET_WEBGL
&LineGLTest::renderDefaults2D<LineGL2D::Flag::ShaderStorageBuffers>,
#endif
&LineGLTest::renderDefaults3D,
&LineGLTest::renderDefaults3D<LineGL3D::Flag::UniformBuffers>},
&LineGLTest::renderDefaults3D<LineGL3D::Flag::UniformBuffers>,
#ifndef MAGNUM_TARGET_WEBGL
&LineGLTest::renderDefaults3D<LineGL3D::Flag::ShaderStorageBuffers>
#endif
},
&LineGLTest::renderSetupSmall,
&LineGLTest::renderTeardown);
@ -414,6 +456,9 @@ LineGLTest::LineGLTest() {
addInstancedTests<LineGLTest>({
&LineGLTest::renderLineCapsJoins2D,
&LineGLTest::renderLineCapsJoins2D<LineGL2D::Flag::UniformBuffers>,
#ifndef MAGNUM_TARGET_WEBGL
&LineGLTest::renderLineCapsJoins2D<LineGL2D::Flag::ShaderStorageBuffers>,
#endif
&LineGLTest::renderLineCapsJoins2DReversed,
&LineGLTest::renderLineCapsJoins2DTransformed},
Containers::arraySize(RenderLineCapsJoins2DData),
@ -423,7 +468,11 @@ LineGLTest::LineGLTest() {
/* MSVC needs explicit type due to default template args */
addInstancedTests<LineGLTest>({
&LineGLTest::renderCube3D,
&LineGLTest::renderCube3D<LineGL3D::Flag::UniformBuffers>},
&LineGLTest::renderCube3D<LineGL3D::Flag::UniformBuffers>,
#ifndef MAGNUM_TARGET_WEBGL
&LineGLTest::renderCube3D<LineGL3D::Flag::ShaderStorageBuffers>
#endif
},
Containers::arraySize(RenderCube3DData),
&LineGLTest::renderSetupLarge,
&LineGLTest::renderTeardown);
@ -436,12 +485,25 @@ LineGLTest::LineGLTest() {
addTests<LineGLTest>({
&LineGLTest::renderVertexColor2D<Color3>,
&LineGLTest::renderVertexColor2D<Color3, LineGL2D::Flag::UniformBuffers>,
#ifndef MAGNUM_TARGET_WEBGL
&LineGLTest::renderVertexColor2D<Color3, LineGL2D::Flag::ShaderStorageBuffers>,
#endif
&LineGLTest::renderVertexColor2D<Color4>,
&LineGLTest::renderVertexColor2D<Color4, LineGL2D::Flag::UniformBuffers>,
#ifndef MAGNUM_TARGET_WEBGL
&LineGLTest::renderVertexColor2D<Color4, LineGL2D::Flag::ShaderStorageBuffers>,
#endif
&LineGLTest::renderVertexColor3D<Color3>,
&LineGLTest::renderVertexColor3D<Color3, LineGL3D::Flag::UniformBuffers>,
#ifndef MAGNUM_TARGET_WEBGL
&LineGLTest::renderVertexColor3D<Color3, LineGL3D::Flag::ShaderStorageBuffers>,
#endif
&LineGLTest::renderVertexColor3D<Color4>,
&LineGLTest::renderVertexColor3D<Color4, LineGL3D::Flag::UniformBuffers>},
&LineGLTest::renderVertexColor3D<Color4, LineGL3D::Flag::UniformBuffers>,
#ifndef MAGNUM_TARGET_WEBGL
&LineGLTest::renderVertexColor3D<Color4, LineGL3D::Flag::ShaderStorageBuffers>,
#endif
},
&LineGLTest::renderSetupSmall,
&LineGLTest::renderTeardown);
@ -449,8 +511,15 @@ LineGLTest::LineGLTest() {
addInstancedTests<LineGLTest>({
&LineGLTest::renderObjectId2D,
&LineGLTest::renderObjectId2D<LineGL2D::Flag::UniformBuffers>,
#ifndef MAGNUM_TARGET_WEBGL
&LineGLTest::renderObjectId2D<LineGL2D::Flag::ShaderStorageBuffers>,
#endif
&LineGLTest::renderObjectId3D,
&LineGLTest::renderObjectId3D<LineGL3D::Flag::UniformBuffers>},
&LineGLTest::renderObjectId3D<LineGL3D::Flag::UniformBuffers>,
#ifndef MAGNUM_TARGET_WEBGL
&LineGLTest::renderObjectId3D<LineGL3D::Flag::ShaderStorageBuffers>
#endif
},
Containers::arraySize(RenderObjectIdData),
&LineGLTest::renderSetupSmall,
&LineGLTest::renderTeardown);
@ -459,8 +528,15 @@ LineGLTest::LineGLTest() {
addInstancedTests<LineGLTest>({
&LineGLTest::renderInstanced2D,
&LineGLTest::renderInstanced2D<LineGL2D::Flag::UniformBuffers>,
#ifndef MAGNUM_TARGET_WEBGL
&LineGLTest::renderInstanced2D<LineGL2D::Flag::ShaderStorageBuffers>,
#endif
&LineGLTest::renderInstanced3D,
&LineGLTest::renderInstanced3D<LineGL2D::Flag::UniformBuffers>},
&LineGLTest::renderInstanced3D<LineGL2D::Flag::UniformBuffers>,
#ifndef MAGNUM_TARGET_WEBGL
&LineGLTest::renderInstanced3D<LineGL2D::Flag::ShaderStorageBuffers>,
#endif
},
Containers::arraySize(RenderInstancedData),
&LineGLTest::renderSetupSmall,
&LineGLTest::renderTeardown);
@ -557,6 +633,18 @@ template<UnsignedInt dimensions> void LineGLTest::constructUniformBuffers() {
CORRADE_SKIP(GL::Extensions::ARB::uniform_buffer_object::string() << "is not supported.");
#endif
#ifndef MAGNUM_TARGET_WEBGL
if(data.flags >= LineGL2D::Flag::ShaderStorageBuffers) {
#ifndef MAGNUM_TARGET_GLES
if(!GL::Context::current().isExtensionSupported<GL::Extensions::ARB::shader_storage_buffer_object>())
CORRADE_SKIP(GL::Extensions::ARB::shader_storage_buffer_object::string() << "is not supported.");
#else
if(!GL::Context::current().isVersionSupported(GL::Version::GLES310))
CORRADE_SKIP(GL::Version::GLES310 << "is not supported.");
#endif
}
#endif
if(data.flags >= LineGL2D::Flag::MultiDraw) {
#ifndef MAGNUM_TARGET_GLES
if(!GL::Context::current().isExtensionSupported<GL::Extensions::ARB::shader_draw_parameters>())
@ -1080,6 +1168,19 @@ GL::Mesh generateLineMesh(std::initializer_list<Vector3> lineSegments) {
}
template<LineGL2D::Flag flag> void LineGLTest::renderDefaults2D() {
#ifndef MAGNUM_TARGET_WEBGL
if(flag == LineGL2D::Flag::ShaderStorageBuffers) {
setTestCaseTemplateName("Flag::ShaderStorageBuffers");
#ifndef MAGNUM_TARGET_GLES
if(!GL::Context::current().isExtensionSupported<GL::Extensions::ARB::shader_storage_buffer_object>())
CORRADE_SKIP(GL::Extensions::ARB::shader_storage_buffer_object::string() << "is not supported.");
#else
if(!GL::Context::current().isVersionSupported(GL::Version::GLES310))
CORRADE_SKIP(GL::Version::GLES310 << "is not supported.");
#endif
} else
#endif
if(flag == LineGL2D::Flag::UniformBuffers) {
setTestCaseTemplateName("Flag::UniformBuffers");
@ -1120,7 +1221,12 @@ template<LineGL2D::Flag flag> void LineGLTest::renderDefaults2D() {
if(flag == LineGL2D::Flag{}) {
shader.draw(lines);
} else if(flag == LineGL2D::Flag::UniformBuffers) {
} else if(flag == LineGL2D::Flag::UniformBuffers
#ifndef MAGNUM_TARGET_WEBGL
|| flag == LineGL2D::Flag::ShaderStorageBuffers
#endif
) {
/* Target hints matter just on WebGL (which doesn't have SSBOs) */
GL::Buffer transformationProjectionUniform{GL::Buffer::TargetHint::Uniform, {
TransformationProjectionUniform2D{}
}};
@ -1153,6 +1259,19 @@ template<LineGL2D::Flag flag> void LineGLTest::renderDefaults2D() {
}
template<LineGL3D::Flag flag> void LineGLTest::renderDefaults3D() {
#ifndef MAGNUM_TARGET_WEBGL
if(flag == LineGL3D::Flag::ShaderStorageBuffers) {
setTestCaseTemplateName("Flag::ShaderStorageBuffers");
#ifndef MAGNUM_TARGET_GLES
if(!GL::Context::current().isExtensionSupported<GL::Extensions::ARB::shader_storage_buffer_object>())
CORRADE_SKIP(GL::Extensions::ARB::shader_storage_buffer_object::string() << "is not supported.");
#else
if(!GL::Context::current().isVersionSupported(GL::Version::GLES310))
CORRADE_SKIP(GL::Version::GLES310 << "is not supported.");
#endif
} else
#endif
if(flag == LineGL3D::Flag::UniformBuffers) {
setTestCaseTemplateName("Flag::UniformBuffers");
@ -1196,7 +1315,12 @@ template<LineGL3D::Flag flag> void LineGLTest::renderDefaults3D() {
if(flag == LineGL3D::Flag{}) {
shader.draw(lines);
} else if(flag == LineGL3D::Flag::UniformBuffers) {
} else if(flag == LineGL2D::Flag::UniformBuffers
#ifndef MAGNUM_TARGET_WEBGL
|| flag == LineGL2D::Flag::ShaderStorageBuffers
#endif
) {
/* Target hints matter just on WebGL (which doesn't have SSBOs) */
GL::Buffer transformationProjectionUniform{GL::Buffer::TargetHint::Uniform, {
TransformationProjectionUniform3D{}
}};
@ -1282,6 +1406,19 @@ template<LineGL2D::Flag flag> void LineGLTest::renderLineCapsJoins2D() {
auto&& data = RenderLineCapsJoins2DData[testCaseInstanceId()];
setTestCaseDescription(data.name);
#ifndef MAGNUM_TARGET_WEBGL
if(flag == LineGL2D::Flag::ShaderStorageBuffers) {
setTestCaseTemplateName("Flag::ShaderStorageBuffers");
#ifndef MAGNUM_TARGET_GLES
if(!GL::Context::current().isExtensionSupported<GL::Extensions::ARB::shader_storage_buffer_object>())
CORRADE_SKIP(GL::Extensions::ARB::shader_storage_buffer_object::string() << "is not supported.");
#else
if(!GL::Context::current().isVersionSupported(GL::Version::GLES310))
CORRADE_SKIP(GL::Version::GLES310 << "is not supported.");
#endif
} else
#endif
if(flag == LineGL2D::Flag::UniformBuffers) {
setTestCaseTemplateName("Flag::UniformBuffers");
@ -1322,7 +1459,12 @@ template<LineGL2D::Flag flag> void LineGLTest::renderLineCapsJoins2D() {
if(data.miterAngleLimit)
shader.setMiterAngleLimit(*data.miterAngleLimit);
shader.draw(lines);
} else if(flag == LineGL2D::Flag::UniformBuffers) {
} else if(flag == LineGL2D::Flag::UniformBuffers
#ifndef MAGNUM_TARGET_WEBGL
|| flag == LineGL2D::Flag::ShaderStorageBuffers
#endif
) {
/* Target hints matter just on WebGL (which doesn't have SSBOs) */
GL::Buffer transformationProjectionUniform{GL::Buffer::TargetHint::Uniform, {
TransformationProjectionUniform2D{}
}};
@ -1498,6 +1640,19 @@ template<LineGL3D::Flag flag> void LineGLTest::renderCube3D() {
auto&& data = RenderCube3DData[testCaseInstanceId()];
setTestCaseDescription(data.name);
#ifndef MAGNUM_TARGET_WEBGL
if(flag == LineGL3D::Flag::ShaderStorageBuffers) {
setTestCaseTemplateName("Flag::ShaderStorageBuffers");
#ifndef MAGNUM_TARGET_GLES
if(!GL::Context::current().isExtensionSupported<GL::Extensions::ARB::shader_storage_buffer_object>())
CORRADE_SKIP(GL::Extensions::ARB::shader_storage_buffer_object::string() << "is not supported.");
#else
if(!GL::Context::current().isVersionSupported(GL::Version::GLES310))
CORRADE_SKIP(GL::Version::GLES310 << "is not supported.");
#endif
} else
#endif
if(flag == LineGL3D::Flag::UniformBuffers) {
setTestCaseTemplateName("Flag::UniformBuffers");
@ -1628,7 +1783,12 @@ template<LineGL3D::Flag flag> void LineGLTest::renderCube3D() {
if(data.miterLengthLimit)
shader.setMiterLengthLimit(*data.miterLengthLimit);
shader.draw(lines);
} else if(flag == LineGL3D::Flag::UniformBuffers) {
} else if(flag == LineGL3D::Flag::UniformBuffers
#ifndef MAGNUM_TARGET_WEBGL
|| flag == LineGL3D::Flag::ShaderStorageBuffers
#endif
) {
/* Target hints matter just on WebGL (which doesn't have SSBOs) */
GL::Buffer transformationProjectionUniform{GL::Buffer::TargetHint::Uniform, {
TransformationProjectionUniform3D{}
.setTransformationProjectionMatrix(projection*transformation)
@ -1713,6 +1873,19 @@ void LineGLTest::renderPerspective3D() {
}
template<class T, LineGL2D::Flag flag> void LineGLTest::renderVertexColor2D() {
#ifndef MAGNUM_TARGET_WEBGL
if(flag == LineGL2D::Flag::ShaderStorageBuffers) {
setTestCaseTemplateName({T::Size == 3 ? "Color3" : "Color4", "Flag::ShaderStorageBuffers"});
#ifndef MAGNUM_TARGET_GLES
if(!GL::Context::current().isExtensionSupported<GL::Extensions::ARB::shader_storage_buffer_object>())
CORRADE_SKIP(GL::Extensions::ARB::shader_storage_buffer_object::string() << "is not supported.");
#else
if(!GL::Context::current().isVersionSupported(GL::Version::GLES310))
CORRADE_SKIP(GL::Version::GLES310 << "is not supported.");
#endif
} else
#endif
if(flag == LineGL2D::Flag::UniformBuffers) {
setTestCaseTemplateName({T::Size == 3 ? "Color3" : "Color4", "Flag::UniformBuffers"});
@ -1765,7 +1938,12 @@ template<class T, LineGL2D::Flag flag> void LineGLTest::renderVertexColor2D() {
.setWidth(4.0f)
.setSmoothness(1.0f)
.draw(lines);
} else if(flag == LineGL2D::Flag::UniformBuffers) {
} else if(flag == LineGL2D::Flag::UniformBuffers
#ifndef MAGNUM_TARGET_WEBGL
|| flag == LineGL2D::Flag::ShaderStorageBuffers
#endif
) {
/* Target hints matter just on WebGL (which doesn't have SSBOs) */
GL::Buffer transformationProjectionUniform{GL::Buffer::TargetHint::Uniform, {
TransformationProjectionUniform2D{}
}};
@ -1802,6 +1980,19 @@ template<class T, LineGL2D::Flag flag> void LineGLTest::renderVertexColor2D() {
}
template<class T, LineGL3D::Flag flag> void LineGLTest::renderVertexColor3D() {
#ifndef MAGNUM_TARGET_WEBGL
if(flag == LineGL2D::Flag::ShaderStorageBuffers) {
setTestCaseTemplateName({T::Size == 3 ? "Color3" : "Color4", "Flag::ShaderStorageBuffers"});
#ifndef MAGNUM_TARGET_GLES
if(!GL::Context::current().isExtensionSupported<GL::Extensions::ARB::shader_storage_buffer_object>())
CORRADE_SKIP(GL::Extensions::ARB::shader_storage_buffer_object::string() << "is not supported.");
#else
if(!GL::Context::current().isVersionSupported(GL::Version::GLES310))
CORRADE_SKIP(GL::Version::GLES310 << "is not supported.");
#endif
} else
#endif
if(flag == LineGL3D::Flag::UniformBuffers) {
setTestCaseTemplateName({T::Size == 3 ? "Color3" : "Color4", "Flag::UniformBuffers"});
@ -1857,7 +2048,12 @@ template<class T, LineGL3D::Flag flag> void LineGLTest::renderVertexColor3D() {
.setWidth(4.0f)
.setSmoothness(1.0f)
.draw(lines);
} else if(flag == LineGL3D::Flag::UniformBuffers) {
} else if(flag == LineGL3D::Flag::UniformBuffers
#ifndef MAGNUM_TARGET_WEBGL
|| flag == LineGL3D::Flag::ShaderStorageBuffers
#endif
) {
/* Target hints matter just on WebGL (which doesn't have SSBOs) */
GL::Buffer transformationProjectionUniform{GL::Buffer::TargetHint::Uniform, {
TransformationProjectionUniform3D{}
}};
@ -1897,6 +2093,19 @@ template<LineGL2D::Flag flag> void LineGLTest::renderObjectId2D() {
auto&& data = RenderObjectIdData[testCaseInstanceId()];
setTestCaseDescription(data.name);
#ifndef MAGNUM_TARGET_WEBGL
if(flag == LineGL2D::Flag::ShaderStorageBuffers) {
setTestCaseTemplateName("Flag::ShaderStorageBuffers");
#ifndef MAGNUM_TARGET_GLES
if(!GL::Context::current().isExtensionSupported<GL::Extensions::ARB::shader_storage_buffer_object>())
CORRADE_SKIP(GL::Extensions::ARB::shader_storage_buffer_object::string() << "is not supported.");
#else
if(!GL::Context::current().isVersionSupported(GL::Version::GLES310))
CORRADE_SKIP(GL::Version::GLES310 << "is not supported.");
#endif
} else
#endif
if(flag == LineGL3D::Flag::UniformBuffers) {
setTestCaseTemplateName("Flag::UniformBuffers");
@ -1936,7 +2145,12 @@ template<LineGL2D::Flag flag> void LineGLTest::renderObjectId2D() {
.setSmoothness(data.smoothness)
.setObjectId(47365)
.draw(lines);
} else if(flag == LineGL2D::Flag::UniformBuffers) {
} else if(flag == LineGL2D::Flag::UniformBuffers
#ifndef MAGNUM_TARGET_WEBGL
|| flag == LineGL2D::Flag::ShaderStorageBuffers
#endif
) {
/* Target hints matter just on WebGL (which doesn't have SSBOs) */
GL::Buffer transformationProjectionUniform{GL::Buffer::TargetHint::Uniform, {
TransformationProjectionUniform2D{}
}};
@ -1983,6 +2197,19 @@ template<LineGL3D::Flag flag> void LineGLTest::renderObjectId3D() {
auto&& data = RenderObjectIdData[testCaseInstanceId()];
setTestCaseDescription(data.name);
#ifndef MAGNUM_TARGET_WEBGL
if(flag == LineGL3D::Flag::ShaderStorageBuffers) {
setTestCaseTemplateName("Flag::ShaderStorageBuffers");
#ifndef MAGNUM_TARGET_GLES
if(!GL::Context::current().isExtensionSupported<GL::Extensions::ARB::shader_storage_buffer_object>())
CORRADE_SKIP(GL::Extensions::ARB::shader_storage_buffer_object::string() << "is not supported.");
#else
if(!GL::Context::current().isVersionSupported(GL::Version::GLES310))
CORRADE_SKIP(GL::Version::GLES310 << "is not supported.");
#endif
} else
#endif
if(flag == LineGL3D::Flag::UniformBuffers) {
setTestCaseTemplateName("Flag::UniformBuffers");
@ -2024,7 +2251,12 @@ template<LineGL3D::Flag flag> void LineGLTest::renderObjectId3D() {
.setSmoothness(data.smoothness)
.setObjectId(47365)
.draw(lines);
} else if(flag == LineGL3D::Flag::UniformBuffers) {
} else if(flag == LineGL3D::Flag::UniformBuffers
#ifndef MAGNUM_TARGET_WEBGL
|| flag == LineGL3D::Flag::ShaderStorageBuffers
#endif
) {
/* Target hints matter just on WebGL (which doesn't have SSBOs) */
GL::Buffer transformationProjectionUniform{GL::Buffer::TargetHint::Uniform, {
TransformationProjectionUniform3D{}
}};
@ -2071,6 +2303,19 @@ template<LineGL2D::Flag flag> void LineGLTest::renderInstanced2D() {
auto&& data = RenderInstancedData[testCaseInstanceId()];
setTestCaseDescription(data.name);
#ifndef MAGNUM_TARGET_WEBGL
if(flag == LineGL3D::Flag::ShaderStorageBuffers) {
setTestCaseTemplateName("Flag::ShaderStorageBuffers");
#ifndef MAGNUM_TARGET_GLES
if(!GL::Context::current().isExtensionSupported<GL::Extensions::ARB::shader_storage_buffer_object>())
CORRADE_SKIP(GL::Extensions::ARB::shader_storage_buffer_object::string() << "is not supported.");
#else
if(!GL::Context::current().isVersionSupported(GL::Version::GLES310))
CORRADE_SKIP(GL::Version::GLES310 << "is not supported.");
#endif
} else
#endif
if(flag == LineGL3D::Flag::UniformBuffers) {
setTestCaseTemplateName("Flag::UniformBuffers");
@ -2137,8 +2382,12 @@ template<LineGL2D::Flag flag> void LineGLTest::renderInstanced2D() {
/* Gets added to the per-instance ID, if that's enabled as well */
shader.setObjectId(1000);
shader.draw(lines);
} else if(flag == LineGL2D::Flag::UniformBuffers) {
} else if(flag == LineGL2D::Flag::UniformBuffers
#ifndef MAGNUM_TARGET_WEBGL
|| flag == LineGL2D::Flag::ShaderStorageBuffers
#endif
) {
/* Target hints matter just on WebGL (which doesn't have SSBOs) */
GL::Buffer transformationProjectionUniform{GL::Buffer::TargetHint::Uniform, {
TransformationProjectionUniform2D{}
.setTransformationProjectionMatrix(
@ -2206,6 +2455,19 @@ template<LineGL3D::Flag flag> void LineGLTest::renderInstanced3D() {
auto&& data = RenderInstancedData[testCaseInstanceId()];
setTestCaseDescription(data.name);
#ifndef MAGNUM_TARGET_WEBGL
if(flag == LineGL3D::Flag::ShaderStorageBuffers) {
setTestCaseTemplateName("Flag::ShaderStorageBuffers");
#ifndef MAGNUM_TARGET_GLES
if(!GL::Context::current().isExtensionSupported<GL::Extensions::ARB::shader_storage_buffer_object>())
CORRADE_SKIP(GL::Extensions::ARB::shader_storage_buffer_object::string() << "is not supported.");
#else
if(!GL::Context::current().isVersionSupported(GL::Version::GLES310))
CORRADE_SKIP(GL::Version::GLES310 << "is not supported.");
#endif
} else
#endif
if(flag == LineGL3D::Flag::UniformBuffers) {
setTestCaseTemplateName("Flag::UniformBuffers");
@ -2272,8 +2534,12 @@ template<LineGL3D::Flag flag> void LineGLTest::renderInstanced3D() {
/* Gets added to the per-instance ID, if that's enabled as well */
shader.setObjectId(1000);
shader.draw(lines);
} else if(flag == LineGL2D::Flag::UniformBuffers) {
} else if(flag == LineGL3D::Flag::UniformBuffers
#ifndef MAGNUM_TARGET_WEBGL
|| flag == LineGL3D::Flag::ShaderStorageBuffers
#endif
) {
/* Target hints matter just on WebGL (which doesn't have SSBOs) */
GL::Buffer transformationProjectionUniform{GL::Buffer::TargetHint::Uniform, {
TransformationProjectionUniform3D{}
.setTransformationProjectionMatrix(
@ -2348,6 +2614,18 @@ void LineGLTest::renderMulti2D() {
CORRADE_SKIP(GL::Extensions::ARB::uniform_buffer_object::string() << "is not supported.");
#endif
#ifndef MAGNUM_TARGET_WEBGL
if(data.flags >= LineGL2D::Flag::ShaderStorageBuffers) {
#ifndef MAGNUM_TARGET_GLES
if(!GL::Context::current().isExtensionSupported<GL::Extensions::ARB::shader_storage_buffer_object>())
CORRADE_SKIP(GL::Extensions::ARB::shader_storage_buffer_object::string() << "is not supported.");
#else
if(!GL::Context::current().isVersionSupported(GL::Version::GLES310))
CORRADE_SKIP(GL::Version::GLES310 << "is not supported.");
#endif
}
#endif
if(data.flags >= LineGL2D::Flag::MultiDraw) {
#ifndef MAGNUM_TARGET_GLES
if(!GL::Context::current().isExtensionSupported<GL::Extensions::ARB::shader_draw_parameters>())
@ -2448,13 +2726,13 @@ void LineGLTest::renderMulti2D() {
/* Material offsets are zero if we have single draw, as those are
done with UBO offset bindings instead. */
drawData[0*data.uniformIncrement] = LineDrawUniform{}
.setMaterialId(data.drawCount == 1 ? 0 : 1)
.setMaterialId(data.bindWithOffset ? 0 : 1)
.setObjectId(1211);
drawData[1*data.uniformIncrement] = LineDrawUniform{}
.setMaterialId(data.drawCount == 1 ? 0 : 0)
.setMaterialId(data.bindWithOffset ? 0 : 0)
.setObjectId(5627);
drawData[2*data.uniformIncrement] = LineDrawUniform{}
.setMaterialId(data.drawCount == 1 ? 0 : 1)
.setMaterialId(data.bindWithOffset ? 0 : 1)
.setObjectId(36363);
GL::Buffer drawUniform{GL::Buffer::TargetHint::Uniform, drawData};
@ -2464,8 +2742,8 @@ void LineGLTest::renderMulti2D() {
GL::Renderer::BlendFunction::One,
GL::Renderer::BlendFunction::OneMinusSourceAlpha);
/* Just one draw, rebinding UBOs each time */
if(data.drawCount == 1) {
/* Rebinding UBOs / SSBOs each time */
if(data.bindWithOffset) {
shader.bindMaterialBuffer(materialUniform,
1*data.uniformIncrement*sizeof(LineMaterialUniform),
sizeof(LineMaterialUniform));
@ -2564,6 +2842,18 @@ void LineGLTest::renderMulti3D() {
CORRADE_SKIP(GL::Extensions::ARB::uniform_buffer_object::string() << "is not supported.");
#endif
#ifndef MAGNUM_TARGET_WEBGL
if(data.flags >= LineGL2D::Flag::ShaderStorageBuffers) {
#ifndef MAGNUM_TARGET_GLES
if(!GL::Context::current().isExtensionSupported<GL::Extensions::ARB::shader_storage_buffer_object>())
CORRADE_SKIP(GL::Extensions::ARB::shader_storage_buffer_object::string() << "is not supported.");
#else
if(!GL::Context::current().isVersionSupported(GL::Version::GLES310))
CORRADE_SKIP(GL::Version::GLES310 << "is not supported.");
#endif
}
#endif
if(data.flags >= LineGL2D::Flag::MultiDraw) {
#ifndef MAGNUM_TARGET_GLES
if(!GL::Context::current().isExtensionSupported<GL::Extensions::ARB::shader_draw_parameters>())
@ -2663,13 +2953,13 @@ void LineGLTest::renderMulti3D() {
/* Material offsets are zero if we have single draw, as those are
done with UBO offset bindings instead. */
drawData[0*data.uniformIncrement] = LineDrawUniform{}
.setMaterialId(data.drawCount == 1 ? 0 : 1)
.setMaterialId(data.bindWithOffset ? 0 : 1)
.setObjectId(1211);
drawData[1*data.uniformIncrement] = LineDrawUniform{}
.setMaterialId(data.drawCount == 1 ? 0 : 0)
.setMaterialId(data.bindWithOffset ? 0 : 0)
.setObjectId(5627);
drawData[2*data.uniformIncrement] = LineDrawUniform{}
.setMaterialId(data.drawCount == 1 ? 0 : 1)
.setMaterialId(data.bindWithOffset ? 0 : 1)
.setObjectId(36363);
GL::Buffer drawUniform{GL::Buffer::TargetHint::Uniform, drawData};
@ -2679,8 +2969,8 @@ void LineGLTest::renderMulti3D() {
GL::Renderer::BlendFunction::One,
GL::Renderer::BlendFunction::OneMinusSourceAlpha);
/* Just one draw, rebinding UBOs each time */
if(data.drawCount == 1) {
/* Rebinding UBOs / SSBOs each time */
if(data.bindWithOffset) {
shader.bindMaterialBuffer(materialUniform,
1*data.uniformIncrement*sizeof(LineMaterialUniform),
sizeof(LineMaterialUniform));

17
src/Magnum/Shaders/Test/LineGL_Test.cpp

@ -143,13 +143,26 @@ void LineGL_Test::debugFlagsSupersets() {
std::ostringstream out;
Debug{&out} << (LineGL3D::Flag::ObjectId|LineGL3D::Flag::InstancedObjectId);
CORRADE_COMPARE(out.str(), "Shaders::LineGL::Flag::InstancedObjectId\n");
}
/* MultiDraw is a superset of UniformBuffers so only one should be printed */
} {
/* MultiDraw and ShaderStorageBuffers are a superset of UniformBuffers so
only one should be printed, but if there are both then both should be */
{
std::ostringstream out;
Debug{&out} << (LineGL3D::Flag::MultiDraw|LineGL3D::Flag::UniformBuffers);
CORRADE_COMPARE(out.str(), "Shaders::LineGL::Flag::MultiDraw\n");
}
#ifndef MAGNUM_TARGET_WEBGL
{
std::ostringstream out;
Debug{&out} << (LineGL2D::Flag::ShaderStorageBuffers|LineGL2D::Flag::UniformBuffers);
CORRADE_COMPARE(out.str(), "Shaders::LineGL::Flag::ShaderStorageBuffers\n");
} {
std::ostringstream out;
Debug{&out} << (LineGL2D::Flag::MultiDraw|LineGL2D::Flag::ShaderStorageBuffers|LineGL2D::Flag::UniformBuffers);
CORRADE_COMPARE(out.str(), "Shaders::LineGL::Flag::MultiDraw|Shaders::LineGL::Flag::ShaderStorageBuffers\n");
}
#endif
}
}}}}

867
src/Magnum/Shaders/Test/MeshVisualizerGLTest.cpp

File diff suppressed because it is too large Load Diff

39
src/Magnum/Shaders/Test/MeshVisualizerGL_Test.cpp

@ -74,13 +74,10 @@ const struct {
"expected at most 4 secondary per-vertex joints, got 5"},
{"joint count but no per-vertex joint count",
10, 0, 0,
"count has to be non-zero iff (secondary) per-vertex joint count is non-zero"},
{"per-vertex joint count but no joint count",
0, 2, 0,
"count has to be non-zero iff (secondary) per-vertex joint count is non-zero"},
{"secondary per-vertex joint count but no joint count",
0, 0, 3,
"count has to be non-zero iff (secondary) per-vertex joint count is non-zero"},
"count has to be zero if per-vertex joint count is zero"},
/* The rest depends on flags being set and is thus verified in constructor,
tested in MeshVisualizerGLTest::constructInvalid() and
constructUniformBuffersInvalid() */
};
#endif
@ -243,12 +240,24 @@ void MeshVisualizerGL_Test::debugFlagsSupersets2D() {
CORRADE_COMPARE(out.str(), "Shaders::MeshVisualizerGL2D::Flag::InstancedTextureOffset\n");
}
/* MultiDraw is a superset of UniformBuffers so only one should be printed */
/* MultiDraw and ShaderStorageBuffers are a superset of UniformBuffers so
only one should be printed, but if there are both then both should be */
{
std::ostringstream out;
Debug{&out} << (MeshVisualizerGL2D::Flag::MultiDraw|MeshVisualizerGL2D::Flag::UniformBuffers);
CORRADE_COMPARE(out.str(), "Shaders::MeshVisualizerGL2D::Flag::MultiDraw\n");
}
#ifndef MAGNUM_TARGET_WEBGL
{
std::ostringstream out;
Debug{&out} << (MeshVisualizerGL2D::Flag::ShaderStorageBuffers|MeshVisualizerGL2D::Flag::UniformBuffers);
CORRADE_COMPARE(out.str(), "Shaders::MeshVisualizerGL2D::Flag::ShaderStorageBuffers\n");
} {
std::ostringstream out;
Debug{&out} << (MeshVisualizerGL2D::Flag::MultiDraw|MeshVisualizerGL2D::Flag::ShaderStorageBuffers|MeshVisualizerGL2D::Flag::UniformBuffers);
CORRADE_COMPARE(out.str(), "Shaders::MeshVisualizerGL2D::Flag::MultiDraw|Shaders::MeshVisualizerGL2D::Flag::ShaderStorageBuffers\n");
}
#endif
}
void MeshVisualizerGL_Test::debugFlagsSupersets3D() {
@ -276,12 +285,24 @@ void MeshVisualizerGL_Test::debugFlagsSupersets3D() {
CORRADE_COMPARE(out.str(), "Shaders::MeshVisualizerGL3D::Flag::InstancedTextureOffset\n");
}
/* MultiDraw is a superset of UniformBuffers so only one should be printed */
/* MultiDraw and ShaderStorageBuffers are a superset of UniformBuffers so
only one should be printed, but if there are both then both should be */
{
std::ostringstream out;
Debug{&out} << (MeshVisualizerGL3D::Flag::MultiDraw|MeshVisualizerGL3D::Flag::UniformBuffers);
CORRADE_COMPARE(out.str(), "Shaders::MeshVisualizerGL3D::Flag::MultiDraw\n");
}
#ifndef MAGNUM_TARGET_WEBGL
{
std::ostringstream out;
Debug{&out} << (MeshVisualizerGL3D::Flag::ShaderStorageBuffers|MeshVisualizerGL3D::Flag::UniformBuffers);
CORRADE_COMPARE(out.str(), "Shaders::MeshVisualizerGL3D::Flag::ShaderStorageBuffers\n");
} {
std::ostringstream out;
Debug{&out} << (MeshVisualizerGL3D::Flag::MultiDraw|MeshVisualizerGL3D::Flag::ShaderStorageBuffers|MeshVisualizerGL3D::Flag::UniformBuffers);
CORRADE_COMPARE(out.str(), "Shaders::MeshVisualizerGL3D::Flag::MultiDraw|Shaders::MeshVisualizerGL3D::Flag::ShaderStorageBuffers\n");
}
#endif
}
#endif

615
src/Magnum/Shaders/Test/PhongGLTest.cpp

File diff suppressed because it is too large Load Diff

36
src/Magnum/Shaders/Test/PhongGL_Test.cpp

@ -55,15 +55,12 @@ const struct {
UnsignedInt count, perDrawCount;
const char* message;
} ConfigurationSetLightCountInvalidData[] {
{"per-draw count larger than count",
10, 11,
"per-draw light count expected to be not larger than total count of 10, got 11"},
{"count but no per-draw count",
10, 0,
"count has to be non-zero iff per-draw count is non-zero"},
{"per-draw count but no count",
0, 2,
"count has to be non-zero iff per-draw count is non-zero"},
"count has to be zero if per-draw count is zero"},
/* The rest depends on flags being set and is thus verified in constructor,
tested in PhongGLTest::constructInvalid() and
constructUniformBuffersInvalid() */
};
#ifndef MAGNUM_TARGET_GLES2
@ -80,13 +77,10 @@ const struct {
"expected at most 4 secondary per-vertex joints, got 5"},
{"joint count but no per-vertex joint count",
10, 0, 0,
"count has to be non-zero iff (secondary) per-vertex joint count is non-zero"},
{"per-vertex joint count but no joint count",
0, 2, 0,
"count has to be non-zero iff (secondary) per-vertex joint count is non-zero"},
{"secondary per-vertex joint count but no joint count",
0, 0, 3,
"count has to be non-zero iff (secondary) per-vertex joint count is non-zero"},
"count has to be zero if per-vertex joint count is zero"},
/* The rest depends on flags being set and is thus verified in constructor,
tested in PhongGLTest::constructInvalid() and
constructUniformBuffersInvalid() */
};
#endif
@ -195,12 +189,24 @@ void PhongGL_Test::debugFlagsSupersets() {
}
#ifndef MAGNUM_TARGET_GLES2
/* MultiDraw is a superset of UniformBuffers so only one should be printed */
/* MultiDraw and ShaderStorageBuffers are a superset of UniformBuffers so
only one should be printed, but if there are both then both should be */
{
std::ostringstream out;
Debug{&out} << (PhongGL::Flag::MultiDraw|PhongGL::Flag::UniformBuffers);
CORRADE_COMPARE(out.str(), "Shaders::PhongGL::Flag::MultiDraw\n");
}
#ifndef MAGNUM_TARGET_WEBGL
{
std::ostringstream out;
Debug{&out} << (PhongGL::Flag::ShaderStorageBuffers|PhongGL::Flag::UniformBuffers);
CORRADE_COMPARE(out.str(), "Shaders::PhongGL::Flag::ShaderStorageBuffers\n");
} {
std::ostringstream out;
Debug{&out} << (PhongGL::Flag::MultiDraw|PhongGL::Flag::ShaderStorageBuffers|PhongGL::Flag::UniformBuffers);
CORRADE_COMPARE(out.str(), "Shaders::PhongGL::Flag::MultiDraw|Shaders::PhongGL::Flag::ShaderStorageBuffers\n");
}
#endif
#endif
}

179
src/Magnum/Shaders/Test/VectorGLTest.cpp

@ -186,7 +186,10 @@ constexpr struct {
/* SwiftShader has 256 uniform vectors at most, per-draw is 4+1 in 3D case
and 3+1 in 2D, per-material 3 */
{"multiple materials, draws", VectorGL2D::Flag::UniformBuffers, 15, 42},
{"multidraw with all the things", VectorGL2D::Flag::MultiDraw|VectorGL2D::Flag::TextureTransformation, 15, 42}
{"multidraw with all the things", VectorGL2D::Flag::MultiDraw|VectorGL2D::Flag::TextureTransformation, 15, 42},
#ifndef MAGNUM_TARGET_WEBGL
{"shader storage + multidraw with all the things", VectorGL2D::Flag::ShaderStorageBuffers|VectorGL2D::Flag::MultiDraw|VectorGL2D::Flag::TextureTransformation, 0, 0}
#endif
};
#endif
@ -197,6 +200,7 @@ constexpr struct {
UnsignedInt materialCount, drawCount;
const char* message;
} ConstructUniformBuffersInvalidData[]{
/* These two fail for UBOs but not SSBOs */
{"zero draws", VectorGL2D::Flag::UniformBuffers, 1, 0,
"draw count can't be zero"},
{"zero materials", VectorGL2D::Flag::UniformBuffers, 0, 1,
@ -228,21 +232,40 @@ constexpr struct {
const char* expected3D;
VectorGL2D::Flags flags;
UnsignedInt materialCount, drawCount;
bool bindWithOffset;
UnsignedInt uniformIncrement;
Float maxThreshold, meanThreshold;
} RenderMultiData[] {
{"bind with offset", "multidraw2D.tga", "multidraw3D.tga",
{}, 1, 1, 16,
{}, 1, 1, true, 16,
/* Minor differences on ARM Mali */
1.34f, 0.02f},
#ifndef MAGNUM_TARGET_WEBGL
{"bind with offset, shader storage", "multidraw2D.tga", "multidraw3D.tga",
VectorGL2D::Flag::ShaderStorageBuffers, 0, 0, true, 16,
/* Minor differences on ARM Mali */
1.34f, 0.02f},
#endif
{"draw offset", "multidraw2D.tga", "multidraw3D.tga",
{}, 2, 3, 1,
{}, 2, 3, false, 1,
/* Minor differences on ARM Mali */
1.34f, 0.02f},
#ifndef MAGNUM_TARGET_WEBGL
{"draw offset, shader storage", "multidraw2D.tga", "multidraw3D.tga",
VectorGL2D::Flag::ShaderStorageBuffers, 0, 0, false, 1,
/* Minor differences on ARM Mali */
1.34f, 0.02f},
#endif
{"multidraw", "multidraw2D.tga", "multidraw3D.tga",
VectorGL2D::Flag::MultiDraw, 2, 3, 1,
VectorGL2D::Flag::MultiDraw, 2, 3, false, 1,
/* Minor differences on ARM Mali */
1.34f, 0.02f},
#ifndef MAGNUM_TARGET_WEBGL
{"multidraw, shader storage", "multidraw2D.tga", "multidraw3D.tga",
VectorGL2D::Flag::ShaderStorageBuffers|VectorGL2D::Flag::MultiDraw, 0, 0, false, 1,
/* Minor differences on ARM Mali */
1.34f, 0.02f},
#endif
};
#endif
@ -308,10 +331,16 @@ VectorGLTest::VectorGLTest() {
&VectorGLTest::renderDefaults2D,
#ifndef MAGNUM_TARGET_GLES2
&VectorGLTest::renderDefaults2D<VectorGL2D::Flag::UniformBuffers>,
#ifndef MAGNUM_TARGET_WEBGL
&VectorGLTest::renderDefaults2D<VectorGL2D::Flag::ShaderStorageBuffers>,
#endif
#endif
&VectorGLTest::renderDefaults3D,
#ifndef MAGNUM_TARGET_GLES2
&VectorGLTest::renderDefaults3D<VectorGL3D::Flag::UniformBuffers>,
#ifndef MAGNUM_TARGET_WEBGL
&VectorGLTest::renderDefaults3D<VectorGL3D::Flag::ShaderStorageBuffers>,
#endif
#endif
},
&VectorGLTest::renderSetup,
@ -322,10 +351,16 @@ VectorGLTest::VectorGLTest() {
&VectorGLTest::render2D,
#ifndef MAGNUM_TARGET_GLES2
&VectorGLTest::render2D<VectorGL2D::Flag::UniformBuffers>,
#ifndef MAGNUM_TARGET_WEBGL
&VectorGLTest::render2D<VectorGL2D::Flag::ShaderStorageBuffers>,
#endif
#endif
&VectorGLTest::render3D,
#ifndef MAGNUM_TARGET_GLES2
&VectorGLTest::render3D<VectorGL3D::Flag::UniformBuffers>,
#ifndef MAGNUM_TARGET_WEBGL
&VectorGLTest::render3D<VectorGL3D::Flag::ShaderStorageBuffers>,
#endif
#endif
},
Containers::arraySize(RenderData),
@ -421,6 +456,18 @@ template<UnsignedInt dimensions> void VectorGLTest::constructUniformBuffers() {
CORRADE_SKIP(GL::Extensions::ARB::uniform_buffer_object::string() << "is not supported.");
#endif
#ifndef MAGNUM_TARGET_WEBGL
if(data.flags >= VectorGL2D::Flag::ShaderStorageBuffers) {
#ifndef MAGNUM_TARGET_GLES
if(!GL::Context::current().isExtensionSupported<GL::Extensions::ARB::shader_storage_buffer_object>())
CORRADE_SKIP(GL::Extensions::ARB::shader_storage_buffer_object::string() << "is not supported.");
#else
if(!GL::Context::current().isVersionSupported(GL::Version::GLES310))
CORRADE_SKIP(GL::Version::GLES310 << "is not supported.");
#endif
}
#endif
if(data.flags >= VectorGL2D::Flag::MultiDraw) {
#ifndef MAGNUM_TARGET_GLES
if(!GL::Context::current().isExtensionSupported<GL::Extensions::ARB::shader_draw_parameters>())
@ -727,6 +774,19 @@ constexpr GL::TextureFormat TextureFormatR =
template<VectorGL2D::Flag flag> void VectorGLTest::renderDefaults2D() {
#ifndef MAGNUM_TARGET_GLES2
#ifndef MAGNUM_TARGET_WEBGL
if(flag == VectorGL2D::Flag::ShaderStorageBuffers) {
setTestCaseTemplateName("Flag::ShaderStorageBuffers");
#ifndef MAGNUM_TARGET_GLES
if(!GL::Context::current().isExtensionSupported<GL::Extensions::ARB::shader_storage_buffer_object>())
CORRADE_SKIP(GL::Extensions::ARB::shader_storage_buffer_object::string() << "is not supported.");
#else
if(!GL::Context::current().isVersionSupported(GL::Version::GLES310))
CORRADE_SKIP(GL::Version::GLES310 << "is not supported.");
#endif
} else
#endif
if(flag == VectorGL2D::Flag::UniformBuffers) {
setTestCaseTemplateName("Flag::UniformBuffers");
@ -770,7 +830,12 @@ template<VectorGL2D::Flag flag> void VectorGLTest::renderDefaults2D() {
shader.draw(square);
}
#ifndef MAGNUM_TARGET_GLES2
else if(flag == VectorGL2D::Flag::UniformBuffers) {
else if(flag == VectorGL2D::Flag::UniformBuffers
#ifndef MAGNUM_TARGET_WEBGL
|| flag == VectorGL2D::Flag::ShaderStorageBuffers
#endif
) {
/* Target hints matter just on WebGL (which doesn't have SSBOs) */
GL::Buffer transformationProjectionUniform{GL::Buffer::TargetHint::Uniform, {
TransformationProjectionUniform2D{}
}};
@ -807,6 +872,19 @@ template<VectorGL2D::Flag flag> void VectorGLTest::renderDefaults2D() {
template<VectorGL3D::Flag flag> void VectorGLTest::renderDefaults3D() {
#ifndef MAGNUM_TARGET_GLES2
#ifndef MAGNUM_TARGET_WEBGL
if(flag == VectorGL2D::Flag::ShaderStorageBuffers) {
setTestCaseTemplateName("Flag::ShaderStorageBuffers");
#ifndef MAGNUM_TARGET_GLES
if(!GL::Context::current().isExtensionSupported<GL::Extensions::ARB::shader_storage_buffer_object>())
CORRADE_SKIP(GL::Extensions::ARB::shader_storage_buffer_object::string() << "is not supported.");
#else
if(!GL::Context::current().isVersionSupported(GL::Version::GLES310))
CORRADE_SKIP(GL::Version::GLES310 << "is not supported.");
#endif
} else
#endif
if(flag == VectorGL3D::Flag::UniformBuffers) {
setTestCaseTemplateName("Flag::UniformBuffers");
@ -850,7 +928,12 @@ template<VectorGL3D::Flag flag> void VectorGLTest::renderDefaults3D() {
shader.draw(plane);
}
#ifndef MAGNUM_TARGET_GLES2
else if(flag == VectorGL2D::Flag::UniformBuffers) {
else if(flag == VectorGL2D::Flag::UniformBuffers
#ifndef MAGNUM_TARGET_WEBGL
|| flag == VectorGL2D::Flag::ShaderStorageBuffers
#endif
) {
/* Target hints matter just on WebGL (which doesn't have SSBOs) */
GL::Buffer transformationProjectionUniform{GL::Buffer::TargetHint::Uniform, {
TransformationProjectionUniform3D{}
}};
@ -890,6 +973,19 @@ template<VectorGL2D::Flag flag> void VectorGLTest::render2D() {
setTestCaseDescription(data.name);
#ifndef MAGNUM_TARGET_GLES2
#ifndef MAGNUM_TARGET_WEBGL
if(flag == VectorGL2D::Flag::ShaderStorageBuffers) {
setTestCaseTemplateName("Flag::ShaderStorageBuffers");
#ifndef MAGNUM_TARGET_GLES
if(!GL::Context::current().isExtensionSupported<GL::Extensions::ARB::shader_storage_buffer_object>())
CORRADE_SKIP(GL::Extensions::ARB::shader_storage_buffer_object::string() << "is not supported.");
#else
if(!GL::Context::current().isVersionSupported(GL::Version::GLES310))
CORRADE_SKIP(GL::Version::GLES310 << "is not supported.");
#endif
} else
#endif
if(flag == VectorGL2D::Flag::UniformBuffers) {
setTestCaseTemplateName("Flag::UniformBuffers");
@ -940,7 +1036,12 @@ template<VectorGL2D::Flag flag> void VectorGLTest::render2D() {
shader.draw(square);
}
#ifndef MAGNUM_TARGET_GLES2
else if(flag == VectorGL2D::Flag::UniformBuffers) {
else if(flag == VectorGL2D::Flag::UniformBuffers
#ifndef MAGNUM_TARGET_WEBGL
|| flag == VectorGL2D::Flag::ShaderStorageBuffers
#endif
) {
/* Target hints matter just on WebGL (which doesn't have SSBOs) */
GL::Buffer transformationProjectionUniform{GL::Buffer::TargetHint::Uniform, {
TransformationProjectionUniform2D{}
.setTransformationProjectionMatrix(
@ -996,6 +1097,19 @@ template<VectorGL3D::Flag flag> void VectorGLTest::render3D() {
setTestCaseDescription(data.name);
#ifndef MAGNUM_TARGET_GLES2
#ifndef MAGNUM_TARGET_WEBGL
if(flag == VectorGL2D::Flag::ShaderStorageBuffers) {
setTestCaseTemplateName("Flag::ShaderStorageBuffers");
#ifndef MAGNUM_TARGET_GLES
if(!GL::Context::current().isExtensionSupported<GL::Extensions::ARB::shader_storage_buffer_object>())
CORRADE_SKIP(GL::Extensions::ARB::shader_storage_buffer_object::string() << "is not supported.");
#else
if(!GL::Context::current().isVersionSupported(GL::Version::GLES310))
CORRADE_SKIP(GL::Version::GLES310 << "is not supported.");
#endif
} else
#endif
if(flag == VectorGL3D::Flag::UniformBuffers) {
setTestCaseTemplateName("Flag::UniformBuffers");
@ -1048,7 +1162,12 @@ template<VectorGL3D::Flag flag> void VectorGLTest::render3D() {
shader.draw(plane);
}
#ifndef MAGNUM_TARGET_GLES2
else if(flag == VectorGL3D::Flag::UniformBuffers) {
else if(flag == VectorGL2D::Flag::UniformBuffers
#ifndef MAGNUM_TARGET_WEBGL
|| flag == VectorGL2D::Flag::ShaderStorageBuffers
#endif
) {
/* Target hints matter just on WebGL (which doesn't have SSBOs) */
GL::Buffer transformationProjectionUniform{GL::Buffer::TargetHint::Uniform, {
TransformationProjectionUniform3D{}
.setTransformationProjectionMatrix(
@ -1111,6 +1230,18 @@ void VectorGLTest::renderMulti2D() {
CORRADE_SKIP(GL::Extensions::ARB::uniform_buffer_object::string() << "is not supported.");
#endif
#ifndef MAGNUM_TARGET_WEBGL
if(data.flags >= VectorGL2D::Flag::ShaderStorageBuffers) {
#ifndef MAGNUM_TARGET_GLES
if(!GL::Context::current().isExtensionSupported<GL::Extensions::ARB::shader_storage_buffer_object>())
CORRADE_SKIP(GL::Extensions::ARB::shader_storage_buffer_object::string() << "is not supported.");
#else
if(!GL::Context::current().isVersionSupported(GL::Version::GLES310))
CORRADE_SKIP(GL::Version::GLES310 << "is not supported.");
#endif
}
#endif
if(data.flags >= VectorGL2D::Flag::MultiDraw) {
#ifndef MAGNUM_TARGET_GLES
if(!GL::Context::current().isExtensionSupported<GL::Extensions::ARB::shader_draw_parameters>())
@ -1217,11 +1348,11 @@ void VectorGLTest::renderMulti2D() {
/* Material offsets are zero if we have single draw, as those are done with
UBO offset bindings instead. */
drawData[0*data.uniformIncrement] = VectorDrawUniform{}
.setMaterialId(data.drawCount == 1 ? 0 : 1);
.setMaterialId(data.bindWithOffset ? 0 : 1);
drawData[1*data.uniformIncrement] = VectorDrawUniform{}
.setMaterialId(data.drawCount == 1 ? 0 : 0);
.setMaterialId(data.bindWithOffset ? 0 : 0);
drawData[2*data.uniformIncrement] = VectorDrawUniform{}
.setMaterialId(data.drawCount == 1 ? 0 : 1);
.setMaterialId(data.bindWithOffset ? 0 : 1);
GL::Buffer drawUniform{GL::Buffer::TargetHint::Uniform, drawData};
VectorGL2D shader{VectorGL2D::Configuration{}
@ -1230,8 +1361,8 @@ void VectorGLTest::renderMulti2D() {
.setDrawCount(data.drawCount)};
shader.bindVectorTexture(vector);
/* Just one draw, rebinding UBOs each time */
if(data.drawCount == 1) {
/* Rebinding UBOs / SSBOs each time */
if(data.bindWithOffset) {
shader.bindMaterialBuffer(materialUniform,
1*data.uniformIncrement*sizeof(VectorMaterialUniform),
sizeof(VectorMaterialUniform));
@ -1315,6 +1446,18 @@ void VectorGLTest::renderMulti3D() {
CORRADE_SKIP(GL::Extensions::ARB::uniform_buffer_object::string() << "is not supported.");
#endif
#ifndef MAGNUM_TARGET_WEBGL
if(data.flags >= VectorGL3D::Flag::ShaderStorageBuffers) {
#ifndef MAGNUM_TARGET_GLES
if(!GL::Context::current().isExtensionSupported<GL::Extensions::ARB::shader_storage_buffer_object>())
CORRADE_SKIP(GL::Extensions::ARB::shader_storage_buffer_object::string() << "is not supported.");
#else
if(!GL::Context::current().isVersionSupported(GL::Version::GLES310))
CORRADE_SKIP(GL::Version::GLES310 << "is not supported.");
#endif
}
#endif
if(data.flags >= VectorGL3D::Flag::MultiDraw) {
#ifndef MAGNUM_TARGET_GLES
if(!GL::Context::current().isExtensionSupported<GL::Extensions::ARB::shader_draw_parameters>())
@ -1426,11 +1569,11 @@ void VectorGLTest::renderMulti3D() {
/* Material offsets are zero if we have single draw, as those are done with
UBO offset bindings instead. */
drawData[0*data.uniformIncrement] = VectorDrawUniform{}
.setMaterialId(data.drawCount == 1 ? 0 : 1);
.setMaterialId(data.bindWithOffset ? 0 : 1);
drawData[1*data.uniformIncrement] = VectorDrawUniform{}
.setMaterialId(data.drawCount == 1 ? 0 : 0);
.setMaterialId(data.bindWithOffset ? 0 : 0);
drawData[2*data.uniformIncrement] = VectorDrawUniform{}
.setMaterialId(data.drawCount == 1 ? 0 : 1);
.setMaterialId(data.bindWithOffset ? 0 : 1);
GL::Buffer drawUniform{GL::Buffer::TargetHint::Uniform, drawData};
VectorGL3D shader{VectorGL3D::Configuration{}
@ -1439,8 +1582,8 @@ void VectorGLTest::renderMulti3D() {
.setDrawCount(data.drawCount)};
shader.bindVectorTexture(vector);
/* Just one draw, rebinding UBOs each time */
if(data.drawCount == 1) {
/* Rebinding UBOs / SSBOs each time */
if(data.bindWithOffset) {
shader.bindMaterialBuffer(materialUniform,
1*data.uniformIncrement*sizeof(VectorMaterialUniform),
sizeof(VectorMaterialUniform));

22
src/Magnum/Shaders/Test/VectorGL_Test.cpp

@ -99,10 +99,24 @@ void VectorGL_Test::debugFlags() {
#ifndef MAGNUM_TARGET_GLES2
void VectorGL_Test::debugFlagsSupersets() {
/* MultiDraw is a superset of UniformBuffers so only one should be printed */
std::ostringstream out;
Debug{&out} << (VectorGL3D::Flag::MultiDraw|VectorGL3D::Flag::UniformBuffers);
CORRADE_COMPARE(out.str(), "Shaders::VectorGL::Flag::MultiDraw\n");
/* MultiDraw and ShaderStorageBuffers are a superset of UniformBuffers so
only one should be printed, but if there are both then both should be */
{
std::ostringstream out;
Debug{&out} << (VectorGL3D::Flag::MultiDraw|VectorGL3D::Flag::UniformBuffers);
CORRADE_COMPARE(out.str(), "Shaders::VectorGL::Flag::MultiDraw\n");
}
#ifndef MAGNUM_TARGET_WEBGL
{
std::ostringstream out;
Debug{&out} << (VectorGL2D::Flag::ShaderStorageBuffers|VectorGL2D::Flag::UniformBuffers);
CORRADE_COMPARE(out.str(), "Shaders::VectorGL::Flag::ShaderStorageBuffers\n");
} {
std::ostringstream out;
Debug{&out} << (VectorGL3D::Flag::MultiDraw|VectorGL3D::Flag::ShaderStorageBuffers|VectorGL3D::Flag::UniformBuffers);
CORRADE_COMPARE(out.str(), "Shaders::VectorGL::Flag::MultiDraw|Shaders::VectorGL::Flag::ShaderStorageBuffers\n");
}
#endif
}
#endif

179
src/Magnum/Shaders/Test/VertexColorGLTest.cpp

@ -164,7 +164,10 @@ constexpr struct {
/* SwiftShader has 256 uniform vectors at most, per-draw is 4 in 3D case
and 3 in 2D; one needs to be reserved for drawOffset */
{"multiple draws", VertexColorGL2D::Flag::UniformBuffers, 63},
{"multidraw with all the things", VertexColorGL2D::Flag::MultiDraw, 63}
{"multidraw with all the things", VertexColorGL2D::Flag::MultiDraw, 63},
#ifndef MAGNUM_TARGET_WEBGL
{"shader storage + multidraw with all the things", VertexColorGL2D::Flag::ShaderStorageBuffers|VertexColorGL2D::Flag::MultiDraw, 0}
#endif
};
#endif
@ -175,21 +178,40 @@ constexpr struct {
const char* expected3D;
VertexColorGL2D::Flags flags;
UnsignedInt drawCount;
bool bindWithOffset;
UnsignedInt uniformIncrement;
Float maxThreshold, meanThreshold;
} RenderMultiData[] {
{"bind with offset", "multidraw2D.tga", "multidraw3D.tga",
{}, 1, 16,
{}, 1, true, 16,
/* Minor differences on ARM Mali */
0.34f, 0.01f},
#ifndef MAGNUM_TARGET_WEBGL
{"bind with offset, shader storage", "multidraw2D.tga", "multidraw3D.tga",
VertexColorGL2D::Flag::ShaderStorageBuffers, 1, true, 16,
/* Minor differences on ARM Mali */
0.34f, 0.01f},
#endif
{"draw offset", "multidraw2D.tga", "multidraw3D.tga",
{}, 3, 1,
{}, 3, false, 1,
/* Minor differences on ARM Mali */
0.34f, 0.01f},
#ifndef MAGNUM_TARGET_WEBGL
{"draw offset, shader storage", "multidraw2D.tga", "multidraw3D.tga",
VertexColorGL2D::Flag::ShaderStorageBuffers, 3, false, 1,
/* Minor differences on ARM Mali */
0.34f, 0.01f},
#endif
{"multidraw", "multidraw2D.tga", "multidraw3D.tga",
VertexColorGL2D::Flag::MultiDraw, 3, 1,
VertexColorGL2D::Flag::MultiDraw, 3, false, 1,
/* Minor differences on ARM Mali */
0.34f, 0.01f},
#ifndef MAGNUM_TARGET_WEBGL
{"multidraw, shader storage", "multidraw2D.tga", "multidraw3D.tga",
VertexColorGL2D::Flag::ShaderStorageBuffers|VertexColorGL2D::Flag::MultiDraw, 0, false, 1,
/* Minor differences on ARM Mali */
0.34f, 0.01f}
#endif
};
#endif
@ -240,35 +262,59 @@ VertexColorGLTest::VertexColorGLTest() {
&VertexColorGLTest::renderDefaults2D<Color3>,
#ifndef MAGNUM_TARGET_GLES2
&VertexColorGLTest::renderDefaults2D<Color3, VertexColorGL2D::Flag::UniformBuffers>,
#ifndef MAGNUM_TARGET_WEBGL
&VertexColorGLTest::renderDefaults2D<Color3, VertexColorGL2D::Flag::ShaderStorageBuffers>,
#endif
#endif
&VertexColorGLTest::renderDefaults2D<Color4>,
#ifndef MAGNUM_TARGET_GLES2
&VertexColorGLTest::renderDefaults2D<Color4, VertexColorGL2D::Flag::UniformBuffers>,
#ifndef MAGNUM_TARGET_WEBGL
&VertexColorGLTest::renderDefaults2D<Color4, VertexColorGL2D::Flag::ShaderStorageBuffers>,
#endif
#endif
&VertexColorGLTest::renderDefaults3D<Color3>,
#ifndef MAGNUM_TARGET_GLES2
&VertexColorGLTest::renderDefaults3D<Color3, VertexColorGL3D::Flag::UniformBuffers>,
#ifndef MAGNUM_TARGET_WEBGL
&VertexColorGLTest::renderDefaults3D<Color3, VertexColorGL3D::Flag::ShaderStorageBuffers>,
#endif
#endif
&VertexColorGLTest::renderDefaults3D<Color4>,
#ifndef MAGNUM_TARGET_GLES2
&VertexColorGLTest::renderDefaults3D<Color4, VertexColorGL3D::Flag::UniformBuffers>,
#ifndef MAGNUM_TARGET_WEBGL
&VertexColorGLTest::renderDefaults3D<Color4, VertexColorGL3D::Flag::ShaderStorageBuffers>,
#endif
#endif
&VertexColorGLTest::render2D<Color3>,
#ifndef MAGNUM_TARGET_GLES2
&VertexColorGLTest::render2D<Color3, VertexColorGL2D::Flag::UniformBuffers>,
#ifndef MAGNUM_TARGET_WEBGL
&VertexColorGLTest::render2D<Color3, VertexColorGL2D::Flag::ShaderStorageBuffers>,
#endif
#endif
&VertexColorGLTest::render2D<Color4>,
#ifndef MAGNUM_TARGET_GLES2
&VertexColorGLTest::render2D<Color4, VertexColorGL2D::Flag::UniformBuffers>,
#ifndef MAGNUM_TARGET_WEBGL
&VertexColorGLTest::render2D<Color4, VertexColorGL2D::Flag::ShaderStorageBuffers>,
#endif
#endif
&VertexColorGLTest::render3D<Color3>,
#ifndef MAGNUM_TARGET_GLES2
&VertexColorGLTest::render3D<Color3, VertexColorGL3D::Flag::UniformBuffers>,
#ifndef MAGNUM_TARGET_WEBGL
&VertexColorGLTest::render3D<Color3, VertexColorGL3D::Flag::ShaderStorageBuffers>,
#endif
#endif
&VertexColorGLTest::render3D<Color4>,
#ifndef MAGNUM_TARGET_GLES2
&VertexColorGLTest::render3D<Color4, VertexColorGL3D::Flag::UniformBuffers>,
#ifndef MAGNUM_TARGET_WEBGL
&VertexColorGLTest::render3D<Color4, VertexColorGL3D::Flag::ShaderStorageBuffers>,
#endif
#endif
},
&VertexColorGLTest::renderSetup,
@ -355,6 +401,18 @@ template<UnsignedInt dimensions> void VertexColorGLTest::constructUniformBuffers
CORRADE_SKIP(GL::Extensions::ARB::uniform_buffer_object::string() << "is not supported.");
#endif
#ifndef MAGNUM_TARGET_WEBGL
if(data.flags >= VertexColorGL2D::Flag::ShaderStorageBuffers) {
#ifndef MAGNUM_TARGET_GLES
if(!GL::Context::current().isExtensionSupported<GL::Extensions::ARB::shader_storage_buffer_object>())
CORRADE_SKIP(GL::Extensions::ARB::shader_storage_buffer_object::string() << "is not supported.");
#else
if(!GL::Context::current().isVersionSupported(GL::Version::GLES310))
CORRADE_SKIP(GL::Version::GLES310 << "is not supported.");
#endif
}
#endif
if(data.flags >= VertexColorGL2D::Flag::MultiDraw) {
#ifndef MAGNUM_TARGET_GLES
if(!GL::Context::current().isExtensionSupported<GL::Extensions::ARB::shader_draw_parameters>())
@ -479,6 +537,7 @@ template<UnsignedInt dimensions> void VertexColorGLTest::constructUniformBuffers
CORRADE_SKIP(GL::Extensions::ARB::uniform_buffer_object::string() << "is not supported.");
#endif
/* This fails for UBOs but not SSBOs */
std::ostringstream out;
Error redirectError{&out};
VertexColorGL<dimensions>{typename VertexColorGL<dimensions>::Configuration{}
@ -580,6 +639,19 @@ void VertexColorGLTest::renderTeardown() {
template<class T, VertexColorGL2D::Flag flag> void VertexColorGLTest::renderDefaults2D() {
#ifndef MAGNUM_TARGET_GLES2
#ifndef MAGNUM_TARGET_WEBGL
if(flag == VertexColorGL2D::Flag::ShaderStorageBuffers) {
setTestCaseTemplateName({T::Size == 3 ? "Color3" : "Color4", "Flag::ShaderStorageBuffers"});
#ifndef MAGNUM_TARGET_GLES
if(!GL::Context::current().isExtensionSupported<GL::Extensions::ARB::shader_storage_buffer_object>())
CORRADE_SKIP(GL::Extensions::ARB::shader_storage_buffer_object::string() << "is not supported.");
#else
if(!GL::Context::current().isVersionSupported(GL::Version::GLES310))
CORRADE_SKIP(GL::Version::GLES310 << "is not supported.");
#endif
} else
#endif
if(flag == VertexColorGL2D::Flag::UniformBuffers) {
setTestCaseTemplateName({T::Size == 3 ? "Color3" : "Color4", "Flag::UniformBuffers"});
@ -611,7 +683,12 @@ template<class T, VertexColorGL2D::Flag flag> void VertexColorGLTest::renderDefa
shader.draw(circle);
}
#ifndef MAGNUM_TARGET_GLES2
else if(flag == VertexColorGL2D::Flag::UniformBuffers) {
else if(flag == VertexColorGL2D::Flag::UniformBuffers
#ifndef MAGNUM_TARGET_WEBGL
|| flag == VertexColorGL2D::Flag::ShaderStorageBuffers
#endif
) {
/* Target hints matter just on WebGL (which doesn't have SSBOs) */
GL::Buffer transformationProjectionUniform{GL::Buffer::TargetHint::Uniform, {
TransformationProjectionUniform2D{}
}};
@ -643,6 +720,19 @@ template<class T, VertexColorGL2D::Flag flag> void VertexColorGLTest::renderDefa
template<class T, VertexColorGL2D::Flag flag> void VertexColorGLTest::renderDefaults3D() {
#ifndef MAGNUM_TARGET_GLES2
#ifndef MAGNUM_TARGET_WEBGL
if(flag == VertexColorGL2D::Flag::ShaderStorageBuffers) {
setTestCaseTemplateName({T::Size == 3 ? "Color3" : "Color4", "Flag::ShaderStorageBuffers"});
#ifndef MAGNUM_TARGET_GLES
if(!GL::Context::current().isExtensionSupported<GL::Extensions::ARB::shader_storage_buffer_object>())
CORRADE_SKIP(GL::Extensions::ARB::shader_storage_buffer_object::string() << "is not supported.");
#else
if(!GL::Context::current().isVersionSupported(GL::Version::GLES310))
CORRADE_SKIP(GL::Version::GLES310 << "is not supported.");
#endif
} else
#endif
if(flag == VertexColorGL2D::Flag::UniformBuffers) {
setTestCaseTemplateName({T::Size == 3 ? "Color3" : "Color4", "Flag::UniformBuffers"});
@ -678,7 +768,12 @@ template<class T, VertexColorGL2D::Flag flag> void VertexColorGLTest::renderDefa
shader.draw(sphere);
}
#ifndef MAGNUM_TARGET_GLES2
else if(flag == VertexColorGL3D::Flag::UniformBuffers) {
else if(flag == VertexColorGL2D::Flag::UniformBuffers
#ifndef MAGNUM_TARGET_WEBGL
|| flag == VertexColorGL2D::Flag::ShaderStorageBuffers
#endif
) {
/* Target hints matter just on WebGL (which doesn't have SSBOs) */
GL::Buffer transformationProjectionUniform{GL::Buffer::TargetHint::Uniform, {
TransformationProjectionUniform3D{}
}};
@ -706,6 +801,19 @@ template<class T, VertexColorGL2D::Flag flag> void VertexColorGLTest::renderDefa
template<class T, VertexColorGL2D::Flag flag> void VertexColorGLTest::render2D() {
#ifndef MAGNUM_TARGET_GLES2
#ifndef MAGNUM_TARGET_WEBGL
if(flag == VertexColorGL2D::Flag::ShaderStorageBuffers) {
setTestCaseTemplateName({T::Size == 3 ? "Color3" : "Color4", "Flag::ShaderStorageBuffers"});
#ifndef MAGNUM_TARGET_GLES
if(!GL::Context::current().isExtensionSupported<GL::Extensions::ARB::shader_storage_buffer_object>())
CORRADE_SKIP(GL::Extensions::ARB::shader_storage_buffer_object::string() << "is not supported.");
#else
if(!GL::Context::current().isVersionSupported(GL::Version::GLES310))
CORRADE_SKIP(GL::Version::GLES310 << "is not supported.");
#endif
} else
#endif
if(flag == VertexColorGL2D::Flag::UniformBuffers) {
setTestCaseTemplateName({T::Size == 3 ? "Color3" : "Color4", "Flag::UniformBuffers"});
@ -740,7 +848,12 @@ template<class T, VertexColorGL2D::Flag flag> void VertexColorGLTest::render2D()
.draw(circle);
}
#ifndef MAGNUM_TARGET_GLES2
else if(flag == VertexColorGL2D::Flag::UniformBuffers) {
else if(flag == VertexColorGL2D::Flag::UniformBuffers
#ifndef MAGNUM_TARGET_WEBGL
|| flag == VertexColorGL2D::Flag::ShaderStorageBuffers
#endif
) {
/* Target hints matter just on WebGL (which doesn't have SSBOs) */
GL::Buffer transformationProjectionUniform{GL::Buffer::TargetHint::Uniform, {
TransformationProjectionUniform2D{}
.setTransformationProjectionMatrix(Matrix3::projection({2.1f, 2.1f}))
@ -774,6 +887,19 @@ template<class T, VertexColorGL2D::Flag flag> void VertexColorGLTest::render2D()
template<class T, VertexColorGL3D::Flag flag> void VertexColorGLTest::render3D() {
#ifndef MAGNUM_TARGET_GLES2
#ifndef MAGNUM_TARGET_WEBGL
if(flag == VertexColorGL2D::Flag::ShaderStorageBuffers) {
setTestCaseTemplateName({T::Size == 3 ? "Color3" : "Color4", "Flag::ShaderStorageBuffers"});
#ifndef MAGNUM_TARGET_GLES
if(!GL::Context::current().isExtensionSupported<GL::Extensions::ARB::shader_storage_buffer_object>())
CORRADE_SKIP(GL::Extensions::ARB::shader_storage_buffer_object::string() << "is not supported.");
#else
if(!GL::Context::current().isVersionSupported(GL::Version::GLES310))
CORRADE_SKIP(GL::Version::GLES310 << "is not supported.");
#endif
} else
#endif
if(flag == VertexColorGL3D::Flag::UniformBuffers) {
setTestCaseTemplateName({T::Size == 3 ? "Color3" : "Color4", "Flag::UniformBuffers"});
@ -812,7 +938,12 @@ template<class T, VertexColorGL3D::Flag flag> void VertexColorGLTest::render3D()
.draw(sphere);
}
#ifndef MAGNUM_TARGET_GLES2
else if(flag == VertexColorGL3D::Flag::UniformBuffers) {
else if(flag == VertexColorGL2D::Flag::UniformBuffers
#ifndef MAGNUM_TARGET_WEBGL
|| flag == VertexColorGL2D::Flag::ShaderStorageBuffers
#endif
) {
/* Target hints matter just on WebGL (which doesn't have SSBOs) */
GL::Buffer transformationProjectionUniform{GL::Buffer::TargetHint::Uniform, {
TransformationProjectionUniform3D{}
.setTransformationProjectionMatrix(
@ -859,6 +990,18 @@ void VertexColorGLTest::renderMulti2D() {
CORRADE_SKIP(GL::Extensions::ARB::uniform_buffer_object::string() << "is not supported.");
#endif
#ifndef MAGNUM_TARGET_WEBGL
if(data.flags >= VertexColorGL2D::Flag::ShaderStorageBuffers) {
#ifndef MAGNUM_TARGET_GLES
if(!GL::Context::current().isExtensionSupported<GL::Extensions::ARB::shader_storage_buffer_object>())
CORRADE_SKIP(GL::Extensions::ARB::shader_storage_buffer_object::string() << "is not supported.");
#else
if(!GL::Context::current().isVersionSupported(GL::Version::GLES310))
CORRADE_SKIP(GL::Version::GLES310 << "is not supported.");
#endif
}
#endif
if(data.flags >= VertexColorGL2D::Flag::MultiDraw) {
#ifndef MAGNUM_TARGET_GLES
if(!GL::Context::current().isExtensionSupported<GL::Extensions::ARB::shader_draw_parameters>())
@ -929,8 +1072,8 @@ void VertexColorGLTest::renderMulti2D() {
.setFlags(VertexColorGL2D::Flag::UniformBuffers|data.flags)
.setDrawCount(data.drawCount)};
/* Just one draw, rebinding UBOs each time */
if(data.drawCount == 1) {
/* Rebinding UBOs / SSBOs each time */
if(data.bindWithOffset) {
shader.bindTransformationProjectionBuffer(transformationProjectionUniform,
0*data.uniformIncrement*sizeof(TransformationProjectionUniform2D),
sizeof(TransformationProjectionUniform2D));
@ -989,6 +1132,18 @@ void VertexColorGLTest::renderMulti3D() {
CORRADE_SKIP(GL::Extensions::ARB::uniform_buffer_object::string() << "is not supported.");
#endif
#ifndef MAGNUM_TARGET_WEBGL
if(data.flags >= VertexColorGL3D::Flag::ShaderStorageBuffers) {
#ifndef MAGNUM_TARGET_GLES
if(!GL::Context::current().isExtensionSupported<GL::Extensions::ARB::shader_storage_buffer_object>())
CORRADE_SKIP(GL::Extensions::ARB::shader_storage_buffer_object::string() << "is not supported.");
#else
if(!GL::Context::current().isVersionSupported(GL::Version::GLES310))
CORRADE_SKIP(GL::Version::GLES310 << "is not supported.");
#endif
}
#endif
if(data.flags >= VertexColorGL3D::Flag::MultiDraw) {
#ifndef MAGNUM_TARGET_GLES
if(!GL::Context::current().isExtensionSupported<GL::Extensions::ARB::shader_draw_parameters>())
@ -1062,8 +1217,8 @@ void VertexColorGLTest::renderMulti3D() {
.setFlags(VertexColorGL3D::Flag::UniformBuffers|data.flags)
.setDrawCount(data.drawCount)};
/* Just one draw, rebinding UBOs each time */
if(data.drawCount == 1) {
/* Rebinding UBOs / SSBOs each time */
if(data.bindWithOffset) {
shader.bindTransformationProjectionBuffer(transformationProjectionUniform,
0*data.uniformIncrement*sizeof(TransformationProjectionUniform3D),
sizeof(TransformationProjectionUniform3D));

22
src/Magnum/Shaders/Test/VertexColorGL_Test.cpp

@ -108,10 +108,24 @@ void VertexColorGL_Test::debugFlags() {
#ifndef MAGNUM_TARGET_GLES2
void VertexColorGL_Test::debugFlagsSupersets() {
/* MultiDraw is a superset of UniformBuffers so only one should be printed */
std::ostringstream out;
Debug{&out} << (VertexColorGL3D::Flag::MultiDraw|VertexColorGL3D::Flag::UniformBuffers);
CORRADE_COMPARE(out.str(), "Shaders::VertexColorGL::Flag::MultiDraw\n");
/* MultiDraw and ShaderStorageBuffers are a superset of UniformBuffers so
only one should be printed, but if there are both then both should be */
{
std::ostringstream out;
Debug{&out} << (VertexColorGL3D::Flag::MultiDraw|VertexColorGL3D::Flag::UniformBuffers);
CORRADE_COMPARE(out.str(), "Shaders::VertexColorGL::Flag::MultiDraw\n");
}
#ifndef MAGNUM_TARGET_WEBGL
{
std::ostringstream out;
Debug{&out} << (VertexColorGL2D::Flag::ShaderStorageBuffers|VertexColorGL2D::Flag::UniformBuffers);
CORRADE_COMPARE(out.str(), "Shaders::VertexColorGL::Flag::ShaderStorageBuffers\n");
} {
std::ostringstream out;
Debug{&out} << (VertexColorGL3D::Flag::MultiDraw|VertexColorGL3D::Flag::ShaderStorageBuffers|VertexColorGL3D::Flag::UniformBuffers);
CORRADE_COMPARE(out.str(), "Shaders::VertexColorGL::Flag::MultiDraw|Shaders::VertexColorGL::Flag::ShaderStorageBuffers\n");
}
#endif
}
#endif

37
src/Magnum/Shaders/Vector.frag

@ -23,6 +23,10 @@
DEALINGS IN THE SOFTWARE.
*/
#if defined(SHADER_STORAGE_BUFFERS) && !defined(GL_ES)
#extension GL_ARB_shader_storage_buffer_object: require
#endif
#ifndef NEW_GLSL
#define in varying
#define fragmentColor gl_FragColor
@ -50,11 +54,24 @@ uniform lowp vec4 color
#endif
;
/* Uniform buffers */
/* Uniform / shader storage buffers */
#else
/* For SSBOs, the per-draw and material arrays are unbounded */
#ifdef SHADER_STORAGE_BUFFERS
#define DRAW_COUNT
#define MATERIAL_COUNT
#define BUFFER_OR_UNIFORM buffer
#define BUFFER_READONLY readonly
#else
#define BUFFER_OR_UNIFORM uniform
#define BUFFER_READONLY
#endif
#ifndef MULTI_DRAW
#if DRAW_COUNT > 1
/* With SSBOs DRAW_COUNT is defined to be empty, +0 makes the condition not
cause a compile error */
#if defined(SHADER_STORAGE_BUFFERS) || DRAW_COUNT+0 > 1
#ifdef EXPLICIT_UNIFORM_LOCATION
layout(location = 0)
#endif
@ -75,11 +92,11 @@ struct DrawUniform {
};
layout(std140
#ifdef EXPLICIT_BINDING
#if defined(EXPLICIT_BINDING) || defined(SHADER_STORAGE_BUFFERS)
, binding = 2
#endif
) uniform Draw {
DrawUniform draws[DRAW_COUNT];
) BUFFER_OR_UNIFORM Draw {
BUFFER_READONLY DrawUniform draws[DRAW_COUNT];
};
struct MaterialUniform {
@ -89,11 +106,11 @@ struct MaterialUniform {
};
layout(std140
#ifdef EXPLICIT_BINDING
#if defined(EXPLICIT_BINDING) || defined(SHADER_STORAGE_BUFFERS)
, binding = 4
#endif
) uniform Material {
MaterialUniform materials[MATERIAL_COUNT];
) BUFFER_OR_UNIFORM Material {
BUFFER_READONLY MaterialUniform materials[MATERIAL_COUNT];
};
#endif
@ -123,7 +140,9 @@ out lowp vec4 fragmentColor;
void main() {
#ifdef UNIFORM_BUFFERS
#if MATERIAL_COUNT > 1
/* With SSBOs MATERIAL_COUNT is defined to be empty, +0 makes the condition
not cause a compile error */
#if defined(SHADER_STORAGE_BUFFERS) || MATERIAL_COUNT+0 > 1
mediump const uint materialId = draws[drawId].draw_materialIdReserved & 0xffffu;
#else
#define materialId 0u

32
src/Magnum/Shaders/Vector.vert

@ -23,6 +23,10 @@
DEALINGS IN THE SOFTWARE.
*/
#if defined(SHADER_STORAGE_BUFFERS) && !defined(GL_ES)
#extension GL_ARB_shader_storage_buffer_object: require
#endif
#ifdef MULTI_DRAW
#ifndef GL_ES
#extension GL_ARB_shader_draw_parameters: require
@ -73,10 +77,22 @@ uniform mediump mat3 textureMatrix
;
#endif
/* Uniform buffers */
/* Uniform / shader storage buffers */
#else
#if DRAW_COUNT > 1
/* For SSBOs, the per-draw arrays are unbounded */
#ifdef SHADER_STORAGE_BUFFERS
#define DRAW_COUNT
#define BUFFER_OR_UNIFORM buffer
#define BUFFER_READONLY readonly
#else
#define BUFFER_OR_UNIFORM uniform
#define BUFFER_READONLY
#endif
/* With SSBOs DRAW_COUNT is defined to be empty, +0 makes the condition not
cause a compile error */
#if defined(SHADER_STORAGE_BUFFERS) || DRAW_COUNT+0 > 1
#ifdef EXPLICIT_UNIFORM_LOCATION
layout(location = 0)
#endif
@ -90,11 +106,11 @@ uniform highp uint drawOffset
#endif
layout(std140
#ifdef EXPLICIT_BINDING
#if defined(EXPLICIT_BINDING) || defined(SHADER_STORAGE_BUFFERS)
, binding = 1
#endif
) uniform TransformationProjection {
highp
) BUFFER_OR_UNIFORM TransformationProjection {
BUFFER_READONLY highp
#ifdef TWO_DIMENSIONS
/* Can't be a mat3 because of ANGLE, see DrawUniform in Phong.vert for
details */
@ -115,11 +131,11 @@ struct TextureTransformationUniform {
};
layout(std140
#ifdef EXPLICIT_BINDING
#if defined(EXPLICIT_BINDING) || defined(SHADER_STORAGE_BUFFERS)
, binding = 3
#endif
) uniform TextureTransformation {
TextureTransformationUniform textureTransformations[DRAW_COUNT];
) BUFFER_OR_UNIFORM TextureTransformation {
BUFFER_READONLY TextureTransformationUniform textureTransformations[DRAW_COUNT];
};
#endif
#endif

158
src/Magnum/Shaders/VectorGL.cpp

@ -68,17 +68,31 @@ namespace {
}
template<UnsignedInt dimensions> typename VectorGL<dimensions>::CompileState VectorGL<dimensions>::compile(const Configuration& configuration) {
#ifndef MAGNUM_TARGET_GLES2
CORRADE_ASSERT(!(configuration.flags() >= Flag::UniformBuffers) || configuration.materialCount(),
"Shaders::VectorGL: material count can't be zero", CompileState{NoCreate});
CORRADE_ASSERT(!(configuration.flags() >= Flag::UniformBuffers) || configuration.drawCount(),
"Shaders::VectorGL: draw count can't be zero", CompileState{NoCreate});
#if !defined(MAGNUM_TARGET_GLES2) && !defined(CORRADE_NO_ASSERT)
#ifndef MAGNUM_TARGET_WEBGL
if(!(configuration.flags() >= Flag::ShaderStorageBuffers))
#endif
{
CORRADE_ASSERT(!(configuration.flags() >= Flag::UniformBuffers) || configuration.materialCount(),
"Shaders::VectorGL: material count can't be zero", CompileState{NoCreate});
CORRADE_ASSERT(!(configuration.flags() >= Flag::UniformBuffers) || configuration.drawCount(),
"Shaders::VectorGL: draw count can't be zero", CompileState{NoCreate});
}
#endif
#ifndef MAGNUM_TARGET_GLES
if(configuration.flags() >= Flag::UniformBuffers)
MAGNUM_ASSERT_GL_EXTENSION_SUPPORTED(GL::Extensions::ARB::uniform_buffer_object);
#endif
#if !defined(MAGNUM_TARGET_GLES2) && !defined(MAGNUM_TARGET_WEBGL)
if(configuration.flags() >= Flag::ShaderStorageBuffers) {
#ifndef MAGNUM_TARGET_GLES
MAGNUM_ASSERT_GL_EXTENSION_SUPPORTED(GL::Extensions::ARB::shader_storage_buffer_object);
#else
MAGNUM_ASSERT_GL_VERSION_SUPPORTED(GL::Version::GLES310);
#endif
}
#endif
#ifndef MAGNUM_TARGET_GLES2
if(configuration.flags() >= Flag::MultiDraw) {
#ifndef MAGNUM_TARGET_GLES
@ -115,10 +129,21 @@ template<UnsignedInt dimensions> typename VectorGL<dimensions>::CompileState Vec
.addSource(dimensions == 2 ? "#define TWO_DIMENSIONS\n"_s : "#define THREE_DIMENSIONS\n"_s);
#ifndef MAGNUM_TARGET_GLES2
if(configuration.flags() >= Flag::UniformBuffers) {
vert.addSource(Utility::format(
"#define UNIFORM_BUFFERS\n"
"#define DRAW_COUNT {}\n",
configuration.drawCount()));
#ifndef MAGNUM_TARGET_WEBGL
/* SSBOs have unbounded per-draw arrays so just a plain string can be
passed */
if(configuration.flags() >= Flag::ShaderStorageBuffers) {
vert.addSource(
"#define UNIFORM_BUFFERS\n"
"#define SHADER_STORAGE_BUFFERS\n"_s);
} else
#endif
{
vert.addSource(Utility::format(
"#define UNIFORM_BUFFERS\n"
"#define DRAW_COUNT {}\n",
configuration.drawCount()));
}
vert.addSource(configuration.flags() >= Flag::MultiDraw ? "#define MULTI_DRAW\n"_s : ""_s);
}
#endif
@ -129,12 +154,23 @@ template<UnsignedInt dimensions> typename VectorGL<dimensions>::CompileState Vec
GL::Shader frag = Implementation::createCompatibilityShader(rs, version, GL::Shader::Type::Fragment);
#ifndef MAGNUM_TARGET_GLES2
if(configuration.flags() >= Flag::UniformBuffers) {
frag.addSource(Utility::format(
"#define UNIFORM_BUFFERS\n"
"#define DRAW_COUNT {}\n"
"#define MATERIAL_COUNT {}\n",
configuration.drawCount(),
configuration.materialCount()));
#ifndef MAGNUM_TARGET_WEBGL
/* SSBOs have unbounded per-draw arrays so just a plain string can be
passed */
if(configuration.flags() >= Flag::ShaderStorageBuffers) {
frag.addSource(
"#define UNIFORM_BUFFERS\n"
"#define SHADER_STORAGE_BUFFERS\n"_s);
} else
#endif
{
frag.addSource(Utility::format(
"#define UNIFORM_BUFFERS\n"
"#define DRAW_COUNT {}\n"
"#define MATERIAL_COUNT {}\n",
configuration.drawCount(),
configuration.materialCount()));
}
frag.addSource(configuration.flags() >= Flag::MultiDraw ? "#define MULTI_DRAW\n"_s : ""_s);
}
#endif
@ -205,7 +241,11 @@ template<UnsignedInt dimensions> VectorGL<dimensions>::VectorGL(CompileState&& s
{
#ifndef MAGNUM_TARGET_GLES2
if(_flags >= Flag::UniformBuffers) {
if(_drawCount > 1) _drawOffsetUniform = uniformLocation("drawOffset"_s);
if(_drawCount > 1
#ifndef MAGNUM_TARGET_WEBGL
|| flags() >= Flag::ShaderStorageBuffers
#endif
) _drawOffsetUniform = uniformLocation("drawOffset"_s);
} else
#endif
{
@ -225,7 +265,12 @@ template<UnsignedInt dimensions> VectorGL<dimensions>::VectorGL(CompileState&& s
{
setUniform(uniformLocation("vectorTexture"_s), TextureUnit);
#ifndef MAGNUM_TARGET_GLES2
if(_flags >= Flag::UniformBuffers) {
/* SSBOs have bindings defined in the source always */
if(_flags >= Flag::UniformBuffers
#ifndef MAGNUM_TARGET_WEBGL
&& !(_flags >= Flag::ShaderStorageBuffers)
#endif
) {
setUniformBlockBinding(uniformBlockIndex("TransformationProjection"_s), TransformationProjectionBufferBinding);
setUniformBlockBinding(uniformBlockIndex("Draw"_s), DrawBufferBinding);
if(_flags & Flag::TextureTransformation)
@ -310,37 +355,62 @@ template<UnsignedInt dimensions> VectorGL<dimensions>& VectorGL<dimensions>::set
template<UnsignedInt dimensions> VectorGL<dimensions>& VectorGL<dimensions>::setDrawOffset(const UnsignedInt offset) {
CORRADE_ASSERT(_flags >= Flag::UniformBuffers,
"Shaders::VectorGL::setDrawOffset(): the shader was not created with uniform buffers enabled", *this);
#ifndef MAGNUM_TARGET_WEBGL
CORRADE_ASSERT(_flags >= Flag::ShaderStorageBuffers || offset < _drawCount,
"Shaders::VectorGL::setDrawOffset(): draw offset" << offset << "is out of bounds for" << _drawCount << "draws", *this);
#else
CORRADE_ASSERT(offset < _drawCount,
"Shaders::VectorGL::setDrawOffset(): draw offset" << offset << "is out of bounds for" << _drawCount << "draws", *this);
if(_drawCount > 1) setUniform(_drawOffsetUniform, offset);
#endif
if(_drawCount > 1
#ifndef MAGNUM_TARGET_WEBGL
|| _flags >= Flag::ShaderStorageBuffers
#endif
) setUniform(_drawOffsetUniform, offset);
return *this;
}
template<UnsignedInt dimensions> VectorGL<dimensions>& VectorGL<dimensions>::bindTransformationProjectionBuffer(GL::Buffer& buffer) {
CORRADE_ASSERT(_flags >= Flag::UniformBuffers,
"Shaders::VectorGL::bindTransformationProjectionBuffer(): the shader was not created with uniform buffers enabled", *this);
buffer.bind(GL::Buffer::Target::Uniform, TransformationProjectionBufferBinding);
buffer.bind(
#ifndef MAGNUM_TARGET_WEBGL
_flags >= Flag::ShaderStorageBuffers ? GL::Buffer::Target::ShaderStorage :
#endif
GL::Buffer::Target::Uniform, TransformationProjectionBufferBinding);
return *this;
}
template<UnsignedInt dimensions> VectorGL<dimensions>& VectorGL<dimensions>::bindTransformationProjectionBuffer(GL::Buffer& buffer, const GLintptr offset, const GLsizeiptr size) {
CORRADE_ASSERT(_flags >= Flag::UniformBuffers,
"Shaders::VectorGL::bindTransformationProjectionBuffer(): the shader was not created with uniform buffers enabled", *this);
buffer.bind(GL::Buffer::Target::Uniform, TransformationProjectionBufferBinding, offset, size);
buffer.bind(
#ifndef MAGNUM_TARGET_WEBGL
_flags >= Flag::ShaderStorageBuffers ? GL::Buffer::Target::ShaderStorage :
#endif
GL::Buffer::Target::Uniform, TransformationProjectionBufferBinding, offset, size);
return *this;
}
template<UnsignedInt dimensions> VectorGL<dimensions>& VectorGL<dimensions>::bindDrawBuffer(GL::Buffer& buffer) {
CORRADE_ASSERT(_flags >= Flag::UniformBuffers,
"Shaders::VectorGL::bindDrawBuffer(): the shader was not created with uniform buffers enabled", *this);
buffer.bind(GL::Buffer::Target::Uniform, DrawBufferBinding);
buffer.bind(
#ifndef MAGNUM_TARGET_WEBGL
_flags >= Flag::ShaderStorageBuffers ? GL::Buffer::Target::ShaderStorage :
#endif
GL::Buffer::Target::Uniform, DrawBufferBinding);
return *this;
}
template<UnsignedInt dimensions> VectorGL<dimensions>& VectorGL<dimensions>::bindDrawBuffer(GL::Buffer& buffer, const GLintptr offset, const GLsizeiptr size) {
CORRADE_ASSERT(_flags >= Flag::UniformBuffers,
"Shaders::VectorGL::bindDrawBuffer(): the shader was not created with uniform buffers enabled", *this);
buffer.bind(GL::Buffer::Target::Uniform, DrawBufferBinding, offset, size);
buffer.bind(
#ifndef MAGNUM_TARGET_WEBGL
_flags >= Flag::ShaderStorageBuffers ? GL::Buffer::Target::ShaderStorage :
#endif
GL::Buffer::Target::Uniform, DrawBufferBinding, offset, size);
return *this;
}
@ -349,7 +419,11 @@ template<UnsignedInt dimensions> VectorGL<dimensions>& VectorGL<dimensions>::bin
"Shaders::VectorGL::bindTextureTransformationBuffer(): the shader was not created with uniform buffers enabled", *this);
CORRADE_ASSERT(_flags & Flag::TextureTransformation,
"Shaders::VectorGL::bindTextureTransformationBuffer(): the shader was not created with texture transformation enabled", *this);
buffer.bind(GL::Buffer::Target::Uniform, TextureTransformationBufferBinding);
buffer.bind(
#ifndef MAGNUM_TARGET_WEBGL
_flags >= Flag::ShaderStorageBuffers ? GL::Buffer::Target::ShaderStorage :
#endif
GL::Buffer::Target::Uniform, TextureTransformationBufferBinding);
return *this;
}
@ -358,21 +432,33 @@ template<UnsignedInt dimensions> VectorGL<dimensions>& VectorGL<dimensions>::bin
"Shaders::VectorGL::bindTextureTransformationBuffer(): the shader was not created with uniform buffers enabled", *this);
CORRADE_ASSERT(_flags & Flag::TextureTransformation,
"Shaders::VectorGL::bindTextureTransformationBuffer(): the shader was not created with texture transformation enabled", *this);
buffer.bind(GL::Buffer::Target::Uniform, TextureTransformationBufferBinding, offset, size);
buffer.bind(
#ifndef MAGNUM_TARGET_WEBGL
_flags >= Flag::ShaderStorageBuffers ? GL::Buffer::Target::ShaderStorage :
#endif
GL::Buffer::Target::Uniform, TextureTransformationBufferBinding, offset, size);
return *this;
}
template<UnsignedInt dimensions> VectorGL<dimensions>& VectorGL<dimensions>::bindMaterialBuffer(GL::Buffer& buffer) {
CORRADE_ASSERT(_flags >= Flag::UniformBuffers,
"Shaders::VectorGL::bindMaterialBuffer(): the shader was not created with uniform buffers enabled", *this);
buffer.bind(GL::Buffer::Target::Uniform, MaterialBufferBinding);
buffer.bind(
#ifndef MAGNUM_TARGET_WEBGL
_flags >= Flag::ShaderStorageBuffers ? GL::Buffer::Target::ShaderStorage :
#endif
GL::Buffer::Target::Uniform, MaterialBufferBinding);
return *this;
}
template<UnsignedInt dimensions> VectorGL<dimensions>& VectorGL<dimensions>::bindMaterialBuffer(GL::Buffer& buffer, const GLintptr offset, const GLsizeiptr size) {
CORRADE_ASSERT(_flags >= Flag::UniformBuffers,
"Shaders::VectorGL::bindMaterialBuffer(): the shader was not created with uniform buffers enabled", *this);
buffer.bind(GL::Buffer::Target::Uniform, MaterialBufferBinding, offset, size);
buffer.bind(
#ifndef MAGNUM_TARGET_WEBGL
_flags >= Flag::ShaderStorageBuffers ? GL::Buffer::Target::ShaderStorage :
#endif
GL::Buffer::Target::Uniform, MaterialBufferBinding, offset, size);
return *this;
}
#endif
@ -388,6 +474,14 @@ template class MAGNUM_SHADERS_EXPORT VectorGL<3>;
namespace Implementation {
Debug& operator<<(Debug& debug, const VectorGLFlag value) {
#if !defined(MAGNUM_TARGET_GLES2) && !defined(MAGNUM_TARGET_WEBGL)
/* Special case coming from the Flags printer. As both flags are a superset
of UniformBuffers, printing just one would result in
`Flag::MultiDraw|Flag(0x8)` in the output. */
if(value == VectorGLFlag(UnsignedByte(VectorGLFlag::MultiDraw|VectorGLFlag::ShaderStorageBuffers)))
return debug << VectorGLFlag::MultiDraw << Debug::nospace << "|" << Debug::nospace << VectorGLFlag::ShaderStorageBuffers;
#endif
debug << "Shaders::VectorGL::Flag" << Debug::nospace;
switch(value) {
@ -396,6 +490,9 @@ Debug& operator<<(Debug& debug, const VectorGLFlag value) {
_c(TextureTransformation)
#ifndef MAGNUM_TARGET_GLES2
_c(UniformBuffers)
#ifndef MAGNUM_TARGET_WEBGL
_c(ShaderStorageBuffers)
#endif
_c(MultiDraw)
#endif
#undef _c
@ -409,7 +506,16 @@ Debug& operator<<(Debug& debug, const VectorGLFlags value) {
return Containers::enumSetDebugOutput(debug, value, "Shaders::VectorGL::Flags{}", {
VectorGLFlag::TextureTransformation,
#ifndef MAGNUM_TARGET_GLES2
#ifndef MAGNUM_TARGET_WEBGL
/* Both are a superset of UniformBuffers, meaning printing just one
would result in `Flag::MultiDraw|Flag(0x8)` in the output. So we
pass both and let the Flag printer deal with that. */
VectorGLFlag(UnsignedByte(VectorGLFlag::MultiDraw|VectorGLFlag::ShaderStorageBuffers)),
#endif
VectorGLFlag::MultiDraw, /* Superset of UniformBuffers */
#ifndef MAGNUM_TARGET_WEBGL
VectorGLFlag::ShaderStorageBuffers, /* Superset of UniformBuffers */
#endif
VectorGLFlag::UniformBuffers
#endif
});

54
src/Magnum/Shaders/VectorGL.h

@ -46,6 +46,9 @@ namespace Implementation {
TextureTransformation = 1 << 0,
#ifndef MAGNUM_TARGET_GLES2
UniformBuffers = 1 << 1,
#ifndef MAGNUM_TARGET_WEBGL
ShaderStorageBuffers = UniformBuffers|(1 << 3),
#endif
MultiDraw = UniformBuffers|(1 << 2)
#endif
};
@ -172,6 +175,7 @@ template<UnsignedInt dimensions> class MAGNUM_SHADERS_EXPORT VectorGL: public GL
* @ref bindTransformationProjectionBuffer(),
* @ref bindDrawBuffer(), @ref bindTextureTransformationBuffer()
* and @ref bindMaterialBuffer() instead of direct uniform setters.
* @see @ref Flag::ShaderStorageBuffers
* @requires_gl31 Extension @gl_extension{ARB,uniform_buffer_object}
* @requires_gles30 Uniform buffers are not available in OpenGL ES
* 2.0.
@ -181,6 +185,23 @@ template<UnsignedInt dimensions> class MAGNUM_SHADERS_EXPORT VectorGL: public GL
*/
UniformBuffers = 1 << 1,
#ifndef MAGNUM_TARGET_WEBGL
/**
* Use shader storage buffers. Superset of functionality provided
* by @ref Flag::UniformBuffers, compared to it doesn't have any
* size limits on @ref Configuration::setMaterialCount() and
* @relativeref{Configuration,setDrawCount()} in exchange for
* potentially more costly access and narrower platform support.
* @requires_gl43 Extension @gl_extension{ARB,shader_storage_buffer_object}
* @requires_gles31 Shader storage buffers are not available in
* OpenGL ES 3.0 and older.
* @requires_gles Shader storage buffers are not available in
* WebGL.
* @m_since_latest
*/
ShaderStorageBuffers = UniformBuffers|(1 << 3),
#endif
/**
* Enable multidraw functionality. Implies @ref Flag::UniformBuffers
* and adds the value from @ref setDrawOffset() with the
@ -337,7 +358,8 @@ template<UnsignedInt dimensions> class MAGNUM_SHADERS_EXPORT VectorGL: public GL
*
* Statically defined size of the @ref VectorMaterialUniform uniform
* buffer bound with @ref bindMaterialBuffer(). Has use only if
* @ref Flag::UniformBuffers is set.
* @ref Flag::UniformBuffers is set and @ref Flag::ShaderStorageBuffers
* is not set.
* @see @ref Configuration::setMaterialCount()
* @requires_gles30 Not defined on OpenGL ES 2.0 builds.
* @requires_webgl20 Not defined on WebGL 1.0 builds.
@ -354,7 +376,8 @@ template<UnsignedInt dimensions> class MAGNUM_SHADERS_EXPORT VectorGL: public GL
* @ref TextureTransformationUniform uniform buffers bound with
* @ref bindTransformationProjectionBuffer(), @ref bindDrawBuffer() and
* @ref bindTextureTransformationBuffer(). Has use only if
* @ref Flag::UniformBuffers is set.
* @ref Flag::UniformBuffers is set and @ref Flag::ShaderStorageBuffers
* is not set.
* @see @ref Configuration::setDrawCount()
* @requires_gles30 Not defined on OpenGL ES 2.0 builds.
* @requires_webgl20 Not defined on WebGL 1.0 builds.
@ -429,7 +452,7 @@ template<UnsignedInt dimensions> class MAGNUM_SHADERS_EXPORT VectorGL: public GL
#ifndef MAGNUM_TARGET_GLES2
/** @{
* @name Uniform buffer binding and related uniform setters
* @name Uniform / shader storage buffer binding and related uniform setters
*
* Used if @ref Flag::UniformBuffers is set.
*/
@ -461,7 +484,7 @@ template<UnsignedInt dimensions> class MAGNUM_SHADERS_EXPORT VectorGL: public GL
VectorGL<dimensions>& setDrawOffset(UnsignedInt offset);
/**
* @brief Bind a transformation and projection uniform buffer
* @brief Bind a transformation and projection uniform / shader storage buffer
* @return Reference to self (for method chaining)
* @m_since_latest
*
@ -482,7 +505,7 @@ template<UnsignedInt dimensions> class MAGNUM_SHADERS_EXPORT VectorGL: public GL
VectorGL<dimensions>& bindTransformationProjectionBuffer(GL::Buffer& buffer, GLintptr offset, GLsizeiptr size);
/**
* @brief Bind a draw uniform buffer
* @brief Bind a draw uniform / shader storage buffer
* @return Reference to self (for method chaining)
* @m_since_latest
*
@ -503,7 +526,7 @@ template<UnsignedInt dimensions> class MAGNUM_SHADERS_EXPORT VectorGL: public GL
VectorGL<dimensions>& bindDrawBuffer(GL::Buffer& buffer, GLintptr offset, GLsizeiptr size);
/**
* @brief Bind a texture transformation uniform buffer
* @brief Bind a texture transformation uniform / shader storage buffer
* @return Reference to self (for method chaining)
* @m_since_latest
*
@ -523,7 +546,7 @@ template<UnsignedInt dimensions> class MAGNUM_SHADERS_EXPORT VectorGL: public GL
VectorGL<dimensions>& bindTextureTransformationBuffer(GL::Buffer& buffer, GLintptr offset, GLsizeiptr size);
/**
* @brief Bind a material uniform buffer
* @brief Bind a material uniform / shader storage buffer
* @return Reference to self (for method chaining)
* @m_since_latest
*
@ -626,10 +649,11 @@ template<UnsignedInt dimensions> class VectorGL<dimensions>::Configuration {
* @ref VectorMaterialUniform buffer bound with
* @ref bindMaterialBuffer(). Uniform buffers have a statically defined
* size and @cpp count*sizeof(VectorMaterialUniform) @ce has to be
* within @ref GL::AbstractShaderProgram::maxUniformBlockSize().
*
* The per-draw materials are then specified via
* @ref VectorDrawUniform::materialId. Default value is @cpp 1 @ce.
* within @ref GL::AbstractShaderProgram::maxUniformBlockSize(),
* if @ref Flag::ShaderStorageBuffers is set as well, the buffer is
* unbounded and @p count is ignored. The per-draw materials are
* specified via @ref VectorDrawUniform::materialId. Default value is
* @cpp 1 @ce.
*
* If @ref Flag::UniformBuffers isn't set, this value is ignored.
* @see @ref setFlags(), @ref setDrawCount(),
@ -665,10 +689,10 @@ template<UnsignedInt dimensions> class VectorGL<dimensions>::Configuration {
* @cpp count*sizeof(TransformationProjectionUniform3D) @ce,
* @cpp count*sizeof(VectorDrawUniform) @ce and
* @cpp count*sizeof(TextureTransformationUniform) @ce has to be within
* @ref GL::AbstractShaderProgram::maxUniformBlockSize().
*
* The draw offset is then set via @ref setDrawOffset(). Default value
* is @cpp 1 @ce.
* @ref GL::AbstractShaderProgram::maxUniformBlockSize(), if
* @ref Flag::ShaderStorageBuffers is set as well, the buffer is
* unbounded and @p count is ignored. The draw offset is then set via
* @ref setDrawOffset(). Default value is @cpp 1 @ce.
*
* If @ref Flag::UniformBuffers isn't set, this value is ignored.
* @see @ref setFlags(), @ref setMaterialCount(),

26
src/Magnum/Shaders/VertexColor.vert

@ -23,6 +23,10 @@
DEALINGS IN THE SOFTWARE.
*/
#if defined(SHADER_STORAGE_BUFFERS) && !defined(GL_ES)
#extension GL_ARB_shader_storage_buffer_object: require
#endif
#ifdef MULTI_DRAW
#ifndef GL_ES
#extension GL_ARB_shader_draw_parameters: require
@ -62,10 +66,22 @@ uniform highp mat4 transformationProjectionMatrix
#error
#endif
/* Uniform buffers */
/* Uniform / shader storage buffers */
#else
#if DRAW_COUNT > 1
/* For SSBOs, the per-draw arrays are unbounded */
#ifdef SHADER_STORAGE_BUFFERS
#define DRAW_COUNT
#define BUFFER_OR_UNIFORM buffer
#define BUFFER_READONLY readonly
#else
#define BUFFER_OR_UNIFORM uniform
#define BUFFER_READONLY
#endif
/* With SSBOs DRAW_COUNT is defined to be empty, +0 makes the condition not
cause a compile error */
#if defined(SHADER_STORAGE_BUFFERS) || DRAW_COUNT+0 > 1
#ifdef EXPLICIT_UNIFORM_LOCATION
layout(location = 0)
#endif
@ -79,11 +95,11 @@ uniform highp uint drawOffset
#endif
layout(std140
#ifdef EXPLICIT_BINDING
#if defined(EXPLICIT_BINDING) || defined(SHADER_STORAGE_BUFFERS)
, binding = 1
#endif
) uniform TransformationProjection {
highp
) BUFFER_OR_UNIFORM TransformationProjection {
BUFFER_READONLY highp
#ifdef TWO_DIMENSIONS
/* Can't be a mat3 because of ANGLE, see DrawUniform in Phong.vert for
details */

86
src/Magnum/Shaders/VertexColorGL.cpp

@ -61,15 +61,29 @@ namespace {
}
template<UnsignedInt dimensions> typename VertexColorGL<dimensions>::CompileState VertexColorGL<dimensions>::compile(const Configuration& configuration) {
#ifndef MAGNUM_TARGET_GLES2
CORRADE_ASSERT(!(configuration.flags() >= Flag::UniformBuffers) || configuration.drawCount(),
"Shaders::VertexColorGL: draw count can't be zero", CompileState{NoCreate});
#if !defined(MAGNUM_TARGET_GLES2) && !defined(CORRADE_NO_ASSERT)
#ifndef MAGNUM_TARGET_WEBGL
if(!(configuration.flags() >= Flag::ShaderStorageBuffers))
#endif
{
CORRADE_ASSERT(!(configuration.flags() >= Flag::UniformBuffers) || configuration.drawCount(),
"Shaders::VertexColorGL: draw count can't be zero", CompileState{NoCreate});
}
#endif
#ifndef MAGNUM_TARGET_GLES
if(configuration.flags() >= Flag::UniformBuffers)
MAGNUM_ASSERT_GL_EXTENSION_SUPPORTED(GL::Extensions::ARB::uniform_buffer_object);
#endif
#if !defined(MAGNUM_TARGET_GLES2) && !defined(MAGNUM_TARGET_WEBGL)
if(configuration.flags() >= Flag::ShaderStorageBuffers) {
#ifndef MAGNUM_TARGET_GLES
MAGNUM_ASSERT_GL_EXTENSION_SUPPORTED(GL::Extensions::ARB::shader_storage_buffer_object);
#else
MAGNUM_ASSERT_GL_VERSION_SUPPORTED(GL::Version::GLES310);
#endif
}
#endif
#ifndef MAGNUM_TARGET_GLES2
if(configuration.flags() >= Flag::MultiDraw) {
#ifndef MAGNUM_TARGET_GLES
@ -105,10 +119,21 @@ template<UnsignedInt dimensions> typename VertexColorGL<dimensions>::CompileStat
vert.addSource(dimensions == 2 ? "#define TWO_DIMENSIONS\n"_s : "#define THREE_DIMENSIONS\n"_s);
#ifndef MAGNUM_TARGET_GLES2
if(configuration.flags() >= Flag::UniformBuffers) {
vert.addSource(Utility::format(
"#define UNIFORM_BUFFERS\n"
"#define DRAW_COUNT {}\n",
configuration.drawCount()));
#ifndef MAGNUM_TARGET_WEBGL
/* SSBOs have unbounded per-draw arrays so just a plain string can be
passed */
if(configuration.flags() >= Flag::ShaderStorageBuffers) {
vert.addSource(
"#define UNIFORM_BUFFERS\n"
"#define SHADER_STORAGE_BUFFERS\n"_s);
} else
#endif
{
vert.addSource(Utility::format(
"#define UNIFORM_BUFFERS\n"
"#define DRAW_COUNT {}\n",
configuration.drawCount()));
}
vert.addSource(configuration.flags() >= Flag::MultiDraw ? "#define MULTI_DRAW\n"_s : ""_s);
}
#endif
@ -182,7 +207,11 @@ template<UnsignedInt dimensions> VertexColorGL<dimensions>::VertexColorGL(Compil
{
#ifndef MAGNUM_TARGET_GLES2
if(_flags >= Flag::UniformBuffers) {
if(_drawCount > 1) _drawOffsetUniform = uniformLocation("drawOffset"_s);
if(_drawCount > 1
#ifndef MAGNUM_TARGET_WEBGL
|| flags() >= Flag::ShaderStorageBuffers
#endif
) _drawOffsetUniform = uniformLocation("drawOffset"_s);
} else
#endif
{
@ -191,7 +220,11 @@ template<UnsignedInt dimensions> VertexColorGL<dimensions>::VertexColorGL(Compil
}
#ifndef MAGNUM_TARGET_GLES2
/* SSBOs have bindings defined in the source always */
if(_flags >= Flag::UniformBuffers
#ifndef MAGNUM_TARGET_WEBGL
&& !(_flags >= Flag::ShaderStorageBuffers)
#endif
#ifndef MAGNUM_TARGET_GLES
&& !context.isExtensionSupported<GL::Extensions::ARB::shading_language_420pack>(state._version)
#elif !defined(MAGNUM_TARGET_GLES2) && !defined(MAGNUM_TARGET_WEBGL)
@ -243,8 +276,13 @@ template<UnsignedInt dimensions> VertexColorGL<dimensions>& VertexColorGL<dimens
template<UnsignedInt dimensions> VertexColorGL<dimensions>& VertexColorGL<dimensions>::setDrawOffset(const UnsignedInt offset) {
CORRADE_ASSERT(_flags >= Flag::UniformBuffers,
"Shaders::VertexColorGL::setDrawOffset(): the shader was not created with uniform buffers enabled", *this);
#ifndef MAGNUM_TARGET_WEBGL
CORRADE_ASSERT(_flags >= Flag::ShaderStorageBuffers || offset < _drawCount,
"Shaders::VertexColorGL::setDrawOffset(): draw offset" << offset << "is out of bounds for" << _drawCount << "draws", *this);
#else
CORRADE_ASSERT(offset < _drawCount,
"Shaders::VertexColorGL::setDrawOffset(): draw offset" << offset << "is out of bounds for" << _drawCount << "draws", *this);
#endif
if(_drawCount > 1) setUniform(_drawOffsetUniform, offset);
return *this;
}
@ -252,14 +290,22 @@ template<UnsignedInt dimensions> VertexColorGL<dimensions>& VertexColorGL<dimens
template<UnsignedInt dimensions> VertexColorGL<dimensions>& VertexColorGL<dimensions>::bindTransformationProjectionBuffer(GL::Buffer& buffer) {
CORRADE_ASSERT(_flags >= Flag::UniformBuffers,
"Shaders::VertexColorGL::bindTransformationProjectionBuffer(): the shader was not created with uniform buffers enabled", *this);
buffer.bind(GL::Buffer::Target::Uniform, TransformationProjectionBufferBinding);
buffer.bind(
#ifndef MAGNUM_TARGET_WEBGL
_flags >= Flag::ShaderStorageBuffers ? GL::Buffer::Target::ShaderStorage :
#endif
GL::Buffer::Target::Uniform, TransformationProjectionBufferBinding);
return *this;
}
template<UnsignedInt dimensions> VertexColorGL<dimensions>& VertexColorGL<dimensions>::bindTransformationProjectionBuffer(GL::Buffer& buffer, const GLintptr offset, const GLsizeiptr size) {
CORRADE_ASSERT(_flags >= Flag::UniformBuffers,
"Shaders::VertexColorGL::bindTransformationProjectionBuffer(): the shader was not created with uniform buffers enabled", *this);
buffer.bind(GL::Buffer::Target::Uniform, TransformationProjectionBufferBinding, offset, size);
buffer.bind(
#ifndef MAGNUM_TARGET_WEBGL
_flags >= Flag::ShaderStorageBuffers ? GL::Buffer::Target::ShaderStorage :
#endif
GL::Buffer::Target::Uniform, TransformationProjectionBufferBinding, offset, size);
return *this;
}
#endif
@ -270,6 +316,14 @@ template class MAGNUM_SHADERS_EXPORT VertexColorGL<3>;
namespace Implementation {
Debug& operator<<(Debug& debug, const VertexColorGLFlag value) {
#if !defined(MAGNUM_TARGET_GLES2) && !defined(MAGNUM_TARGET_WEBGL)
/* Special case coming from the Flags printer. As both flags are a superset
of UniformBuffers, printing just one would result in
`Flag::MultiDraw|Flag(0x4)` in the output. */
if(value == VertexColorGLFlag(UnsignedByte(VertexColorGLFlag::MultiDraw|VertexColorGLFlag::ShaderStorageBuffers)))
return debug << VertexColorGLFlag::MultiDraw << Debug::nospace << "|" << Debug::nospace << VertexColorGLFlag::ShaderStorageBuffers;
#endif
debug << "Shaders::VertexColorGL::Flag" << Debug::nospace;
switch(value) {
@ -277,6 +331,9 @@ Debug& operator<<(Debug& debug, const VertexColorGLFlag value) {
#define _c(v) case VertexColorGLFlag::v: return debug << "::" #v;
#ifndef MAGNUM_TARGET_GLES2
_c(UniformBuffers)
#ifndef MAGNUM_TARGET_WEBGL
_c(ShaderStorageBuffers)
#endif
_c(MultiDraw)
#endif
#undef _c
@ -289,7 +346,16 @@ Debug& operator<<(Debug& debug, const VertexColorGLFlag value) {
Debug& operator<<(Debug& debug, const VertexColorGLFlags value) {
return Containers::enumSetDebugOutput(debug, value, "Shaders::VertexColorGL::Flags{}", {
#ifndef MAGNUM_TARGET_GLES2
#ifndef MAGNUM_TARGET_WEBGL
/* Both are a superset of UniformBuffers, meaning printing just one
would result in `Flag::MultiDraw|Flag(0x4)` in the output. So we
pass both and let the Flag printer deal with that. */
VertexColorGLFlag(UnsignedByte(VertexColorGLFlag::MultiDraw|VertexColorGLFlag::ShaderStorageBuffers)),
#endif
VertexColorGLFlag::MultiDraw, /* Superset of UniformBuffers */
#ifndef MAGNUM_TARGET_WEBGL
VertexColorGLFlag::ShaderStorageBuffers, /* Superset of UniformBuffers */
#endif
VertexColorGLFlag::UniformBuffers
#endif
});

36
src/Magnum/Shaders/VertexColorGL.h

@ -45,6 +45,9 @@ namespace Implementation {
enum class VertexColorGLFlag: UnsignedByte {
#ifndef MAGNUM_TARGET_GLES2
UniformBuffers = 1 << 0,
#ifndef MAGNUM_TARGET_WEBGL
ShaderStorageBuffers = UniformBuffers|(1 << 2),
#endif
MultiDraw = UniformBuffers|(1 << 1)
#endif
};
@ -165,6 +168,7 @@ template<UnsignedInt dimensions> class MAGNUM_SHADERS_EXPORT VertexColorGL: publ
* Use uniform buffers. Expects that uniform data are supplied via
* @ref bindTransformationProjectionBuffer() instead of direct
* uniform setters.
* @see @ref Flag::ShaderStorageBuffers
* @requires_gl31 Extension @gl_extension{ARB,uniform_buffer_object}
* @requires_gles30 Uniform buffers are not available in OpenGL ES
* 2.0.
@ -174,6 +178,23 @@ template<UnsignedInt dimensions> class MAGNUM_SHADERS_EXPORT VertexColorGL: publ
*/
UniformBuffers = 1 << 0,
#ifndef MAGNUM_TARGET_WEBGL
/**
* Use shader storage buffers. Superset of functionality provided
* by @ref Flag::UniformBuffers, compared to it doesn't have any
* size limits on @relativeref{Configuration,setDrawCount()} in
* exchange for potentially more costly access and narrower
* platform support.
* @requires_gl43 Extension @gl_extension{ARB,shader_storage_buffer_object}
* @requires_gles31 Shader storage buffers are not available in
* OpenGL ES 3.0 and older.
* @requires_gles Shader storage buffers are not available in
* WebGL.
* @m_since_latest
*/
ShaderStorageBuffers = UniformBuffers|(1 << 2),
#endif
/**
* Enable multidraw functionality. Implies @ref Flag::UniformBuffers
* and adds the value from @ref setDrawOffset() with the
@ -331,7 +352,8 @@ template<UnsignedInt dimensions> class MAGNUM_SHADERS_EXPORT VertexColorGL: publ
* @ref TransformationProjectionUniform2D /
* @ref TransformationProjectionUniform3D uniform buffers bound with
* @ref bindTransformationProjectionBuffer(). Has use only if
* @ref Flag::UniformBuffers is set.
* @ref Flag::UniformBuffers is set and @ref Flag::ShaderStorageBuffers
* is not set.
* @see @ref Configuration::setDrawCount()
* @requires_gles30 Not defined on OpenGL ES 2.0 builds.
* @requires_webgl20 Not defined on WebGL 1.0 builds.
@ -364,7 +386,7 @@ template<UnsignedInt dimensions> class MAGNUM_SHADERS_EXPORT VertexColorGL: publ
#ifndef MAGNUM_TARGET_GLES2
/** @{
* @name Uniform buffer binding and related uniform setters
* @name Uniform / shader storage buffer binding and related uniform setters
*
* Used if @ref Flag::UniformBuffers is set.
*/
@ -393,7 +415,7 @@ template<UnsignedInt dimensions> class MAGNUM_SHADERS_EXPORT VertexColorGL: publ
VertexColorGL<dimensions>& setDrawOffset(UnsignedInt offset);
/**
* @brief Bind a transformation and projection uniform buffer
* @brief Bind a transformation and projection uniform / shader storage buffer
* @return Reference to self (for method chaining)
* @m_since_latest
*
@ -480,10 +502,10 @@ template<UnsignedInt dimensions> class VertexColorGL<dimensions>::Configuration
* statically defined size and
* @cpp count*sizeof(TransformationProjectionUniform2D) @ce /,
* @cpp count*sizeof(TransformationProjectionUniform3D) @ce has to be
* within @ref GL::AbstractShaderProgram::maxUniformBlockSize().
*
* The draw offset is then set via @ref setDrawOffset(). Default value
* is @cpp 1 @ce.
* within @ref GL::AbstractShaderProgram::maxUniformBlockSize(), if
* @ref Flag::ShaderStorageBuffers is set as well, the buffers are
* unbounded and @p count is ignored. The draw offset is set via
* @ref setDrawOffset(). Default value is @cpp 1 @ce.
*
* If @ref Flag::UniformBuffers isn't set, this value is ignored.
* @see @ref setFlags(), @ref VertexColorGL::drawCount()

Loading…
Cancel
Save