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#601](https://github.com/mosra/magnum/pull/601) and
[mosra/magnum#610](https://github.com/mosra/magnum/pull/610). [mosra/magnum#610](https://github.com/mosra/magnum/pull/610).
- All builtin shaders now have opt-in support for uniform buffers on desktop, - 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 OpenGL ES 3.0+ and WebGL 2.0, as well as shader storage buffers on desktop
massive driver overhead reduction. The @ref shaders overview page was and ES 3.1+. This includes multi-draw functionality for massive driver
updated with an introduction the new features. 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 - All builtin shaders now have opt-in capability of
@ref shaders-async "async compilation and linking" (see @ref shaders-async "async compilation and linking" (see
[mosra/magnum534](https://github.com/mosra/magnum/issues/534) and [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 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 to fit evenly into multiples of 768 bytes, which should be large enough for
even the strictest @ref GL::Buffer::uniformOffsetAlignment() requirements. 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 @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_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_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_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 MAGNUM_DISABLE_EXTENSIONS="GL_KHR_debug" ctest -C $config --output-on-failure -j9 -R GLTest
# Run all Vulkan tests with llvmpipe as well # 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_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_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_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 MAGNUM_DISABLE_EXTENSIONS="GL_KHR_debug" ctest --output-on-failure -j9 -R GLTest || true
# Run all Vulkan tests with llvmpipe as well # Run all Vulkan tests with llvmpipe as well

37
src/Magnum/Shaders/DistanceFieldVector.frag

@ -23,6 +23,10 @@
DEALINGS IN THE SOFTWARE. DEALINGS IN THE SOFTWARE.
*/ */
#if defined(SHADER_STORAGE_BUFFERS) && !defined(GL_ES)
#extension GL_ARB_shader_storage_buffer_object: require
#endif
#ifndef NEW_GLSL #ifndef NEW_GLSL
#define in varying #define in varying
#define fragmentColor gl_FragColor #define fragmentColor gl_FragColor
@ -68,11 +72,24 @@ uniform lowp float smoothness
#endif #endif
; ;
/* Uniform buffers */ /* Uniform / shader storage buffers */
#else #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 #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 #ifdef EXPLICIT_UNIFORM_LOCATION
layout(location = 0) layout(location = 0)
#endif #endif
@ -93,11 +110,11 @@ struct DrawUniform {
}; };
layout(std140 layout(std140
#ifdef EXPLICIT_BINDING #if defined(EXPLICIT_BINDING) || defined(SHADER_STORAGE_BUFFERS)
, binding = 2 , binding = 2
#endif #endif
) uniform Draw { ) BUFFER_OR_UNIFORM Draw {
DrawUniform draws[DRAW_COUNT]; BUFFER_READONLY DrawUniform draws[DRAW_COUNT];
}; };
struct MaterialUniform { struct MaterialUniform {
@ -110,11 +127,11 @@ struct MaterialUniform {
}; };
layout(std140 layout(std140
#ifdef EXPLICIT_BINDING #if defined(EXPLICIT_BINDING) || defined(SHADER_STORAGE_BUFFERS)
, binding = 4 , binding = 4
#endif #endif
) uniform Material { ) BUFFER_OR_UNIFORM Material {
MaterialUniform materials[MATERIAL_COUNT]; BUFFER_READONLY MaterialUniform materials[MATERIAL_COUNT];
}; };
#endif #endif
@ -144,7 +161,9 @@ out lowp vec4 fragmentColor;
void main() { void main() {
#ifdef UNIFORM_BUFFERS #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; mediump const uint materialId = draws[drawId].draw_materialIdReserved & 0xffffu;
#else #else
#define materialId 0u #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) { template<UnsignedInt dimensions> typename DistanceFieldVectorGL<dimensions>::CompileState DistanceFieldVectorGL<dimensions>::compile(const Configuration& configuration) {
#ifndef MAGNUM_TARGET_GLES2 #if !defined(MAGNUM_TARGET_GLES2) && !defined(CORRADE_NO_ASSERT)
CORRADE_ASSERT(!(configuration.flags() >= Flag::UniformBuffers) || configuration.materialCount(), #ifndef MAGNUM_TARGET_WEBGL
"Shaders::DistanceFieldVectorGL: material count can't be zero", CompileState{NoCreate}); if(!(configuration.flags() >= Flag::ShaderStorageBuffers))
CORRADE_ASSERT(!(configuration.flags() >= Flag::UniformBuffers) || configuration.drawCount(), #endif
"Shaders::DistanceFieldVectorGL: draw count can't be zero", CompileState{NoCreate}); {
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 #endif
#ifndef MAGNUM_TARGET_GLES #ifndef MAGNUM_TARGET_GLES
if(configuration.flags() >= Flag::UniformBuffers) if(configuration.flags() >= Flag::UniformBuffers)
MAGNUM_ASSERT_GL_EXTENSION_SUPPORTED(GL::Extensions::ARB::uniform_buffer_object); MAGNUM_ASSERT_GL_EXTENSION_SUPPORTED(GL::Extensions::ARB::uniform_buffer_object);
#endif #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 #ifndef MAGNUM_TARGET_GLES2
if(configuration.flags() >= Flag::MultiDraw) { if(configuration.flags() >= Flag::MultiDraw) {
#ifndef MAGNUM_TARGET_GLES #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); .addSource(dimensions == 2 ? "#define TWO_DIMENSIONS\n"_s : "#define THREE_DIMENSIONS\n"_s);
#ifndef MAGNUM_TARGET_GLES2 #ifndef MAGNUM_TARGET_GLES2
if(configuration.flags() >= Flag::UniformBuffers) { if(configuration.flags() >= Flag::UniformBuffers) {
vert.addSource(Utility::format( #ifndef MAGNUM_TARGET_WEBGL
"#define UNIFORM_BUFFERS\n" /* SSBOs have unbounded per-draw arrays so just a plain string can be
"#define DRAW_COUNT {}\n", passed */
configuration.drawCount())); 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); vert.addSource(configuration.flags() >= Flag::MultiDraw ? "#define MULTI_DRAW\n"_s : ""_s);
} }
#endif #endif
@ -129,12 +154,23 @@ template<UnsignedInt dimensions> typename DistanceFieldVectorGL<dimensions>::Com
GL::Shader frag = Implementation::createCompatibilityShader(rs, version, GL::Shader::Type::Fragment); GL::Shader frag = Implementation::createCompatibilityShader(rs, version, GL::Shader::Type::Fragment);
#ifndef MAGNUM_TARGET_GLES2 #ifndef MAGNUM_TARGET_GLES2
if(configuration.flags() >= Flag::UniformBuffers) { if(configuration.flags() >= Flag::UniformBuffers) {
frag.addSource(Utility::format( #ifndef MAGNUM_TARGET_WEBGL
"#define UNIFORM_BUFFERS\n" /* SSBOs have unbounded per-draw and material arrays so just a plain
"#define MATERIAL_COUNT {}\n" string can be passed */
"#define DRAW_COUNT {}\n", if(configuration.flags() >= Flag::ShaderStorageBuffers) {
configuration.materialCount(), frag.addSource(
configuration.drawCount())); "#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); frag.addSource(configuration.flags() >= Flag::MultiDraw ? "#define MULTI_DRAW\n"_s : ""_s);
} }
#endif #endif
@ -204,7 +240,11 @@ template<UnsignedInt dimensions> DistanceFieldVectorGL<dimensions>::DistanceFiel
{ {
#ifndef MAGNUM_TARGET_GLES2 #ifndef MAGNUM_TARGET_GLES2
if(_flags >= Flag::UniformBuffers) { 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 } else
#endif #endif
{ {
@ -226,7 +266,12 @@ template<UnsignedInt dimensions> DistanceFieldVectorGL<dimensions>::DistanceFiel
{ {
setUniform(uniformLocation("vectorTexture"_s), TextureUnit); setUniform(uniformLocation("vectorTexture"_s), TextureUnit);
#ifndef MAGNUM_TARGET_GLES2 #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("TransformationProjection"_s), TransformationProjectionBufferBinding);
setUniformBlockBinding(uniformBlockIndex("Draw"_s), DrawBufferBinding); setUniformBlockBinding(uniformBlockIndex("Draw"_s), DrawBufferBinding);
setUniformBlockBinding(uniformBlockIndex("Material"_s), MaterialBufferBinding); 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) { template<UnsignedInt dimensions> DistanceFieldVectorGL<dimensions>& DistanceFieldVectorGL<dimensions>::setDrawOffset(const UnsignedInt offset) {
CORRADE_ASSERT(_flags >= Flag::UniformBuffers, CORRADE_ASSERT(_flags >= Flag::UniformBuffers,
"Shaders::DistanceFieldVectorGL::setDrawOffset(): the shader was not created with uniform buffers enabled", *this); "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, CORRADE_ASSERT(offset < _drawCount,
"Shaders::DistanceFieldVectorGL::setDrawOffset(): draw offset" << offset << "is out of bounds for" << _drawCount << "draws", *this); "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; return *this;
} }
template<UnsignedInt dimensions> DistanceFieldVectorGL<dimensions>& DistanceFieldVectorGL<dimensions>::bindTransformationProjectionBuffer(GL::Buffer& buffer) { template<UnsignedInt dimensions> DistanceFieldVectorGL<dimensions>& DistanceFieldVectorGL<dimensions>::bindTransformationProjectionBuffer(GL::Buffer& buffer) {
CORRADE_ASSERT(_flags >= Flag::UniformBuffers, CORRADE_ASSERT(_flags >= Flag::UniformBuffers,
"Shaders::DistanceFieldVectorGL::bindTransformationProjectionBuffer(): the shader was not created with uniform buffers enabled", *this); "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; return *this;
} }
template<UnsignedInt dimensions> DistanceFieldVectorGL<dimensions>& DistanceFieldVectorGL<dimensions>::bindTransformationProjectionBuffer(GL::Buffer& buffer, const GLintptr offset, const GLsizeiptr size) { template<UnsignedInt dimensions> DistanceFieldVectorGL<dimensions>& DistanceFieldVectorGL<dimensions>::bindTransformationProjectionBuffer(GL::Buffer& buffer, const GLintptr offset, const GLsizeiptr size) {
CORRADE_ASSERT(_flags >= Flag::UniformBuffers, CORRADE_ASSERT(_flags >= Flag::UniformBuffers,
"Shaders::DistanceFieldVectorGL::bindTransformationProjectionBuffer(): the shader was not created with uniform buffers enabled", *this); "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; return *this;
} }
template<UnsignedInt dimensions> DistanceFieldVectorGL<dimensions>& DistanceFieldVectorGL<dimensions>::bindDrawBuffer(GL::Buffer& buffer) { template<UnsignedInt dimensions> DistanceFieldVectorGL<dimensions>& DistanceFieldVectorGL<dimensions>::bindDrawBuffer(GL::Buffer& buffer) {
CORRADE_ASSERT(_flags >= Flag::UniformBuffers, CORRADE_ASSERT(_flags >= Flag::UniformBuffers,
"Shaders::DistanceFieldVectorGL::bindDrawBuffer(): the shader was not created with uniform buffers enabled", *this); "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; return *this;
} }
template<UnsignedInt dimensions> DistanceFieldVectorGL<dimensions>& DistanceFieldVectorGL<dimensions>::bindDrawBuffer(GL::Buffer& buffer, const GLintptr offset, const GLsizeiptr size) { template<UnsignedInt dimensions> DistanceFieldVectorGL<dimensions>& DistanceFieldVectorGL<dimensions>::bindDrawBuffer(GL::Buffer& buffer, const GLintptr offset, const GLsizeiptr size) {
CORRADE_ASSERT(_flags >= Flag::UniformBuffers, CORRADE_ASSERT(_flags >= Flag::UniformBuffers,
"Shaders::DistanceFieldVectorGL::bindDrawBuffer(): the shader was not created with uniform buffers enabled", *this); "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; 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); "Shaders::DistanceFieldVectorGL::bindTextureTransformationBuffer(): the shader was not created with uniform buffers enabled", *this);
CORRADE_ASSERT(_flags & Flag::TextureTransformation, CORRADE_ASSERT(_flags & Flag::TextureTransformation,
"Shaders::DistanceFieldVectorGL::bindTextureTransformationBuffer(): the shader was not created with texture transformation enabled", *this); "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; 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); "Shaders::DistanceFieldVectorGL::bindTextureTransformationBuffer(): the shader was not created with uniform buffers enabled", *this);
CORRADE_ASSERT(_flags & Flag::TextureTransformation, CORRADE_ASSERT(_flags & Flag::TextureTransformation,
"Shaders::DistanceFieldVectorGL::bindTextureTransformationBuffer(): the shader was not created with texture transformation enabled", *this); "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; return *this;
} }
template<UnsignedInt dimensions> DistanceFieldVectorGL<dimensions>& DistanceFieldVectorGL<dimensions>::bindMaterialBuffer(GL::Buffer& buffer) { template<UnsignedInt dimensions> DistanceFieldVectorGL<dimensions>& DistanceFieldVectorGL<dimensions>::bindMaterialBuffer(GL::Buffer& buffer) {
CORRADE_ASSERT(_flags >= Flag::UniformBuffers, CORRADE_ASSERT(_flags >= Flag::UniformBuffers,
"Shaders::DistanceFieldVectorGL::bindMaterialBuffer(): the shader was not created with uniform buffers enabled", *this); "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; return *this;
} }
template<UnsignedInt dimensions> DistanceFieldVectorGL<dimensions>& DistanceFieldVectorGL<dimensions>::bindMaterialBuffer(GL::Buffer& buffer, const GLintptr offset, const GLsizeiptr size) { template<UnsignedInt dimensions> DistanceFieldVectorGL<dimensions>& DistanceFieldVectorGL<dimensions>::bindMaterialBuffer(GL::Buffer& buffer, const GLintptr offset, const GLsizeiptr size) {
CORRADE_ASSERT(_flags >= Flag::UniformBuffers, CORRADE_ASSERT(_flags >= Flag::UniformBuffers,
"Shaders::DistanceFieldVectorGL::bindMaterialBuffer(): the shader was not created with uniform buffers enabled", *this); "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; return *this;
} }
#endif #endif
@ -409,6 +495,14 @@ template class MAGNUM_SHADERS_EXPORT DistanceFieldVectorGL<3>;
namespace Implementation { namespace Implementation {
Debug& operator<<(Debug& debug, const DistanceFieldVectorGLFlag value) { 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; debug << "Shaders::DistanceFieldVectorGL::Flag" << Debug::nospace;
switch(value) { switch(value) {
@ -417,6 +511,9 @@ Debug& operator<<(Debug& debug, const DistanceFieldVectorGLFlag value) {
_c(TextureTransformation) _c(TextureTransformation)
#ifndef MAGNUM_TARGET_GLES2 #ifndef MAGNUM_TARGET_GLES2
_c(UniformBuffers) _c(UniformBuffers)
#ifndef MAGNUM_TARGET_WEBGL
_c(ShaderStorageBuffers)
#endif
_c(MultiDraw) _c(MultiDraw)
#endif #endif
#undef _c #undef _c
@ -430,7 +527,16 @@ Debug& operator<<(Debug& debug, const DistanceFieldVectorGLFlags value) {
return Containers::enumSetDebugOutput(debug, value, "Shaders::DistanceFieldVectorGL::Flags{}", { return Containers::enumSetDebugOutput(debug, value, "Shaders::DistanceFieldVectorGL::Flags{}", {
DistanceFieldVectorGLFlag::TextureTransformation, DistanceFieldVectorGLFlag::TextureTransformation,
#ifndef MAGNUM_TARGET_GLES2 #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 */ DistanceFieldVectorGLFlag::MultiDraw, /* Superset of UniformBuffers */
#ifndef MAGNUM_TARGET_WEBGL
DistanceFieldVectorGLFlag::ShaderStorageBuffers, /* Superset of UniformBuffers */
#endif
DistanceFieldVectorGLFlag::UniformBuffers DistanceFieldVectorGLFlag::UniformBuffers
#endif #endif
}); });

54
src/Magnum/Shaders/DistanceFieldVectorGL.h

@ -46,6 +46,9 @@ namespace Implementation {
TextureTransformation = 1 << 0, TextureTransformation = 1 << 0,
#ifndef MAGNUM_TARGET_GLES2 #ifndef MAGNUM_TARGET_GLES2
UniformBuffers = 1 << 1, UniformBuffers = 1 << 1,
#ifndef MAGNUM_TARGET_WEBGL
ShaderStorageBuffers = UniformBuffers|(1 << 3),
#endif
MultiDraw = UniformBuffers|(1 << 2) MultiDraw = UniformBuffers|(1 << 2)
#endif #endif
}; };
@ -178,6 +181,7 @@ template<UnsignedInt dimensions> class MAGNUM_SHADERS_EXPORT DistanceFieldVector
* @ref bindTransformationProjectionBuffer(), * @ref bindTransformationProjectionBuffer(),
* @ref bindDrawBuffer(), @ref bindTextureTransformationBuffer(), * @ref bindDrawBuffer(), @ref bindTextureTransformationBuffer(),
* and @ref bindMaterialBuffer() instead of direct uniform setters. * and @ref bindMaterialBuffer() instead of direct uniform setters.
* @see @ref Flag::ShaderStorageBuffers
* @requires_gl31 Extension @gl_extension{ARB,uniform_buffer_object} * @requires_gl31 Extension @gl_extension{ARB,uniform_buffer_object}
* @requires_gles30 Uniform buffers are not available in OpenGL ES * @requires_gles30 Uniform buffers are not available in OpenGL ES
* 2.0. * 2.0.
@ -187,6 +191,23 @@ template<UnsignedInt dimensions> class MAGNUM_SHADERS_EXPORT DistanceFieldVector
*/ */
UniformBuffers = 1 << 1, 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 * Enable multidraw functionality. Implies @ref Flag::UniformBuffers
* and adds the value from @ref setDrawOffset() with the * 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 * Statically defined size of the
* @ref DistanceFieldVectorMaterialUniform uniform buffer bound with * @ref DistanceFieldVectorMaterialUniform uniform buffer bound with
* @ref bindMaterialBuffer(). Has use only if @ref Flag::UniformBuffers * @ref bindMaterialBuffer(). Has use only if @ref Flag::UniformBuffers
* is set. * is set and @ref Flag::ShaderStorageBuffers is not set.
* @see @ref Configuration::setMaterialCount() * @see @ref Configuration::setMaterialCount()
* @requires_gles30 Not defined on OpenGL ES 2.0 builds. * @requires_gles30 Not defined on OpenGL ES 2.0 builds.
* @requires_webgl20 Not defined on WebGL 1.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 TextureTransformationUniform uniform buffers bound with
* @ref bindTransformationProjectionBuffer(), @ref bindDrawBuffer() and * @ref bindTransformationProjectionBuffer(), @ref bindDrawBuffer() and
* @ref bindTextureTransformationBuffer(). Has use only if * @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() * @see @ref Configuration::setDrawCount()
* @requires_gles30 Not defined on OpenGL ES 2.0 builds. * @requires_gles30 Not defined on OpenGL ES 2.0 builds.
* @requires_webgl20 Not defined on WebGL 1.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 #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. * Used if @ref Flag::UniformBuffers is set.
*/ */
@ -504,7 +526,7 @@ template<UnsignedInt dimensions> class MAGNUM_SHADERS_EXPORT DistanceFieldVector
DistanceFieldVectorGL<dimensions>& setDrawOffset(UnsignedInt offset); 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) * @return Reference to self (for method chaining)
* @m_since_latest * @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); 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) * @return Reference to self (for method chaining)
* @m_since_latest * @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); 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) * @return Reference to self (for method chaining)
* @m_since_latest * @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); 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) * @return Reference to self (for method chaining)
* @m_since_latest * @m_since_latest
* *
@ -675,11 +697,11 @@ template<UnsignedInt dimensions> class DistanceFieldVectorGL<dimensions>::Config
* @ref DistanceFieldVectorMaterialUniform buffer bound with * @ref DistanceFieldVectorMaterialUniform buffer bound with
* @ref bindMaterialBuffer(). Uniform buffers have a statically defined * @ref bindMaterialBuffer(). Uniform buffers have a statically defined
* size and @cpp count*sizeof(DistanceFieldVectorMaterialUniform) @ce * size and @cpp count*sizeof(DistanceFieldVectorMaterialUniform) @ce
* has to be within @ref GL::AbstractShaderProgram::maxUniformBlockSize(). * has to be within @ref GL::AbstractShaderProgram::maxUniformBlockSize(),
* * if @ref Flag::ShaderStorageBuffers is set as well, the buffer is
* The per-draw materials are then specified via * unbounded and @p count is ignored. The per-draw materials are
* @ref DistanceFieldVectorDrawUniform::materialId. Default value is * specified via @ref DistanceFieldVectorDrawUniform::materialId.
* @cpp 1 @ce. * Default value is @cpp 1 @ce.
* *
* If @ref Flag::UniformBuffers isn't set, this value is ignored. * If @ref Flag::UniformBuffers isn't set, this value is ignored.
* @see @ref setFlags(), @ref setDrawCount(), * @see @ref setFlags(), @ref setDrawCount(),
@ -716,10 +738,10 @@ template<UnsignedInt dimensions> class DistanceFieldVectorGL<dimensions>::Config
* @cpp count*sizeof(TransformationProjectionUniform3D) @ce, * @cpp count*sizeof(TransformationProjectionUniform3D) @ce,
* @cpp count*sizeof(DistanceFieldVectorDrawUniform) @ce and * @cpp count*sizeof(DistanceFieldVectorDrawUniform) @ce and
* @cpp count*sizeof(TextureTransformationUniform) @ce has to be within * @cpp count*sizeof(TextureTransformationUniform) @ce has to be within
* @ref GL::AbstractShaderProgram::maxUniformBlockSize(). * @ref GL::AbstractShaderProgram::maxUniformBlockSize(), if
* * @ref Flag::ShaderStorageBuffers is set as well, the buffers are
* The draw offset is then set via @ref setDrawOffset(). Default value * unbounded and @p count is ignored. The draw offset is set via
* is @cpp 1 @ce. * @ref setDrawOffset(). Default value is @cpp 1 @ce.
* *
* If @ref Flag::UniformBuffers isn't set, this value is ignored. * If @ref Flag::UniformBuffers isn't set, this value is ignored.
* @see @ref setFlags(), @ref setMaterialCount(), * @see @ref setFlags(), @ref setMaterialCount(),

37
src/Magnum/Shaders/Flat.frag

@ -27,6 +27,10 @@
#extension GL_EXT_gpu_shader4: require #extension GL_EXT_gpu_shader4: require
#endif #endif
#if defined(SHADER_STORAGE_BUFFERS) && !defined(GL_ES)
#extension GL_ARB_shader_storage_buffer_object: require
#endif
#ifndef NEW_GLSL #ifndef NEW_GLSL
#define fragmentColor gl_FragColor #define fragmentColor gl_FragColor
#define texture texture2D #define texture texture2D
@ -68,11 +72,24 @@ layout(location = 5)
uniform highp uint objectId; /* defaults to zero */ uniform highp uint objectId; /* defaults to zero */
#endif #endif
/* Uniform buffers */ /* Uniform / shader storage buffers */
#else #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 #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 #ifdef EXPLICIT_UNIFORM_LOCATION
layout(location = 0) layout(location = 0)
#endif #endif
@ -95,11 +112,11 @@ struct DrawUniform {
}; };
layout(std140 layout(std140
#ifdef EXPLICIT_BINDING #if defined(EXPLICIT_BINDING) || defined(SHADER_STORAGE_BUFFERS)
, binding = 2 , binding = 2
#endif #endif
) uniform Draw { ) BUFFER_OR_UNIFORM Draw {
DrawUniform draws[DRAW_COUNT]; BUFFER_READONLY DrawUniform draws[DRAW_COUNT];
}; };
struct MaterialUniform { struct MaterialUniform {
@ -109,11 +126,11 @@ struct MaterialUniform {
}; };
layout(std140 layout(std140
#ifdef EXPLICIT_BINDING #if defined(EXPLICIT_BINDING) || defined(SHADER_STORAGE_BUFFERS)
, binding = 4 , binding = 4
#endif #endif
) uniform Material { ) BUFFER_OR_UNIFORM Material {
MaterialUniform materials[MATERIAL_COUNT]; BUFFER_READONLY MaterialUniform materials[MATERIAL_COUNT];
}; };
#endif #endif
@ -190,7 +207,9 @@ void main() {
#ifdef OBJECT_ID #ifdef OBJECT_ID
highp const uint objectId = draws[drawId].draw_objectId; highp const uint objectId = draws[drawId].draw_objectId;
#endif #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; mediump const uint materialId = draws[drawId].draw_materialIdReserved & 0xffffu;
#else #else
#define materialId 0u #define materialId 0u

49
src/Magnum/Shaders/Flat.vert

@ -31,6 +31,10 @@
#extension GL_ARB_shader_bit_encoding: require #extension GL_ARB_shader_bit_encoding: require
#endif #endif
#if defined(SHADER_STORAGE_BUFFERS) && !defined(GL_ES)
#extension GL_ARB_shader_storage_buffer_object: require
#endif
#ifdef MULTI_DRAW #ifdef MULTI_DRAW
#ifndef GL_ES #ifndef GL_ES
#extension GL_ARB_shader_draw_parameters: require #extension GL_ARB_shader_draw_parameters: require
@ -128,10 +132,27 @@ layout(location = PER_INSTANCE_JOINT_COUNT_LOCATION)
uniform uint perInstanceJointCount; /* defaults to zero */ uniform uint perInstanceJointCount; /* defaults to zero */
#endif #endif
/* Uniform buffers */ /* Uniform / shader storage buffers */
#else #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 #ifdef EXPLICIT_UNIFORM_LOCATION
layout(location = 0) layout(location = 0)
#endif #endif
@ -152,19 +173,19 @@ struct DrawUniform {
}; };
layout(std140 layout(std140
#ifdef EXPLICIT_BINDING #if defined(EXPLICIT_BINDING) || defined(SHADER_STORAGE_BUFFERS)
, binding = 2 , binding = 2
#endif #endif
) uniform Draw { ) BUFFER_OR_UNIFORM Draw {
DrawUniform draws[DRAW_COUNT]; BUFFER_READONLY DrawUniform draws[DRAW_COUNT];
}; };
layout(std140 layout(std140
#ifdef EXPLICIT_BINDING #if defined(EXPLICIT_BINDING) || defined(SHADER_STORAGE_BUFFERS)
, binding = 1 , binding = 1
#endif #endif
) uniform TransformationProjection { ) BUFFER_OR_UNIFORM TransformationProjection {
highp BUFFER_READONLY highp
#ifdef TWO_DIMENSIONS #ifdef TWO_DIMENSIONS
/* Can't be a mat3 because of ANGLE, see DrawUniform in Phong.vert for /* Can't be a mat3 because of ANGLE, see DrawUniform in Phong.vert for
details */ details */
@ -179,11 +200,11 @@ layout(std140
#ifdef JOINT_COUNT #ifdef JOINT_COUNT
layout(std140 layout(std140
#ifdef EXPLICIT_BINDING #if defined(EXPLICIT_BINDING) || defined(SHADER_STORAGE_BUFFERS)
, binding = 6 , binding = 6
#endif #endif
) uniform Joint { ) BUFFER_OR_UNIFORM Joint {
highp BUFFER_READONLY highp
#ifdef TWO_DIMENSIONS #ifdef TWO_DIMENSIONS
/* Can't be a mat3 because of ANGLE, see DrawUniform in Phong.vert for /* Can't be a mat3 because of ANGLE, see DrawUniform in Phong.vert for
details */ details */
@ -206,11 +227,11 @@ struct TextureTransformationUniform {
}; };
layout(std140 layout(std140
#ifdef EXPLICIT_BINDING #if defined(EXPLICIT_BINDING) || defined(SHADER_STORAGE_BUFFERS)
, binding = 3 , binding = 3
#endif #endif
) uniform TextureTransformation { ) BUFFER_OR_UNIFORM TextureTransformation {
TextureTransformationUniform textureTransformations[DRAW_COUNT]; BUFFER_READONLY TextureTransformationUniform textureTransformations[DRAW_COUNT];
}; };
#endif #endif
#endif #endif

186
src/Magnum/Shaders/FlatGL.cpp

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

71
src/Magnum/Shaders/FlatGL.h

@ -60,6 +60,9 @@ namespace Implementation {
InstancedTextureOffset = (1 << 7)|TextureTransformation, InstancedTextureOffset = (1 << 7)|TextureTransformation,
#ifndef MAGNUM_TARGET_GLES2 #ifndef MAGNUM_TARGET_GLES2
UniformBuffers = 1 << 8, UniformBuffers = 1 << 8,
#ifndef MAGNUM_TARGET_WEBGL
ShaderStorageBuffers = UniformBuffers|(1 << 13),
#endif
MultiDraw = UniformBuffers|(1 << 9), MultiDraw = UniformBuffers|(1 << 9),
TextureArrays = 1 << 10, TextureArrays = 1 << 10,
DynamicPerVertexJointCount = 1 << 12 DynamicPerVertexJointCount = 1 << 12
@ -597,6 +600,7 @@ template<UnsignedInt dimensions> class MAGNUM_SHADERS_EXPORT FlatGL: public GL::
* @ref bindTransformationProjectionBuffer(), * @ref bindTransformationProjectionBuffer(),
* @ref bindDrawBuffer(), @ref bindTextureTransformationBuffer() * @ref bindDrawBuffer(), @ref bindTextureTransformationBuffer()
* and @ref bindMaterialBuffer() instead of direct uniform setters. * and @ref bindMaterialBuffer() instead of direct uniform setters.
* @see @ref Flag::ShaderStorageBuffers
* @requires_gl31 Extension @gl_extension{ARB,uniform_buffer_object} * @requires_gl31 Extension @gl_extension{ARB,uniform_buffer_object}
* @requires_gles30 Uniform buffers are not available in OpenGL ES * @requires_gles30 Uniform buffers are not available in OpenGL ES
* 2.0. * 2.0.
@ -606,6 +610,24 @@ template<UnsignedInt dimensions> class MAGNUM_SHADERS_EXPORT FlatGL: public GL::
*/ */
UniformBuffers = 1 << 8, 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 * Enable multidraw functionality. Implies @ref Flag::UniformBuffers
* and adds the value from @ref setDrawOffset() with the * 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 * If @ref Flag::UniformBuffers is set, this is the statically defined
* size of the @ref TransformationUniform2D / * size of the @ref TransformationUniform2D /
* @ref TransformationUniform3D uniform buffer bound with * @ref TransformationUniform3D uniform buffer bound with
* @ref bindJointBuffer(). * @ref bindJointBuffer(). Has no use if @ref Flag::ShaderStorageBuffers
* is set.
* @see @ref Configuration::setJointCount() * @see @ref Configuration::setJointCount()
* @requires_gles30 Not defined on OpenGL ES 2.0 builds. * @requires_gles30 Not defined on OpenGL ES 2.0 builds.
* @requires_webgl20 Not defined on WebGL 1.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 * Statically defined size of the @ref FlatMaterialUniform uniform
* buffer bound with @ref bindMaterialBuffer(). Has use only if * 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() * @see @ref Configuration::setMaterialCount()
* @requires_gles30 Not defined on OpenGL ES 2.0 builds. * @requires_gles30 Not defined on OpenGL ES 2.0 builds.
* @requires_webgl20 Not defined on WebGL 1.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 TextureTransformationUniform uniform buffers bound with
* @ref bindTransformationProjectionBuffer(), @ref bindDrawBuffer() and * @ref bindTransformationProjectionBuffer(), @ref bindDrawBuffer() and
* @ref bindTextureTransformationBuffer(). Has use only if * @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() * @see @ref Configuration::setDrawCount()
* @requires_gles30 Not defined on OpenGL ES 2.0 builds. * @requires_gles30 Not defined on OpenGL ES 2.0 builds.
* @requires_webgl20 Not defined on WebGL 1.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 #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. * 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); 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) * @return Reference to self (for method chaining)
* @m_since_latest * @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); 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) * @return Reference to self (for method chaining)
* @m_since_latest * @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); 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) * @return Reference to self (for method chaining)
* @m_since_latest * @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); 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) * @return Reference to self (for method chaining)
* @m_since_latest * @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); 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) * @return Reference to self (for method chaining)
* @m_since_latest * @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 * bound with @ref bindJointBuffer(). Uniform buffers have a statically
* defined size and @cpp count*sizeof(TransformationUniform2D) @ce / * defined size and @cpp count*sizeof(TransformationUniform2D) @ce /
* @cpp count*sizeof(TransformationUniform3D) @ce has to be within * @cpp count*sizeof(TransformationUniform3D) @ce has to be within
* @ref GL::AbstractShaderProgram::maxUniformBlockSize(). The * @ref GL::AbstractShaderProgram::maxUniformBlockSize(), if
* per-vertex joints then index into the array offset by * @ref Flag::ShaderStorageBuffers is set as well, the buffer is
* @ref FlatDrawUniform::jointOffset. * 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 * The @p perVertexCount and @p secondaryPerVertexCount parameters
* describe how many components are taken from @ref JointIds / * 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 * @cpp 4 @ce, setting either of these to @cpp 0 @ce means given
* attribute is not used at all. If both @p perVertexCount and * attribute is not used at all. If both @p perVertexCount and
* @p secondaryPerVertexCount are set to @cpp 0 @ce, skinning is not * @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 * performed. Unless @ref Flag::ShaderStorageBuffers is set, if either
* non-zero as well. * of them is non-zero, @p count is expected to be non-zero as well.
* *
* Default value for all three is @cpp 0 @ce. * Default value for all three is @cpp 0 @ce.
* @see @ref FlatGL::jointCount(), @ref FlatGL::perVertexJointCount(), * @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 FlatMaterialUniform buffer bound with
* @ref bindMaterialBuffer(). Uniform buffers have a statically defined * @ref bindMaterialBuffer(). Uniform buffers have a statically defined
* size and @cpp count*sizeof(FlatMaterialUniform) @ce has to be within * size and @cpp count*sizeof(FlatMaterialUniform) @ce has to be within
* @ref GL::AbstractShaderProgram::maxUniformBlockSize(). * @ref GL::AbstractShaderProgram::maxUniformBlockSize(), if
* * @ref Flag::ShaderStorageBuffers is set as well, the buffer is
* The per-draw materials are then specified via * unbounded and @p count is ignored. The per-draw materials are
* @ref FlatDrawUniform::materialId. Default value is @cpp 1 @ce. * specified via @ref FlatDrawUniform::materialId. Default value is
* @cpp 1 @ce.
* *
* If @ref Flag::UniformBuffers isn't set, this value is ignored. * If @ref Flag::UniformBuffers isn't set, this value is ignored.
* @see @ref setFlags(), @ref setDrawCount(), * @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(TransformationProjectionUniform3D) @ce,
* @cpp count*sizeof(FlatDrawUniform) @ce and * @cpp count*sizeof(FlatDrawUniform) @ce and
* @cpp count*sizeof(TextureTransformationUniform) @ce has to be within * @cpp count*sizeof(TextureTransformationUniform) @ce has to be within
* @ref GL::AbstractShaderProgram::maxUniformBlockSize(). * @ref GL::AbstractShaderProgram::maxUniformBlockSize(), if
* * @ref Flag::ShaderStorageBuffers is set as well, the buffers are
* The draw offset is then set via @ref setDrawOffset(). Default value * unbounded and @p count is ignored. The draw offset is set via
* is @cpp 1 @ce. * @ref setDrawOffset(). Default value is @cpp 1 @ce.
* *
* If @ref Flag::UniformBuffers isn't set, this value is ignored. * If @ref Flag::UniformBuffers isn't set, this value is ignored.
* @see @ref setFlags(), @ref setMaterialCount(), * @see @ref setFlags(), @ref setMaterialCount(),

37
src/Magnum/Shaders/Line.frag

@ -27,6 +27,10 @@
#extension GL_EXT_gpu_shader4: require #extension GL_EXT_gpu_shader4: require
#endif #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 */ /* See the corresponding block in Line.vert for more information */
#ifndef GL_ES #ifndef GL_ES
#define CAN_USE_NOPERSPECTIVE #define CAN_USE_NOPERSPECTIVE
@ -91,11 +95,24 @@ layout(location = 7)
uniform highp uint objectId; /* defaults to zero */ uniform highp uint objectId; /* defaults to zero */
#endif #endif
/* Uniform buffers */ /* Uniform / shader storage buffers */
#else #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 #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 #ifdef EXPLICIT_UNIFORM_LOCATION
layout(location = 1) layout(location = 1)
#endif #endif
@ -117,11 +134,11 @@ struct DrawUniform {
}; };
layout(std140 layout(std140
#ifdef EXPLICIT_BINDING #if defined(EXPLICIT_BINDING) || defined(SHADER_STORAGE_BUFFERS)
, binding = 2 , binding = 2
#endif #endif
) uniform Draw { ) BUFFER_OR_UNIFORM Draw {
DrawUniform draws[DRAW_COUNT]; BUFFER_READONLY DrawUniform draws[DRAW_COUNT];
}; };
struct MaterialUniform { struct MaterialUniform {
@ -134,11 +151,11 @@ struct MaterialUniform {
}; };
layout(std140 layout(std140
#ifdef EXPLICIT_BINDING #if defined(EXPLICIT_BINDING) || defined(SHADER_STORAGE_BUFFERS)
, binding = 3 , binding = 3
#endif #endif
) uniform Material { ) BUFFER_OR_UNIFORM Material {
MaterialUniform materials[MATERIAL_COUNT]; BUFFER_READONLY MaterialUniform materials[MATERIAL_COUNT];
}; };
#endif #endif
@ -187,7 +204,9 @@ void main() {
#ifdef OBJECT_ID #ifdef OBJECT_ID
highp const uint objectId = draws[drawId].draw_objectId; highp const uint objectId = draws[drawId].draw_objectId;
#endif #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; mediump const uint materialId = draws[drawId].draw_materialIdReserved & 0xffffu;
#else #else
#define materialId 0u #define materialId 0u

43
src/Magnum/Shaders/Line.vert

@ -27,6 +27,10 @@
#extension GL_EXT_gpu_shader4: require #extension GL_EXT_gpu_shader4: require
#endif #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 /* Use the noperspective keyword to avoid artifacts in screen-space
interpolation if perspective projection is used in 3D. If not available, 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 it's worked around by dividing gl_Position with gl_Position.w (which is
@ -112,10 +116,23 @@ uniform mediump float miterLimit
#endif #endif
; ;
/* Uniform buffers */ /* Uniform / shader storage buffers */
#else #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 #ifdef EXPLICIT_UNIFORM_LOCATION
layout(location = 1) layout(location = 1)
#endif #endif
@ -129,11 +146,11 @@ uniform highp uint drawOffset
#endif #endif
layout(std140 layout(std140
#ifdef EXPLICIT_BINDING #if defined(EXPLICIT_BINDING) || defined(SHADER_STORAGE_BUFFERS)
, binding = 1 , binding = 1
#endif #endif
) uniform TransformationProjection { ) BUFFER_OR_UNIFORM TransformationProjection {
highp BUFFER_READONLY highp
#ifdef TWO_DIMENSIONS #ifdef TWO_DIMENSIONS
/* Can't be a mat3 because of ANGLE, see DrawUniform in Phong.vert for /* Can't be a mat3 because of ANGLE, see DrawUniform in Phong.vert for
details */ details */
@ -153,11 +170,11 @@ struct DrawUniform {
}; };
layout(std140 layout(std140
#ifdef EXPLICIT_BINDING #if defined(EXPLICIT_BINDING) || defined(SHADER_STORAGE_BUFFERS)
, binding = 2 , binding = 2
#endif #endif
) uniform Draw { ) BUFFER_OR_UNIFORM Draw {
DrawUniform draws[DRAW_COUNT]; BUFFER_READONLY DrawUniform draws[DRAW_COUNT];
}; };
struct MaterialUniform { struct MaterialUniform {
@ -170,11 +187,11 @@ struct MaterialUniform {
}; };
layout(std140 layout(std140
#ifdef EXPLICIT_BINDING #if defined(EXPLICIT_BINDING) || defined(SHADER_STORAGE_BUFFERS)
, binding = 3 , binding = 3
#endif #endif
) uniform Material { ) BUFFER_OR_UNIFORM Material {
MaterialUniform materials[MATERIAL_COUNT]; BUFFER_READONLY MaterialUniform materials[MATERIAL_COUNT];
}; };
#endif #endif
@ -300,7 +317,9 @@ void main() {
#else #else
#error #error
#endif #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; mediump const uint materialId = draws[drawId].draw_materialIdReserved & 0xffffu;
#else #else
#define materialId 0u #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) { template<UnsignedInt dimensions> typename LineGL<dimensions>::CompileState LineGL<dimensions>::compile(const Configuration& configuration) {
CORRADE_ASSERT(!(configuration.flags() >= Flag::UniformBuffers) || configuration.materialCount(), #ifndef CORRADE_NO_ASSERT
"Shaders::LineGL: material count can't be zero", CompileState{NoCreate}); #ifndef MAGNUM_TARGET_WEBGL
CORRADE_ASSERT(!(configuration.flags() >= Flag::UniformBuffers) || configuration.drawCount(), if(!(configuration.flags() >= Flag::ShaderStorageBuffers))
"Shaders::LineGL: draw count can't be zero", CompileState{NoCreate}); #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 #ifndef MAGNUM_TARGET_GLES
MAGNUM_ASSERT_GL_EXTENSION_SUPPORTED(GL::Extensions::EXT::gpu_shader4); MAGNUM_ASSERT_GL_EXTENSION_SUPPORTED(GL::Extensions::EXT::gpu_shader4);
if(configuration.flags() >= Flag::UniformBuffers) if(configuration.flags() >= Flag::UniformBuffers)
MAGNUM_ASSERT_GL_EXTENSION_SUPPORTED(GL::Extensions::ARB::uniform_buffer_object); MAGNUM_ASSERT_GL_EXTENSION_SUPPORTED(GL::Extensions::ARB::uniform_buffer_object);
#endif #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) { if(configuration.flags() >= Flag::MultiDraw) {
#ifndef MAGNUM_TARGET_GLES #ifndef MAGNUM_TARGET_GLES
MAGNUM_ASSERT_GL_EXTENSION_SUPPORTED(GL::Extensions::ARB::shader_draw_parameters); 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::InstancedObjectId ? "#define INSTANCED_OBJECT_ID\n"_s : ""_s)
.addSource(configuration.flags() & Flag::InstancedTransformation ? "#define INSTANCED_TRANSFORMATION\n"_s : ""_s); .addSource(configuration.flags() & Flag::InstancedTransformation ? "#define INSTANCED_TRANSFORMATION\n"_s : ""_s);
if(configuration.flags() >= Flag::UniformBuffers) { if(configuration.flags() >= Flag::UniformBuffers) {
vert.addSource(Utility::format( #ifndef MAGNUM_TARGET_WEBGL
"#define UNIFORM_BUFFERS\n" /* SSBOs have unbounded per-draw arrays so just a plain string can be
"#define DRAW_COUNT {}\n" passed */
"#define MATERIAL_COUNT {}\n", if(configuration.flags() >= Flag::ShaderStorageBuffers) {
configuration.drawCount(), vert.addSource(
configuration.materialCount())); "#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(configuration.flags() >= Flag::MultiDraw ? "#define MULTI_DRAW\n"_s : ""_s);
} }
vert.addSource(rs.getString("generic.glsl"_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::ObjectId ? "#define OBJECT_ID\n"_s : ""_s)
.addSource(configuration.flags() >= Flag::InstancedObjectId ? "#define INSTANCED_OBJECT_ID\n"_s : ""_s); .addSource(configuration.flags() >= Flag::InstancedObjectId ? "#define INSTANCED_OBJECT_ID\n"_s : ""_s);
if(configuration.flags() >= Flag::UniformBuffers) { if(configuration.flags() >= Flag::UniformBuffers) {
frag.addSource(Utility::format( #ifndef MAGNUM_TARGET_WEBGL
"#define UNIFORM_BUFFERS\n" /* SSBOs have unbounded per-draw arrays so just a plain string can be
"#define DRAW_COUNT {}\n" passed */
"#define MATERIAL_COUNT {}\n", if(configuration.flags() >= Flag::ShaderStorageBuffers) {
configuration.drawCount(), frag.addSource(
configuration.materialCount())); "#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(configuration.flags() >= Flag::MultiDraw ? "#define MULTI_DRAW\n"_s : ""_s);
} }
frag.addSource(rs.getString("generic.glsl"_s)) frag.addSource(rs.getString("generic.glsl"_s))
@ -225,8 +263,11 @@ template<UnsignedInt dimensions> LineGL<dimensions>::LineGL(CompileState&& state
{ {
_viewportSizeUniform = uniformLocation("viewportSize"_s); _viewportSizeUniform = uniformLocation("viewportSize"_s);
if(_flags >= Flag::UniformBuffers) { if(_flags >= Flag::UniformBuffers) {
if(_drawCount > 1) if(_drawCount > 1
_drawOffsetUniform = uniformLocation("drawOffset"_s); #ifndef MAGNUM_TARGET_WEBGL
|| flags() >= Flag::ShaderStorageBuffers
#endif
) _drawOffsetUniform = uniformLocation("drawOffset"_s);
} else { } else {
_transformationProjectionMatrixUniform = uniformLocation("transformationProjectionMatrix"_s); _transformationProjectionMatrixUniform = uniformLocation("transformationProjectionMatrix"_s);
_widthUniform = uniformLocation("width"_s); _widthUniform = uniformLocation("width"_s);
@ -246,7 +287,12 @@ template<UnsignedInt dimensions> LineGL<dimensions>::LineGL(CompileState&& state
if(state._version < GL::Version::GLES310) if(state._version < GL::Version::GLES310)
#endif #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("TransformationProjection"_s), TransformationProjectionBufferBinding);
setUniformBlockBinding(uniformBlockIndex("Draw"_s), DrawBufferBinding); setUniformBlockBinding(uniformBlockIndex("Draw"_s), DrawBufferBinding);
setUniformBlockBinding(uniformBlockIndex("Material"_s), MaterialBufferBinding); 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) { template<UnsignedInt dimensions> LineGL<dimensions>& LineGL<dimensions>::setDrawOffset(const UnsignedInt offset) {
CORRADE_ASSERT(_flags >= Flag::UniformBuffers, CORRADE_ASSERT(_flags >= Flag::UniformBuffers,
"Shaders::LineGL::setDrawOffset(): the shader was not created with uniform buffers enabled", *this); "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, CORRADE_ASSERT(offset < _drawCount,
"Shaders::LineGL::setDrawOffset(): draw offset" << offset << "is out of bounds for" << _drawCount << "draws", *this); "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; return *this;
} }
template<UnsignedInt dimensions> LineGL<dimensions>& LineGL<dimensions>::bindTransformationProjectionBuffer(GL::Buffer& buffer) { template<UnsignedInt dimensions> LineGL<dimensions>& LineGL<dimensions>::bindTransformationProjectionBuffer(GL::Buffer& buffer) {
CORRADE_ASSERT(_flags >= Flag::UniformBuffers, CORRADE_ASSERT(_flags >= Flag::UniformBuffers,
"Shaders::LineGL::bindTransformationProjectionBuffer(): the shader was not created with uniform buffers enabled", *this); "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; return *this;
} }
template<UnsignedInt dimensions> LineGL<dimensions>& LineGL<dimensions>::bindTransformationProjectionBuffer(GL::Buffer& buffer, const GLintptr offset, const GLsizeiptr size) { template<UnsignedInt dimensions> LineGL<dimensions>& LineGL<dimensions>::bindTransformationProjectionBuffer(GL::Buffer& buffer, const GLintptr offset, const GLsizeiptr size) {
CORRADE_ASSERT(_flags >= Flag::UniformBuffers, CORRADE_ASSERT(_flags >= Flag::UniformBuffers,
"Shaders::LineGL::bindTransformationProjectionBuffer(): the shader was not created with uniform buffers enabled", *this); "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; return *this;
} }
template<UnsignedInt dimensions> LineGL<dimensions>& LineGL<dimensions>::bindDrawBuffer(GL::Buffer& buffer) { template<UnsignedInt dimensions> LineGL<dimensions>& LineGL<dimensions>::bindDrawBuffer(GL::Buffer& buffer) {
CORRADE_ASSERT(_flags >= Flag::UniformBuffers, CORRADE_ASSERT(_flags >= Flag::UniformBuffers,
"Shaders::LineGL::bindDrawBuffer(): the shader was not created with uniform buffers enabled", *this); "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; return *this;
} }
template<UnsignedInt dimensions> LineGL<dimensions>& LineGL<dimensions>::bindDrawBuffer(GL::Buffer& buffer, const GLintptr offset, const GLsizeiptr size) { template<UnsignedInt dimensions> LineGL<dimensions>& LineGL<dimensions>::bindDrawBuffer(GL::Buffer& buffer, const GLintptr offset, const GLsizeiptr size) {
CORRADE_ASSERT(_flags >= Flag::UniformBuffers, CORRADE_ASSERT(_flags >= Flag::UniformBuffers,
"Shaders::LineGL::bindDrawBuffer(): the shader was not created with uniform buffers enabled", *this); "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; return *this;
} }
template<UnsignedInt dimensions> LineGL<dimensions>& LineGL<dimensions>::bindMaterialBuffer(GL::Buffer& buffer) { template<UnsignedInt dimensions> LineGL<dimensions>& LineGL<dimensions>::bindMaterialBuffer(GL::Buffer& buffer) {
CORRADE_ASSERT(_flags >= Flag::UniformBuffers, CORRADE_ASSERT(_flags >= Flag::UniformBuffers,
"Shaders::LineGL::bindMaterialBuffer(): the shader was not created with uniform buffers enabled", *this); "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; return *this;
} }
template<UnsignedInt dimensions> LineGL<dimensions>& LineGL<dimensions>::bindMaterialBuffer(GL::Buffer& buffer, const GLintptr offset, const GLsizeiptr size) { template<UnsignedInt dimensions> LineGL<dimensions>& LineGL<dimensions>::bindMaterialBuffer(GL::Buffer& buffer, const GLintptr offset, const GLsizeiptr size) {
CORRADE_ASSERT(_flags >= Flag::UniformBuffers, CORRADE_ASSERT(_flags >= Flag::UniformBuffers,
"Shaders::LineGL::bindMaterialBuffer(): the shader was not created with uniform buffers enabled", *this); "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; return *this;
} }
@ -399,6 +478,14 @@ template class MAGNUM_SHADERS_EXPORT LineGL<3>;
namespace Implementation { namespace Implementation {
Debug& operator<<(Debug& debug, const LineGLFlag value) { 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; debug << "Shaders::LineGL::Flag" << Debug::nospace;
switch(value) { switch(value) {
@ -409,6 +496,9 @@ Debug& operator<<(Debug& debug, const LineGLFlag value) {
_c(InstancedObjectId) _c(InstancedObjectId)
_c(InstancedTransformation) _c(InstancedTransformation)
_c(UniformBuffers) _c(UniformBuffers)
#ifndef MAGNUM_TARGET_WEBGL
_c(ShaderStorageBuffers)
#endif
_c(MultiDraw) _c(MultiDraw)
#undef _c #undef _c
/* LCOV_EXCL_STOP */ /* LCOV_EXCL_STOP */
@ -423,7 +513,16 @@ Debug& operator<<(Debug& debug, const LineGLFlags value) {
LineGLFlag::InstancedObjectId, /* Superset of ObjectId */ LineGLFlag::InstancedObjectId, /* Superset of ObjectId */
LineGLFlag::ObjectId, LineGLFlag::ObjectId,
LineGLFlag::InstancedTransformation, 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 */ LineGLFlag::MultiDraw, /* Superset of UniformBuffers */
#ifndef MAGNUM_TARGET_WEBGL
LineGLFlag::ShaderStorageBuffers, /* Superset of UniformBuffers */
#endif
LineGLFlag::UniformBuffers LineGLFlag::UniformBuffers
}); });
} }

55
src/Magnum/Shaders/LineGL.h

@ -46,15 +46,14 @@ namespace Magnum { namespace Shaders {
namespace Implementation { namespace Implementation {
enum class LineGLFlag: UnsignedShort { enum class LineGLFlag: UnsignedShort {
VertexColor = 1 << 0, VertexColor = 1 << 0,
#ifndef MAGNUM_TARGET_GLES2
ObjectId = 1 << 1, ObjectId = 1 << 1,
InstancedObjectId = (1 << 2)|ObjectId, InstancedObjectId = (1 << 2)|ObjectId,
#endif
InstancedTransformation = 1 << 3, InstancedTransformation = 1 << 3,
#ifndef MAGNUM_TARGET_GLES2
UniformBuffers = 1 << 4, UniformBuffers = 1 << 4,
MultiDraw = UniformBuffers|(1 << 5) #ifndef MAGNUM_TARGET_WEBGL
ShaderStorageBuffers = UniformBuffers|(1 << 6),
#endif #endif
MultiDraw = UniformBuffers|(1 << 5)
}; };
typedef Containers::EnumSet<LineGLFlag> LineGLFlags; typedef Containers::EnumSet<LineGLFlag> LineGLFlags;
CORRADE_ENUMSET_OPERATORS(LineGLFlags) CORRADE_ENUMSET_OPERATORS(LineGLFlags)
@ -572,10 +571,28 @@ template<UnsignedInt dimensions> class MAGNUM_SHADERS_EXPORT LineGL: public GL::
* @ref bindTransformationProjectionBuffer(), * @ref bindTransformationProjectionBuffer(),
* @ref bindDrawBuffer() and @ref bindMaterialBuffer() instead of * @ref bindDrawBuffer() and @ref bindMaterialBuffer() instead of
* direct uniform setters. * direct uniform setters.
* @see @ref Flag::ShaderStorageBuffers
* @requires_gl31 Extension @gl_extension{ARB,uniform_buffer_object} * @requires_gl31 Extension @gl_extension{ARB,uniform_buffer_object}
*/ */
UniformBuffers = 1 << 4, 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 * Enable multidraw functionality. Implies @ref Flag::UniformBuffers
* and adds the value from @ref setDrawOffset() with the * 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 * Statically defined size of the @ref LineMaterialUniform uniform
* buffer bound with @ref bindMaterialBuffer(). Has use only if * 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() * @see @ref Configuration::setMaterialCount()
*/ */
UnsignedInt materialCount() const { return _materialCount; } UnsignedInt materialCount() const { return _materialCount; }
@ -706,7 +724,7 @@ template<UnsignedInt dimensions> class MAGNUM_SHADERS_EXPORT LineGL: public GL::
* @ref TransformationProjectionUniform3D and @ref LineDrawUniform * @ref TransformationProjectionUniform3D and @ref LineDrawUniform
* uniform buffers bound with @ref bindTransformationProjectionBuffer() * uniform buffers bound with @ref bindTransformationProjectionBuffer()
* and @ref bindDrawBuffer(). Has use only if @ref Flag::UniformBuffers * 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() * @see @ref Configuration::setDrawCount()
*/ */
UnsignedInt drawCount() const { return _drawCount; } 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. * 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); 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) * @return Reference to self (for method chaining)
* *
* Expects that @ref Flag::UniformBuffers is set. The buffer is * 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 */ 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) * @return Reference to self (for method chaining)
* *
* Expects that @ref Flag::UniformBuffers is set. The buffer is * 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 */ 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) * @return Reference to self (for method chaining)
* *
* Expects that @ref Flag::UniformBuffers is set. The buffer is * 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 LineMaterialUniform buffer bound with
* @ref bindMaterialBuffer(). Uniform buffers have a statically defined * @ref bindMaterialBuffer(). Uniform buffers have a statically defined
* size and @cpp count*sizeof(LineMaterialUniform) @ce has to be within * size and @cpp count*sizeof(LineMaterialUniform) @ce has to be within
* @ref GL::AbstractShaderProgram::maxUniformBlockSize(). * @ref GL::AbstractShaderProgram::maxUniformBlockSize(), if
* * @ref Flag::ShaderStorageBuffers is set as well, the buffer is
* The per-draw materials are then specified via * unbounded and @p count is ignored. The per-draw materials are
* @ref LineDrawUniform::materialId. Default value is @cpp 1 @ce. * specified via @ref LineDrawUniform::materialId. Default value is
* @cpp 1 @ce.
* *
* If @ref Flag::UniformBuffers isn't set, this value is ignored. * If @ref Flag::UniformBuffers isn't set, this value is ignored.
* @see @ref setFlags(), @ref setDrawCount(), * @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(TransformationProjectionUniform2D) @ce /
* @cpp count*sizeof(TransformationProjectionUniform3D) @ce and * @cpp count*sizeof(TransformationProjectionUniform3D) @ce and
* @cpp count*sizeof(LineDrawUniform) @ce has to be within * @cpp count*sizeof(LineDrawUniform) @ce has to be within
* @ref GL::AbstractShaderProgram::maxUniformBlockSize(). * @ref GL::AbstractShaderProgram::maxUniformBlockSize(), if
* * @ref Flag::ShaderStorageBuffers is set as well, the buffers are
* The draw offset is then set via @ref setDrawOffset(). Default value * unbounded and @p count is ignored. The draw offset is set via
* is @cpp 1 @ce. * @ref setDrawOffset(). Default value is @cpp 1 @ce.
* *
* If @ref Flag::UniformBuffers isn't set, this value is ignored. * If @ref Flag::UniformBuffers isn't set, this value is ignored.
* @see @ref setFlags(), @ref setMaterialCount(), * @see @ref setFlags(), @ref setMaterialCount(),

37
src/Magnum/Shaders/MeshVisualizer.frag

@ -32,6 +32,10 @@
#define const #define const
#endif #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 #if defined(WIREFRAME_RENDERING) && defined(GL_ES) && __VERSION__ < 300
#extension GL_OES_standard_derivatives : enable #extension GL_OES_standard_derivatives : enable
#endif #endif
@ -115,11 +119,24 @@ layout(location = 6)
uniform highp uint objectId; /* defaults to zero */ uniform highp uint objectId; /* defaults to zero */
#endif #endif
/* Uniform buffers */ /* Uniform / shader storage buffers */
#else #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 #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 #ifdef EXPLICIT_UNIFORM_LOCATION
layout(location = 1) layout(location = 1)
#endif #endif
@ -151,11 +168,11 @@ struct DrawUniform {
}; };
layout(std140 layout(std140
#ifdef EXPLICIT_BINDING #if defined(EXPLICIT_BINDING) || defined(SHADER_STORAGE_BUFFERS)
, binding = 2 , binding = 2
#endif #endif
) uniform Draw { ) BUFFER_OR_UNIFORM Draw {
DrawUniform draws[DRAW_COUNT]; BUFFER_READONLY DrawUniform draws[DRAW_COUNT];
}; };
/* Keep in sync with MeshVisualizer.vert and MeshVisualizer.geom. Can't /* Keep in sync with MeshVisualizer.vert and MeshVisualizer.geom. Can't
@ -175,11 +192,11 @@ struct MaterialUniform {
}; };
layout(std140 layout(std140
#ifdef EXPLICIT_BINDING #if defined(EXPLICIT_BINDING) || defined(SHADER_STORAGE_BUFFERS)
, binding = 4 , binding = 4
#endif #endif
) uniform Material { ) BUFFER_OR_UNIFORM Material {
MaterialUniform materials[MATERIAL_COUNT]; BUFFER_READONLY MaterialUniform materials[MATERIAL_COUNT];
}; };
#endif #endif
@ -261,7 +278,9 @@ void main() {
#ifdef OBJECT_ID #ifdef OBJECT_ID
highp const uint objectId = draws[drawId].draw_objectId; highp const uint objectId = draws[drawId].draw_objectId;
#endif #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; mediump const uint materialId = draws[drawId].draw_materialIdReserved & 0xffffu;
#else #else
#define materialId 0u #define materialId 0u

33
src/Magnum/Shaders/MeshVisualizer.geom

@ -27,6 +27,10 @@
#define const #define const
#endif #endif
#if defined(SHADER_STORAGE_BUFFERS) && !defined(GL_ES)
#extension GL_ARB_shader_storage_buffer_object: require
#endif
#ifdef GL_ES #ifdef GL_ES
#extension GL_EXT_geometry_shader: require #extension GL_EXT_geometry_shader: require
#ifdef GL_NV_shader_noperspective_interpolation #ifdef GL_NV_shader_noperspective_interpolation
@ -84,9 +88,20 @@ uniform lowp float smoothness
; ;
#endif #endif
/* Uniform buffers */ /* Uniform / shader storage buffers */
#else #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 #ifndef MULTI_DRAW
#ifdef EXPLICIT_UNIFORM_LOCATION #ifdef EXPLICIT_UNIFORM_LOCATION
layout(location = 1) layout(location = 1)
@ -115,11 +130,11 @@ struct DrawUniform {
}; };
layout(std140 layout(std140
#ifdef EXPLICIT_BINDING #if defined(EXPLICIT_BINDING) || defined(SHADER_STORAGE_BUFFERS)
, binding = 2 , binding = 2
#endif #endif
) uniform Draw { ) BUFFER_OR_UNIFORM Draw {
DrawUniform draws[DRAW_COUNT]; BUFFER_READONLY DrawUniform draws[DRAW_COUNT];
}; };
/* Keep in sync with MeshVisualizer.vert and MeshVisualizer.frag. Can't /* Keep in sync with MeshVisualizer.vert and MeshVisualizer.frag. Can't
@ -139,11 +154,11 @@ struct MaterialUniform {
}; };
layout(std140 layout(std140
#ifdef EXPLICIT_BINDING #if defined(EXPLICIT_BINDING) || defined(SHADER_STORAGE_BUFFERS)
, binding = 4 , binding = 4
#endif #endif
) uniform Material { ) BUFFER_OR_UNIFORM Material {
MaterialUniform materials[MATERIAL_COUNT]; BUFFER_READONLY MaterialUniform materials[MATERIAL_COUNT];
}; };
#endif #endif
@ -292,7 +307,9 @@ void main() {
#define drawId drawOffset #define drawId drawOffset
#endif #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; mediump const uint materialId = draws[drawId].draw_materialIdReserved & 0xffffu;
#else #else
#define materialId 0u #define materialId 0u

72
src/Magnum/Shaders/MeshVisualizer.vert

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

325
src/Magnum/Shaders/MeshVisualizerGL.cpp

@ -108,6 +108,15 @@ void MeshVisualizerGLBase::assertExtensions(const FlagsBase flags) {
if(flags >= FlagBase::UniformBuffers) if(flags >= FlagBase::UniformBuffers)
MAGNUM_ASSERT_GL_EXTENSION_SUPPORTED(GL::Extensions::ARB::uniform_buffer_object); MAGNUM_ASSERT_GL_EXTENSION_SUPPORTED(GL::Extensions::ARB::uniform_buffer_object);
#endif #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 #ifndef MAGNUM_TARGET_GLES2
if(flags >= FlagBase::MultiDraw) { if(flags >= FlagBase::MultiDraw) {
#ifndef MAGNUM_TARGET_GLES #ifndef MAGNUM_TARGET_GLES
@ -228,9 +237,15 @@ GL::Version MeshVisualizerGLBase::setupShaders(GL::Shader& vert, GL::Shader& fra
#endif #endif
{ {
vert.addSource(Utility::format( vert.addSource(Utility::format(
"#define JOINT_COUNT {}\n" /* SSBOs have an unbounded joints array */
"#define PER_VERTEX_JOINT_COUNT {}u\n" #ifndef MAGNUM_TARGET_WEBGL
"#define SECONDARY_PER_VERTEX_JOINT_COUNT {}u\n", 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, jointCount,
perVertexJointCount, perVertexJointCount,
secondaryPerVertexJointCount)); secondaryPerVertexJointCount));
@ -240,7 +255,7 @@ GL::Version MeshVisualizerGLBase::setupShaders(GL::Shader& vert, GL::Shader& fra
#ifndef MAGNUM_TARGET_WEBGL #ifndef MAGNUM_TARGET_WEBGL
/* The _LOCATION is needed only if explicit uniform location (desktop / /* The _LOCATION is needed only if explicit uniform location (desktop /
ES3.1) is supported, a plain string can be added otherwise. This is 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 #ifndef MAGNUM_TARGET_GLES
if(context.isExtensionSupported<GL::Extensions::ARB::explicit_uniform_location>(version)) if(context.isExtensionSupported<GL::Extensions::ARB::explicit_uniform_location>(version))
#else #else
@ -260,12 +275,23 @@ GL::Version MeshVisualizerGLBase::setupShaders(GL::Shader& vert, GL::Shader& fra
#endif #endif
#ifndef MAGNUM_TARGET_GLES2 #ifndef MAGNUM_TARGET_GLES2
if(flags >= FlagBase::UniformBuffers) { if(flags >= FlagBase::UniformBuffers) {
vert.addSource(Utility::format( #ifndef MAGNUM_TARGET_WEBGL
"#define UNIFORM_BUFFERS\n" /* SSBOs have unbounded per-draw arrays so just a plain string can be
"#define DRAW_COUNT {}\n" passed */
"#define MATERIAL_COUNT {}\n", if(flags >= FlagBase::ShaderStorageBuffers) {
drawCount, vert.addSource(
materialCount)); "#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); vert.addSource(flags >= FlagBase::MultiDraw ? "#define MULTI_DRAW\n"_s : ""_s);
} }
#endif #endif
@ -286,12 +312,23 @@ GL::Version MeshVisualizerGLBase::setupShaders(GL::Shader& vert, GL::Shader& fra
; ;
#ifndef MAGNUM_TARGET_GLES2 #ifndef MAGNUM_TARGET_GLES2
if(flags >= FlagBase::UniformBuffers) { if(flags >= FlagBase::UniformBuffers) {
frag.addSource(Utility::format( #ifndef MAGNUM_TARGET_WEBGL
"#define UNIFORM_BUFFERS\n" /* SSBOs have unbounded per-draw arrays so just a plain string can be
"#define DRAW_COUNT {}\n" passed */
"#define MATERIAL_COUNT {}\n", if(flags >= FlagBase::ShaderStorageBuffers) {
drawCount, frag.addSource(
materialCount)); "#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); frag.addSource(flags >= FlagBase::MultiDraw ? "#define MULTI_DRAW\n"_s : ""_s);
} }
#endif #endif
@ -403,9 +440,18 @@ MeshVisualizerGLBase& MeshVisualizerGLBase::setPerInstanceJointCount(const Unsig
MeshVisualizerGLBase& MeshVisualizerGLBase::setDrawOffset(const UnsignedInt offset) { MeshVisualizerGLBase& MeshVisualizerGLBase::setDrawOffset(const UnsignedInt offset) {
CORRADE_ASSERT(_flags >= FlagBase::UniformBuffers, CORRADE_ASSERT(_flags >= FlagBase::UniformBuffers,
"Shaders::MeshVisualizerGL::setDrawOffset(): the shader was not created with uniform buffers enabled", *this); "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, CORRADE_ASSERT(offset < _drawCount,
"Shaders::MeshVisualizerGL::setDrawOffset(): draw offset" << offset << "is out of bounds for" << _drawCount << "draws", *this); "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; return *this;
} }
@ -414,7 +460,11 @@ MeshVisualizerGLBase& MeshVisualizerGLBase::bindTextureTransformationBuffer(GL::
"Shaders::MeshVisualizerGL::bindTextureTransformationBuffer(): the shader was not created with uniform buffers enabled", *this); "Shaders::MeshVisualizerGL::bindTextureTransformationBuffer(): the shader was not created with uniform buffers enabled", *this);
CORRADE_ASSERT(_flags & FlagBase::TextureTransformation, CORRADE_ASSERT(_flags & FlagBase::TextureTransformation,
"Shaders::MeshVisualizerGL::bindTextureTransformationBuffer(): the shader was not created with texture transformation enabled", *this); "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; return *this;
} }
@ -423,35 +473,55 @@ MeshVisualizerGLBase& MeshVisualizerGLBase::bindTextureTransformationBuffer(GL::
"Shaders::MeshVisualizerGL::bindTextureTransformationBuffer(): the shader was not created with uniform buffers enabled", *this); "Shaders::MeshVisualizerGL::bindTextureTransformationBuffer(): the shader was not created with uniform buffers enabled", *this);
CORRADE_ASSERT(_flags & FlagBase::TextureTransformation, CORRADE_ASSERT(_flags & FlagBase::TextureTransformation,
"Shaders::MeshVisualizerGL::bindTextureTransformationBuffer(): the shader was not created with texture transformation enabled", *this); "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; return *this;
} }
MeshVisualizerGLBase& MeshVisualizerGLBase::bindMaterialBuffer(GL::Buffer& buffer) { MeshVisualizerGLBase& MeshVisualizerGLBase::bindMaterialBuffer(GL::Buffer& buffer) {
CORRADE_ASSERT(_flags >= FlagBase::UniformBuffers, CORRADE_ASSERT(_flags >= FlagBase::UniformBuffers,
"Shaders::MeshVisualizerGL::bindMaterialBuffer(): the shader was not created with uniform buffers enabled", *this); "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; return *this;
} }
MeshVisualizerGLBase& MeshVisualizerGLBase::bindMaterialBuffer(GL::Buffer& buffer, const GLintptr offset, const GLsizeiptr size) { MeshVisualizerGLBase& MeshVisualizerGLBase::bindMaterialBuffer(GL::Buffer& buffer, const GLintptr offset, const GLsizeiptr size) {
CORRADE_ASSERT(_flags >= FlagBase::UniformBuffers, CORRADE_ASSERT(_flags >= FlagBase::UniformBuffers,
"Shaders::MeshVisualizerGL::bindMaterialBuffer(): the shader was not created with uniform buffers enabled", *this); "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; return *this;
} }
MeshVisualizerGLBase& MeshVisualizerGLBase::bindJointBuffer(GL::Buffer& buffer) { MeshVisualizerGLBase& MeshVisualizerGLBase::bindJointBuffer(GL::Buffer& buffer) {
CORRADE_ASSERT(_flags >= FlagBase::UniformBuffers, CORRADE_ASSERT(_flags >= FlagBase::UniformBuffers,
"Shaders::MeshVisualizerGL::bindJointBuffer(): the shader was not created with uniform buffers enabled", *this); "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; return *this;
} }
MeshVisualizerGLBase& MeshVisualizerGLBase::bindJointBuffer(GL::Buffer& buffer, const GLintptr offset, const GLsizeiptr size) { MeshVisualizerGLBase& MeshVisualizerGLBase::bindJointBuffer(GL::Buffer& buffer, const GLintptr offset, const GLsizeiptr size) {
CORRADE_ASSERT(_flags >= FlagBase::UniformBuffers, CORRADE_ASSERT(_flags >= FlagBase::UniformBuffers,
"Shaders::MeshVisualizerGL::bindJointBuffer(): the shader was not created with uniform buffers enabled", *this); "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; return *this;
} }
#endif #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 /* 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 constructor when testing for asserts -- GLSL compilation would fail
otherwise */ otherwise */
#ifndef MAGNUM_TARGET_GLES2 #if !defined(MAGNUM_TARGET_GLES2) && !defined(CORRADE_NO_ASSERT)
CORRADE_ASSERT(!(configuration.flags() >= Flag::UniformBuffers) || configuration.materialCount(), #ifndef MAGNUM_TARGET_WEBGL
"Shaders::MeshVisualizerGL2D: material count can't be zero", CompileState{NoCreate}); if(!(configuration.flags() >= Flag::ShaderStorageBuffers))
CORRADE_ASSERT(!(configuration.flags() >= Flag::UniformBuffers) || configuration.drawCount(), #endif
"Shaders::MeshVisualizerGL2D: draw count can't be zero", CompileState{NoCreate}); {
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 #endif
/* Has to be here and not in the base class in order to have it exit the /* 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); "#define PRIMITIVE_ID\n"_s) : ""_s);
#ifndef MAGNUM_TARGET_GLES2 #ifndef MAGNUM_TARGET_GLES2
if(configuration.flags() >= Flag::UniformBuffers) { if(configuration.flags() >= Flag::UniformBuffers) {
geom->addSource(Utility::format( /* SSBOs have unbounded per-draw arrays so just a plain string can
"#define TWO_DIMENSIONS\n" be passed */
"#define UNIFORM_BUFFERS\n" if(configuration.flags() >= Flag::ShaderStorageBuffers) {
"#define DRAW_COUNT {}\n" vert.addSource(
"#define MATERIAL_COUNT {}\n", "#define TWO_DIMENSIONS\n"
configuration.drawCount(), "#define UNIFORM_BUFFERS\n"
configuration.materialCount())); "#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); geom->addSource(configuration.flags() >= Flag::MultiDraw ? "#define MULTI_DRAW\n"_s : ""_s);
} }
#endif #endif
@ -710,7 +796,11 @@ MeshVisualizerGL2D::MeshVisualizerGL2D(CompileState&& state): MeshVisualizerGL2D
if(flags() >= Flag::DynamicPerVertexJointCount) if(flags() >= Flag::DynamicPerVertexJointCount)
_perVertexJointCountUniform = uniformLocation("perVertexJointCount"_s); _perVertexJointCountUniform = uniformLocation("perVertexJointCount"_s);
if(flags() >= Flag::UniformBuffers) { 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 } else
#endif #endif
{ {
@ -761,7 +851,12 @@ MeshVisualizerGL2D::MeshVisualizerGL2D(CompileState&& state): MeshVisualizerGL2D
#ifndef MAGNUM_TARGET_GLES2 #ifndef MAGNUM_TARGET_GLES2
if(flags() >= Flag::ObjectIdTexture) if(flags() >= Flag::ObjectIdTexture)
setUniform(uniformLocation("objectIdTextureData"_s), ObjectIdTextureUnit); 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("TransformationProjection"_s), TransformationProjectionBufferBinding);
setUniformBlockBinding(uniformBlockIndex("Draw"_s), DrawBufferBinding); setUniformBlockBinding(uniformBlockIndex("Draw"_s), DrawBufferBinding);
setUniformBlockBinding(uniformBlockIndex("Material"_s), MaterialBufferBinding); setUniformBlockBinding(uniformBlockIndex("Material"_s), MaterialBufferBinding);
@ -886,28 +981,44 @@ MeshVisualizerGL2D& MeshVisualizerGL2D::setJointMatrix(const UnsignedInt id, con
MeshVisualizerGL2D& MeshVisualizerGL2D::bindTransformationProjectionBuffer(GL::Buffer& buffer) { MeshVisualizerGL2D& MeshVisualizerGL2D::bindTransformationProjectionBuffer(GL::Buffer& buffer) {
CORRADE_ASSERT(flags() >= Flag::UniformBuffers, CORRADE_ASSERT(flags() >= Flag::UniformBuffers,
"Shaders::MeshVisualizerGL2D::bindTransformationProjectionBuffer(): the shader was not created with uniform buffers enabled", *this); "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; return *this;
} }
MeshVisualizerGL2D& MeshVisualizerGL2D::bindTransformationProjectionBuffer(GL::Buffer& buffer, const GLintptr offset, const GLsizeiptr size) { MeshVisualizerGL2D& MeshVisualizerGL2D::bindTransformationProjectionBuffer(GL::Buffer& buffer, const GLintptr offset, const GLsizeiptr size) {
CORRADE_ASSERT(flags() >= Flag::UniformBuffers, CORRADE_ASSERT(flags() >= Flag::UniformBuffers,
"Shaders::MeshVisualizerGL2D::bindTransformationProjectionBuffer(): the shader was not created with uniform buffers enabled", *this); "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; return *this;
} }
MeshVisualizerGL2D& MeshVisualizerGL2D::bindDrawBuffer(GL::Buffer& buffer) { MeshVisualizerGL2D& MeshVisualizerGL2D::bindDrawBuffer(GL::Buffer& buffer) {
CORRADE_ASSERT(flags() >= Flag::UniformBuffers, CORRADE_ASSERT(flags() >= Flag::UniformBuffers,
"Shaders::MeshVisualizerGL2D::bindDrawBuffer(): the shader was not created with uniform buffers enabled", *this); "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; return *this;
} }
MeshVisualizerGL2D& MeshVisualizerGL2D::bindDrawBuffer(GL::Buffer& buffer, const GLintptr offset, const GLsizeiptr size) { MeshVisualizerGL2D& MeshVisualizerGL2D::bindDrawBuffer(GL::Buffer& buffer, const GLintptr offset, const GLsizeiptr size) {
CORRADE_ASSERT(flags() >= Flag::UniformBuffers, CORRADE_ASSERT(flags() >= Flag::UniformBuffers,
"Shaders::MeshVisualizerGL2D::bindDrawBuffer(): the shader was not created with uniform buffers enabled", *this); "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; return *this;
} }
#endif #endif
@ -918,8 +1029,8 @@ MeshVisualizerGL2D::Configuration& MeshVisualizerGL2D::Configuration::setJointCo
"Shaders::MeshVisualizerGL2D::Configuration::setJointCount(): expected at most 4 per-vertex joints, got" << perVertexCount, *this); "Shaders::MeshVisualizerGL2D::Configuration::setJointCount(): expected at most 4 per-vertex joints, got" << perVertexCount, *this);
CORRADE_ASSERT(secondaryPerVertexCount <= 4, CORRADE_ASSERT(secondaryPerVertexCount <= 4,
"Shaders::MeshVisualizerGL2D::Configuration::setJointCount(): expected at most 4 secondary per-vertex joints, got" << secondaryPerVertexCount, *this); "Shaders::MeshVisualizerGL2D::Configuration::setJointCount(): expected at most 4 secondary per-vertex joints, got" << secondaryPerVertexCount, *this);
CORRADE_ASSERT(!count == (!perVertexCount && !secondaryPerVertexCount), CORRADE_ASSERT(perVertexCount || secondaryPerVertexCount || !count,
"Shaders::MeshVisualizerGL2D::Configuration::setJointCount(): count has to be non-zero iff (secondary) per-vertex joint count is non-zero", *this); "Shaders::MeshVisualizerGL2D::Configuration::setJointCount(): count has to be zero if per-vertex joint count is zero", *this);
_jointCount = count; _jointCount = count;
_perVertexJointCount = perVertexCount; _perVertexJointCount = perVertexCount;
_secondaryPerVertexJointCount = secondaryPerVertexCount; _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 /* 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 constructor when testing for asserts -- GLSL compilation would fail
otherwise */ otherwise */
#ifndef MAGNUM_TARGET_GLES2 /* Has to be here and not in the base class in order to have it exit the
CORRADE_ASSERT(!(configuration.flags() >= Flag::UniformBuffers) || configuration.materialCount(), constructor when testing for asserts -- GLSL compilation would fail
"Shaders::MeshVisualizerGL3D: material count can't be zero", CompileState{NoCreate}); otherwise */
CORRADE_ASSERT(!(configuration.flags() >= Flag::UniformBuffers) || configuration.drawCount(), #if !defined(MAGNUM_TARGET_GLES2) && !defined(CORRADE_NO_ASSERT)
"Shaders::MeshVisualizerGL3D: draw count can't be zero", CompileState{NoCreate}); #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 #endif
/* Has to be here and not in the base class in order to have it exit the /* 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); .addSource(configuration.flags() & Flag::NormalDirection ? "#define NORMAL_DIRECTION\n"_s : ""_s);
#ifndef MAGNUM_TARGET_GLES2 #ifndef MAGNUM_TARGET_GLES2
if(configuration.flags() >= Flag::UniformBuffers) { if(configuration.flags() >= Flag::UniformBuffers) {
geom->addSource(Utility::format( /* SSBOs have unbounded per-draw arrays so just a plain string can
"#define THREE_DIMENSIONS\n" be passed */
"#define UNIFORM_BUFFERS\n" if(configuration.flags() >= Flag::ShaderStorageBuffers) {
"#define DRAW_COUNT {}\n" geom->addSource(
"#define MATERIAL_COUNT {}\n", "#define THREE_DIMENSIONS\n"
configuration.drawCount(), "#define UNIFORM_BUFFERS\n"
configuration.materialCount())); "#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); geom->addSource(configuration.flags() >= Flag::MultiDraw ? "#define MULTI_DRAW\n"_s : ""_s);
} }
#endif #endif
@ -1215,7 +1345,11 @@ MeshVisualizerGL3D::MeshVisualizerGL3D(CompileState&& state): MeshVisualizerGL3D
if(flags() >= Flag::DynamicPerVertexJointCount) if(flags() >= Flag::DynamicPerVertexJointCount)
_perVertexJointCountUniform = uniformLocation("perVertexJointCount"_s); _perVertexJointCountUniform = uniformLocation("perVertexJointCount"_s);
if(flags() >= Flag::UniformBuffers) { 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 } else
#endif #endif
{ {
@ -1280,7 +1414,12 @@ MeshVisualizerGL3D::MeshVisualizerGL3D(CompileState&& state): MeshVisualizerGL3D
#ifndef MAGNUM_TARGET_GLES2 #ifndef MAGNUM_TARGET_GLES2
if(flags() >= Flag::ObjectIdTexture) if(flags() >= Flag::ObjectIdTexture)
setUniform(uniformLocation("objectIdTextureData"_s), ObjectIdTextureUnit); 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("Projection"_s), ProjectionBufferBinding);
setUniformBlockBinding(uniformBlockIndex("Transformation"_s), TransformationBufferBinding); setUniformBlockBinding(uniformBlockIndex("Transformation"_s), TransformationBufferBinding);
setUniformBlockBinding(uniformBlockIndex("Draw"_s), DrawBufferBinding); setUniformBlockBinding(uniformBlockIndex("Draw"_s), DrawBufferBinding);
@ -1473,42 +1612,66 @@ MeshVisualizerGL3D& MeshVisualizerGL3D::setJointMatrix(const UnsignedInt id, con
MeshVisualizerGL3D& MeshVisualizerGL3D::bindProjectionBuffer(GL::Buffer& buffer) { MeshVisualizerGL3D& MeshVisualizerGL3D::bindProjectionBuffer(GL::Buffer& buffer) {
CORRADE_ASSERT(flags() >= Flag::UniformBuffers, CORRADE_ASSERT(flags() >= Flag::UniformBuffers,
"Shaders::MeshVisualizerGL3D::bindProjectionBuffer(): the shader was not created with uniform buffers enabled", *this); "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; return *this;
} }
MeshVisualizerGL3D& MeshVisualizerGL3D::bindProjectionBuffer(GL::Buffer& buffer, const GLintptr offset, const GLsizeiptr size) { MeshVisualizerGL3D& MeshVisualizerGL3D::bindProjectionBuffer(GL::Buffer& buffer, const GLintptr offset, const GLsizeiptr size) {
CORRADE_ASSERT(flags() >= Flag::UniformBuffers, CORRADE_ASSERT(flags() >= Flag::UniformBuffers,
"Shaders::MeshVisualizerGL3D::bindProjectionBuffer(): the shader was not created with uniform buffers enabled", *this); "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; return *this;
} }
MeshVisualizerGL3D& MeshVisualizerGL3D::bindTransformationBuffer(GL::Buffer& buffer) { MeshVisualizerGL3D& MeshVisualizerGL3D::bindTransformationBuffer(GL::Buffer& buffer) {
CORRADE_ASSERT(flags() >= Flag::UniformBuffers, CORRADE_ASSERT(flags() >= Flag::UniformBuffers,
"Shaders::MeshVisualizerGL3D::bindTransformationBuffer(): the shader was not created with uniform buffers enabled", *this); "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; return *this;
} }
MeshVisualizerGL3D& MeshVisualizerGL3D::bindTransformationBuffer(GL::Buffer& buffer, const GLintptr offset, const GLsizeiptr size) { MeshVisualizerGL3D& MeshVisualizerGL3D::bindTransformationBuffer(GL::Buffer& buffer, const GLintptr offset, const GLsizeiptr size) {
CORRADE_ASSERT(flags() >= Flag::UniformBuffers, CORRADE_ASSERT(flags() >= Flag::UniformBuffers,
"Shaders::MeshVisualizerGL3D::bindTransformationBuffer(): the shader was not created with uniform buffers enabled", *this); "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; return *this;
} }
MeshVisualizerGL3D& MeshVisualizerGL3D::bindDrawBuffer(GL::Buffer& buffer) { MeshVisualizerGL3D& MeshVisualizerGL3D::bindDrawBuffer(GL::Buffer& buffer) {
CORRADE_ASSERT(flags() >= Flag::UniformBuffers, CORRADE_ASSERT(flags() >= Flag::UniformBuffers,
"Shaders::MeshVisualizerGL3D::bindDrawBuffer(): the shader was not created with uniform buffers enabled", *this); "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; return *this;
} }
MeshVisualizerGL3D& MeshVisualizerGL3D::bindDrawBuffer(GL::Buffer& buffer, const GLintptr offset, const GLsizeiptr size) { MeshVisualizerGL3D& MeshVisualizerGL3D::bindDrawBuffer(GL::Buffer& buffer, const GLintptr offset, const GLsizeiptr size) {
CORRADE_ASSERT(flags() >= Flag::UniformBuffers, CORRADE_ASSERT(flags() >= Flag::UniformBuffers,
"Shaders::MeshVisualizerGL3D::bindDrawBuffer(): the shader was not created with uniform buffers enabled", *this); "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; return *this;
} }
#endif #endif
@ -1519,8 +1682,8 @@ MeshVisualizerGL3D::Configuration& MeshVisualizerGL3D::Configuration::setJointCo
"Shaders::MeshVisualizerGL3D::Configuration::setJointCount(): expected at most 4 per-vertex joints, got" << perVertexCount, *this); "Shaders::MeshVisualizerGL3D::Configuration::setJointCount(): expected at most 4 per-vertex joints, got" << perVertexCount, *this);
CORRADE_ASSERT(secondaryPerVertexCount <= 4, CORRADE_ASSERT(secondaryPerVertexCount <= 4,
"Shaders::MeshVisualizerGL3D::Configuration::setJointCount(): expected at most 4 secondary per-vertex joints, got" << secondaryPerVertexCount, *this); "Shaders::MeshVisualizerGL3D::Configuration::setJointCount(): expected at most 4 secondary per-vertex joints, got" << secondaryPerVertexCount, *this);
CORRADE_ASSERT(!count == (!perVertexCount && !secondaryPerVertexCount), CORRADE_ASSERT(perVertexCount || secondaryPerVertexCount || !count,
"Shaders::MeshVisualizerGL3D::Configuration::setJointCount(): count has to be non-zero iff (secondary) per-vertex joint count is non-zero", *this); "Shaders::MeshVisualizerGL3D::Configuration::setJointCount(): count has to be zero if per-vertex joint count is zero", *this);
_jointCount = count; _jointCount = count;
_perVertexJointCount = perVertexCount; _perVertexJointCount = perVertexCount;
_secondaryPerVertexJointCount = secondaryPerVertexCount; _secondaryPerVertexJointCount = secondaryPerVertexCount;
@ -1535,6 +1698,11 @@ Debug& operator<<(Debug& debug, const MeshVisualizerGL2D::Flag value) {
`Flag::InstancedObjectId|Flag(0x4000)` in the output. */ `Flag::InstancedObjectId|Flag(0x4000)` in the output. */
if(value == MeshVisualizerGL2D::Flag(UnsignedInt(MeshVisualizerGL2D::Flag::InstancedObjectId|MeshVisualizerGL2D::Flag::ObjectIdTexture))) if(value == MeshVisualizerGL2D::Flag(UnsignedInt(MeshVisualizerGL2D::Flag::InstancedObjectId|MeshVisualizerGL2D::Flag::ObjectIdTexture)))
return debug << MeshVisualizerGL2D::Flag::InstancedObjectId << Debug::nospace << "|" << Debug::nospace << 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 #endif
debug << "Shaders::MeshVisualizerGL2D::Flag" << Debug::nospace; debug << "Shaders::MeshVisualizerGL2D::Flag" << Debug::nospace;
@ -1561,6 +1729,9 @@ Debug& operator<<(Debug& debug, const MeshVisualizerGL2D::Flag value) {
#endif #endif
#ifndef MAGNUM_TARGET_GLES2 #ifndef MAGNUM_TARGET_GLES2
_c(UniformBuffers) _c(UniformBuffers)
#ifndef MAGNUM_TARGET_WEBGL
_c(ShaderStorageBuffers)
#endif
_c(MultiDraw) _c(MultiDraw)
_c(TextureArrays) _c(TextureArrays)
_c(DynamicPerVertexJointCount) _c(DynamicPerVertexJointCount)
@ -1579,6 +1750,11 @@ Debug& operator<<(Debug& debug, const MeshVisualizerGL3D::Flag value) {
`Flag::InstancedObjectId|Flag(0x4000)` in the output. */ `Flag::InstancedObjectId|Flag(0x4000)` in the output. */
if(value == MeshVisualizerGL3D::Flag(UnsignedInt(MeshVisualizerGL3D::Flag::InstancedObjectId|MeshVisualizerGL3D::Flag::ObjectIdTexture))) if(value == MeshVisualizerGL3D::Flag(UnsignedInt(MeshVisualizerGL3D::Flag::InstancedObjectId|MeshVisualizerGL3D::Flag::ObjectIdTexture)))
return debug << MeshVisualizerGL3D::Flag::InstancedObjectId << Debug::nospace << "|" << Debug::nospace << 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 #endif
debug << "Shaders::MeshVisualizerGL3D::Flag" << Debug::nospace; debug << "Shaders::MeshVisualizerGL3D::Flag" << Debug::nospace;
@ -1611,6 +1787,9 @@ Debug& operator<<(Debug& debug, const MeshVisualizerGL3D::Flag value) {
#endif #endif
#ifndef MAGNUM_TARGET_GLES2 #ifndef MAGNUM_TARGET_GLES2
_c(UniformBuffers) _c(UniformBuffers)
#ifndef MAGNUM_TARGET_WEBGL
_c(ShaderStorageBuffers)
#endif
_c(MultiDraw) _c(MultiDraw)
_c(TextureArrays) _c(TextureArrays)
_c(DynamicPerVertexJointCount) _c(DynamicPerVertexJointCount)
@ -1647,7 +1826,15 @@ Debug& operator<<(Debug& debug, const MeshVisualizerGL2D::Flags value) {
MeshVisualizerGL2D::Flag::PrimitiveId, MeshVisualizerGL2D::Flag::PrimitiveId,
#endif #endif
#ifndef MAGNUM_TARGET_GLES2 #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 */ MeshVisualizerGL2D::Flag::MultiDraw, /* Superset of UniformBuffers */
#ifndef MAGNUM_TARGET_WEBGL
MeshVisualizerGL2D::Flag::ShaderStorageBuffers, /* Superset of UniformBuffers */
#endif
MeshVisualizerGL2D::Flag::UniformBuffers, MeshVisualizerGL2D::Flag::UniformBuffers,
MeshVisualizerGL2D::Flag::TextureArrays, MeshVisualizerGL2D::Flag::TextureArrays,
MeshVisualizerGL2D::Flag::DynamicPerVertexJointCount, MeshVisualizerGL2D::Flag::DynamicPerVertexJointCount,
@ -1687,7 +1874,15 @@ Debug& operator<<(Debug& debug, const MeshVisualizerGL3D::Flags value) {
MeshVisualizerGL3D::Flag::PrimitiveId, MeshVisualizerGL3D::Flag::PrimitiveId,
#endif #endif
#ifndef MAGNUM_TARGET_GLES2 #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 */ MeshVisualizerGL3D::Flag::MultiDraw, /* Superset of UniformBuffers */
#ifndef MAGNUM_TARGET_WEBGL
MeshVisualizerGL3D::Flag::ShaderStorageBuffers, /* Superset of UniformBuffers */
#endif
MeshVisualizerGL3D::Flag::UniformBuffers, MeshVisualizerGL3D::Flag::UniformBuffers,
MeshVisualizerGL3D::Flag::TextureArrays, MeshVisualizerGL3D::Flag::TextureArrays,
MeshVisualizerGL3D::Flag::DynamicPerVertexJointCount, 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, PrimitiveIdFromVertexId = (1 << 5)|PrimitiveId,
/* bit 6, 7, 8, 9 used by 3D-specific TBN visualization */ /* bit 6, 7, 8, 9 used by 3D-specific TBN visualization */
UniformBuffers = 1 << 10, UniformBuffers = 1 << 10,
ShaderStorageBuffers = UniformBuffers|(1 << 19),
MultiDraw = UniformBuffers|(1 << 11), MultiDraw = UniformBuffers|(1 << 11),
TextureArrays = 1 << 17, TextureArrays = 1 << 17,
DynamicPerVertexJointCount = 1 << 18 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 * Use uniform buffers. Expects that uniform data are supplied via
* @ref bindTransformationProjectionBuffer(), @ref bindDrawBuffer() * @ref bindTransformationProjectionBuffer(), @ref bindDrawBuffer()
* and @ref bindMaterialBuffer() instead of direct uniform setters. * and @ref bindMaterialBuffer() instead of direct uniform setters.
* @see @ref Flag::ShaderStorageBuffers
* @requires_gl31 Extension @gl_extension{ARB,uniform_buffer_object} * @requires_gl31 Extension @gl_extension{ARB,uniform_buffer_object}
* @requires_gles30 Uniform buffers are not available in OpenGL ES * @requires_gles30 Uniform buffers are not available in OpenGL ES
* 2.0. * 2.0.
@ -499,6 +501,24 @@ class MAGNUM_SHADERS_EXPORT MeshVisualizerGL2D: public Implementation::MeshVisua
*/ */
UniformBuffers = 1 << 10, 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 * Enable multidraw functionality. Implies @ref Flag::UniformBuffers
* and combines the value from @ref setDrawOffset() with the * 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(). * matrices accepted by @ref setJointMatrices() / @ref setJointMatrix().
* If @ref Flag::UniformBuffers is set, this is the statically defined * If @ref Flag::UniformBuffers is set, this is the statically defined
* size of the @ref TransformationUniform2D uniform buffer bound with * 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() * @see @ref Configuration::setJointCount()
* @requires_gles30 Not defined on OpenGL ES 2.0 builds. * @requires_gles30 Not defined on OpenGL ES 2.0 builds.
* @requires_webgl20 Not defined on WebGL 1.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 * Statically defined size of the @ref MeshVisualizerMaterialUniform
* uniform buffer bound with @ref bindMaterialBuffer(). Has use only if * 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() * @see @ref Configuration::setMaterialCount()
* @requires_gles30 Not defined on OpenGL ES 2.0 builds. * @requires_gles30 Not defined on OpenGL ES 2.0 builds.
* @requires_webgl20 Not defined on WebGL 1.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 TransformationProjectionUniform2D and
* @ref MeshVisualizerDrawUniform2D uniform buffers bound with * @ref MeshVisualizerDrawUniform2D uniform buffers bound with
* @ref bindTransformationProjectionBuffer() and @ref bindDrawBuffer(). * @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() * @see @ref Configuration::setDrawCount()
* @requires_gles30 Not defined on OpenGL ES 2.0 builds. * @requires_gles30 Not defined on OpenGL ES 2.0 builds.
* @requires_webgl20 Not defined on WebGL 1.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 #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. * 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) * @return Reference to self (for method chaining)
* @m_since_latest * @m_since_latest
* *
@ -1035,7 +1058,7 @@ class MAGNUM_SHADERS_EXPORT MeshVisualizerGL2D: public Implementation::MeshVisua
MeshVisualizerGL2D& bindTransformationProjectionBuffer(GL::Buffer& buffer, GLintptr offset, GLsizeiptr size); 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) * @return Reference to self (for method chaining)
* @m_since_latest * @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) * @return Reference to self (for method chaining)
* @m_since_latest * @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) * @return Reference to self (for method chaining)
* @m_since_latest * @m_since_latest
* *
@ -1216,9 +1239,10 @@ class MAGNUM_SHADERS_EXPORT MeshVisualizerGL2D::Configuration {
* @ref TransformationUniform2D buffer bound with * @ref TransformationUniform2D buffer bound with
* @ref bindJointBuffer(). Uniform buffers have a statically defined * @ref bindJointBuffer(). Uniform buffers have a statically defined
* size and @cpp count*sizeof(TransformationUniform2D) @ce has to be * size and @cpp count*sizeof(TransformationUniform2D) @ce has to be
* within @ref GL::AbstractShaderProgram::maxUniformBlockSize(). The * within @ref GL::AbstractShaderProgram::maxUniformBlockSize(), if
* per-vertex joints then index into the array offset by * @ref Flag::ShaderStorageBuffers is set as well, the buffer is
* @ref MeshVisualizerDrawUniform2D::jointOffset. * 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 * The @p perVertexCount and @p secondaryPerVertexCount parameters
* describe how many components are taken from @ref JointIds / * 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 * @cpp 4 @ce, setting either of these to @cpp 0 @ce means given
* attribute is not used at all. If both @p perVertexCount and * attribute is not used at all. If both @p perVertexCount and
* @p secondaryPerVertexCount are set to @cpp 0 @ce, skinning is not * @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 * performed. Unless @ref Flag::ShaderStorageBuffers is set, if either
* non-zero as well. * of them is non-zero, @p count is expected to be non-zero as well.
* *
* Default value for all three is @cpp 0 @ce. * Default value for all three is @cpp 0 @ce.
* @see @ref MeshVisualizerGL2D::jointCount(), * @see @ref MeshVisualizerGL2D::jointCount(),
@ -1259,11 +1283,11 @@ class MAGNUM_SHADERS_EXPORT MeshVisualizerGL2D::Configuration {
* @ref MeshVisualizerMaterialUniform buffer bound with * @ref MeshVisualizerMaterialUniform buffer bound with
* @ref bindMaterialBuffer(). Uniform buffers have a statically defined * @ref bindMaterialBuffer(). Uniform buffers have a statically defined
* size and @cpp count*sizeof(MeshVisualizerMaterialUniform) @ce has to * size and @cpp count*sizeof(MeshVisualizerMaterialUniform) @ce has to
* be within @ref GL::AbstractShaderProgram::maxUniformBlockSize(). * be within @ref GL::AbstractShaderProgram::maxUniformBlockSize(), if
* * @ref Flag::ShaderStorageBuffers is set as well, the buffer is
* The per-draw materials are then specified via * unbounded and @p count is ignored. The per-draw materials are
* @ref MeshVisualizerDrawUniform2D::materialId. Default value is * specified via @ref MeshVisualizerDrawUniform2D::materialId. Default
* @cpp 1 @ce. * value is @cpp 1 @ce.
* *
* If @ref Flag::UniformBuffers isn't set, this value is ignored. * If @ref Flag::UniformBuffers isn't set, this value is ignored.
* @see @ref setFlags(), @ref setDrawCount(), * @see @ref setFlags(), @ref setDrawCount(),
@ -1297,10 +1321,10 @@ class MAGNUM_SHADERS_EXPORT MeshVisualizerGL2D::Configuration {
* @cpp count*sizeof(TransformationProjectionUniform2D) @ce, * @cpp count*sizeof(TransformationProjectionUniform2D) @ce,
* @cpp count*sizeof(MeshVisualizerDrawUniform2D) @ce and * @cpp count*sizeof(MeshVisualizerDrawUniform2D) @ce and
* @cpp count*sizeof(TextureTransformationUniform) @ce has to be within * @cpp count*sizeof(TextureTransformationUniform) @ce has to be within
* @ref GL::AbstractShaderProgram::maxUniformBlockSize(). * @ref GL::AbstractShaderProgram::maxUniformBlockSize(), if
* * @ref Flag::ShaderStorageBuffers is set as well, the buffers are
* The draw offset is then set via @ref setDrawOffset(). Default value * unbounded and @p count is ignored. The draw offset is set via
* is @cpp 1 @ce. * @ref setDrawOffset(). Default value is @cpp 1 @ce.
* *
* If @ref Flag::UniformBuffers isn't set, this value is ignored. * If @ref Flag::UniformBuffers isn't set, this value is ignored.
* @see @ref setFlags(), @ref setMaterialCount(), * @see @ref setFlags(), @ref setMaterialCount(),
@ -2175,6 +2199,7 @@ class MAGNUM_SHADERS_EXPORT MeshVisualizerGL3D: public Implementation::MeshVisua
* @ref bindProjectionBuffer(), @ref bindTransformationBuffer(), * @ref bindProjectionBuffer(), @ref bindTransformationBuffer(),
* @ref bindDrawBuffer() and @ref bindMaterialBuffer() instead of * @ref bindDrawBuffer() and @ref bindMaterialBuffer() instead of
* direct uniform setters. * direct uniform setters.
* @see @ref Flag::ShaderStorageBuffers
* @requires_gl31 Extension @gl_extension{ARB,uniform_buffer_object} * @requires_gl31 Extension @gl_extension{ARB,uniform_buffer_object}
* @requires_gles30 Uniform buffers are not available in OpenGL ES * @requires_gles30 Uniform buffers are not available in OpenGL ES
* 2.0. * 2.0.
@ -2184,6 +2209,24 @@ class MAGNUM_SHADERS_EXPORT MeshVisualizerGL3D: public Implementation::MeshVisua
*/ */
UniformBuffers = 1 << 10, 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 * Enable multidraw functionality. Implies @ref Flag::UniformBuffers
* and combines the value from @ref setDrawOffset() with the * 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(). * matrices accepted by @ref setJointMatrices() / @ref setJointMatrix().
* If @ref Flag::UniformBuffers is set, this is the statically defined * If @ref Flag::UniformBuffers is set, this is the statically defined
* size of the @ref TransformationUniform3D uniform buffer bound with * 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() * @see @ref Configuration::setJointCount()
* @requires_gles30 Not defined on OpenGL ES 2.0 builds. * @requires_gles30 Not defined on OpenGL ES 2.0 builds.
* @requires_webgl20 Not defined on WebGL 1.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 * Statically defined size of the @ref MeshVisualizerMaterialUniform
* uniform buffer bound with @ref bindMaterialBuffer(). Has use only if * 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() * @see @ref Configuration::setMaterialCount()
* @requires_gles30 Not defined on OpenGL ES 2.0 builds. * @requires_gles30 Not defined on OpenGL ES 2.0 builds.
* @requires_webgl20 Not defined on WebGL 1.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 TransformationUniform3D and
* @ref MeshVisualizerDrawUniform3D uniform buffers, bound with * @ref MeshVisualizerDrawUniform3D uniform buffers, bound with
* @ref bindTransformationBuffer() and @ref bindDrawBuffer(). Has use * @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() * @see @ref Configuration::setDrawCount()
* @requires_gles30 Not defined on OpenGL ES 2.0 builds. * @requires_gles30 Not defined on OpenGL ES 2.0 builds.
* @requires_webgl20 Not defined on WebGL 1.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 #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. * 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) * @return Reference to self (for method chaining)
* @m_since_latest * @m_since_latest
* *
@ -2927,7 +2973,7 @@ class MAGNUM_SHADERS_EXPORT MeshVisualizerGL3D: public Implementation::MeshVisua
MeshVisualizerGL3D& bindProjectionBuffer(GL::Buffer& buffer, GLintptr offset, GLsizeiptr size); 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) * @return Reference to self (for method chaining)
* @m_since_latest * @m_since_latest
* *
@ -2947,7 +2993,7 @@ class MAGNUM_SHADERS_EXPORT MeshVisualizerGL3D: public Implementation::MeshVisua
MeshVisualizerGL3D& bindTransformationBuffer(GL::Buffer& buffer, GLintptr offset, GLsizeiptr size); 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) * @return Reference to self (for method chaining)
* @m_since_latest * @m_since_latest
* *
@ -2968,7 +3014,7 @@ class MAGNUM_SHADERS_EXPORT MeshVisualizerGL3D: public Implementation::MeshVisua
MeshVisualizerGL3D& bindDrawBuffer(GL::Buffer& buffer, GLintptr offset, GLsizeiptr size); 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) * @return Reference to self (for method chaining)
* @m_since_latest * @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) * @return Reference to self (for method chaining)
* @m_since_latest * @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) * @return Reference to self (for method chaining)
* @m_since_latest * @m_since_latest
* *
@ -3208,9 +3254,10 @@ class MeshVisualizerGL3D::Configuration {
* @ref TransformationUniform3D buffer bound with * @ref TransformationUniform3D buffer bound with
* @ref bindJointBuffer(). Uniform buffers have a statically defined * @ref bindJointBuffer(). Uniform buffers have a statically defined
* size and @cpp count*sizeof(TransformationUniform3D) @ce has to be * size and @cpp count*sizeof(TransformationUniform3D) @ce has to be
* within @ref GL::AbstractShaderProgram::maxUniformBlockSize(). The * within @ref GL::AbstractShaderProgram::maxUniformBlockSize(), if
* per-vertex joints then index into the array offset by * @ref Flag::ShaderStorageBuffers is set as well, the buffer is
* @ref MeshVisualizerDrawUniform3D::jointOffset. * 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 * The @p perVertexCount and @p secondaryPerVertexCount parameters
* describe how many components are taken from @ref JointIds / * 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 * @cpp 4 @ce, setting either of these to @cpp 0 @ce means given
* attribute is not used at all. If both @p perVertexCount and * attribute is not used at all. If both @p perVertexCount and
* @p secondaryPerVertexCount are set to @cpp 0 @ce, skinning is not * @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 * performed. Unless @ref Flag::ShaderStorageBuffers is set, if either
* non-zero as well. * of them is non-zero, @p count is expected to be non-zero as well.
* *
* Default value for all three is @cpp 0 @ce. * Default value for all three is @cpp 0 @ce.
* @see @ref MeshVisualizerGL2D::jointCount(), * @see @ref MeshVisualizerGL2D::jointCount(),
@ -3251,11 +3298,11 @@ class MeshVisualizerGL3D::Configuration {
* @ref MeshVisualizerMaterialUniform buffer bound with * @ref MeshVisualizerMaterialUniform buffer bound with
* @ref bindMaterialBuffer(). Uniform buffers have a statically defined * @ref bindMaterialBuffer(). Uniform buffers have a statically defined
* size and @cpp count*sizeof(MeshVisualizerMaterialUniform) @ce has to * size and @cpp count*sizeof(MeshVisualizerMaterialUniform) @ce has to
* be within @ref GL::AbstractShaderProgram::maxUniformBlockSize(). * be within @ref GL::AbstractShaderProgram::maxUniformBlockSize(), if
* * @ref Flag::ShaderStorageBuffers is set as well, the buffer is
* The per-draw materials are then specified via * unbounded and @p count is ignored. The per-draw materials are
* @ref MeshVisualizerDrawUniform3D::materialId. Default value is * specified via @ref MeshVisualizerDrawUniform3D::materialId. Default
* @cpp 1 @ce. * value is @cpp 1 @ce.
* *
* If @ref Flag::UniformBuffers isn't set, this value is ignored. * If @ref Flag::UniformBuffers isn't set, this value is ignored.
* @see @ref setFlags(), @ref setDrawCount(), * @see @ref setFlags(), @ref setDrawCount(),
@ -3289,10 +3336,10 @@ class MeshVisualizerGL3D::Configuration {
* @cpp count*sizeof(TransformationUniform3D) @ce, * @cpp count*sizeof(TransformationUniform3D) @ce,
* @cpp count*sizeof(MeshVisualizerDrawUniform3D) @ce and * @cpp count*sizeof(MeshVisualizerDrawUniform3D) @ce and
* @cpp count*sizeof(TextureTransformationUniform) @ce has to be within * @cpp count*sizeof(TextureTransformationUniform) @ce has to be within
* @ref GL::AbstractShaderProgram::maxUniformBlockSize(). * @ref GL::AbstractShaderProgram::maxUniformBlockSize(), if
* * @ref Flag::ShaderStorageBuffers is set as well, the buffers are
* The draw offset is then set via @ref setDrawOffset(). Default value * unbounded and @p count is ignored. The draw offset is set via
* is @cpp 1 @ce. * @ref setDrawOffset(). Default value is @cpp 1 @ce.
* *
* If @ref Flag::UniformBuffers isn't set, this value is ignored. * If @ref Flag::UniformBuffers isn't set, this value is ignored.
* @see @ref setFlags(), @ref setMaterialCount(), * @see @ref setFlags(), @ref setMaterialCount(),

48
src/Magnum/Shaders/Phong.frag

@ -27,6 +27,10 @@
#extension GL_EXT_gpu_shader4: require #extension GL_EXT_gpu_shader4: require
#endif #endif
#if defined(SHADER_STORAGE_BUFFERS) && !defined(GL_ES)
#extension GL_ARB_shader_storage_buffer_object: require
#endif
#ifndef NEW_GLSL #ifndef NEW_GLSL
#define in varying #define in varying
#define fragmentColor gl_FragColor #define fragmentColor gl_FragColor
@ -159,11 +163,25 @@ uniform lowp float lightRanges[LIGHT_COUNT]
; ;
#endif #endif
/* Uniform buffers */ /* Uniform / shader storage buffers */
#else #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 #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 #ifdef EXPLICIT_UNIFORM_LOCATION
layout(location = 0) layout(location = 0)
#endif #endif
@ -191,11 +209,11 @@ struct DrawUniform {
}; };
layout(std140 layout(std140
#ifdef EXPLICIT_BINDING #if defined(EXPLICIT_BINDING) || defined(SHADER_STORAGE_BUFFERS)
, binding = 2 , binding = 2
#endif #endif
) uniform Draw { ) BUFFER_OR_UNIFORM Draw {
DrawUniform draws[DRAW_COUNT]; BUFFER_READONLY DrawUniform draws[DRAW_COUNT];
}; };
struct MaterialUniform { struct MaterialUniform {
@ -209,14 +227,16 @@ struct MaterialUniform {
}; };
layout(std140 layout(std140
#ifdef EXPLICIT_BINDING #if defined(EXPLICIT_BINDING) || defined(SHADER_STORAGE_BUFFERS)
, binding = 4 , binding = 4
#endif #endif
) uniform Material { ) BUFFER_OR_UNIFORM Material {
MaterialUniform materials[MATERIAL_COUNT]; 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 { struct LightUniform {
highp vec4 position; highp vec4 position;
lowp vec3 colorReserved; lowp vec3 colorReserved;
@ -228,11 +248,11 @@ struct LightUniform {
}; };
layout(std140 layout(std140
#ifdef EXPLICIT_BINDING #if defined(EXPLICIT_BINDING) || defined(SHADER_STORAGE_BUFFERS)
, binding = 5 , binding = 5
#endif #endif
) uniform Light { ) BUFFER_OR_UNIFORM Light {
LightUniform lights[LIGHT_COUNT]; BUFFER_READONLY LightUniform lights[LIGHT_COUNT];
}; };
#endif #endif
#endif #endif
@ -364,7 +384,9 @@ void main() {
#ifdef OBJECT_ID #ifdef OBJECT_ID
highp const uint objectId = draws[drawId].draw_objectId; highp const uint objectId = draws[drawId].draw_objectId;
#endif #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; mediump const uint materialId = draws[drawId].draw_materialIdReserved & 0xffffu;
#else #else
#define materialId 0u #define materialId 0u

55
src/Magnum/Shaders/Phong.vert

@ -31,6 +31,10 @@
#extension GL_ARB_shader_bit_encoding: require #extension GL_ARB_shader_bit_encoding: require
#endif #endif
#if defined(SHADER_STORAGE_BUFFERS) && !defined(GL_ES)
#extension GL_ARB_shader_storage_buffer_object: require
#endif
#ifdef MULTI_DRAW #ifdef MULTI_DRAW
#ifndef GL_ES #ifndef GL_ES
#extension GL_ARB_shader_draw_parameters: require #extension GL_ARB_shader_draw_parameters: require
@ -128,10 +132,27 @@ layout(location = PER_INSTANCE_JOINT_COUNT_LOCATION)
uniform uint perInstanceJointCount; /* defaults to zero */ uniform uint perInstanceJointCount; /* defaults to zero */
#endif #endif
/* Uniform buffers */ /* Uniform / shader storage buffers */
#else #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 #ifdef EXPLICIT_UNIFORM_LOCATION
layout(location = 0) layout(location = 0)
#endif #endif
@ -169,36 +190,36 @@ struct DrawUniform {
}; };
layout(std140 layout(std140
#ifdef EXPLICIT_BINDING #if defined(EXPLICIT_BINDING) || defined(SHADER_STORAGE_BUFFERS)
, binding = 2 , binding = 2
#endif #endif
) uniform Draw { ) BUFFER_OR_UNIFORM Draw {
DrawUniform draws[DRAW_COUNT]; BUFFER_READONLY DrawUniform draws[DRAW_COUNT];
}; };
layout(std140 layout(std140
#ifdef EXPLICIT_BINDING #if defined(EXPLICIT_BINDING) || defined(SHADER_STORAGE_BUFFERS)
, binding = 0 , binding = 0
#endif #endif
) uniform Projection { ) BUFFER_OR_UNIFORM Projection {
highp mat4 projectionMatrix; BUFFER_READONLY highp mat4 projectionMatrix;
}; };
layout(std140 layout(std140
#ifdef EXPLICIT_BINDING #if defined(EXPLICIT_BINDING) || defined(SHADER_STORAGE_BUFFERS)
, binding = 1 , binding = 1
#endif #endif
) uniform Transformation { ) BUFFER_OR_UNIFORM Transformation {
highp mat4 transformationMatrices[DRAW_COUNT]; BUFFER_READONLY highp mat4 transformationMatrices[DRAW_COUNT];
}; };
#ifdef JOINT_COUNT #ifdef JOINT_COUNT
layout(std140 layout(std140
#ifdef EXPLICIT_BINDING #if defined(EXPLICIT_BINDING) || defined(SHADER_STORAGE_BUFFERS)
, binding = 6 , binding = 6
#endif #endif
) uniform Joint { ) BUFFER_OR_UNIFORM Joint {
highp mat4 jointMatrices[JOINT_COUNT]; BUFFER_READONLY highp mat4 jointMatrices[JOINT_COUNT];
}; };
#endif #endif
@ -211,11 +232,11 @@ struct TextureTransformationUniform {
}; };
layout(std140 layout(std140
#ifdef EXPLICIT_BINDING #if defined(EXPLICIT_BINDING) || defined(SHADER_STORAGE_BUFFERS)
, binding = 3 , binding = 3
#endif #endif
) uniform TextureTransformation { ) BUFFER_OR_UNIFORM TextureTransformation {
TextureTransformationUniform textureTransformations[DRAW_COUNT]; BUFFER_READONLY TextureTransformationUniform textureTransformations[DRAW_COUNT];
}; };
#endif #endif
#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}); "Shaders::PhongGL: Bitangent attribute binding conflicts with the ObjectId attribute, use a Tangent4 attribute with instanced object ID rendering instead", CompileState{NoCreate});
#endif #endif
#ifndef MAGNUM_TARGET_GLES2 #ifndef CORRADE_NO_ASSERT
CORRADE_ASSERT(!(configuration.flags() >= Flag::UniformBuffers) || configuration.materialCount(), #if !defined(MAGNUM_TARGET_GLES2) && !defined(MAGNUM_TARGET_WEBGL)
"Shaders::PhongGL: material count can't be zero", CompileState{NoCreate}); if(!(configuration.flags() >= Flag::ShaderStorageBuffers))
CORRADE_ASSERT(!(configuration.flags() >= Flag::UniformBuffers) || configuration.drawCount(), #endif
"Shaders::PhongGL: draw count can't be zero", CompileState{NoCreate}); {
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 #endif
#ifndef MAGNUM_TARGET_GLES2 #ifndef MAGNUM_TARGET_GLES2
@ -131,6 +142,15 @@ PhongGL::CompileState PhongGL::compile(const Configuration& configuration) {
if(configuration.flags() >= Flag::UniformBuffers) if(configuration.flags() >= Flag::UniformBuffers)
MAGNUM_ASSERT_GL_EXTENSION_SUPPORTED(GL::Extensions::ARB::uniform_buffer_object); MAGNUM_ASSERT_GL_EXTENSION_SUPPORTED(GL::Extensions::ARB::uniform_buffer_object);
#endif #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 #ifndef MAGNUM_TARGET_GLES2
if(configuration.flags() >= Flag::MultiDraw) { if(configuration.flags() >= Flag::MultiDraw) {
#ifndef MAGNUM_TARGET_GLES #ifndef MAGNUM_TARGET_GLES
@ -252,9 +272,15 @@ PhongGL::CompileState PhongGL::compile(const Configuration& configuration) {
#endif #endif
{ {
vert.addSource(Utility::format( vert.addSource(Utility::format(
"#define JOINT_COUNT {}\n" /* SSBOs have an unbounded joints array */
"#define PER_VERTEX_JOINT_COUNT {}u\n" #ifndef MAGNUM_TARGET_WEBGL
"#define SECONDARY_PER_VERTEX_JOINT_COUNT {}u\n", 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.jointCount(),
configuration.perVertexJointCount(), configuration.perVertexJointCount(),
configuration.secondaryPerVertexJointCount())); configuration.secondaryPerVertexJointCount()));
@ -264,7 +290,7 @@ PhongGL::CompileState PhongGL::compile(const Configuration& configuration) {
#ifndef MAGNUM_TARGET_WEBGL #ifndef MAGNUM_TARGET_WEBGL
/* The _LOCATION is needed only if explicit uniform location (desktop / /* The _LOCATION is needed only if explicit uniform location (desktop /
ES3.1) is supported, a plain string can be added otherwise. This is 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 #ifndef MAGNUM_TARGET_GLES
if(context.isExtensionSupported<GL::Extensions::ARB::explicit_uniform_location>(version)) if(context.isExtensionSupported<GL::Extensions::ARB::explicit_uniform_location>(version))
#else #else
@ -284,10 +310,21 @@ PhongGL::CompileState PhongGL::compile(const Configuration& configuration) {
#endif #endif
#ifndef MAGNUM_TARGET_GLES2 #ifndef MAGNUM_TARGET_GLES2
if(configuration.flags() >= Flag::UniformBuffers) { if(configuration.flags() >= Flag::UniformBuffers) {
vert.addSource(Utility::format( #ifndef MAGNUM_TARGET_WEBGL
"#define UNIFORM_BUFFERS\n" /* SSBOs have unbounded per-draw arrays so just a plain string can be
"#define DRAW_COUNT {}\n", passed */
configuration.drawCount())); 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); vert.addSource(configuration.flags() >= Flag::MultiDraw ? "#define MULTI_DRAW\n"_s : ""_s);
} }
#endif #endif
@ -316,15 +353,22 @@ PhongGL::CompileState PhongGL::compile(const Configuration& configuration) {
#ifndef MAGNUM_TARGET_GLES2 #ifndef MAGNUM_TARGET_GLES2
if(configuration.flags() >= Flag::UniformBuffers) { if(configuration.flags() >= Flag::UniformBuffers) {
frag.addSource(Utility::format( frag.addSource(Utility::format(
"#define UNIFORM_BUFFERS\n" #ifndef MAGNUM_TARGET_WEBGL
"#define DRAW_COUNT {}\n" /* SSBOs have unbounded per-draw, material and light arrays */
"#define MATERIAL_COUNT {}\n" configuration.flags() >= Flag::ShaderStorageBuffers ?
"#define LIGHT_COUNT {}\n" "#define UNIFORM_BUFFERS\n"
"#define PER_DRAW_LIGHT_COUNT {}\n", "#define SHADER_STORAGE_BUFFERS\n"
configuration.drawCount(), "#define PER_DRAW_LIGHT_COUNT {3}\n" :
configuration.materialCount(), #endif
configuration.lightCount(), "#define UNIFORM_BUFFERS\n"
configuration.perDrawLightCount())); "#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) frag.addSource(configuration.flags() >= Flag::MultiDraw ? "#define MULTI_DRAW\n"_s : ""_s)
.addSource(configuration.flags() >= Flag::LightCulling ? "#define LIGHT_CULLING\n"_s : ""_s); .addSource(configuration.flags() >= Flag::LightCulling ? "#define LIGHT_CULLING\n"_s : ""_s);
} else } else
@ -469,7 +513,11 @@ PhongGL::PhongGL(CompileState&& state): PhongGL{static_cast<PhongGL&&>(std::move
if(_flags >= Flag::DynamicPerVertexJointCount) if(_flags >= Flag::DynamicPerVertexJointCount)
_perVertexJointCountUniform = uniformLocation("perVertexJointCount"_s); _perVertexJointCountUniform = uniformLocation("perVertexJointCount"_s);
if(_flags >= Flag::UniformBuffers) { 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 } else
#endif #endif
{ {
@ -524,7 +572,12 @@ PhongGL::PhongGL(CompileState&& state): PhongGL{static_cast<PhongGL&&>(std::move
} }
#ifndef MAGNUM_TARGET_GLES2 #ifndef MAGNUM_TARGET_GLES2
if(_flags >= Flag::ObjectIdTexture) setUniform(uniformLocation("objectIdTextureData"_s), ObjectIdTextureUnit); 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("Projection"_s), ProjectionBufferBinding);
setUniformBlockBinding(uniformBlockIndex("Transformation"_s), TransformationBufferBinding); setUniformBlockBinding(uniformBlockIndex("Transformation"_s), TransformationBufferBinding);
setUniformBlockBinding(uniformBlockIndex("Draw"_s), DrawBufferBinding); setUniformBlockBinding(uniformBlockIndex("Draw"_s), DrawBufferBinding);
@ -940,51 +993,84 @@ PhongGL& PhongGL::setPerInstanceJointCount(const UnsignedInt count) {
PhongGL& PhongGL::setDrawOffset(const UnsignedInt offset) { PhongGL& PhongGL::setDrawOffset(const UnsignedInt offset) {
CORRADE_ASSERT(_flags >= Flag::UniformBuffers, CORRADE_ASSERT(_flags >= Flag::UniformBuffers,
"Shaders::PhongGL::setDrawOffset(): the shader was not created with uniform buffers enabled", *this); "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, CORRADE_ASSERT(offset < _drawCount,
"Shaders::PhongGL::setDrawOffset(): draw offset" << offset << "is out of bounds for" << _drawCount << "draws", *this); "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; return *this;
} }
PhongGL& PhongGL::bindProjectionBuffer(GL::Buffer& buffer) { PhongGL& PhongGL::bindProjectionBuffer(GL::Buffer& buffer) {
CORRADE_ASSERT(_flags >= Flag::UniformBuffers, CORRADE_ASSERT(_flags >= Flag::UniformBuffers,
"Shaders::PhongGL::bindProjectionBuffer(): the shader was not created with uniform buffers enabled", *this); "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; return *this;
} }
PhongGL& PhongGL::bindProjectionBuffer(GL::Buffer& buffer, const GLintptr offset, const GLsizeiptr size) { PhongGL& PhongGL::bindProjectionBuffer(GL::Buffer& buffer, const GLintptr offset, const GLsizeiptr size) {
CORRADE_ASSERT(_flags >= Flag::UniformBuffers, CORRADE_ASSERT(_flags >= Flag::UniformBuffers,
"Shaders::PhongGL::bindProjectionBuffer(): the shader was not created with uniform buffers enabled", *this); "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; return *this;
} }
PhongGL& PhongGL::bindTransformationBuffer(GL::Buffer& buffer) { PhongGL& PhongGL::bindTransformationBuffer(GL::Buffer& buffer) {
CORRADE_ASSERT(_flags >= Flag::UniformBuffers, CORRADE_ASSERT(_flags >= Flag::UniformBuffers,
"Shaders::PhongGL::bindTransformationBuffer(): the shader was not created with uniform buffers enabled", *this); "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; return *this;
} }
PhongGL& PhongGL::bindTransformationBuffer(GL::Buffer& buffer, const GLintptr offset, const GLsizeiptr size) { PhongGL& PhongGL::bindTransformationBuffer(GL::Buffer& buffer, const GLintptr offset, const GLsizeiptr size) {
CORRADE_ASSERT(_flags >= Flag::UniformBuffers, CORRADE_ASSERT(_flags >= Flag::UniformBuffers,
"Shaders::PhongGL::bindTransformationBuffer(): the shader was not created with uniform buffers enabled", *this); "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; return *this;
} }
PhongGL& PhongGL::bindDrawBuffer(GL::Buffer& buffer) { PhongGL& PhongGL::bindDrawBuffer(GL::Buffer& buffer) {
CORRADE_ASSERT(_flags >= Flag::UniformBuffers, CORRADE_ASSERT(_flags >= Flag::UniformBuffers,
"Shaders::PhongGL::bindDrawBuffer(): the shader was not created with uniform buffers enabled", *this); "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; return *this;
} }
PhongGL& PhongGL::bindDrawBuffer(GL::Buffer& buffer, const GLintptr offset, const GLsizeiptr size) { PhongGL& PhongGL::bindDrawBuffer(GL::Buffer& buffer, const GLintptr offset, const GLsizeiptr size) {
CORRADE_ASSERT(_flags >= Flag::UniformBuffers, CORRADE_ASSERT(_flags >= Flag::UniformBuffers,
"Shaders::PhongGL::bindDrawBuffer(): the shader was not created with uniform buffers enabled", *this); "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; 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); "Shaders::PhongGL::bindTextureTransformationBuffer(): the shader was not created with uniform buffers enabled", *this);
CORRADE_ASSERT(_flags & Flag::TextureTransformation, CORRADE_ASSERT(_flags & Flag::TextureTransformation,
"Shaders::PhongGL::bindTextureTransformationBuffer(): the shader was not created with texture transformation enabled", *this); "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; 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); "Shaders::PhongGL::bindTextureTransformationBuffer(): the shader was not created with uniform buffers enabled", *this);
CORRADE_ASSERT(_flags & Flag::TextureTransformation, CORRADE_ASSERT(_flags & Flag::TextureTransformation,
"Shaders::PhongGL::bindTextureTransformationBuffer(): the shader was not created with texture transformation enabled", *this); "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; return *this;
} }
PhongGL& PhongGL::bindMaterialBuffer(GL::Buffer& buffer) { PhongGL& PhongGL::bindMaterialBuffer(GL::Buffer& buffer) {
CORRADE_ASSERT(_flags >= Flag::UniformBuffers, CORRADE_ASSERT(_flags >= Flag::UniformBuffers,
"Shaders::PhongGL::bindMaterialBuffer(): the shader was not created with uniform buffers enabled", *this); "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; return *this;
} }
PhongGL& PhongGL::bindMaterialBuffer(GL::Buffer& buffer, const GLintptr offset, const GLsizeiptr size) { PhongGL& PhongGL::bindMaterialBuffer(GL::Buffer& buffer, const GLintptr offset, const GLsizeiptr size) {
CORRADE_ASSERT(_flags >= Flag::UniformBuffers, CORRADE_ASSERT(_flags >= Flag::UniformBuffers,
"Shaders::PhongGL::bindMaterialBuffer(): the shader was not created with uniform buffers enabled", *this); "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; return *this;
} }
PhongGL& PhongGL::bindLightBuffer(GL::Buffer& buffer) { PhongGL& PhongGL::bindLightBuffer(GL::Buffer& buffer) {
CORRADE_ASSERT(_flags >= Flag::UniformBuffers, CORRADE_ASSERT(_flags >= Flag::UniformBuffers,
"Shaders::PhongGL::bindLightBuffer(): the shader was not created with uniform buffers enabled", *this); "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; return *this;
} }
PhongGL& PhongGL::bindLightBuffer(GL::Buffer& buffer, const GLintptr offset, const GLsizeiptr size) { PhongGL& PhongGL::bindLightBuffer(GL::Buffer& buffer, const GLintptr offset, const GLsizeiptr size) {
CORRADE_ASSERT(_flags >= Flag::UniformBuffers, CORRADE_ASSERT(_flags >= Flag::UniformBuffers,
"Shaders::PhongGL::bindLightBuffer(): the shader was not created with uniform buffers enabled", *this); "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; return *this;
} }
PhongGL& PhongGL::bindJointBuffer(GL::Buffer& buffer) { PhongGL& PhongGL::bindJointBuffer(GL::Buffer& buffer) {
CORRADE_ASSERT(_flags >= Flag::UniformBuffers, CORRADE_ASSERT(_flags >= Flag::UniformBuffers,
"Shaders::PhongGL::bindJointBuffer(): the shader was not created with uniform buffers enabled", *this); "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; return *this;
} }
PhongGL& PhongGL::bindJointBuffer(GL::Buffer& buffer, const GLintptr offset, const GLsizeiptr size) { PhongGL& PhongGL::bindJointBuffer(GL::Buffer& buffer, const GLintptr offset, const GLsizeiptr size) {
CORRADE_ASSERT(_flags >= Flag::UniformBuffers, CORRADE_ASSERT(_flags >= Flag::UniformBuffers,
"Shaders::PhongGL::bindJointBuffer(): the shader was not created with uniform buffers enabled", *this); "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; return *this;
} }
#endif #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) { PhongGL::Configuration& PhongGL::Configuration::setLightCount(const UnsignedInt count, const UnsignedInt perDrawCount) {
CORRADE_ASSERT(!count == !perDrawCount, CORRADE_ASSERT(perDrawCount || !count,
"Shaders::PhongGL::Configuration::setLightCount(): count has to be non-zero iff per-draw count is non-zero", *this); "Shaders::PhongGL::Configuration::setLightCount(): count has to be zero if per-draw count is 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);
_lightCount = count; _lightCount = count;
_perDrawLightCount = perDrawCount; _perDrawLightCount = perDrawCount;
return *this; 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); "Shaders::PhongGL::Configuration::setJointCount(): expected at most 4 per-vertex joints, got" << perVertexCount, *this);
CORRADE_ASSERT(secondaryPerVertexCount <= 4, CORRADE_ASSERT(secondaryPerVertexCount <= 4,
"Shaders::PhongGL::Configuration::setJointCount(): expected at most 4 secondary per-vertex joints, got" << secondaryPerVertexCount, *this); "Shaders::PhongGL::Configuration::setJointCount(): expected at most 4 secondary per-vertex joints, got" << secondaryPerVertexCount, *this);
CORRADE_ASSERT(!count == (!perVertexCount && !secondaryPerVertexCount), CORRADE_ASSERT(perVertexCount || secondaryPerVertexCount || !count,
"Shaders::PhongGL::Configuration::setJointCount(): count has to be non-zero iff (secondary) per-vertex joint count is non-zero", *this); "Shaders::PhongGL::Configuration::setJointCount(): count has to be zero if per-vertex joint count is zero", *this);
_jointCount = count; _jointCount = count;
_perVertexJointCount = perVertexCount; _perVertexJointCount = perVertexCount;
_secondaryPerVertexJointCount = secondaryPerVertexCount; _secondaryPerVertexJointCount = secondaryPerVertexCount;
@ -1202,6 +1318,11 @@ Debug& operator<<(Debug& debug, const PhongGL::Flag value) {
`Flag::InstancedObjectId|Flag(0x20000)` in the output. */ `Flag::InstancedObjectId|Flag(0x20000)` in the output. */
if(value == PhongGL::Flag(UnsignedInt(PhongGL::Flag::InstancedObjectId|PhongGL::Flag::ObjectIdTexture))) if(value == PhongGL::Flag(UnsignedInt(PhongGL::Flag::InstancedObjectId|PhongGL::Flag::ObjectIdTexture)))
return debug << PhongGL::Flag::InstancedObjectId << Debug::nospace << "|" << Debug::nospace << 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 #endif
debug << "Shaders::PhongGL::Flag" << Debug::nospace; debug << "Shaders::PhongGL::Flag" << Debug::nospace;
@ -1226,6 +1347,9 @@ Debug& operator<<(Debug& debug, const PhongGL::Flag value) {
_c(InstancedTextureOffset) _c(InstancedTextureOffset)
#ifndef MAGNUM_TARGET_GLES2 #ifndef MAGNUM_TARGET_GLES2
_c(UniformBuffers) _c(UniformBuffers)
#ifndef MAGNUM_TARGET_WEBGL
_c(ShaderStorageBuffers)
#endif
_c(MultiDraw) _c(MultiDraw)
_c(TextureArrays) _c(TextureArrays)
_c(LightCulling) _c(LightCulling)
@ -1263,7 +1387,15 @@ Debug& operator<<(Debug& debug, const PhongGL::Flags value) {
#endif #endif
PhongGL::Flag::InstancedTransformation, PhongGL::Flag::InstancedTransformation,
#ifndef MAGNUM_TARGET_GLES2 #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 */ PhongGL::Flag::MultiDraw, /* Superset of UniformBuffers */
#ifndef MAGNUM_TARGET_WEBGL
PhongGL::Flag::ShaderStorageBuffers, /* Superset of UniformBuffers */
#endif
PhongGL::Flag::UniformBuffers, PhongGL::Flag::UniformBuffers,
PhongGL::Flag::TextureArrays, PhongGL::Flag::TextureArrays,
PhongGL::Flag::LightCulling, 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 bindDrawBuffer(), @ref bindTextureTransformationBuffer(),
* @ref bindMaterialBuffer() and @ref bindLightBuffer() instead of * @ref bindMaterialBuffer() and @ref bindLightBuffer() instead of
* direct uniform setters. * direct uniform setters.
* @see @ref Flag::ShaderStorageBuffers
* @requires_gl31 Extension @gl_extension{ARB,uniform_buffer_object} * @requires_gl31 Extension @gl_extension{ARB,uniform_buffer_object}
* @requires_gles30 Uniform buffers are not available in OpenGL ES * @requires_gles30 Uniform buffers are not available in OpenGL ES
* 2.0. * 2.0.
@ -798,6 +799,25 @@ class MAGNUM_SHADERS_EXPORT PhongGL: public GL::AbstractShaderProgram {
*/ */
UniformBuffers = 1 << 12, 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 * Enable multidraw functionality. Implies @ref Flag::UniformBuffers
* and adds the value from @ref setDrawOffset() with the * 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 * If @ref Flag::UniformBuffers is set, this is the statically defined
* size of the @ref PhongLightUniform uniform buffer bound with * 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() * @see @ref perDrawLightCount(), @ref Configuration::setLightCount()
*/ */
UnsignedInt lightCount() const { return _lightCount; } UnsignedInt lightCount() const { return _lightCount; }
@ -1060,7 +1081,8 @@ class MAGNUM_SHADERS_EXPORT PhongGL: public GL::AbstractShaderProgram {
* matrices accepted by @ref setJointMatrices() / @ref setJointMatrix(). * matrices accepted by @ref setJointMatrices() / @ref setJointMatrix().
* If @ref Flag::UniformBuffers is set, this is the statically defined * If @ref Flag::UniformBuffers is set, this is the statically defined
* size of the @ref TransformationUniform3D uniform buffer bound with * 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() * @see @ref Configuration::setJointCount()
* @requires_gles30 Not defined on OpenGL ES 2.0 builds. * @requires_gles30 Not defined on OpenGL ES 2.0 builds.
* @requires_webgl20 Not defined on WebGL 1.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 * Statically defined size of the @ref PhongMaterialUniform uniform
* buffer bound with @ref bindMaterialBuffer(). Has use only if * 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() * @see @ref Configuration::setMaterialCount()
* @requires_gles30 Not defined on OpenGL ES 2.0 builds. * @requires_gles30 Not defined on OpenGL ES 2.0 builds.
* @requires_webgl20 Not defined on WebGL 1.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 * @ref PhongDrawUniform and @ref TextureTransformationUniform uniform
* buffers bound with @ref bindTransformationBuffer(), * buffers bound with @ref bindTransformationBuffer(),
* @ref bindDrawBuffer() and @ref bindTextureTransformationBuffer(). * @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() * @see @ref Configuration::setDrawCount()
* @requires_gles30 Not defined on OpenGL ES 2.0 builds. * @requires_gles30 Not defined on OpenGL ES 2.0 builds.
* @requires_webgl20 Not defined on WebGL 1.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 #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. * Used if @ref Flag::UniformBuffers is set.
*/ */
@ -1721,7 +1745,7 @@ class MAGNUM_SHADERS_EXPORT PhongGL: public GL::AbstractShaderProgram {
PhongGL& setDrawOffset(UnsignedInt offset); 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) * @return Reference to self (for method chaining)
* @m_since_latest * @m_since_latest
* *
@ -1742,7 +1766,7 @@ class MAGNUM_SHADERS_EXPORT PhongGL: public GL::AbstractShaderProgram {
PhongGL& bindProjectionBuffer(GL::Buffer& buffer, GLintptr offset, GLsizeiptr size); 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) * @return Reference to self (for method chaining)
* @m_since_latest * @m_since_latest
* *
@ -1763,7 +1787,7 @@ class MAGNUM_SHADERS_EXPORT PhongGL: public GL::AbstractShaderProgram {
PhongGL& bindTransformationBuffer(GL::Buffer& buffer, GLintptr offset, GLsizeiptr size); 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) * @return Reference to self (for method chaining)
* @m_since_latest * @m_since_latest
* *
@ -1784,7 +1808,7 @@ class MAGNUM_SHADERS_EXPORT PhongGL: public GL::AbstractShaderProgram {
PhongGL& bindDrawBuffer(GL::Buffer& buffer, GLintptr offset, GLsizeiptr size); 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) * @return Reference to self (for method chaining)
* @m_since_latest * @m_since_latest
* *
@ -1804,7 +1828,7 @@ class MAGNUM_SHADERS_EXPORT PhongGL: public GL::AbstractShaderProgram {
PhongGL& bindTextureTransformationBuffer(GL::Buffer& buffer, GLintptr offset, GLsizeiptr size); 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) * @return Reference to self (for method chaining)
* @m_since_latest * @m_since_latest
* *
@ -1825,7 +1849,7 @@ class MAGNUM_SHADERS_EXPORT PhongGL: public GL::AbstractShaderProgram {
PhongGL& bindMaterialBuffer(GL::Buffer& buffer, GLintptr offset, GLsizeiptr size); 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) * @return Reference to self (for method chaining)
* @m_since_latest * @m_since_latest
* *
@ -1844,7 +1868,7 @@ class MAGNUM_SHADERS_EXPORT PhongGL: public GL::AbstractShaderProgram {
PhongGL& bindLightBuffer(GL::Buffer& buffer, GLintptr offset, GLsizeiptr size); 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) * @return Reference to self (for method chaining)
* @m_since_latest * @m_since_latest
* *
@ -2169,15 +2193,18 @@ class MAGNUM_SHADERS_EXPORT PhongGL::Configuration {
* @ref PhongLightUniform buffer bound with @ref bindLightBuffer(). * @ref PhongLightUniform buffer bound with @ref bindLightBuffer().
* Uniform buffers have a statically defined size and * Uniform buffers have a statically defined size and
* @cpp count*sizeof(PhongLightUniform) @ce has to be within * @cpp count*sizeof(PhongLightUniform) @ce has to be within
* @ref GL::AbstractShaderProgram::maxUniformBlockSize(). The per-draw * @ref GL::AbstractShaderProgram::maxUniformBlockSize(), if
* lights are then specified via @ref PhongDrawUniform::lightOffset and * @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. * @ref PhongDrawUniform::lightCount.
* *
* The @p perDrawCount parameter describes how many lights out of * The @p perDrawCount parameter describes how many lights out of
* @p count get applied to each draw. Useful mainly in combination with * @p count get applied to each draw. Useful mainly in combination with
* @ref Flag::LightCulling, without it can be used for conveniently * @ref Flag::LightCulling, without it can be used for conveniently
* reducing the light count without having to reduce sizes of the light * 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 * to @cpp 0 @ce, no lighting calculations are performed and only the
* ambient contribution to the color is used. If @p perDrawCount is * ambient contribution to the color is used. If @p perDrawCount is
* @cpp 0 @ce, @p count is expected to be zero as well. * @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 TransformationUniform3D buffer bound with
* @ref bindJointBuffer(). Uniform buffers have a statically defined * @ref bindJointBuffer(). Uniform buffers have a statically defined
* size and @cpp count*sizeof(TransformationUniform3D) @ce has to be * size and @cpp count*sizeof(TransformationUniform3D) @ce has to be
* within @ref GL::AbstractShaderProgram::maxUniformBlockSize(). The * within @ref GL::AbstractShaderProgram::maxUniformBlockSize(), if
* per-vertex joints then index into the array offset by * @ref Flag::ShaderStorageBuffers is set as well, the buffer is
* @ref PhongDrawUniform::jointOffset. * 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 * The @p perVertexCount and @p secondaryPerVertexCount parameters
* describe how many components are taken from @ref JointIds / * 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 * @cpp 4 @ce, setting either of these to @cpp 0 @ce means given
* attribute is not used at all. If both @p perVertexCount and * attribute is not used at all. If both @p perVertexCount and
* @p secondaryPerVertexCount are set to @cpp 0 @ce, skinning is not * @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 * performed. Unless @ref Flag::ShaderStorageBuffers is set, if either
* non-zero as well. * of them is non-zero, @p count is expected to be non-zero as well.
* *
* Default value for all three is @cpp 0 @ce. * Default value for all three is @cpp 0 @ce.
* @see @ref PhongGL::jointCount(), @ref PhongGL::perVertexJointCount(), * @see @ref PhongGL::jointCount(), @ref PhongGL::perVertexJointCount(),
@ -2276,10 +2304,11 @@ class MAGNUM_SHADERS_EXPORT PhongGL::Configuration {
* @ref PhongMaterialUniform buffer bound with * @ref PhongMaterialUniform buffer bound with
* @ref bindMaterialBuffer(). Uniform buffers have a statically defined * @ref bindMaterialBuffer(). Uniform buffers have a statically defined
* size and @cpp count*sizeof(PhongMaterialUniform) @ce has to be * size and @cpp count*sizeof(PhongMaterialUniform) @ce has to be
* within @ref GL::AbstractShaderProgram::maxUniformBlockSize(). * within @ref GL::AbstractShaderProgram::maxUniformBlockSize(), if
* * @ref Flag::ShaderStorageBuffers is set as well, the buffer is
* The per-draw materials are then specified via * unbounded and @p count is ignored. The per-draw materials are
* @ref PhongDrawUniform::materialId. Default value is @cpp 1 @ce. * specified via @ref PhongDrawUniform::materialId. Default value is
* @cpp 1 @ce.
* *
* If @ref Flag::UniformBuffers isn't set, this value is ignored. * If @ref Flag::UniformBuffers isn't set, this value is ignored.
* @see @ref setFlags(), @ref setLightCount(), @ref setDrawCount(), * @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(TransformationUniform3D) @ce,
* @cpp count*sizeof(PhongDrawUniform) @ce and * @cpp count*sizeof(PhongDrawUniform) @ce and
* @cpp count*sizeof(TextureTransformationUniform) @ce has to be within * @cpp count*sizeof(TextureTransformationUniform) @ce has to be within
* @ref GL::AbstractShaderProgram::maxUniformBlockSize(). * @ref GL::AbstractShaderProgram::maxUniformBlockSize(), if
* * @ref Flag::ShaderStorageBuffers is set as well, the buffers are
* The draw offset is then set via @ref setDrawOffset(). Default value * unbounded and @p count is ignored. The draw offset is set via
* is @cpp 1 @ce. * @ref setDrawOffset(). Default value is @cpp 1 @ce.
* *
* If @ref Flag::UniformBuffers isn't set, this value is ignored. * If @ref Flag::UniformBuffers isn't set, this value is ignored.
* @see @ref setFlags(), @ref setLightCount(), @ref setMaterialCount(), * @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 /* SwiftShader has 256 uniform vectors at most, per-draw is 4+1 in 3D case
and 3+1 in 2D, per-material 4 */ and 3+1 in 2D, per-material 4 */
{"multiple materials, draws", DistanceFieldVectorGL2D::Flag::UniformBuffers, 16, 48}, {"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 { constexpr struct {
@ -196,6 +199,7 @@ constexpr struct {
UnsignedInt materialCount, drawCount; UnsignedInt materialCount, drawCount;
const char* message; const char* message;
} ConstructUniformBuffersInvalidData[]{ } ConstructUniformBuffersInvalidData[]{
/* These two fail for UBOs but not SSBOs */
{"zero draws", DistanceFieldVectorGL2D::Flag::UniformBuffers, 1, 0, {"zero draws", DistanceFieldVectorGL2D::Flag::UniformBuffers, 1, 0,
"draw count can't be zero"}, "draw count can't be zero"},
{"zero materials", DistanceFieldVectorGL2D::Flag::UniformBuffers, 0, 1, {"zero materials", DistanceFieldVectorGL2D::Flag::UniformBuffers, 0, 1,
@ -232,21 +236,40 @@ constexpr struct {
const char* expected3D; const char* expected3D;
DistanceFieldVectorGL2D::Flags flags; DistanceFieldVectorGL2D::Flags flags;
UnsignedInt materialCount, drawCount; UnsignedInt materialCount, drawCount;
bool bindWithOffset;
UnsignedInt uniformIncrement; UnsignedInt uniformIncrement;
Float maxThreshold, meanThreshold; Float maxThreshold, meanThreshold;
} RenderMultiData[] { } RenderMultiData[] {
{"bind with offset", "multidraw2D-distancefield.tga", "multidraw3D-distancefield.tga", {"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 */ /* Minor differences on ARM Mali */
1.67f, 0.012f}, 1.67f, 0.012f},
#endif
{"draw offset", "multidraw2D-distancefield.tga", "multidraw3D-distancefield.tga", {"draw offset", "multidraw2D-distancefield.tga", "multidraw3D-distancefield.tga",
{}, 2, 3, 1, {}, 2, 3, false, 1,
/* Minor differences on ARM Mali */ /* Minor differences on ARM Mali */
1.67f, 0.012f}, 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", {"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 */ /* Minor differences on ARM Mali */
1.67f, 0.012f}, 1.67f, 0.012f},
#endif
}; };
#endif #endif
@ -312,10 +335,16 @@ DistanceFieldVectorGLTest::DistanceFieldVectorGLTest() {
&DistanceFieldVectorGLTest::renderDefaults2D, &DistanceFieldVectorGLTest::renderDefaults2D,
#ifndef MAGNUM_TARGET_GLES2 #ifndef MAGNUM_TARGET_GLES2
&DistanceFieldVectorGLTest::renderDefaults2D<DistanceFieldVectorGL2D::Flag::UniformBuffers>, &DistanceFieldVectorGLTest::renderDefaults2D<DistanceFieldVectorGL2D::Flag::UniformBuffers>,
#ifndef MAGNUM_TARGET_WEBGL
&DistanceFieldVectorGLTest::renderDefaults2D<DistanceFieldVectorGL2D::Flag::ShaderStorageBuffers>,
#endif
#endif #endif
&DistanceFieldVectorGLTest::renderDefaults3D, &DistanceFieldVectorGLTest::renderDefaults3D,
#ifndef MAGNUM_TARGET_GLES2 #ifndef MAGNUM_TARGET_GLES2
&DistanceFieldVectorGLTest::renderDefaults3D<DistanceFieldVectorGL3D::Flag::UniformBuffers>, &DistanceFieldVectorGLTest::renderDefaults3D<DistanceFieldVectorGL3D::Flag::UniformBuffers>,
#ifndef MAGNUM_TARGET_WEBGL
&DistanceFieldVectorGLTest::renderDefaults3D<DistanceFieldVectorGL3D::Flag::ShaderStorageBuffers>,
#endif
#endif #endif
}, },
&DistanceFieldVectorGLTest::renderSetup, &DistanceFieldVectorGLTest::renderSetup,
@ -326,10 +355,16 @@ DistanceFieldVectorGLTest::DistanceFieldVectorGLTest() {
&DistanceFieldVectorGLTest::render2D, &DistanceFieldVectorGLTest::render2D,
#ifndef MAGNUM_TARGET_GLES2 #ifndef MAGNUM_TARGET_GLES2
&DistanceFieldVectorGLTest::render2D<DistanceFieldVectorGL2D::Flag::UniformBuffers>, &DistanceFieldVectorGLTest::render2D<DistanceFieldVectorGL2D::Flag::UniformBuffers>,
#ifndef MAGNUM_TARGET_WEBGL
&DistanceFieldVectorGLTest::render2D<DistanceFieldVectorGL2D::Flag::ShaderStorageBuffers>,
#endif
#endif #endif
&DistanceFieldVectorGLTest::render3D, &DistanceFieldVectorGLTest::render3D,
#ifndef MAGNUM_TARGET_GLES2 #ifndef MAGNUM_TARGET_GLES2
&DistanceFieldVectorGLTest::render3D<DistanceFieldVectorGL3D::Flag::UniformBuffers>, &DistanceFieldVectorGLTest::render3D<DistanceFieldVectorGL3D::Flag::UniformBuffers>,
#ifndef MAGNUM_TARGET_WEBGL
&DistanceFieldVectorGLTest::render3D<DistanceFieldVectorGL3D::Flag::ShaderStorageBuffers>,
#endif
#endif #endif
}, },
Containers::arraySize(RenderData), 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."); CORRADE_SKIP(GL::Extensions::ARB::uniform_buffer_object::string() << "is not supported.");
#endif #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) { if(data.flags >= DistanceFieldVectorGL2D::Flag::MultiDraw) {
#ifndef MAGNUM_TARGET_GLES #ifndef MAGNUM_TARGET_GLES
if(!GL::Context::current().isExtensionSupported<GL::Extensions::ARB::shader_draw_parameters>()) 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() { template<DistanceFieldVectorGL2D::Flag flag> void DistanceFieldVectorGLTest::renderDefaults2D() {
#ifndef MAGNUM_TARGET_GLES2 #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) { if(flag == DistanceFieldVectorGL2D::Flag::UniformBuffers) {
setTestCaseTemplateName("Flag::UniformBuffers"); setTestCaseTemplateName("Flag::UniformBuffers");
@ -779,7 +839,12 @@ template<DistanceFieldVectorGL2D::Flag flag> void DistanceFieldVectorGLTest::ren
shader.draw(square); shader.draw(square);
} }
#ifndef MAGNUM_TARGET_GLES2 #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, { GL::Buffer transformationProjectionUniform{GL::Buffer::TargetHint::Uniform, {
TransformationProjectionUniform2D{} TransformationProjectionUniform2D{}
}}; }};
@ -825,6 +890,19 @@ template<DistanceFieldVectorGL2D::Flag flag> void DistanceFieldVectorGLTest::ren
template<DistanceFieldVectorGL3D::Flag flag> void DistanceFieldVectorGLTest::renderDefaults3D() { template<DistanceFieldVectorGL3D::Flag flag> void DistanceFieldVectorGLTest::renderDefaults3D() {
#ifndef MAGNUM_TARGET_GLES2 #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) { if(flag == DistanceFieldVectorGL3D::Flag::UniformBuffers) {
setTestCaseTemplateName("Flag::UniformBuffers"); setTestCaseTemplateName("Flag::UniformBuffers");
@ -868,7 +946,12 @@ template<DistanceFieldVectorGL3D::Flag flag> void DistanceFieldVectorGLTest::ren
shader.draw(plane); shader.draw(plane);
} }
#ifndef MAGNUM_TARGET_GLES2 #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, { GL::Buffer transformationProjectionUniform{GL::Buffer::TargetHint::Uniform, {
TransformationProjectionUniform3D{} TransformationProjectionUniform3D{}
}}; }};
@ -917,6 +1000,19 @@ template<DistanceFieldVectorGL2D::Flag flag> void DistanceFieldVectorGLTest::ren
setTestCaseDescription(data.name); setTestCaseDescription(data.name);
#ifndef MAGNUM_TARGET_GLES2 #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) { if(flag == DistanceFieldVectorGL2D::Flag::UniformBuffers) {
setTestCaseTemplateName("Flag::UniformBuffers"); setTestCaseTemplateName("Flag::UniformBuffers");
@ -968,7 +1064,12 @@ template<DistanceFieldVectorGL2D::Flag flag> void DistanceFieldVectorGLTest::ren
.draw(square); .draw(square);
} }
#ifndef MAGNUM_TARGET_GLES2 #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, { GL::Buffer transformationProjectionUniform{GL::Buffer::TargetHint::Uniform, {
TransformationProjectionUniform2D{} TransformationProjectionUniform2D{}
.setTransformationProjectionMatrix( .setTransformationProjectionMatrix(
@ -1026,6 +1127,19 @@ template<DistanceFieldVectorGL3D::Flag flag> void DistanceFieldVectorGLTest::ren
setTestCaseDescription(data.name); setTestCaseDescription(data.name);
#ifndef MAGNUM_TARGET_GLES2 #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) { if(flag == DistanceFieldVectorGL3D::Flag::UniformBuffers) {
setTestCaseTemplateName("Flag::UniformBuffers"); setTestCaseTemplateName("Flag::UniformBuffers");
@ -1080,7 +1194,12 @@ template<DistanceFieldVectorGL3D::Flag flag> void DistanceFieldVectorGLTest::ren
.draw(plane); .draw(plane);
} }
#ifndef MAGNUM_TARGET_GLES2 #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, { GL::Buffer transformationProjectionUniform{GL::Buffer::TargetHint::Uniform, {
TransformationProjectionUniform3D{} TransformationProjectionUniform3D{}
.setTransformationProjectionMatrix( .setTransformationProjectionMatrix(
@ -1146,6 +1265,18 @@ void DistanceFieldVectorGLTest::renderMulti2D() {
CORRADE_SKIP(GL::Extensions::ARB::uniform_buffer_object::string() << "is not supported."); CORRADE_SKIP(GL::Extensions::ARB::uniform_buffer_object::string() << "is not supported.");
#endif #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) { if(data.flags >= DistanceFieldVectorGL2D::Flag::MultiDraw) {
#ifndef MAGNUM_TARGET_GLES #ifndef MAGNUM_TARGET_GLES
if(!GL::Context::current().isExtensionSupported<GL::Extensions::ARB::shader_draw_parameters>()) 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 /* Material offsets are zero if we have single draw, as those are done with
UBO offset bindings instead. */ UBO offset bindings instead. */
drawData[0*data.uniformIncrement] = DistanceFieldVectorDrawUniform{} drawData[0*data.uniformIncrement] = DistanceFieldVectorDrawUniform{}
.setMaterialId(data.drawCount == 1 ? 0 : 0); .setMaterialId(data.bindWithOffset ? 0 : 0);
drawData[1*data.uniformIncrement] = DistanceFieldVectorDrawUniform{} drawData[1*data.uniformIncrement] = DistanceFieldVectorDrawUniform{}
.setMaterialId(data.drawCount == 1 ? 0 : 1); .setMaterialId(data.bindWithOffset ? 0 : 1);
drawData[2*data.uniformIncrement] = DistanceFieldVectorDrawUniform{} drawData[2*data.uniformIncrement] = DistanceFieldVectorDrawUniform{}
.setMaterialId(data.drawCount == 1 ? 0 : 0); .setMaterialId(data.bindWithOffset ? 0 : 0);
GL::Buffer drawUniform{GL::Buffer::TargetHint::Uniform, drawData}; GL::Buffer drawUniform{GL::Buffer::TargetHint::Uniform, drawData};
DistanceFieldVectorGL2D shader{DistanceFieldVectorGL2D::Configuration{} DistanceFieldVectorGL2D shader{DistanceFieldVectorGL2D::Configuration{}
@ -1265,8 +1396,8 @@ void DistanceFieldVectorGLTest::renderMulti2D() {
.setDrawCount(data.drawCount)}; .setDrawCount(data.drawCount)};
shader.bindVectorTexture(vector); shader.bindVectorTexture(vector);
/* Just one draw, rebinding UBOs each time */ /* Rebinding UBOs / SSBOs each time */
if(data.drawCount == 1) { if(data.bindWithOffset) {
shader.bindMaterialBuffer(materialUniform, shader.bindMaterialBuffer(materialUniform,
0*data.uniformIncrement*sizeof(DistanceFieldVectorMaterialUniform), 0*data.uniformIncrement*sizeof(DistanceFieldVectorMaterialUniform),
sizeof(DistanceFieldVectorMaterialUniform)); sizeof(DistanceFieldVectorMaterialUniform));
@ -1350,6 +1481,18 @@ void DistanceFieldVectorGLTest::renderMulti3D() {
CORRADE_SKIP(GL::Extensions::ARB::uniform_buffer_object::string() << "is not supported."); CORRADE_SKIP(GL::Extensions::ARB::uniform_buffer_object::string() << "is not supported.");
#endif #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) { if(data.flags >= DistanceFieldVectorGL2D::Flag::MultiDraw) {
#ifndef MAGNUM_TARGET_GLES #ifndef MAGNUM_TARGET_GLES
if(!GL::Context::current().isExtensionSupported<GL::Extensions::ARB::shader_draw_parameters>()) 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 /* Material offsets are zero if we have single draw, as those are done with
UBO offset bindings instead. */ UBO offset bindings instead. */
drawData[0*data.uniformIncrement] = DistanceFieldVectorDrawUniform{} drawData[0*data.uniformIncrement] = DistanceFieldVectorDrawUniform{}
.setMaterialId(data.drawCount == 1 ? 0 : 0); .setMaterialId(data.bindWithOffset ? 0 : 0);
drawData[1*data.uniformIncrement] = DistanceFieldVectorDrawUniform{} drawData[1*data.uniformIncrement] = DistanceFieldVectorDrawUniform{}
.setMaterialId(data.drawCount == 1 ? 0 : 1); .setMaterialId(data.bindWithOffset ? 0 : 1);
drawData[2*data.uniformIncrement] = DistanceFieldVectorDrawUniform{} drawData[2*data.uniformIncrement] = DistanceFieldVectorDrawUniform{}
.setMaterialId(data.drawCount == 1 ? 0 : 0); .setMaterialId(data.bindWithOffset ? 0 : 0);
GL::Buffer drawUniform{GL::Buffer::TargetHint::Uniform, drawData}; GL::Buffer drawUniform{GL::Buffer::TargetHint::Uniform, drawData};
DistanceFieldVectorGL3D shader{DistanceFieldVectorGL3D::Configuration{} DistanceFieldVectorGL3D shader{DistanceFieldVectorGL3D::Configuration{}
@ -1474,8 +1617,8 @@ void DistanceFieldVectorGLTest::renderMulti3D() {
.setDrawCount(data.drawCount)}; .setDrawCount(data.drawCount)};
shader.bindVectorTexture(vector); shader.bindVectorTexture(vector);
/* Just one draw, rebinding UBOs each time */ /* Rebinding UBOs / SSBOs each time */
if(data.drawCount == 1) { if(data.bindWithOffset) {
shader.bindMaterialBuffer(materialUniform, shader.bindMaterialBuffer(materialUniform,
0*data.uniformIncrement*sizeof(DistanceFieldVectorMaterialUniform), 0*data.uniformIncrement*sizeof(DistanceFieldVectorMaterialUniform),
sizeof(DistanceFieldVectorMaterialUniform)); sizeof(DistanceFieldVectorMaterialUniform));

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

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

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

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

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

@ -143,13 +143,26 @@ void LineGL_Test::debugFlagsSupersets() {
std::ostringstream out; std::ostringstream out;
Debug{&out} << (LineGL3D::Flag::ObjectId|LineGL3D::Flag::InstancedObjectId); Debug{&out} << (LineGL3D::Flag::ObjectId|LineGL3D::Flag::InstancedObjectId);
CORRADE_COMPARE(out.str(), "Shaders::LineGL::Flag::InstancedObjectId\n"); 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; std::ostringstream out;
Debug{&out} << (LineGL3D::Flag::MultiDraw|LineGL3D::Flag::UniformBuffers); Debug{&out} << (LineGL3D::Flag::MultiDraw|LineGL3D::Flag::UniformBuffers);
CORRADE_COMPARE(out.str(), "Shaders::LineGL::Flag::MultiDraw\n"); 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"}, "expected at most 4 secondary per-vertex joints, got 5"},
{"joint count but no per-vertex joint count", {"joint count but no per-vertex joint count",
10, 0, 0, 10, 0, 0,
"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"},
{"per-vertex joint count but no joint count", /* The rest depends on flags being set and is thus verified in constructor,
0, 2, 0, tested in MeshVisualizerGLTest::constructInvalid() and
"count has to be non-zero iff (secondary) per-vertex joint count is non-zero"}, constructUniformBuffersInvalid() */
{"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"},
}; };
#endif #endif
@ -243,12 +240,24 @@ void MeshVisualizerGL_Test::debugFlagsSupersets2D() {
CORRADE_COMPARE(out.str(), "Shaders::MeshVisualizerGL2D::Flag::InstancedTextureOffset\n"); 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; std::ostringstream out;
Debug{&out} << (MeshVisualizerGL2D::Flag::MultiDraw|MeshVisualizerGL2D::Flag::UniformBuffers); Debug{&out} << (MeshVisualizerGL2D::Flag::MultiDraw|MeshVisualizerGL2D::Flag::UniformBuffers);
CORRADE_COMPARE(out.str(), "Shaders::MeshVisualizerGL2D::Flag::MultiDraw\n"); 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() { void MeshVisualizerGL_Test::debugFlagsSupersets3D() {
@ -276,12 +285,24 @@ void MeshVisualizerGL_Test::debugFlagsSupersets3D() {
CORRADE_COMPARE(out.str(), "Shaders::MeshVisualizerGL3D::Flag::InstancedTextureOffset\n"); 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; std::ostringstream out;
Debug{&out} << (MeshVisualizerGL3D::Flag::MultiDraw|MeshVisualizerGL3D::Flag::UniformBuffers); Debug{&out} << (MeshVisualizerGL3D::Flag::MultiDraw|MeshVisualizerGL3D::Flag::UniformBuffers);
CORRADE_COMPARE(out.str(), "Shaders::MeshVisualizerGL3D::Flag::MultiDraw\n"); 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 #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; UnsignedInt count, perDrawCount;
const char* message; const char* message;
} ConfigurationSetLightCountInvalidData[] { } 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", {"count but no per-draw count",
10, 0, 10, 0,
"count has to be non-zero iff per-draw count is non-zero"}, "count has to be zero if per-draw count is zero"},
{"per-draw count but no count", /* The rest depends on flags being set and is thus verified in constructor,
0, 2, tested in PhongGLTest::constructInvalid() and
"count has to be non-zero iff per-draw count is non-zero"}, constructUniformBuffersInvalid() */
}; };
#ifndef MAGNUM_TARGET_GLES2 #ifndef MAGNUM_TARGET_GLES2
@ -80,13 +77,10 @@ const struct {
"expected at most 4 secondary per-vertex joints, got 5"}, "expected at most 4 secondary per-vertex joints, got 5"},
{"joint count but no per-vertex joint count", {"joint count but no per-vertex joint count",
10, 0, 0, 10, 0, 0,
"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"},
{"per-vertex joint count but no joint count", /* The rest depends on flags being set and is thus verified in constructor,
0, 2, 0, tested in PhongGLTest::constructInvalid() and
"count has to be non-zero iff (secondary) per-vertex joint count is non-zero"}, constructUniformBuffersInvalid() */
{"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"},
}; };
#endif #endif
@ -195,12 +189,24 @@ void PhongGL_Test::debugFlagsSupersets() {
} }
#ifndef MAGNUM_TARGET_GLES2 #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; std::ostringstream out;
Debug{&out} << (PhongGL::Flag::MultiDraw|PhongGL::Flag::UniformBuffers); Debug{&out} << (PhongGL::Flag::MultiDraw|PhongGL::Flag::UniformBuffers);
CORRADE_COMPARE(out.str(), "Shaders::PhongGL::Flag::MultiDraw\n"); 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 #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 /* SwiftShader has 256 uniform vectors at most, per-draw is 4+1 in 3D case
and 3+1 in 2D, per-material 3 */ and 3+1 in 2D, per-material 3 */
{"multiple materials, draws", VectorGL2D::Flag::UniformBuffers, 15, 42}, {"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 #endif
@ -197,6 +200,7 @@ constexpr struct {
UnsignedInt materialCount, drawCount; UnsignedInt materialCount, drawCount;
const char* message; const char* message;
} ConstructUniformBuffersInvalidData[]{ } ConstructUniformBuffersInvalidData[]{
/* These two fail for UBOs but not SSBOs */
{"zero draws", VectorGL2D::Flag::UniformBuffers, 1, 0, {"zero draws", VectorGL2D::Flag::UniformBuffers, 1, 0,
"draw count can't be zero"}, "draw count can't be zero"},
{"zero materials", VectorGL2D::Flag::UniformBuffers, 0, 1, {"zero materials", VectorGL2D::Flag::UniformBuffers, 0, 1,
@ -228,21 +232,40 @@ constexpr struct {
const char* expected3D; const char* expected3D;
VectorGL2D::Flags flags; VectorGL2D::Flags flags;
UnsignedInt materialCount, drawCount; UnsignedInt materialCount, drawCount;
bool bindWithOffset;
UnsignedInt uniformIncrement; UnsignedInt uniformIncrement;
Float maxThreshold, meanThreshold; Float maxThreshold, meanThreshold;
} RenderMultiData[] { } RenderMultiData[] {
{"bind with offset", "multidraw2D.tga", "multidraw3D.tga", {"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 */ /* Minor differences on ARM Mali */
1.34f, 0.02f}, 1.34f, 0.02f},
#endif
{"draw offset", "multidraw2D.tga", "multidraw3D.tga", {"draw offset", "multidraw2D.tga", "multidraw3D.tga",
{}, 2, 3, 1, {}, 2, 3, false, 1,
/* Minor differences on ARM Mali */ /* Minor differences on ARM Mali */
1.34f, 0.02f}, 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", {"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 */ /* Minor differences on ARM Mali */
1.34f, 0.02f}, 1.34f, 0.02f},
#endif
}; };
#endif #endif
@ -308,10 +331,16 @@ VectorGLTest::VectorGLTest() {
&VectorGLTest::renderDefaults2D, &VectorGLTest::renderDefaults2D,
#ifndef MAGNUM_TARGET_GLES2 #ifndef MAGNUM_TARGET_GLES2
&VectorGLTest::renderDefaults2D<VectorGL2D::Flag::UniformBuffers>, &VectorGLTest::renderDefaults2D<VectorGL2D::Flag::UniformBuffers>,
#ifndef MAGNUM_TARGET_WEBGL
&VectorGLTest::renderDefaults2D<VectorGL2D::Flag::ShaderStorageBuffers>,
#endif
#endif #endif
&VectorGLTest::renderDefaults3D, &VectorGLTest::renderDefaults3D,
#ifndef MAGNUM_TARGET_GLES2 #ifndef MAGNUM_TARGET_GLES2
&VectorGLTest::renderDefaults3D<VectorGL3D::Flag::UniformBuffers>, &VectorGLTest::renderDefaults3D<VectorGL3D::Flag::UniformBuffers>,
#ifndef MAGNUM_TARGET_WEBGL
&VectorGLTest::renderDefaults3D<VectorGL3D::Flag::ShaderStorageBuffers>,
#endif
#endif #endif
}, },
&VectorGLTest::renderSetup, &VectorGLTest::renderSetup,
@ -322,10 +351,16 @@ VectorGLTest::VectorGLTest() {
&VectorGLTest::render2D, &VectorGLTest::render2D,
#ifndef MAGNUM_TARGET_GLES2 #ifndef MAGNUM_TARGET_GLES2
&VectorGLTest::render2D<VectorGL2D::Flag::UniformBuffers>, &VectorGLTest::render2D<VectorGL2D::Flag::UniformBuffers>,
#ifndef MAGNUM_TARGET_WEBGL
&VectorGLTest::render2D<VectorGL2D::Flag::ShaderStorageBuffers>,
#endif
#endif #endif
&VectorGLTest::render3D, &VectorGLTest::render3D,
#ifndef MAGNUM_TARGET_GLES2 #ifndef MAGNUM_TARGET_GLES2
&VectorGLTest::render3D<VectorGL3D::Flag::UniformBuffers>, &VectorGLTest::render3D<VectorGL3D::Flag::UniformBuffers>,
#ifndef MAGNUM_TARGET_WEBGL
&VectorGLTest::render3D<VectorGL3D::Flag::ShaderStorageBuffers>,
#endif
#endif #endif
}, },
Containers::arraySize(RenderData), 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."); CORRADE_SKIP(GL::Extensions::ARB::uniform_buffer_object::string() << "is not supported.");
#endif #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) { if(data.flags >= VectorGL2D::Flag::MultiDraw) {
#ifndef MAGNUM_TARGET_GLES #ifndef MAGNUM_TARGET_GLES
if(!GL::Context::current().isExtensionSupported<GL::Extensions::ARB::shader_draw_parameters>()) 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() { template<VectorGL2D::Flag flag> void VectorGLTest::renderDefaults2D() {
#ifndef MAGNUM_TARGET_GLES2 #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) { if(flag == VectorGL2D::Flag::UniformBuffers) {
setTestCaseTemplateName("Flag::UniformBuffers"); setTestCaseTemplateName("Flag::UniformBuffers");
@ -770,7 +830,12 @@ template<VectorGL2D::Flag flag> void VectorGLTest::renderDefaults2D() {
shader.draw(square); shader.draw(square);
} }
#ifndef MAGNUM_TARGET_GLES2 #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, { GL::Buffer transformationProjectionUniform{GL::Buffer::TargetHint::Uniform, {
TransformationProjectionUniform2D{} TransformationProjectionUniform2D{}
}}; }};
@ -807,6 +872,19 @@ template<VectorGL2D::Flag flag> void VectorGLTest::renderDefaults2D() {
template<VectorGL3D::Flag flag> void VectorGLTest::renderDefaults3D() { template<VectorGL3D::Flag flag> void VectorGLTest::renderDefaults3D() {
#ifndef MAGNUM_TARGET_GLES2 #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) { if(flag == VectorGL3D::Flag::UniformBuffers) {
setTestCaseTemplateName("Flag::UniformBuffers"); setTestCaseTemplateName("Flag::UniformBuffers");
@ -850,7 +928,12 @@ template<VectorGL3D::Flag flag> void VectorGLTest::renderDefaults3D() {
shader.draw(plane); shader.draw(plane);
} }
#ifndef MAGNUM_TARGET_GLES2 #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, { GL::Buffer transformationProjectionUniform{GL::Buffer::TargetHint::Uniform, {
TransformationProjectionUniform3D{} TransformationProjectionUniform3D{}
}}; }};
@ -890,6 +973,19 @@ template<VectorGL2D::Flag flag> void VectorGLTest::render2D() {
setTestCaseDescription(data.name); setTestCaseDescription(data.name);
#ifndef MAGNUM_TARGET_GLES2 #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) { if(flag == VectorGL2D::Flag::UniformBuffers) {
setTestCaseTemplateName("Flag::UniformBuffers"); setTestCaseTemplateName("Flag::UniformBuffers");
@ -940,7 +1036,12 @@ template<VectorGL2D::Flag flag> void VectorGLTest::render2D() {
shader.draw(square); shader.draw(square);
} }
#ifndef MAGNUM_TARGET_GLES2 #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, { GL::Buffer transformationProjectionUniform{GL::Buffer::TargetHint::Uniform, {
TransformationProjectionUniform2D{} TransformationProjectionUniform2D{}
.setTransformationProjectionMatrix( .setTransformationProjectionMatrix(
@ -996,6 +1097,19 @@ template<VectorGL3D::Flag flag> void VectorGLTest::render3D() {
setTestCaseDescription(data.name); setTestCaseDescription(data.name);
#ifndef MAGNUM_TARGET_GLES2 #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) { if(flag == VectorGL3D::Flag::UniformBuffers) {
setTestCaseTemplateName("Flag::UniformBuffers"); setTestCaseTemplateName("Flag::UniformBuffers");
@ -1048,7 +1162,12 @@ template<VectorGL3D::Flag flag> void VectorGLTest::render3D() {
shader.draw(plane); shader.draw(plane);
} }
#ifndef MAGNUM_TARGET_GLES2 #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, { GL::Buffer transformationProjectionUniform{GL::Buffer::TargetHint::Uniform, {
TransformationProjectionUniform3D{} TransformationProjectionUniform3D{}
.setTransformationProjectionMatrix( .setTransformationProjectionMatrix(
@ -1111,6 +1230,18 @@ void VectorGLTest::renderMulti2D() {
CORRADE_SKIP(GL::Extensions::ARB::uniform_buffer_object::string() << "is not supported."); CORRADE_SKIP(GL::Extensions::ARB::uniform_buffer_object::string() << "is not supported.");
#endif #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) { if(data.flags >= VectorGL2D::Flag::MultiDraw) {
#ifndef MAGNUM_TARGET_GLES #ifndef MAGNUM_TARGET_GLES
if(!GL::Context::current().isExtensionSupported<GL::Extensions::ARB::shader_draw_parameters>()) 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 /* Material offsets are zero if we have single draw, as those are done with
UBO offset bindings instead. */ UBO offset bindings instead. */
drawData[0*data.uniformIncrement] = VectorDrawUniform{} drawData[0*data.uniformIncrement] = VectorDrawUniform{}
.setMaterialId(data.drawCount == 1 ? 0 : 1); .setMaterialId(data.bindWithOffset ? 0 : 1);
drawData[1*data.uniformIncrement] = VectorDrawUniform{} drawData[1*data.uniformIncrement] = VectorDrawUniform{}
.setMaterialId(data.drawCount == 1 ? 0 : 0); .setMaterialId(data.bindWithOffset ? 0 : 0);
drawData[2*data.uniformIncrement] = VectorDrawUniform{} drawData[2*data.uniformIncrement] = VectorDrawUniform{}
.setMaterialId(data.drawCount == 1 ? 0 : 1); .setMaterialId(data.bindWithOffset ? 0 : 1);
GL::Buffer drawUniform{GL::Buffer::TargetHint::Uniform, drawData}; GL::Buffer drawUniform{GL::Buffer::TargetHint::Uniform, drawData};
VectorGL2D shader{VectorGL2D::Configuration{} VectorGL2D shader{VectorGL2D::Configuration{}
@ -1230,8 +1361,8 @@ void VectorGLTest::renderMulti2D() {
.setDrawCount(data.drawCount)}; .setDrawCount(data.drawCount)};
shader.bindVectorTexture(vector); shader.bindVectorTexture(vector);
/* Just one draw, rebinding UBOs each time */ /* Rebinding UBOs / SSBOs each time */
if(data.drawCount == 1) { if(data.bindWithOffset) {
shader.bindMaterialBuffer(materialUniform, shader.bindMaterialBuffer(materialUniform,
1*data.uniformIncrement*sizeof(VectorMaterialUniform), 1*data.uniformIncrement*sizeof(VectorMaterialUniform),
sizeof(VectorMaterialUniform)); sizeof(VectorMaterialUniform));
@ -1315,6 +1446,18 @@ void VectorGLTest::renderMulti3D() {
CORRADE_SKIP(GL::Extensions::ARB::uniform_buffer_object::string() << "is not supported."); CORRADE_SKIP(GL::Extensions::ARB::uniform_buffer_object::string() << "is not supported.");
#endif #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) { if(data.flags >= VectorGL3D::Flag::MultiDraw) {
#ifndef MAGNUM_TARGET_GLES #ifndef MAGNUM_TARGET_GLES
if(!GL::Context::current().isExtensionSupported<GL::Extensions::ARB::shader_draw_parameters>()) 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 /* Material offsets are zero if we have single draw, as those are done with
UBO offset bindings instead. */ UBO offset bindings instead. */
drawData[0*data.uniformIncrement] = VectorDrawUniform{} drawData[0*data.uniformIncrement] = VectorDrawUniform{}
.setMaterialId(data.drawCount == 1 ? 0 : 1); .setMaterialId(data.bindWithOffset ? 0 : 1);
drawData[1*data.uniformIncrement] = VectorDrawUniform{} drawData[1*data.uniformIncrement] = VectorDrawUniform{}
.setMaterialId(data.drawCount == 1 ? 0 : 0); .setMaterialId(data.bindWithOffset ? 0 : 0);
drawData[2*data.uniformIncrement] = VectorDrawUniform{} drawData[2*data.uniformIncrement] = VectorDrawUniform{}
.setMaterialId(data.drawCount == 1 ? 0 : 1); .setMaterialId(data.bindWithOffset ? 0 : 1);
GL::Buffer drawUniform{GL::Buffer::TargetHint::Uniform, drawData}; GL::Buffer drawUniform{GL::Buffer::TargetHint::Uniform, drawData};
VectorGL3D shader{VectorGL3D::Configuration{} VectorGL3D shader{VectorGL3D::Configuration{}
@ -1439,8 +1582,8 @@ void VectorGLTest::renderMulti3D() {
.setDrawCount(data.drawCount)}; .setDrawCount(data.drawCount)};
shader.bindVectorTexture(vector); shader.bindVectorTexture(vector);
/* Just one draw, rebinding UBOs each time */ /* Rebinding UBOs / SSBOs each time */
if(data.drawCount == 1) { if(data.bindWithOffset) {
shader.bindMaterialBuffer(materialUniform, shader.bindMaterialBuffer(materialUniform,
1*data.uniformIncrement*sizeof(VectorMaterialUniform), 1*data.uniformIncrement*sizeof(VectorMaterialUniform),
sizeof(VectorMaterialUniform)); sizeof(VectorMaterialUniform));

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

@ -99,10 +99,24 @@ void VectorGL_Test::debugFlags() {
#ifndef MAGNUM_TARGET_GLES2 #ifndef MAGNUM_TARGET_GLES2
void VectorGL_Test::debugFlagsSupersets() { void VectorGL_Test::debugFlagsSupersets() {
/* MultiDraw is a superset of UniformBuffers so only one should be printed */ /* MultiDraw and ShaderStorageBuffers are a superset of UniformBuffers so
std::ostringstream out; only one should be printed, but if there are both then both should be */
Debug{&out} << (VectorGL3D::Flag::MultiDraw|VectorGL3D::Flag::UniformBuffers); {
CORRADE_COMPARE(out.str(), "Shaders::VectorGL::Flag::MultiDraw\n"); 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 #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 /* 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 */ and 3 in 2D; one needs to be reserved for drawOffset */
{"multiple draws", VertexColorGL2D::Flag::UniformBuffers, 63}, {"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 #endif
@ -175,21 +178,40 @@ constexpr struct {
const char* expected3D; const char* expected3D;
VertexColorGL2D::Flags flags; VertexColorGL2D::Flags flags;
UnsignedInt drawCount; UnsignedInt drawCount;
bool bindWithOffset;
UnsignedInt uniformIncrement; UnsignedInt uniformIncrement;
Float maxThreshold, meanThreshold; Float maxThreshold, meanThreshold;
} RenderMultiData[] { } RenderMultiData[] {
{"bind with offset", "multidraw2D.tga", "multidraw3D.tga", {"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 */ /* Minor differences on ARM Mali */
0.34f, 0.01f}, 0.34f, 0.01f},
#endif
{"draw offset", "multidraw2D.tga", "multidraw3D.tga", {"draw offset", "multidraw2D.tga", "multidraw3D.tga",
{}, 3, 1, {}, 3, false, 1,
/* Minor differences on ARM Mali */ /* Minor differences on ARM Mali */
0.34f, 0.01f}, 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", {"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 */ /* Minor differences on ARM Mali */
0.34f, 0.01f} 0.34f, 0.01f}
#endif
}; };
#endif #endif
@ -240,35 +262,59 @@ VertexColorGLTest::VertexColorGLTest() {
&VertexColorGLTest::renderDefaults2D<Color3>, &VertexColorGLTest::renderDefaults2D<Color3>,
#ifndef MAGNUM_TARGET_GLES2 #ifndef MAGNUM_TARGET_GLES2
&VertexColorGLTest::renderDefaults2D<Color3, VertexColorGL2D::Flag::UniformBuffers>, &VertexColorGLTest::renderDefaults2D<Color3, VertexColorGL2D::Flag::UniformBuffers>,
#ifndef MAGNUM_TARGET_WEBGL
&VertexColorGLTest::renderDefaults2D<Color3, VertexColorGL2D::Flag::ShaderStorageBuffers>,
#endif
#endif #endif
&VertexColorGLTest::renderDefaults2D<Color4>, &VertexColorGLTest::renderDefaults2D<Color4>,
#ifndef MAGNUM_TARGET_GLES2 #ifndef MAGNUM_TARGET_GLES2
&VertexColorGLTest::renderDefaults2D<Color4, VertexColorGL2D::Flag::UniformBuffers>, &VertexColorGLTest::renderDefaults2D<Color4, VertexColorGL2D::Flag::UniformBuffers>,
#ifndef MAGNUM_TARGET_WEBGL
&VertexColorGLTest::renderDefaults2D<Color4, VertexColorGL2D::Flag::ShaderStorageBuffers>,
#endif
#endif #endif
&VertexColorGLTest::renderDefaults3D<Color3>, &VertexColorGLTest::renderDefaults3D<Color3>,
#ifndef MAGNUM_TARGET_GLES2 #ifndef MAGNUM_TARGET_GLES2
&VertexColorGLTest::renderDefaults3D<Color3, VertexColorGL3D::Flag::UniformBuffers>, &VertexColorGLTest::renderDefaults3D<Color3, VertexColorGL3D::Flag::UniformBuffers>,
#ifndef MAGNUM_TARGET_WEBGL
&VertexColorGLTest::renderDefaults3D<Color3, VertexColorGL3D::Flag::ShaderStorageBuffers>,
#endif
#endif #endif
&VertexColorGLTest::renderDefaults3D<Color4>, &VertexColorGLTest::renderDefaults3D<Color4>,
#ifndef MAGNUM_TARGET_GLES2 #ifndef MAGNUM_TARGET_GLES2
&VertexColorGLTest::renderDefaults3D<Color4, VertexColorGL3D::Flag::UniformBuffers>, &VertexColorGLTest::renderDefaults3D<Color4, VertexColorGL3D::Flag::UniformBuffers>,
#ifndef MAGNUM_TARGET_WEBGL
&VertexColorGLTest::renderDefaults3D<Color4, VertexColorGL3D::Flag::ShaderStorageBuffers>,
#endif
#endif #endif
&VertexColorGLTest::render2D<Color3>, &VertexColorGLTest::render2D<Color3>,
#ifndef MAGNUM_TARGET_GLES2 #ifndef MAGNUM_TARGET_GLES2
&VertexColorGLTest::render2D<Color3, VertexColorGL2D::Flag::UniformBuffers>, &VertexColorGLTest::render2D<Color3, VertexColorGL2D::Flag::UniformBuffers>,
#ifndef MAGNUM_TARGET_WEBGL
&VertexColorGLTest::render2D<Color3, VertexColorGL2D::Flag::ShaderStorageBuffers>,
#endif
#endif #endif
&VertexColorGLTest::render2D<Color4>, &VertexColorGLTest::render2D<Color4>,
#ifndef MAGNUM_TARGET_GLES2 #ifndef MAGNUM_TARGET_GLES2
&VertexColorGLTest::render2D<Color4, VertexColorGL2D::Flag::UniformBuffers>, &VertexColorGLTest::render2D<Color4, VertexColorGL2D::Flag::UniformBuffers>,
#ifndef MAGNUM_TARGET_WEBGL
&VertexColorGLTest::render2D<Color4, VertexColorGL2D::Flag::ShaderStorageBuffers>,
#endif
#endif #endif
&VertexColorGLTest::render3D<Color3>, &VertexColorGLTest::render3D<Color3>,
#ifndef MAGNUM_TARGET_GLES2 #ifndef MAGNUM_TARGET_GLES2
&VertexColorGLTest::render3D<Color3, VertexColorGL3D::Flag::UniformBuffers>, &VertexColorGLTest::render3D<Color3, VertexColorGL3D::Flag::UniformBuffers>,
#ifndef MAGNUM_TARGET_WEBGL
&VertexColorGLTest::render3D<Color3, VertexColorGL3D::Flag::ShaderStorageBuffers>,
#endif
#endif #endif
&VertexColorGLTest::render3D<Color4>, &VertexColorGLTest::render3D<Color4>,
#ifndef MAGNUM_TARGET_GLES2 #ifndef MAGNUM_TARGET_GLES2
&VertexColorGLTest::render3D<Color4, VertexColorGL3D::Flag::UniformBuffers>, &VertexColorGLTest::render3D<Color4, VertexColorGL3D::Flag::UniformBuffers>,
#ifndef MAGNUM_TARGET_WEBGL
&VertexColorGLTest::render3D<Color4, VertexColorGL3D::Flag::ShaderStorageBuffers>,
#endif
#endif #endif
}, },
&VertexColorGLTest::renderSetup, &VertexColorGLTest::renderSetup,
@ -355,6 +401,18 @@ template<UnsignedInt dimensions> void VertexColorGLTest::constructUniformBuffers
CORRADE_SKIP(GL::Extensions::ARB::uniform_buffer_object::string() << "is not supported."); CORRADE_SKIP(GL::Extensions::ARB::uniform_buffer_object::string() << "is not supported.");
#endif #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) { if(data.flags >= VertexColorGL2D::Flag::MultiDraw) {
#ifndef MAGNUM_TARGET_GLES #ifndef MAGNUM_TARGET_GLES
if(!GL::Context::current().isExtensionSupported<GL::Extensions::ARB::shader_draw_parameters>()) 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."); CORRADE_SKIP(GL::Extensions::ARB::uniform_buffer_object::string() << "is not supported.");
#endif #endif
/* This fails for UBOs but not SSBOs */
std::ostringstream out; std::ostringstream out;
Error redirectError{&out}; Error redirectError{&out};
VertexColorGL<dimensions>{typename VertexColorGL<dimensions>::Configuration{} VertexColorGL<dimensions>{typename VertexColorGL<dimensions>::Configuration{}
@ -580,6 +639,19 @@ void VertexColorGLTest::renderTeardown() {
template<class T, VertexColorGL2D::Flag flag> void VertexColorGLTest::renderDefaults2D() { template<class T, VertexColorGL2D::Flag flag> void VertexColorGLTest::renderDefaults2D() {
#ifndef MAGNUM_TARGET_GLES2 #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) { if(flag == VertexColorGL2D::Flag::UniformBuffers) {
setTestCaseTemplateName({T::Size == 3 ? "Color3" : "Color4", "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); shader.draw(circle);
} }
#ifndef MAGNUM_TARGET_GLES2 #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, { GL::Buffer transformationProjectionUniform{GL::Buffer::TargetHint::Uniform, {
TransformationProjectionUniform2D{} TransformationProjectionUniform2D{}
}}; }};
@ -643,6 +720,19 @@ template<class T, VertexColorGL2D::Flag flag> void VertexColorGLTest::renderDefa
template<class T, VertexColorGL2D::Flag flag> void VertexColorGLTest::renderDefaults3D() { template<class T, VertexColorGL2D::Flag flag> void VertexColorGLTest::renderDefaults3D() {
#ifndef MAGNUM_TARGET_GLES2 #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) { if(flag == VertexColorGL2D::Flag::UniformBuffers) {
setTestCaseTemplateName({T::Size == 3 ? "Color3" : "Color4", "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); shader.draw(sphere);
} }
#ifndef MAGNUM_TARGET_GLES2 #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, { GL::Buffer transformationProjectionUniform{GL::Buffer::TargetHint::Uniform, {
TransformationProjectionUniform3D{} TransformationProjectionUniform3D{}
}}; }};
@ -706,6 +801,19 @@ template<class T, VertexColorGL2D::Flag flag> void VertexColorGLTest::renderDefa
template<class T, VertexColorGL2D::Flag flag> void VertexColorGLTest::render2D() { template<class T, VertexColorGL2D::Flag flag> void VertexColorGLTest::render2D() {
#ifndef MAGNUM_TARGET_GLES2 #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) { if(flag == VertexColorGL2D::Flag::UniformBuffers) {
setTestCaseTemplateName({T::Size == 3 ? "Color3" : "Color4", "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); .draw(circle);
} }
#ifndef MAGNUM_TARGET_GLES2 #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, { GL::Buffer transformationProjectionUniform{GL::Buffer::TargetHint::Uniform, {
TransformationProjectionUniform2D{} TransformationProjectionUniform2D{}
.setTransformationProjectionMatrix(Matrix3::projection({2.1f, 2.1f})) .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() { template<class T, VertexColorGL3D::Flag flag> void VertexColorGLTest::render3D() {
#ifndef MAGNUM_TARGET_GLES2 #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) { if(flag == VertexColorGL3D::Flag::UniformBuffers) {
setTestCaseTemplateName({T::Size == 3 ? "Color3" : "Color4", "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); .draw(sphere);
} }
#ifndef MAGNUM_TARGET_GLES2 #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, { GL::Buffer transformationProjectionUniform{GL::Buffer::TargetHint::Uniform, {
TransformationProjectionUniform3D{} TransformationProjectionUniform3D{}
.setTransformationProjectionMatrix( .setTransformationProjectionMatrix(
@ -859,6 +990,18 @@ void VertexColorGLTest::renderMulti2D() {
CORRADE_SKIP(GL::Extensions::ARB::uniform_buffer_object::string() << "is not supported."); CORRADE_SKIP(GL::Extensions::ARB::uniform_buffer_object::string() << "is not supported.");
#endif #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) { if(data.flags >= VertexColorGL2D::Flag::MultiDraw) {
#ifndef MAGNUM_TARGET_GLES #ifndef MAGNUM_TARGET_GLES
if(!GL::Context::current().isExtensionSupported<GL::Extensions::ARB::shader_draw_parameters>()) if(!GL::Context::current().isExtensionSupported<GL::Extensions::ARB::shader_draw_parameters>())
@ -929,8 +1072,8 @@ void VertexColorGLTest::renderMulti2D() {
.setFlags(VertexColorGL2D::Flag::UniformBuffers|data.flags) .setFlags(VertexColorGL2D::Flag::UniformBuffers|data.flags)
.setDrawCount(data.drawCount)}; .setDrawCount(data.drawCount)};
/* Just one draw, rebinding UBOs each time */ /* Rebinding UBOs / SSBOs each time */
if(data.drawCount == 1) { if(data.bindWithOffset) {
shader.bindTransformationProjectionBuffer(transformationProjectionUniform, shader.bindTransformationProjectionBuffer(transformationProjectionUniform,
0*data.uniformIncrement*sizeof(TransformationProjectionUniform2D), 0*data.uniformIncrement*sizeof(TransformationProjectionUniform2D),
sizeof(TransformationProjectionUniform2D)); sizeof(TransformationProjectionUniform2D));
@ -989,6 +1132,18 @@ void VertexColorGLTest::renderMulti3D() {
CORRADE_SKIP(GL::Extensions::ARB::uniform_buffer_object::string() << "is not supported."); CORRADE_SKIP(GL::Extensions::ARB::uniform_buffer_object::string() << "is not supported.");
#endif #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) { if(data.flags >= VertexColorGL3D::Flag::MultiDraw) {
#ifndef MAGNUM_TARGET_GLES #ifndef MAGNUM_TARGET_GLES
if(!GL::Context::current().isExtensionSupported<GL::Extensions::ARB::shader_draw_parameters>()) if(!GL::Context::current().isExtensionSupported<GL::Extensions::ARB::shader_draw_parameters>())
@ -1062,8 +1217,8 @@ void VertexColorGLTest::renderMulti3D() {
.setFlags(VertexColorGL3D::Flag::UniformBuffers|data.flags) .setFlags(VertexColorGL3D::Flag::UniformBuffers|data.flags)
.setDrawCount(data.drawCount)}; .setDrawCount(data.drawCount)};
/* Just one draw, rebinding UBOs each time */ /* Rebinding UBOs / SSBOs each time */
if(data.drawCount == 1) { if(data.bindWithOffset) {
shader.bindTransformationProjectionBuffer(transformationProjectionUniform, shader.bindTransformationProjectionBuffer(transformationProjectionUniform,
0*data.uniformIncrement*sizeof(TransformationProjectionUniform3D), 0*data.uniformIncrement*sizeof(TransformationProjectionUniform3D),
sizeof(TransformationProjectionUniform3D)); sizeof(TransformationProjectionUniform3D));

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

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

37
src/Magnum/Shaders/Vector.frag

@ -23,6 +23,10 @@
DEALINGS IN THE SOFTWARE. DEALINGS IN THE SOFTWARE.
*/ */
#if defined(SHADER_STORAGE_BUFFERS) && !defined(GL_ES)
#extension GL_ARB_shader_storage_buffer_object: require
#endif
#ifndef NEW_GLSL #ifndef NEW_GLSL
#define in varying #define in varying
#define fragmentColor gl_FragColor #define fragmentColor gl_FragColor
@ -50,11 +54,24 @@ uniform lowp vec4 color
#endif #endif
; ;
/* Uniform buffers */ /* Uniform / shader storage buffers */
#else #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 #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 #ifdef EXPLICIT_UNIFORM_LOCATION
layout(location = 0) layout(location = 0)
#endif #endif
@ -75,11 +92,11 @@ struct DrawUniform {
}; };
layout(std140 layout(std140
#ifdef EXPLICIT_BINDING #if defined(EXPLICIT_BINDING) || defined(SHADER_STORAGE_BUFFERS)
, binding = 2 , binding = 2
#endif #endif
) uniform Draw { ) BUFFER_OR_UNIFORM Draw {
DrawUniform draws[DRAW_COUNT]; BUFFER_READONLY DrawUniform draws[DRAW_COUNT];
}; };
struct MaterialUniform { struct MaterialUniform {
@ -89,11 +106,11 @@ struct MaterialUniform {
}; };
layout(std140 layout(std140
#ifdef EXPLICIT_BINDING #if defined(EXPLICIT_BINDING) || defined(SHADER_STORAGE_BUFFERS)
, binding = 4 , binding = 4
#endif #endif
) uniform Material { ) BUFFER_OR_UNIFORM Material {
MaterialUniform materials[MATERIAL_COUNT]; BUFFER_READONLY MaterialUniform materials[MATERIAL_COUNT];
}; };
#endif #endif
@ -123,7 +140,9 @@ out lowp vec4 fragmentColor;
void main() { void main() {
#ifdef UNIFORM_BUFFERS #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; mediump const uint materialId = draws[drawId].draw_materialIdReserved & 0xffffu;
#else #else
#define materialId 0u #define materialId 0u

32
src/Magnum/Shaders/Vector.vert

@ -23,6 +23,10 @@
DEALINGS IN THE SOFTWARE. DEALINGS IN THE SOFTWARE.
*/ */
#if defined(SHADER_STORAGE_BUFFERS) && !defined(GL_ES)
#extension GL_ARB_shader_storage_buffer_object: require
#endif
#ifdef MULTI_DRAW #ifdef MULTI_DRAW
#ifndef GL_ES #ifndef GL_ES
#extension GL_ARB_shader_draw_parameters: require #extension GL_ARB_shader_draw_parameters: require
@ -73,10 +77,22 @@ uniform mediump mat3 textureMatrix
; ;
#endif #endif
/* Uniform buffers */ /* Uniform / shader storage buffers */
#else #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 #ifdef EXPLICIT_UNIFORM_LOCATION
layout(location = 0) layout(location = 0)
#endif #endif
@ -90,11 +106,11 @@ uniform highp uint drawOffset
#endif #endif
layout(std140 layout(std140
#ifdef EXPLICIT_BINDING #if defined(EXPLICIT_BINDING) || defined(SHADER_STORAGE_BUFFERS)
, binding = 1 , binding = 1
#endif #endif
) uniform TransformationProjection { ) BUFFER_OR_UNIFORM TransformationProjection {
highp BUFFER_READONLY highp
#ifdef TWO_DIMENSIONS #ifdef TWO_DIMENSIONS
/* Can't be a mat3 because of ANGLE, see DrawUniform in Phong.vert for /* Can't be a mat3 because of ANGLE, see DrawUniform in Phong.vert for
details */ details */
@ -115,11 +131,11 @@ struct TextureTransformationUniform {
}; };
layout(std140 layout(std140
#ifdef EXPLICIT_BINDING #if defined(EXPLICIT_BINDING) || defined(SHADER_STORAGE_BUFFERS)
, binding = 3 , binding = 3
#endif #endif
) uniform TextureTransformation { ) BUFFER_OR_UNIFORM TextureTransformation {
TextureTransformationUniform textureTransformations[DRAW_COUNT]; BUFFER_READONLY TextureTransformationUniform textureTransformations[DRAW_COUNT];
}; };
#endif #endif
#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) { template<UnsignedInt dimensions> typename VectorGL<dimensions>::CompileState VectorGL<dimensions>::compile(const Configuration& configuration) {
#ifndef MAGNUM_TARGET_GLES2 #if !defined(MAGNUM_TARGET_GLES2) && !defined(CORRADE_NO_ASSERT)
CORRADE_ASSERT(!(configuration.flags() >= Flag::UniformBuffers) || configuration.materialCount(), #ifndef MAGNUM_TARGET_WEBGL
"Shaders::VectorGL: material count can't be zero", CompileState{NoCreate}); if(!(configuration.flags() >= Flag::ShaderStorageBuffers))
CORRADE_ASSERT(!(configuration.flags() >= Flag::UniformBuffers) || configuration.drawCount(), #endif
"Shaders::VectorGL: draw count can't be zero", CompileState{NoCreate}); {
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 #endif
#ifndef MAGNUM_TARGET_GLES #ifndef MAGNUM_TARGET_GLES
if(configuration.flags() >= Flag::UniformBuffers) if(configuration.flags() >= Flag::UniformBuffers)
MAGNUM_ASSERT_GL_EXTENSION_SUPPORTED(GL::Extensions::ARB::uniform_buffer_object); MAGNUM_ASSERT_GL_EXTENSION_SUPPORTED(GL::Extensions::ARB::uniform_buffer_object);
#endif #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 #ifndef MAGNUM_TARGET_GLES2
if(configuration.flags() >= Flag::MultiDraw) { if(configuration.flags() >= Flag::MultiDraw) {
#ifndef MAGNUM_TARGET_GLES #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); .addSource(dimensions == 2 ? "#define TWO_DIMENSIONS\n"_s : "#define THREE_DIMENSIONS\n"_s);
#ifndef MAGNUM_TARGET_GLES2 #ifndef MAGNUM_TARGET_GLES2
if(configuration.flags() >= Flag::UniformBuffers) { if(configuration.flags() >= Flag::UniformBuffers) {
vert.addSource(Utility::format( #ifndef MAGNUM_TARGET_WEBGL
"#define UNIFORM_BUFFERS\n" /* SSBOs have unbounded per-draw arrays so just a plain string can be
"#define DRAW_COUNT {}\n", passed */
configuration.drawCount())); 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); vert.addSource(configuration.flags() >= Flag::MultiDraw ? "#define MULTI_DRAW\n"_s : ""_s);
} }
#endif #endif
@ -129,12 +154,23 @@ template<UnsignedInt dimensions> typename VectorGL<dimensions>::CompileState Vec
GL::Shader frag = Implementation::createCompatibilityShader(rs, version, GL::Shader::Type::Fragment); GL::Shader frag = Implementation::createCompatibilityShader(rs, version, GL::Shader::Type::Fragment);
#ifndef MAGNUM_TARGET_GLES2 #ifndef MAGNUM_TARGET_GLES2
if(configuration.flags() >= Flag::UniformBuffers) { if(configuration.flags() >= Flag::UniformBuffers) {
frag.addSource(Utility::format( #ifndef MAGNUM_TARGET_WEBGL
"#define UNIFORM_BUFFERS\n" /* SSBOs have unbounded per-draw arrays so just a plain string can be
"#define DRAW_COUNT {}\n" passed */
"#define MATERIAL_COUNT {}\n", if(configuration.flags() >= Flag::ShaderStorageBuffers) {
configuration.drawCount(), frag.addSource(
configuration.materialCount())); "#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(configuration.flags() >= Flag::MultiDraw ? "#define MULTI_DRAW\n"_s : ""_s);
} }
#endif #endif
@ -205,7 +241,11 @@ template<UnsignedInt dimensions> VectorGL<dimensions>::VectorGL(CompileState&& s
{ {
#ifndef MAGNUM_TARGET_GLES2 #ifndef MAGNUM_TARGET_GLES2
if(_flags >= Flag::UniformBuffers) { 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 } else
#endif #endif
{ {
@ -225,7 +265,12 @@ template<UnsignedInt dimensions> VectorGL<dimensions>::VectorGL(CompileState&& s
{ {
setUniform(uniformLocation("vectorTexture"_s), TextureUnit); setUniform(uniformLocation("vectorTexture"_s), TextureUnit);
#ifndef MAGNUM_TARGET_GLES2 #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("TransformationProjection"_s), TransformationProjectionBufferBinding);
setUniformBlockBinding(uniformBlockIndex("Draw"_s), DrawBufferBinding); setUniformBlockBinding(uniformBlockIndex("Draw"_s), DrawBufferBinding);
if(_flags & Flag::TextureTransformation) 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) { template<UnsignedInt dimensions> VectorGL<dimensions>& VectorGL<dimensions>::setDrawOffset(const UnsignedInt offset) {
CORRADE_ASSERT(_flags >= Flag::UniformBuffers, CORRADE_ASSERT(_flags >= Flag::UniformBuffers,
"Shaders::VectorGL::setDrawOffset(): the shader was not created with uniform buffers enabled", *this); "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, CORRADE_ASSERT(offset < _drawCount,
"Shaders::VectorGL::setDrawOffset(): draw offset" << offset << "is out of bounds for" << _drawCount << "draws", *this); "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; return *this;
} }
template<UnsignedInt dimensions> VectorGL<dimensions>& VectorGL<dimensions>::bindTransformationProjectionBuffer(GL::Buffer& buffer) { template<UnsignedInt dimensions> VectorGL<dimensions>& VectorGL<dimensions>::bindTransformationProjectionBuffer(GL::Buffer& buffer) {
CORRADE_ASSERT(_flags >= Flag::UniformBuffers, CORRADE_ASSERT(_flags >= Flag::UniformBuffers,
"Shaders::VectorGL::bindTransformationProjectionBuffer(): the shader was not created with uniform buffers enabled", *this); "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; return *this;
} }
template<UnsignedInt dimensions> VectorGL<dimensions>& VectorGL<dimensions>::bindTransformationProjectionBuffer(GL::Buffer& buffer, const GLintptr offset, const GLsizeiptr size) { template<UnsignedInt dimensions> VectorGL<dimensions>& VectorGL<dimensions>::bindTransformationProjectionBuffer(GL::Buffer& buffer, const GLintptr offset, const GLsizeiptr size) {
CORRADE_ASSERT(_flags >= Flag::UniformBuffers, CORRADE_ASSERT(_flags >= Flag::UniformBuffers,
"Shaders::VectorGL::bindTransformationProjectionBuffer(): the shader was not created with uniform buffers enabled", *this); "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; return *this;
} }
template<UnsignedInt dimensions> VectorGL<dimensions>& VectorGL<dimensions>::bindDrawBuffer(GL::Buffer& buffer) { template<UnsignedInt dimensions> VectorGL<dimensions>& VectorGL<dimensions>::bindDrawBuffer(GL::Buffer& buffer) {
CORRADE_ASSERT(_flags >= Flag::UniformBuffers, CORRADE_ASSERT(_flags >= Flag::UniformBuffers,
"Shaders::VectorGL::bindDrawBuffer(): the shader was not created with uniform buffers enabled", *this); "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; return *this;
} }
template<UnsignedInt dimensions> VectorGL<dimensions>& VectorGL<dimensions>::bindDrawBuffer(GL::Buffer& buffer, const GLintptr offset, const GLsizeiptr size) { template<UnsignedInt dimensions> VectorGL<dimensions>& VectorGL<dimensions>::bindDrawBuffer(GL::Buffer& buffer, const GLintptr offset, const GLsizeiptr size) {
CORRADE_ASSERT(_flags >= Flag::UniformBuffers, CORRADE_ASSERT(_flags >= Flag::UniformBuffers,
"Shaders::VectorGL::bindDrawBuffer(): the shader was not created with uniform buffers enabled", *this); "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; 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); "Shaders::VectorGL::bindTextureTransformationBuffer(): the shader was not created with uniform buffers enabled", *this);
CORRADE_ASSERT(_flags & Flag::TextureTransformation, CORRADE_ASSERT(_flags & Flag::TextureTransformation,
"Shaders::VectorGL::bindTextureTransformationBuffer(): the shader was not created with texture transformation enabled", *this); "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; 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); "Shaders::VectorGL::bindTextureTransformationBuffer(): the shader was not created with uniform buffers enabled", *this);
CORRADE_ASSERT(_flags & Flag::TextureTransformation, CORRADE_ASSERT(_flags & Flag::TextureTransformation,
"Shaders::VectorGL::bindTextureTransformationBuffer(): the shader was not created with texture transformation enabled", *this); "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; return *this;
} }
template<UnsignedInt dimensions> VectorGL<dimensions>& VectorGL<dimensions>::bindMaterialBuffer(GL::Buffer& buffer) { template<UnsignedInt dimensions> VectorGL<dimensions>& VectorGL<dimensions>::bindMaterialBuffer(GL::Buffer& buffer) {
CORRADE_ASSERT(_flags >= Flag::UniformBuffers, CORRADE_ASSERT(_flags >= Flag::UniformBuffers,
"Shaders::VectorGL::bindMaterialBuffer(): the shader was not created with uniform buffers enabled", *this); "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; return *this;
} }
template<UnsignedInt dimensions> VectorGL<dimensions>& VectorGL<dimensions>::bindMaterialBuffer(GL::Buffer& buffer, const GLintptr offset, const GLsizeiptr size) { template<UnsignedInt dimensions> VectorGL<dimensions>& VectorGL<dimensions>::bindMaterialBuffer(GL::Buffer& buffer, const GLintptr offset, const GLsizeiptr size) {
CORRADE_ASSERT(_flags >= Flag::UniformBuffers, CORRADE_ASSERT(_flags >= Flag::UniformBuffers,
"Shaders::VectorGL::bindMaterialBuffer(): the shader was not created with uniform buffers enabled", *this); "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; return *this;
} }
#endif #endif
@ -388,6 +474,14 @@ template class MAGNUM_SHADERS_EXPORT VectorGL<3>;
namespace Implementation { namespace Implementation {
Debug& operator<<(Debug& debug, const VectorGLFlag value) { 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; debug << "Shaders::VectorGL::Flag" << Debug::nospace;
switch(value) { switch(value) {
@ -396,6 +490,9 @@ Debug& operator<<(Debug& debug, const VectorGLFlag value) {
_c(TextureTransformation) _c(TextureTransformation)
#ifndef MAGNUM_TARGET_GLES2 #ifndef MAGNUM_TARGET_GLES2
_c(UniformBuffers) _c(UniformBuffers)
#ifndef MAGNUM_TARGET_WEBGL
_c(ShaderStorageBuffers)
#endif
_c(MultiDraw) _c(MultiDraw)
#endif #endif
#undef _c #undef _c
@ -409,7 +506,16 @@ Debug& operator<<(Debug& debug, const VectorGLFlags value) {
return Containers::enumSetDebugOutput(debug, value, "Shaders::VectorGL::Flags{}", { return Containers::enumSetDebugOutput(debug, value, "Shaders::VectorGL::Flags{}", {
VectorGLFlag::TextureTransformation, VectorGLFlag::TextureTransformation,
#ifndef MAGNUM_TARGET_GLES2 #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 */ VectorGLFlag::MultiDraw, /* Superset of UniformBuffers */
#ifndef MAGNUM_TARGET_WEBGL
VectorGLFlag::ShaderStorageBuffers, /* Superset of UniformBuffers */
#endif
VectorGLFlag::UniformBuffers VectorGLFlag::UniformBuffers
#endif #endif
}); });

54
src/Magnum/Shaders/VectorGL.h

@ -46,6 +46,9 @@ namespace Implementation {
TextureTransformation = 1 << 0, TextureTransformation = 1 << 0,
#ifndef MAGNUM_TARGET_GLES2 #ifndef MAGNUM_TARGET_GLES2
UniformBuffers = 1 << 1, UniformBuffers = 1 << 1,
#ifndef MAGNUM_TARGET_WEBGL
ShaderStorageBuffers = UniformBuffers|(1 << 3),
#endif
MultiDraw = UniformBuffers|(1 << 2) MultiDraw = UniformBuffers|(1 << 2)
#endif #endif
}; };
@ -172,6 +175,7 @@ template<UnsignedInt dimensions> class MAGNUM_SHADERS_EXPORT VectorGL: public GL
* @ref bindTransformationProjectionBuffer(), * @ref bindTransformationProjectionBuffer(),
* @ref bindDrawBuffer(), @ref bindTextureTransformationBuffer() * @ref bindDrawBuffer(), @ref bindTextureTransformationBuffer()
* and @ref bindMaterialBuffer() instead of direct uniform setters. * and @ref bindMaterialBuffer() instead of direct uniform setters.
* @see @ref Flag::ShaderStorageBuffers
* @requires_gl31 Extension @gl_extension{ARB,uniform_buffer_object} * @requires_gl31 Extension @gl_extension{ARB,uniform_buffer_object}
* @requires_gles30 Uniform buffers are not available in OpenGL ES * @requires_gles30 Uniform buffers are not available in OpenGL ES
* 2.0. * 2.0.
@ -181,6 +185,23 @@ template<UnsignedInt dimensions> class MAGNUM_SHADERS_EXPORT VectorGL: public GL
*/ */
UniformBuffers = 1 << 1, 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 * Enable multidraw functionality. Implies @ref Flag::UniformBuffers
* and adds the value from @ref setDrawOffset() with the * 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 * Statically defined size of the @ref VectorMaterialUniform uniform
* buffer bound with @ref bindMaterialBuffer(). Has use only if * 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() * @see @ref Configuration::setMaterialCount()
* @requires_gles30 Not defined on OpenGL ES 2.0 builds. * @requires_gles30 Not defined on OpenGL ES 2.0 builds.
* @requires_webgl20 Not defined on WebGL 1.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 TextureTransformationUniform uniform buffers bound with
* @ref bindTransformationProjectionBuffer(), @ref bindDrawBuffer() and * @ref bindTransformationProjectionBuffer(), @ref bindDrawBuffer() and
* @ref bindTextureTransformationBuffer(). Has use only if * @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() * @see @ref Configuration::setDrawCount()
* @requires_gles30 Not defined on OpenGL ES 2.0 builds. * @requires_gles30 Not defined on OpenGL ES 2.0 builds.
* @requires_webgl20 Not defined on WebGL 1.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 #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. * 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); 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) * @return Reference to self (for method chaining)
* @m_since_latest * @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); 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) * @return Reference to self (for method chaining)
* @m_since_latest * @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); 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) * @return Reference to self (for method chaining)
* @m_since_latest * @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); 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) * @return Reference to self (for method chaining)
* @m_since_latest * @m_since_latest
* *
@ -626,10 +649,11 @@ template<UnsignedInt dimensions> class VectorGL<dimensions>::Configuration {
* @ref VectorMaterialUniform buffer bound with * @ref VectorMaterialUniform buffer bound with
* @ref bindMaterialBuffer(). Uniform buffers have a statically defined * @ref bindMaterialBuffer(). Uniform buffers have a statically defined
* size and @cpp count*sizeof(VectorMaterialUniform) @ce has to be * size and @cpp count*sizeof(VectorMaterialUniform) @ce has to be
* within @ref GL::AbstractShaderProgram::maxUniformBlockSize(). * within @ref GL::AbstractShaderProgram::maxUniformBlockSize(),
* * if @ref Flag::ShaderStorageBuffers is set as well, the buffer is
* The per-draw materials are then specified via * unbounded and @p count is ignored. The per-draw materials are
* @ref VectorDrawUniform::materialId. Default value is @cpp 1 @ce. * specified via @ref VectorDrawUniform::materialId. Default value is
* @cpp 1 @ce.
* *
* If @ref Flag::UniformBuffers isn't set, this value is ignored. * If @ref Flag::UniformBuffers isn't set, this value is ignored.
* @see @ref setFlags(), @ref setDrawCount(), * @see @ref setFlags(), @ref setDrawCount(),
@ -665,10 +689,10 @@ template<UnsignedInt dimensions> class VectorGL<dimensions>::Configuration {
* @cpp count*sizeof(TransformationProjectionUniform3D) @ce, * @cpp count*sizeof(TransformationProjectionUniform3D) @ce,
* @cpp count*sizeof(VectorDrawUniform) @ce and * @cpp count*sizeof(VectorDrawUniform) @ce and
* @cpp count*sizeof(TextureTransformationUniform) @ce has to be within * @cpp count*sizeof(TextureTransformationUniform) @ce has to be within
* @ref GL::AbstractShaderProgram::maxUniformBlockSize(). * @ref GL::AbstractShaderProgram::maxUniformBlockSize(), if
* * @ref Flag::ShaderStorageBuffers is set as well, the buffer is
* The draw offset is then set via @ref setDrawOffset(). Default value * unbounded and @p count is ignored. The draw offset is then set via
* is @cpp 1 @ce. * @ref setDrawOffset(). Default value is @cpp 1 @ce.
* *
* If @ref Flag::UniformBuffers isn't set, this value is ignored. * If @ref Flag::UniformBuffers isn't set, this value is ignored.
* @see @ref setFlags(), @ref setMaterialCount(), * @see @ref setFlags(), @ref setMaterialCount(),

26
src/Magnum/Shaders/VertexColor.vert

@ -23,6 +23,10 @@
DEALINGS IN THE SOFTWARE. DEALINGS IN THE SOFTWARE.
*/ */
#if defined(SHADER_STORAGE_BUFFERS) && !defined(GL_ES)
#extension GL_ARB_shader_storage_buffer_object: require
#endif
#ifdef MULTI_DRAW #ifdef MULTI_DRAW
#ifndef GL_ES #ifndef GL_ES
#extension GL_ARB_shader_draw_parameters: require #extension GL_ARB_shader_draw_parameters: require
@ -62,10 +66,22 @@ uniform highp mat4 transformationProjectionMatrix
#error #error
#endif #endif
/* Uniform buffers */ /* Uniform / shader storage buffers */
#else #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 #ifdef EXPLICIT_UNIFORM_LOCATION
layout(location = 0) layout(location = 0)
#endif #endif
@ -79,11 +95,11 @@ uniform highp uint drawOffset
#endif #endif
layout(std140 layout(std140
#ifdef EXPLICIT_BINDING #if defined(EXPLICIT_BINDING) || defined(SHADER_STORAGE_BUFFERS)
, binding = 1 , binding = 1
#endif #endif
) uniform TransformationProjection { ) BUFFER_OR_UNIFORM TransformationProjection {
highp BUFFER_READONLY highp
#ifdef TWO_DIMENSIONS #ifdef TWO_DIMENSIONS
/* Can't be a mat3 because of ANGLE, see DrawUniform in Phong.vert for /* Can't be a mat3 because of ANGLE, see DrawUniform in Phong.vert for
details */ 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) { template<UnsignedInt dimensions> typename VertexColorGL<dimensions>::CompileState VertexColorGL<dimensions>::compile(const Configuration& configuration) {
#ifndef MAGNUM_TARGET_GLES2 #if !defined(MAGNUM_TARGET_GLES2) && !defined(CORRADE_NO_ASSERT)
CORRADE_ASSERT(!(configuration.flags() >= Flag::UniformBuffers) || configuration.drawCount(), #ifndef MAGNUM_TARGET_WEBGL
"Shaders::VertexColorGL: draw count can't be zero", CompileState{NoCreate}); 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 #endif
#ifndef MAGNUM_TARGET_GLES #ifndef MAGNUM_TARGET_GLES
if(configuration.flags() >= Flag::UniformBuffers) if(configuration.flags() >= Flag::UniformBuffers)
MAGNUM_ASSERT_GL_EXTENSION_SUPPORTED(GL::Extensions::ARB::uniform_buffer_object); MAGNUM_ASSERT_GL_EXTENSION_SUPPORTED(GL::Extensions::ARB::uniform_buffer_object);
#endif #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 #ifndef MAGNUM_TARGET_GLES2
if(configuration.flags() >= Flag::MultiDraw) { if(configuration.flags() >= Flag::MultiDraw) {
#ifndef MAGNUM_TARGET_GLES #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); vert.addSource(dimensions == 2 ? "#define TWO_DIMENSIONS\n"_s : "#define THREE_DIMENSIONS\n"_s);
#ifndef MAGNUM_TARGET_GLES2 #ifndef MAGNUM_TARGET_GLES2
if(configuration.flags() >= Flag::UniformBuffers) { if(configuration.flags() >= Flag::UniformBuffers) {
vert.addSource(Utility::format( #ifndef MAGNUM_TARGET_WEBGL
"#define UNIFORM_BUFFERS\n" /* SSBOs have unbounded per-draw arrays so just a plain string can be
"#define DRAW_COUNT {}\n", passed */
configuration.drawCount())); 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); vert.addSource(configuration.flags() >= Flag::MultiDraw ? "#define MULTI_DRAW\n"_s : ""_s);
} }
#endif #endif
@ -182,7 +207,11 @@ template<UnsignedInt dimensions> VertexColorGL<dimensions>::VertexColorGL(Compil
{ {
#ifndef MAGNUM_TARGET_GLES2 #ifndef MAGNUM_TARGET_GLES2
if(_flags >= Flag::UniformBuffers) { 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 } else
#endif #endif
{ {
@ -191,7 +220,11 @@ template<UnsignedInt dimensions> VertexColorGL<dimensions>::VertexColorGL(Compil
} }
#ifndef MAGNUM_TARGET_GLES2 #ifndef MAGNUM_TARGET_GLES2
/* SSBOs have bindings defined in the source always */
if(_flags >= Flag::UniformBuffers if(_flags >= Flag::UniformBuffers
#ifndef MAGNUM_TARGET_WEBGL
&& !(_flags >= Flag::ShaderStorageBuffers)
#endif
#ifndef MAGNUM_TARGET_GLES #ifndef MAGNUM_TARGET_GLES
&& !context.isExtensionSupported<GL::Extensions::ARB::shading_language_420pack>(state._version) && !context.isExtensionSupported<GL::Extensions::ARB::shading_language_420pack>(state._version)
#elif !defined(MAGNUM_TARGET_GLES2) && !defined(MAGNUM_TARGET_WEBGL) #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) { template<UnsignedInt dimensions> VertexColorGL<dimensions>& VertexColorGL<dimensions>::setDrawOffset(const UnsignedInt offset) {
CORRADE_ASSERT(_flags >= Flag::UniformBuffers, CORRADE_ASSERT(_flags >= Flag::UniformBuffers,
"Shaders::VertexColorGL::setDrawOffset(): the shader was not created with uniform buffers enabled", *this); "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, CORRADE_ASSERT(offset < _drawCount,
"Shaders::VertexColorGL::setDrawOffset(): draw offset" << offset << "is out of bounds for" << _drawCount << "draws", *this); "Shaders::VertexColorGL::setDrawOffset(): draw offset" << offset << "is out of bounds for" << _drawCount << "draws", *this);
#endif
if(_drawCount > 1) setUniform(_drawOffsetUniform, offset); if(_drawCount > 1) setUniform(_drawOffsetUniform, offset);
return *this; return *this;
} }
@ -252,14 +290,22 @@ template<UnsignedInt dimensions> VertexColorGL<dimensions>& VertexColorGL<dimens
template<UnsignedInt dimensions> VertexColorGL<dimensions>& VertexColorGL<dimensions>::bindTransformationProjectionBuffer(GL::Buffer& buffer) { template<UnsignedInt dimensions> VertexColorGL<dimensions>& VertexColorGL<dimensions>::bindTransformationProjectionBuffer(GL::Buffer& buffer) {
CORRADE_ASSERT(_flags >= Flag::UniformBuffers, CORRADE_ASSERT(_flags >= Flag::UniformBuffers,
"Shaders::VertexColorGL::bindTransformationProjectionBuffer(): the shader was not created with uniform buffers enabled", *this); "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; return *this;
} }
template<UnsignedInt dimensions> VertexColorGL<dimensions>& VertexColorGL<dimensions>::bindTransformationProjectionBuffer(GL::Buffer& buffer, const GLintptr offset, const GLsizeiptr size) { template<UnsignedInt dimensions> VertexColorGL<dimensions>& VertexColorGL<dimensions>::bindTransformationProjectionBuffer(GL::Buffer& buffer, const GLintptr offset, const GLsizeiptr size) {
CORRADE_ASSERT(_flags >= Flag::UniformBuffers, CORRADE_ASSERT(_flags >= Flag::UniformBuffers,
"Shaders::VertexColorGL::bindTransformationProjectionBuffer(): the shader was not created with uniform buffers enabled", *this); "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; return *this;
} }
#endif #endif
@ -270,6 +316,14 @@ template class MAGNUM_SHADERS_EXPORT VertexColorGL<3>;
namespace Implementation { namespace Implementation {
Debug& operator<<(Debug& debug, const VertexColorGLFlag value) { 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; debug << "Shaders::VertexColorGL::Flag" << Debug::nospace;
switch(value) { switch(value) {
@ -277,6 +331,9 @@ Debug& operator<<(Debug& debug, const VertexColorGLFlag value) {
#define _c(v) case VertexColorGLFlag::v: return debug << "::" #v; #define _c(v) case VertexColorGLFlag::v: return debug << "::" #v;
#ifndef MAGNUM_TARGET_GLES2 #ifndef MAGNUM_TARGET_GLES2
_c(UniformBuffers) _c(UniformBuffers)
#ifndef MAGNUM_TARGET_WEBGL
_c(ShaderStorageBuffers)
#endif
_c(MultiDraw) _c(MultiDraw)
#endif #endif
#undef _c #undef _c
@ -289,7 +346,16 @@ Debug& operator<<(Debug& debug, const VertexColorGLFlag value) {
Debug& operator<<(Debug& debug, const VertexColorGLFlags value) { Debug& operator<<(Debug& debug, const VertexColorGLFlags value) {
return Containers::enumSetDebugOutput(debug, value, "Shaders::VertexColorGL::Flags{}", { return Containers::enumSetDebugOutput(debug, value, "Shaders::VertexColorGL::Flags{}", {
#ifndef MAGNUM_TARGET_GLES2 #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 */ VertexColorGLFlag::MultiDraw, /* Superset of UniformBuffers */
#ifndef MAGNUM_TARGET_WEBGL
VertexColorGLFlag::ShaderStorageBuffers, /* Superset of UniformBuffers */
#endif
VertexColorGLFlag::UniformBuffers VertexColorGLFlag::UniformBuffers
#endif #endif
}); });

36
src/Magnum/Shaders/VertexColorGL.h

@ -45,6 +45,9 @@ namespace Implementation {
enum class VertexColorGLFlag: UnsignedByte { enum class VertexColorGLFlag: UnsignedByte {
#ifndef MAGNUM_TARGET_GLES2 #ifndef MAGNUM_TARGET_GLES2
UniformBuffers = 1 << 0, UniformBuffers = 1 << 0,
#ifndef MAGNUM_TARGET_WEBGL
ShaderStorageBuffers = UniformBuffers|(1 << 2),
#endif
MultiDraw = UniformBuffers|(1 << 1) MultiDraw = UniformBuffers|(1 << 1)
#endif #endif
}; };
@ -165,6 +168,7 @@ template<UnsignedInt dimensions> class MAGNUM_SHADERS_EXPORT VertexColorGL: publ
* Use uniform buffers. Expects that uniform data are supplied via * Use uniform buffers. Expects that uniform data are supplied via
* @ref bindTransformationProjectionBuffer() instead of direct * @ref bindTransformationProjectionBuffer() instead of direct
* uniform setters. * uniform setters.
* @see @ref Flag::ShaderStorageBuffers
* @requires_gl31 Extension @gl_extension{ARB,uniform_buffer_object} * @requires_gl31 Extension @gl_extension{ARB,uniform_buffer_object}
* @requires_gles30 Uniform buffers are not available in OpenGL ES * @requires_gles30 Uniform buffers are not available in OpenGL ES
* 2.0. * 2.0.
@ -174,6 +178,23 @@ template<UnsignedInt dimensions> class MAGNUM_SHADERS_EXPORT VertexColorGL: publ
*/ */
UniformBuffers = 1 << 0, 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 * Enable multidraw functionality. Implies @ref Flag::UniformBuffers
* and adds the value from @ref setDrawOffset() with the * 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 TransformationProjectionUniform2D /
* @ref TransformationProjectionUniform3D uniform buffers bound with * @ref TransformationProjectionUniform3D uniform buffers bound with
* @ref bindTransformationProjectionBuffer(). Has use only if * @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() * @see @ref Configuration::setDrawCount()
* @requires_gles30 Not defined on OpenGL ES 2.0 builds. * @requires_gles30 Not defined on OpenGL ES 2.0 builds.
* @requires_webgl20 Not defined on WebGL 1.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 #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. * 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); 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) * @return Reference to self (for method chaining)
* @m_since_latest * @m_since_latest
* *
@ -480,10 +502,10 @@ template<UnsignedInt dimensions> class VertexColorGL<dimensions>::Configuration
* statically defined size and * statically defined size and
* @cpp count*sizeof(TransformationProjectionUniform2D) @ce /, * @cpp count*sizeof(TransformationProjectionUniform2D) @ce /,
* @cpp count*sizeof(TransformationProjectionUniform3D) @ce has to be * @cpp count*sizeof(TransformationProjectionUniform3D) @ce has to be
* within @ref GL::AbstractShaderProgram::maxUniformBlockSize(). * within @ref GL::AbstractShaderProgram::maxUniformBlockSize(), if
* * @ref Flag::ShaderStorageBuffers is set as well, the buffers are
* The draw offset is then set via @ref setDrawOffset(). Default value * unbounded and @p count is ignored. The draw offset is set via
* is @cpp 1 @ce. * @ref setDrawOffset(). Default value is @cpp 1 @ce.
* *
* If @ref Flag::UniformBuffers isn't set, this value is ignored. * If @ref Flag::UniformBuffers isn't set, this value is ignored.
* @see @ref setFlags(), @ref VertexColorGL::drawCount() * @see @ref setFlags(), @ref VertexColorGL::drawCount()

Loading…
Cancel
Save