Browse Source

Shaders: multidraw support in all builtin shaders.

pull/518/head
Vladimír Vondruš 5 years ago
parent
commit
2c09a2a1e6
  1. 3
      doc/changelog.dox
  2. 9
      src/Magnum/Shaders/DistanceFieldVector.frag
  3. 15
      src/Magnum/Shaders/DistanceFieldVectorGL.cpp
  4. 34
      src/Magnum/Shaders/DistanceFieldVectorGL.h
  5. 13
      src/Magnum/Shaders/Flat.frag
  6. 28
      src/Magnum/Shaders/Flat.vert
  7. 15
      src/Magnum/Shaders/FlatGL.cpp
  8. 34
      src/Magnum/Shaders/FlatGL.h
  9. 9
      src/Magnum/Shaders/MeshVisualizer.frag
  10. 18
      src/Magnum/Shaders/MeshVisualizer.geom
  11. 44
      src/Magnum/Shaders/MeshVisualizer.vert
  12. 19
      src/Magnum/Shaders/MeshVisualizerGL.cpp
  13. 65
      src/Magnum/Shaders/MeshVisualizerGL.h
  14. 15
      src/Magnum/Shaders/Phong.frag
  15. 34
      src/Magnum/Shaders/Phong.vert
  16. 15
      src/Magnum/Shaders/PhongGL.cpp
  17. 31
      src/Magnum/Shaders/PhongGL.h
  18. 118
      src/Magnum/Shaders/Test/DistanceFieldVectorGLTest.cpp
  19. 33
      src/Magnum/Shaders/Test/DistanceFieldVectorGL_Test.cpp
  20. 115
      src/Magnum/Shaders/Test/FlatGLTest.cpp
  21. 17
      src/Magnum/Shaders/Test/FlatGL_Test.cpp
  22. 156
      src/Magnum/Shaders/Test/MeshVisualizerGLTest.cpp
  23. 50
      src/Magnum/Shaders/Test/MeshVisualizerGL_Test.cpp
  24. 83
      src/Magnum/Shaders/Test/PhongGLTest.cpp
  25. 17
      src/Magnum/Shaders/Test/PhongGL_Test.cpp
  26. 118
      src/Magnum/Shaders/Test/VectorGLTest.cpp
  27. 33
      src/Magnum/Shaders/Test/VectorGL_Test.cpp
  28. 120
      src/Magnum/Shaders/Test/VertexColorGLTest.cpp
  29. 18
      src/Magnum/Shaders/Test/VertexColorGL_Test.cpp
  30. 11
      src/Magnum/Shaders/Vector.frag
  31. 28
      src/Magnum/Shaders/Vector.vert
  32. 15
      src/Magnum/Shaders/VectorGL.cpp
  33. 34
      src/Magnum/Shaders/VectorGL.h
  34. 22
      src/Magnum/Shaders/VertexColor.vert
  35. 14
      src/Magnum/Shaders/VertexColorGL.cpp
  36. 34
      src/Magnum/Shaders/VertexColorGL.h

3
doc/changelog.dox

@ -148,7 +148,8 @@ See also:
@subsubsection changelog-latest-new-shaders Shaders library @subsubsection changelog-latest-new-shaders Shaders library
- 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 OpenGL ES 3.0+ and WebGL 2.0, including multi-draw functionality for
massive driver overhead reduction
- Added @ref Shaders::PhongGL::setNormalTextureScale(), consuming the - Added @ref Shaders::PhongGL::setNormalTextureScale(), consuming the
recently added @ref Trade::MaterialAttribute::NormalTextureScale material recently added @ref Trade::MaterialAttribute::NormalTextureScale material
attribute attribute

9
src/Magnum/Shaders/DistanceFieldVector.frag

@ -71,6 +71,7 @@ uniform lowp float smoothness
/* Uniform buffers */ /* Uniform buffers */
#else #else
#ifndef MULTI_DRAW
#ifdef EXPLICIT_UNIFORM_LOCATION #ifdef EXPLICIT_UNIFORM_LOCATION
layout(location = 0) layout(location = 0)
#endif #endif
@ -79,6 +80,8 @@ uniform highp uint drawOffset
= 0u = 0u
#endif #endif
; ;
#define drawId drawOffset
#endif
struct DrawUniform { struct DrawUniform {
highp uvec4 materialIdReservedReservedReservedReserved; highp uvec4 materialIdReservedReservedReservedReserved;
@ -122,6 +125,10 @@ uniform lowp sampler2D vectorTexture;
in mediump vec2 interpolatedTextureCoordinates; in mediump vec2 interpolatedTextureCoordinates;
#ifdef MULTI_DRAW
flat in highp uint drawId;
#endif
/* OUtput */ /* OUtput */
#ifdef NEW_GLSL #ifdef NEW_GLSL
@ -133,7 +140,7 @@ out lowp vec4 fragmentColor;
void main() { void main() {
#ifdef UNIFORM_BUFFERS #ifdef UNIFORM_BUFFERS
mediump const uint materialId = draws[drawOffset].draw_materialIdReserved & 0xffffu; mediump const uint materialId = draws[drawId].draw_materialIdReserved & 0xffffu;
lowp const float smoothness = materials[materialId].material_smoothness; lowp const float smoothness = materials[materialId].material_smoothness;
lowp const vec4 color = materials[materialId].color; lowp const vec4 color = materials[materialId].color;
lowp const vec4 outlineColor = materials[materialId].outlineColor; lowp const vec4 outlineColor = materials[materialId].outlineColor;

15
src/Magnum/Shaders/DistanceFieldVectorGL.cpp

@ -85,6 +85,17 @@ template<UnsignedInt dimensions> DistanceFieldVectorGL<dimensions>::DistanceFiel
if(flags >= Flag::UniformBuffers) if(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_GLES2
if(flags >= Flag::MultiDraw) {
#ifndef MAGNUM_TARGET_GLES
MAGNUM_ASSERT_GL_EXTENSION_SUPPORTED(GL::Extensions::ARB::shader_draw_parameters);
#elif !defined(MAGNUM_TARGET_WEBGL)
MAGNUM_ASSERT_GL_EXTENSION_SUPPORTED(GL::Extensions::ANGLE::multi_draw);
#else
MAGNUM_ASSERT_GL_EXTENSION_SUPPORTED(GL::Extensions::WEBGL::multi_draw);
#endif
}
#endif
#ifdef MAGNUM_BUILD_STATIC #ifdef MAGNUM_BUILD_STATIC
/* Import resources on static build, if not already */ /* Import resources on static build, if not already */
@ -112,6 +123,7 @@ template<UnsignedInt dimensions> DistanceFieldVectorGL<dimensions>::DistanceFiel
"#define UNIFORM_BUFFERS\n" "#define UNIFORM_BUFFERS\n"
"#define DRAW_COUNT {}\n", "#define DRAW_COUNT {}\n",
drawCount)); drawCount));
vert.addSource(flags >= Flag::MultiDraw ? "#define MULTI_DRAW\n" : "");
} }
#endif #endif
vert.addSource(rs.get("generic.glsl")) vert.addSource(rs.get("generic.glsl"))
@ -124,6 +136,7 @@ template<UnsignedInt dimensions> DistanceFieldVectorGL<dimensions>::DistanceFiel
"#define DRAW_COUNT {}\n", "#define DRAW_COUNT {}\n",
materialCount, materialCount,
drawCount)); drawCount));
frag.addSource(flags >= Flag::MultiDraw ? "#define MULTI_DRAW\n" : "");
} }
#endif #endif
frag.addSource(rs.get("generic.glsl")) frag.addSource(rs.get("generic.glsl"))
@ -351,6 +364,7 @@ Debug& operator<<(Debug& debug, const DistanceFieldVectorGLFlag value) {
_c(TextureTransformation) _c(TextureTransformation)
#ifndef MAGNUM_TARGET_GLES2 #ifndef MAGNUM_TARGET_GLES2
_c(UniformBuffers) _c(UniformBuffers)
_c(MultiDraw)
#endif #endif
#undef _c #undef _c
/* LCOV_EXCL_STOP */ /* LCOV_EXCL_STOP */
@ -363,6 +377,7 @@ 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
DistanceFieldVectorGLFlag::MultiDraw, /* Superset of UniformBuffers */
DistanceFieldVectorGLFlag::UniformBuffers DistanceFieldVectorGLFlag::UniformBuffers
#endif #endif
}); });

34
src/Magnum/Shaders/DistanceFieldVectorGL.h

@ -41,7 +41,8 @@ namespace Implementation {
enum class DistanceFieldVectorGLFlag: UnsignedByte { enum class DistanceFieldVectorGLFlag: UnsignedByte {
TextureTransformation = 1 << 0, TextureTransformation = 1 << 0,
#ifndef MAGNUM_TARGET_GLES2 #ifndef MAGNUM_TARGET_GLES2
UniformBuffers = 1 << 1 UniformBuffers = 1 << 1,
MultiDraw = UniformBuffers|(1 << 2)
#endif #endif
}; };
typedef Containers::EnumSet<DistanceFieldVectorGLFlag> DistanceFieldVectorGLFlags; typedef Containers::EnumSet<DistanceFieldVectorGLFlag> DistanceFieldVectorGLFlags;
@ -140,7 +141,31 @@ template<UnsignedInt dimensions> class MAGNUM_SHADERS_EXPORT DistanceFieldVector
* 1.0. * 1.0.
* @m_since_latest * @m_since_latest
*/ */
UniformBuffers = 1 << 1 UniformBuffers = 1 << 1,
/**
* Enable multidraw functionality. Implies @ref Flag::UniformBuffers
* and adds the value from @ref setDrawOffset() with the
* @glsl gl_DrawID @ce builtin, which makes draws submitted via
* @ref GL::AbstractShaderProgram::draw(Containers::ArrayView<const Containers::Reference<MeshView>>)
* pick up per-draw parameters directly, without having to rebind
* the uniform buffers or specify @ref setDrawOffset() before each
* draw. In a non-multidraw scenario, @glsl gl_DrawID @ce is
* @cpp 0 @ce, which means a shader with this flag enabled can be
* used for regular draws as well.
* @requires_gl46 Extension @gl_extension{ARB,uniform_buffer_object}
* and @gl_extension{ARB,shader_draw_parameters}
* @requires_es_extension OpenGL ES 3.0 and extension @m_class{m-doc-external} [ANGLE_multi_draw](https://chromium.googlesource.com/angle/angle/+/master/extensions/ANGLE_multi_draw.txt) (unlisted).
* While the extension alone needs only OpenGL ES 2.0, the
* shader implementation relies on uniform buffers, which
* require OpenGL ES 3.0.
* @requires_webgl_extension WebGL 2.0 Extension @webgl_extension{ANGLE,multi_draw}.
* While the extension alone needs only WebGL 1.0, the shader
* implementation relies on uniform buffers, which require
* WebGL 2.0.
* @m_since_latest
*/
MultiDraw = UniformBuffers|(1 << 2)
#endif #endif
}; };
@ -387,6 +412,11 @@ template<UnsignedInt dimensions> class MAGNUM_SHADERS_EXPORT DistanceFieldVector
* @ref bindTextureTransformationBuffer() should be used for current * @ref bindTextureTransformationBuffer() should be used for current
* draw. Expects that @ref Flag::UniformBuffers is set and @p offset is * draw. Expects that @ref Flag::UniformBuffers is set and @p offset is
* less than @ref drawCount(). Initial value is @cpp 0 @ce. * less than @ref drawCount(). Initial value is @cpp 0 @ce.
*
* If @ref Flag::MultiDraw is set, @glsl gl_DrawID @ce is added to this
* value, which makes each draw submitted via
* @ref GL::AbstractShaderProgram::draw(Containers::ArrayView<const Containers::Reference<MeshView>>)
* pick up its own per-draw parameters.
* @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 2.0. * @requires_gles30 Uniform buffers are not available in OpenGL ES 2.0.
* @requires_webgl20 Uniform buffers are not available in WebGL 1.0. * @requires_webgl20 Uniform buffers are not available in WebGL 1.0.

13
src/Magnum/Shaders/Flat.frag

@ -75,6 +75,7 @@ uniform highp uint objectId; /* defaults to zero */
/* Uniform buffers */ /* Uniform buffers */
#else #else
#ifndef MULTI_DRAW
#ifdef EXPLICIT_UNIFORM_LOCATION #ifdef EXPLICIT_UNIFORM_LOCATION
layout(location = 0) layout(location = 0)
#endif #endif
@ -83,6 +84,8 @@ uniform highp uint drawOffset
= 0u = 0u
#endif #endif
; ;
#define drawId drawOffset
#endif
struct DrawUniform { struct DrawUniform {
lowp vec4 color; lowp vec4 color;
@ -139,14 +142,18 @@ layout(location = OBJECT_ID_OUTPUT_ATTRIBUTE_LOCATION)
out highp uint fragmentObjectId; out highp uint fragmentObjectId;
#endif #endif
#ifdef MULTI_DRAW
flat in highp uint drawId;
#endif
void main() { void main() {
#ifdef UNIFORM_BUFFERS #ifdef UNIFORM_BUFFERS
lowp const vec4 color = draws[drawOffset].color; lowp const vec4 color = draws[drawId].color;
#ifdef OBJECT_ID #ifdef OBJECT_ID
highp const uint objectId = draws[drawOffset].draw_objectId; highp const uint objectId = draws[drawId].draw_objectId;
#endif #endif
#ifdef ALPHA_MASK #ifdef ALPHA_MASK
lowp const float alphaMask = uintBitsToFloat(draws[drawOffset].draw_alphaMask); lowp const float alphaMask = uintBitsToFloat(draws[drawId].draw_alphaMask);
#endif #endif
#endif #endif

28
src/Magnum/Shaders/Flat.vert

@ -27,6 +27,14 @@
#extension GL_EXT_gpu_shader4: require #extension GL_EXT_gpu_shader4: require
#endif #endif
#ifdef MULTI_DRAW
#ifndef GL_ES
#extension GL_ARB_shader_draw_parameters: require
#else /* covers WebGL as well */
#extension GL_ANGLE_multi_draw: require
#endif
#endif
#ifndef NEW_GLSL #ifndef NEW_GLSL
#define in attribute #define in attribute
#define out varying #define out varying
@ -182,8 +190,24 @@ out lowp vec4 interpolatedVertexColor;
flat out highp uint interpolatedInstanceObjectId; flat out highp uint interpolatedInstanceObjectId;
#endif #endif
#ifdef MULTI_DRAW
flat out highp uint drawId;
#endif
void main() { void main() {
#ifdef UNIFORM_BUFFERS #ifdef UNIFORM_BUFFERS
#ifdef MULTI_DRAW
drawId = drawOffset + uint(
#ifndef GL_ES
gl_DrawIDARB /* Using GL_ARB_shader_draw_parameters, not GLSL 4.6 */
#else
gl_DrawID
#endif
);
#else
#define drawId drawOffset
#endif
highp const highp const
#ifdef TWO_DIMENSIONS #ifdef TWO_DIMENSIONS
mat3 mat3
@ -192,9 +216,9 @@ void main() {
#else #else
#error #error
#endif #endif
transformationProjectionMatrix = transformationProjectionMatrices[drawOffset]; transformationProjectionMatrix = transformationProjectionMatrices[drawId];
#ifdef TEXTURE_TRANSFORMATION #ifdef TEXTURE_TRANSFORMATION
mediump const mat3 textureMatrix = mat3(textureTransformations[drawOffset].rotationScaling.xy, 0.0, textureTransformations[drawOffset].rotationScaling.zw, 0.0, textureTransformations[drawOffset].textureTransformation_offset, 1.0); mediump const mat3 textureMatrix = mat3(textureTransformations[drawId].rotationScaling.xy, 0.0, textureTransformations[drawId].rotationScaling.zw, 0.0, textureTransformations[drawId].textureTransformation_offset, 1.0);
#endif #endif
#endif #endif

15
src/Magnum/Shaders/FlatGL.cpp

@ -84,6 +84,17 @@ template<UnsignedInt dimensions> FlatGL<dimensions>::FlatGL(const Flags flags
if(flags >= Flag::UniformBuffers) if(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_GLES2
if(flags >= Flag::MultiDraw) {
#ifndef MAGNUM_TARGET_GLES
MAGNUM_ASSERT_GL_EXTENSION_SUPPORTED(GL::Extensions::ARB::shader_draw_parameters);
#elif !defined(MAGNUM_TARGET_WEBGL)
MAGNUM_ASSERT_GL_EXTENSION_SUPPORTED(GL::Extensions::ANGLE::multi_draw);
#else
MAGNUM_ASSERT_GL_EXTENSION_SUPPORTED(GL::Extensions::WEBGL::multi_draw);
#endif
}
#endif
#ifdef MAGNUM_BUILD_STATIC #ifdef MAGNUM_BUILD_STATIC
/* Import resources on static build, if not already */ /* Import resources on static build, if not already */
@ -118,6 +129,7 @@ template<UnsignedInt dimensions> FlatGL<dimensions>::FlatGL(const Flags flags
"#define UNIFORM_BUFFERS\n" "#define UNIFORM_BUFFERS\n"
"#define DRAW_COUNT {}\n", "#define DRAW_COUNT {}\n",
drawCount)); drawCount));
vert.addSource(flags >= Flag::MultiDraw ? "#define MULTI_DRAW\n" : "");
} }
#endif #endif
vert.addSource(rs.get("generic.glsl")) vert.addSource(rs.get("generic.glsl"))
@ -136,6 +148,7 @@ template<UnsignedInt dimensions> FlatGL<dimensions>::FlatGL(const Flags flags
"#define UNIFORM_BUFFERS\n" "#define UNIFORM_BUFFERS\n"
"#define DRAW_COUNT {}\n", "#define DRAW_COUNT {}\n",
drawCount)); drawCount));
frag.addSource(flags >= Flag::MultiDraw ? "#define MULTI_DRAW\n" : "");
} }
#endif #endif
frag.addSource(rs.get("generic.glsl")) frag.addSource(rs.get("generic.glsl"))
@ -370,6 +383,7 @@ Debug& operator<<(Debug& debug, const FlatGLFlag value) {
_c(InstancedTextureOffset) _c(InstancedTextureOffset)
#ifndef MAGNUM_TARGET_GLES2 #ifndef MAGNUM_TARGET_GLES2
_c(UniformBuffers) _c(UniformBuffers)
_c(MultiDraw)
#endif #endif
#undef _c #undef _c
/* LCOV_EXCL_STOP */ /* LCOV_EXCL_STOP */
@ -391,6 +405,7 @@ Debug& operator<<(Debug& debug, const FlatGLFlags value) {
#endif #endif
FlatGLFlag::InstancedTransformation, FlatGLFlag::InstancedTransformation,
#ifndef MAGNUM_TARGET_GLES2 #ifndef MAGNUM_TARGET_GLES2
FlatGLFlag::MultiDraw, /* Superset of UniformBuffers */
FlatGLFlag::UniformBuffers FlatGLFlag::UniformBuffers
#endif #endif
}); });

34
src/Magnum/Shaders/FlatGL.h

@ -50,7 +50,8 @@ namespace Implementation {
InstancedTransformation = 1 << 6, InstancedTransformation = 1 << 6,
InstancedTextureOffset = (1 << 7)|TextureTransformation, InstancedTextureOffset = (1 << 7)|TextureTransformation,
#ifndef MAGNUM_TARGET_GLES2 #ifndef MAGNUM_TARGET_GLES2
UniformBuffers = 1 << 8 UniformBuffers = 1 << 8,
MultiDraw = UniformBuffers|(1 << 9)
#endif #endif
}; };
typedef Containers::EnumSet<FlatGLFlag> FlatGLFlags; typedef Containers::EnumSet<FlatGLFlag> FlatGLFlags;
@ -388,7 +389,31 @@ template<UnsignedInt dimensions> class MAGNUM_SHADERS_EXPORT FlatGL: public GL::
* 1.0. * 1.0.
* @m_since_latest * @m_since_latest
*/ */
UniformBuffers = 1 << 8 UniformBuffers = 1 << 8,
/**
* Enable multidraw functionality. Implies @ref Flag::UniformBuffers
* and adds the value from @ref setDrawOffset() with the
* @glsl gl_DrawID @ce builtin, which makes draws submitted via
* @ref GL::AbstractShaderProgram::draw(Containers::ArrayView<const Containers::Reference<MeshView>>)
* pick up per-draw parameters directly, without having to rebind
* the uniform buffers or specify @ref setDrawOffset() before each
* draw. In a non-multidraw scenario, @glsl gl_DrawID @ce is
* @cpp 0 @ce, which means a shader with this flag enabled can be
* used for regular draws as well.
* @requires_gl46 Extension @gl_extension{ARB,uniform_buffer_object}
* and @gl_extension{ARB,shader_draw_parameters}
* @requires_es_extension OpenGL ES 3.0 and extension @m_class{m-doc-external} [ANGLE_multi_draw](https://chromium.googlesource.com/angle/angle/+/master/extensions/ANGLE_multi_draw.txt) (unlisted).
* While the extension alone needs only OpenGL ES 2.0, the
* shader implementation relies on uniform buffers, which
* require OpenGL ES 3.0.
* @requires_webgl_extension WebGL 2.0 Extension @webgl_extension{ANGLE,multi_draw}.
* While the extension alone needs only WebGL 1.0, the shader
* implementation relies on uniform buffers, which require
* WebGL 2.0.
* @m_since_latest
*/
MultiDraw = UniformBuffers|(1 << 9)
#endif #endif
}; };
@ -602,6 +627,11 @@ template<UnsignedInt dimensions> class MAGNUM_SHADERS_EXPORT FlatGL: public GL::
* @ref bindTextureTransformationBuffer() should be used for current * @ref bindTextureTransformationBuffer() should be used for current
* draw. Expects that @ref Flag::UniformBuffers is set and @p offset is * draw. Expects that @ref Flag::UniformBuffers is set and @p offset is
* less than @ref drawCount(). Initial value is @cpp 0 @ce. * less than @ref drawCount(). Initial value is @cpp 0 @ce.
*
* If @ref Flag::MultiDraw is set, @glsl gl_DrawID @ce is added to this
* value, which makes each draw submitted via
* @ref GL::AbstractShaderProgram::draw(Containers::ArrayView<const Containers::Reference<MeshView>>)
* pick up its own per-draw parameters.
* @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 2.0. * @requires_gles30 Uniform buffers are not available in OpenGL ES 2.0.
* @requires_webgl20 Uniform buffers are not available in WebGL 1.0. * @requires_webgl20 Uniform buffers are not available in WebGL 1.0.

9
src/Magnum/Shaders/MeshVisualizer.frag

@ -110,6 +110,7 @@ uniform lowp vec2 colorMapOffsetScale
/* Uniform buffers */ /* Uniform buffers */
#else #else
#ifndef MULTI_DRAW
#ifdef EXPLICIT_UNIFORM_LOCATION #ifdef EXPLICIT_UNIFORM_LOCATION
layout(location = 1) layout(location = 1)
#endif #endif
@ -118,6 +119,8 @@ uniform highp uint drawOffset
= 0u = 0u
#endif #endif
; ;
#define drawId drawOffset
#endif
/* Keep in sync with MeshVisualizer.vert and MeshVisualizer.geom. Can't /* Keep in sync with MeshVisualizer.vert and MeshVisualizer.geom. Can't
"outsource" to a common file because the extension directives need to be "outsource" to a common file because the extension directives need to be
@ -202,6 +205,10 @@ in lowp vec4 backgroundColor;
in lowp vec4 lineColor; in lowp vec4 lineColor;
#endif #endif
#ifdef MULTI_DRAW
flat in highp uint drawId;
#endif
/* Outputs */ /* Outputs */
#ifdef NEW_GLSL #ifdef NEW_GLSL
@ -213,7 +220,7 @@ out lowp vec4 fragmentColor;
void main() { void main() {
#ifdef UNIFORM_BUFFERS #ifdef UNIFORM_BUFFERS
mediump const uint materialId = draws[drawOffset].draw_materialIdReserved & 0xffffu; mediump const uint materialId = draws[drawId].draw_materialIdReserved & 0xffffu;
#if (defined(WIREFRAME_RENDERING) || defined(INSTANCED_OBJECT_ID) || defined(VERTEX_ID) || defined(PRIMITIVE_ID) || defined(PRIMITIVE_ID_FROM_VERTEX_ID)) && !defined(TBN_DIRECTION) #if (defined(WIREFRAME_RENDERING) || defined(INSTANCED_OBJECT_ID) || defined(VERTEX_ID) || defined(PRIMITIVE_ID) || defined(PRIMITIVE_ID_FROM_VERTEX_ID)) && !defined(TBN_DIRECTION)
lowp const vec4 color = materials[materialId].color; lowp const vec4 color = materials[materialId].color;
lowp const vec4 wireframeColor = materials[materialId].wireframeColor; lowp const vec4 wireframeColor = materials[materialId].wireframeColor;

18
src/Magnum/Shaders/MeshVisualizer.geom

@ -87,6 +87,7 @@ uniform lowp float smoothness
/* Uniform buffers */ /* Uniform buffers */
#else #else
#ifndef MULTI_DRAW
#ifdef EXPLICIT_UNIFORM_LOCATION #ifdef EXPLICIT_UNIFORM_LOCATION
layout(location = 1) layout(location = 1)
#endif #endif
@ -95,6 +96,7 @@ uniform highp uint drawOffset
= 0u = 0u
#endif #endif
; ;
#endif
/* Keep in sync with MeshVisualizer.vert and MeshVisualizer.frag. Can't /* Keep in sync with MeshVisualizer.vert and MeshVisualizer.frag. Can't
"outsource" to a common file because the #extension directives need to be "outsource" to a common file because the #extension directives need to be
@ -166,6 +168,10 @@ in highp float interpolatedVsMappedVertexId[];
flat in highp uint interpolatedVsPrimitiveId[]; flat in highp uint interpolatedVsPrimitiveId[];
#endif #endif
#ifdef MULTI_DRAW
flat in highp uint vsDrawId[];
#endif
/* Outputs */ /* Outputs */
layout(triangle_strip, max_vertices = MAX_VERTICES) out; layout(triangle_strip, max_vertices = MAX_VERTICES) out;
@ -186,6 +192,10 @@ out highp float interpolatedMappedVertexId;
flat out highp uint interpolatedPrimitiveId; flat out highp uint interpolatedPrimitiveId;
#endif #endif
#ifdef MULTI_DRAW
flat out highp uint drawId;
#endif
#if defined(TANGENT_DIRECTION) || defined(BITANGENT_DIRECTION) || defined(NORMAL_DIRECTION) #if defined(TANGENT_DIRECTION) || defined(BITANGENT_DIRECTION) || defined(NORMAL_DIRECTION)
out lowp vec4 backgroundColor; out lowp vec4 backgroundColor;
out lowp vec4 lineColor; out lowp vec4 lineColor;
@ -255,7 +265,13 @@ void emitQuad(
void main() { void main() {
#ifdef UNIFORM_BUFFERS #ifdef UNIFORM_BUFFERS
mediump const uint materialId = draws[drawOffset].draw_materialIdReserved & 0xffffu; #ifdef MULTI_DRAW
drawId = vsDrawId[0];
#else
#define drawId drawOffset
#endif
mediump const uint materialId = draws[drawId].draw_materialIdReserved & 0xffffu;
#if (defined(TANGENT_DIRECTION) || defined(BITANGENT_DIRECTION) || defined(NORMAL_DIRECTION)) && (defined(WIREFRAME_RENDERING) || defined(INSTANCED_OBJECT_ID) || defined(PRIMITIVE_ID) || defined(PRIMITIVE_ID_FROM_VERTEX_ID)) #if (defined(TANGENT_DIRECTION) || defined(BITANGENT_DIRECTION) || defined(NORMAL_DIRECTION)) && (defined(WIREFRAME_RENDERING) || defined(INSTANCED_OBJECT_ID) || defined(PRIMITIVE_ID) || defined(PRIMITIVE_ID_FROM_VERTEX_ID))
lowp const vec4 color = materials[materialId].color; lowp const vec4 color = materials[materialId].color;
lowp const vec4 wireframeColor = materials[materialId].wireframeColor; lowp const vec4 wireframeColor = materials[materialId].wireframeColor;

44
src/Magnum/Shaders/MeshVisualizer.vert

@ -27,6 +27,14 @@
#extension GL_EXT_gpu_shader4: require #extension GL_EXT_gpu_shader4: require
#endif #endif
#ifdef MULTI_DRAW
#ifndef GL_ES
#extension GL_ARB_shader_draw_parameters: require
#else /* covers WebGL as well */
#extension GL_ANGLE_multi_draw: require
#endif
#endif
#ifndef NEW_GLSL #ifndef NEW_GLSL
#define in attribute #define in attribute
#define out varying #define out varying
@ -279,19 +287,47 @@ out highp vec4 bitangentEndpoint;
out highp vec4 normalEndpoint; out highp vec4 normalEndpoint;
#endif #endif
#ifdef MULTI_DRAW
flat out highp uint
#ifdef NO_GEOMETRY_SHADER
drawId
#else
vsDrawId
#endif
;
#endif
void main() { void main() {
#ifdef UNIFORM_BUFFERS #ifdef UNIFORM_BUFFERS
#ifdef MULTI_DRAW
#ifdef NO_GEOMETRY_SHADER
drawId
#else
vsDrawId
#define drawId vsDrawId
#endif
= drawOffset + uint(
#ifndef GL_ES
gl_DrawIDARB /* Using GL_ARB_shader_draw_parameters, not GLSL 4.6 */
#else
gl_DrawID
#endif
);
#else
#define drawId drawOffset
#endif
#ifdef TWO_DIMENSIONS #ifdef TWO_DIMENSIONS
highp const mat3 transformationProjectionMatrix = transformationProjectionMatrices[drawOffset]; highp const mat3 transformationProjectionMatrix = transformationProjectionMatrices[drawId];
#elif defined(THREE_DIMENSIONS) #elif defined(THREE_DIMENSIONS)
highp const mat4 transformationMatrix = transformationMatrices[drawOffset]; highp const mat4 transformationMatrix = transformationMatrices[drawId];
#else #else
#error #error
#endif #endif
#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 = draws[drawOffset].normalMatrix; mediump const mat3 normalMatrix = draws[drawId].normalMatrix;
#endif #endif
mediump const uint materialId = draws[drawOffset].draw_materialIdReserved & 0xffffu; mediump const uint materialId = draws[drawId].draw_materialIdReserved & 0xffffu;
lowp float colorMapOffset = materials[materialId].material_colorMapOffset; lowp float colorMapOffset = materials[materialId].material_colorMapOffset;
lowp float colorMapScale = materials[materialId].material_colorMapScale; lowp float colorMapScale = materials[materialId].material_colorMapScale;
highp float lineLength = materials[materialId].material_lineLength; highp float lineLength = materials[materialId].material_lineLength;

19
src/Magnum/Shaders/MeshVisualizerGL.cpp

@ -97,6 +97,17 @@ MeshVisualizerGLBase::MeshVisualizerGLBase(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
#ifndef MAGNUM_TARGET_GLES2
if(flags >= FlagBase::MultiDraw) {
#ifndef MAGNUM_TARGET_GLES
MAGNUM_ASSERT_GL_EXTENSION_SUPPORTED(GL::Extensions::ARB::shader_draw_parameters);
#elif !defined(MAGNUM_TARGET_WEBGL)
MAGNUM_ASSERT_GL_EXTENSION_SUPPORTED(GL::Extensions::ANGLE::multi_draw);
#else
MAGNUM_ASSERT_GL_EXTENSION_SUPPORTED(GL::Extensions::WEBGL::multi_draw);
#endif
}
#endif
#ifndef MAGNUM_TARGET_GLES2 #ifndef MAGNUM_TARGET_GLES2
if(_flags & FlagBase::Wireframe && !(_flags & FlagBase::NoGeometryShader)) { if(_flags & FlagBase::Wireframe && !(_flags & FlagBase::NoGeometryShader)) {
@ -169,6 +180,7 @@ GL::Version MeshVisualizerGLBase::setupShaders(GL::Shader& vert, GL::Shader& fra
"#define MATERIAL_COUNT {}\n", "#define MATERIAL_COUNT {}\n",
_drawCount, _drawCount,
_materialCount)); _materialCount));
vert.addSource(_flags >= FlagBase::MultiDraw ? "#define MULTI_DRAW\n" : "");
} }
#endif #endif
frag.addSource(_flags & FlagBase::Wireframe ? "#define WIREFRAME_RENDERING\n" : "") frag.addSource(_flags & FlagBase::Wireframe ? "#define WIREFRAME_RENDERING\n" : "")
@ -189,6 +201,7 @@ GL::Version MeshVisualizerGLBase::setupShaders(GL::Shader& vert, GL::Shader& fra
"#define MATERIAL_COUNT {}\n", "#define MATERIAL_COUNT {}\n",
_drawCount, _drawCount,
_materialCount)); _materialCount));
frag.addSource(_flags >= FlagBase::MultiDraw ? "#define MULTI_DRAW\n" : "");
} }
#endif #endif
@ -358,6 +371,7 @@ MeshVisualizerGL2D::MeshVisualizerGL2D(const Flags flags
"#define MATERIAL_COUNT {}\n", "#define MATERIAL_COUNT {}\n",
_drawCount, _drawCount,
_materialCount)); _materialCount));
geom->addSource(flags >= Flag::MultiDraw ? "#define MULTI_DRAW\n" : "");
} }
#endif #endif
geom->addSource(rs.get("MeshVisualizer.geom")); geom->addSource(rs.get("MeshVisualizer.geom"));
@ -673,6 +687,7 @@ MeshVisualizerGL3D::MeshVisualizerGL3D(const Flags flags
"#define MATERIAL_COUNT {}\n", "#define MATERIAL_COUNT {}\n",
_drawCount, _drawCount,
_materialCount)); _materialCount));
geom->addSource(flags >= Flag::MultiDraw ? "#define MULTI_DRAW\n" : "");
} }
#endif #endif
geom->addSource(rs.get("MeshVisualizer.geom")); geom->addSource(rs.get("MeshVisualizer.geom"));
@ -990,6 +1005,7 @@ Debug& operator<<(Debug& debug, const MeshVisualizerGL2D::Flag value) {
#endif #endif
#ifndef MAGNUM_TARGET_GLES2 #ifndef MAGNUM_TARGET_GLES2
_c(UniformBuffers) _c(UniformBuffers)
_c(MultiDraw)
#endif #endif
#undef _c #undef _c
/* LCOV_EXCL_STOP */ /* LCOV_EXCL_STOP */
@ -1022,6 +1038,7 @@ Debug& operator<<(Debug& debug, const MeshVisualizerGL3D::Flag value) {
#endif #endif
#ifndef MAGNUM_TARGET_GLES2 #ifndef MAGNUM_TARGET_GLES2
_c(UniformBuffers) _c(UniformBuffers)
_c(MultiDraw)
#endif #endif
#undef _c #undef _c
/* LCOV_EXCL_STOP */ /* LCOV_EXCL_STOP */
@ -1044,6 +1061,7 @@ Debug& operator<<(Debug& debug, const MeshVisualizerGL2D::Flags value) {
MeshVisualizerGL2D::Flag::PrimitiveId, MeshVisualizerGL2D::Flag::PrimitiveId,
#endif #endif
#ifndef MAGNUM_TARGET_GLES2 #ifndef MAGNUM_TARGET_GLES2
MeshVisualizerGL2D::Flag::MultiDraw, /* Superset of UniformBuffers */
MeshVisualizerGL2D::Flag::UniformBuffers MeshVisualizerGL2D::Flag::UniformBuffers
#endif #endif
#endif #endif
@ -1070,6 +1088,7 @@ Debug& operator<<(Debug& debug, const MeshVisualizerGL3D::Flags value) {
MeshVisualizerGL3D::Flag::PrimitiveId, MeshVisualizerGL3D::Flag::PrimitiveId,
#endif #endif
#ifndef MAGNUM_TARGET_GLES2 #ifndef MAGNUM_TARGET_GLES2
MeshVisualizerGL3D::Flag::MultiDraw, /* Superset of UniformBuffers */
MeshVisualizerGL3D::Flag::UniformBuffers MeshVisualizerGL3D::Flag::UniformBuffers
#endif #endif
#endif #endif

65
src/Magnum/Shaders/MeshVisualizerGL.h

@ -55,7 +55,8 @@ class MAGNUM_SHADERS_EXPORT MeshVisualizerGLBase: public GL::AbstractShaderProgr
PrimitiveId = 1 << 4, PrimitiveId = 1 << 4,
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,
MultiDraw = UniformBuffers|(1 << 11)
#endif #endif
}; };
typedef Containers::EnumSet<FlagBase> FlagsBase; typedef Containers::EnumSet<FlagBase> FlagsBase;
@ -236,7 +237,31 @@ class MAGNUM_SHADERS_EXPORT MeshVisualizerGL2D: public Implementation::MeshVisua
* 1.0. * 1.0.
* @m_since_latest * @m_since_latest
*/ */
UniformBuffers = 1 << 10 UniformBuffers = 1 << 10,
/**
* Enable multidraw functionality. Implies @ref Flag::UniformBuffers
* and combines the value from @ref setDrawOffset() with the
* @glsl gl_DrawID @ce builtin, which makes draws submitted via
* @ref GL::AbstractShaderProgram::draw(Containers::ArrayView<const Containers::Reference<MeshView>>)
* pick up per-draw parameters directly, without having to rebind
* the uniform buffers or specify @ref setDrawOffset() before each
* draw. In a non-multidraw scenario, @glsl gl_DrawID @ce is
* @cpp 0 @ce, which means a shader with this flag enabled can be
* used for regular draws as well.
* @requires_gl46 Extension @gl_extension{ARB,uniform_buffer_object}
* and @gl_extension{ARB,shader_draw_parameters}
* @requires_es_extension OpenGL ES 3.0 and extension @m_class{m-doc-external} [ANGLE_multi_draw](https://chromium.googlesource.com/angle/angle/+/master/extensions/ANGLE_multi_draw.txt) (unlisted).
* While the extension alone needs only OpenGL ES 2.0, the
* shader implementation relies on uniform buffers, which
* require OpenGL ES 3.0.
* @requires_webgl_extension WebGL 2.0 Extension @webgl_extension{ANGLE,multi_draw}.
* While the extension alone needs only WebGL 1.0, the shader
* implementation relies on uniform buffers, which require
* WebGL 2.0.
* @m_since_latest
*/
MultiDraw = UniformBuffers|(1 << 11)
#endif #endif
}; };
@ -470,6 +495,11 @@ class MAGNUM_SHADERS_EXPORT MeshVisualizerGL2D: public Implementation::MeshVisua
* should be used for current draw. Expects that * should be used for current draw. Expects that
* @ref Flag::UniformBuffers is set and @p offset is less than * @ref Flag::UniformBuffers is set and @p offset is less than
* @ref drawCount(). Initial value is @cpp 0 @ce. * @ref drawCount(). Initial value is @cpp 0 @ce.
*
* If @ref Flag::MultiDraw is set, @glsl gl_DrawID @ce is added to this
* value, which makes each draw submitted via
* @ref GL::AbstractShaderProgram::draw(Containers::ArrayView<const Containers::Reference<MeshView>>)
* pick up its own per-draw parameters.
* @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 2.0. * @requires_gles30 Uniform buffers are not available in OpenGL ES 2.0.
* @requires_webgl20 Uniform buffers are not available in WebGL 1.0. * @requires_webgl20 Uniform buffers are not available in WebGL 1.0.
@ -997,7 +1027,31 @@ class MAGNUM_SHADERS_EXPORT MeshVisualizerGL3D: public Implementation::MeshVisua
* 1.0. * 1.0.
* @m_since_latest * @m_since_latest
*/ */
UniformBuffers = 1 << 10 UniformBuffers = 1 << 10,
/**
* Enable multidraw functionality. Implies @ref Flag::UniformBuffers
* and combines the value from @ref setDrawOffset() with the
* @glsl gl_DrawID @ce builtin, which makes draws submitted via
* @ref GL::AbstractShaderProgram::draw(Containers::ArrayView<const Containers::Reference<MeshView>>)
* pick up per-draw parameters directly, without having to rebind
* the uniform buffers or specify @ref setDrawOffset() before each
* draw. In a non-multidraw scenario, @glsl gl_DrawID @ce is
* @cpp 0 @ce, which means a shader with this flag enabled can be
* used for regular draws as well.
* @requires_gl46 Extension @gl_extension{ARB,uniform_buffer_object}
* and @gl_extension{ARB,shader_draw_parameters}
* @requires_es_extension OpenGL ES 3.0 and extension @m_class{m-doc-external} [ANGLE_multi_draw](https://chromium.googlesource.com/angle/angle/+/master/extensions/ANGLE_multi_draw.txt) (unlisted).
* While the extension alone needs only OpenGL ES 2.0, the
* shader implementation relies on uniform buffers, which
* require OpenGL ES 3.0.
* @requires_webgl_extension WebGL 2.0 Extension @webgl_extension{ANGLE,multi_draw}.
* While the extension alone needs only WebGL 1.0, the shader
* implementation relies on uniform buffers, which require
* WebGL 2.0.
* @m_since_latest
*/
MultiDraw = UniformBuffers|(1 << 11)
#endif #endif
}; };
@ -1382,6 +1436,11 @@ class MAGNUM_SHADERS_EXPORT MeshVisualizerGL3D: public Implementation::MeshVisua
* used for current draw. Expects that @ref Flag::UniformBuffers is set * used for current draw. Expects that @ref Flag::UniformBuffers is set
* and @p offset is less than @ref drawCount(). Initial value is * and @p offset is less than @ref drawCount(). Initial value is
* @cpp 0 @ce. * @cpp 0 @ce.
*
* If @ref Flag::MultiDraw is set, @glsl gl_DrawID @ce is added to this
* value, which makes each draw submitted via
* @ref GL::AbstractShaderProgram::draw(Containers::ArrayView<const Containers::Reference<MeshView>>)
* pick up its own per-draw parameters.
* @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 2.0. * @requires_gles30 Uniform buffers are not available in OpenGL ES 2.0.
* @requires_webgl20 Uniform buffers are not available in WebGL 1.0. * @requires_webgl20 Uniform buffers are not available in WebGL 1.0.

15
src/Magnum/Shaders/Phong.frag

@ -148,6 +148,7 @@ uniform lowp float lightRanges[LIGHT_COUNT]
/* Uniform buffers */ /* Uniform buffers */
#else #else
#ifndef MULTI_DRAW
#ifdef EXPLICIT_UNIFORM_LOCATION #ifdef EXPLICIT_UNIFORM_LOCATION
layout(location = 0) layout(location = 0)
#endif #endif
@ -156,6 +157,8 @@ uniform highp uint drawOffset
= 0u = 0u
#endif #endif
; ;
#define drawId drawOffset
#endif
/* Keep in sync with Phong.vert. Can't "outsource" to a common file because /* Keep in sync with Phong.vert. Can't "outsource" to a common file because
the #extension directive needs to be always before any code. */ the #extension directive needs to be always before any code. */
@ -277,6 +280,10 @@ in lowp vec4 interpolatedVertexColor;
flat in highp uint interpolatedInstanceObjectId; flat in highp uint interpolatedInstanceObjectId;
#endif #endif
#ifdef MULTI_DRAW
flat in highp uint drawId;
#endif
/* Outputs */ /* Outputs */
#ifdef NEW_GLSL #ifdef NEW_GLSL
@ -296,9 +303,9 @@ out highp uint fragmentObjectId;
void main() { void main() {
#ifdef UNIFORM_BUFFERS #ifdef UNIFORM_BUFFERS
#ifdef OBJECT_ID #ifdef OBJECT_ID
highp const uint objectId = draws[drawOffset].draw_objectId; highp const uint objectId = draws[drawId].draw_objectId;
#endif #endif
mediump const uint materialId = draws[drawOffset].draw_materialIdReserved & 0xffffu; mediump const uint materialId = draws[drawId].draw_materialIdReserved & 0xffffu;
lowp const vec4 ambientColor = materials[materialId].ambientColor; lowp const vec4 ambientColor = materials[materialId].ambientColor;
#if LIGHT_COUNT #if LIGHT_COUNT
lowp const vec4 diffuseColor = materials[materialId].diffuseColor; lowp const vec4 diffuseColor = materials[materialId].diffuseColor;
@ -312,7 +319,7 @@ void main() {
lowp const float alphaMask = materials[materialId].material_alphaMask; lowp const float alphaMask = materials[materialId].material_alphaMask;
#endif #endif
#if LIGHT_COUNT #if LIGHT_COUNT
mediump const uint lightOffset = draws[drawOffset].draw_lightOffset; mediump const uint lightOffset = draws[drawId].draw_lightOffset;
#endif #endif
#endif #endif
@ -370,7 +377,7 @@ void main() {
#ifndef UNIFORM_BUFFERS #ifndef UNIFORM_BUFFERS
for(int i = 0; i < LIGHT_COUNT; ++i) for(int i = 0; i < LIGHT_COUNT; ++i)
#else #else
for(uint i = 0u, actualLightCount = min(uint(LIGHT_COUNT), draws[drawOffset].draw_lightCount); i < actualLightCount; ++i) for(uint i = 0u, actualLightCount = min(uint(LIGHT_COUNT), draws[drawId].draw_lightCount); i < actualLightCount; ++i)
#endif #endif
{ {
lowp const vec3 lightColor = lowp const vec3 lightColor =

34
src/Magnum/Shaders/Phong.vert

@ -27,6 +27,14 @@
#extension GL_EXT_gpu_shader4: require #extension GL_EXT_gpu_shader4: require
#endif #endif
#ifdef MULTI_DRAW
#ifndef GL_ES
#extension GL_ARB_shader_draw_parameters: require
#else /* covers WebGL as well */
#extension GL_ANGLE_multi_draw: require
#endif
#endif
#ifndef NEW_GLSL #ifndef NEW_GLSL
#define in attribute #define in attribute
#define out varying #define out varying
@ -273,17 +281,33 @@ out highp vec4 lightDirections[LIGHT_COUNT];
out highp vec3 cameraDirection; out highp vec3 cameraDirection;
#endif #endif
#ifdef MULTI_DRAW
flat out highp uint drawId;
#endif
void main() { void main() {
#ifdef UNIFORM_BUFFERS #ifdef UNIFORM_BUFFERS
highp const mat4 transformationMatrix = transformationMatrices[drawOffset]; #ifdef MULTI_DRAW
drawId = drawOffset + uint(
#ifndef GL_ES
gl_DrawIDARB /* Using GL_ARB_shader_draw_parameters, not GLSL 4.6 */
#else
gl_DrawID
#endif
);
#else
#define drawId drawOffset
#endif
highp const mat4 transformationMatrix = transformationMatrices[drawId];
#if LIGHT_COUNT #if LIGHT_COUNT
mediump const mat3 normalMatrix = draws[drawOffset].normalMatrix; mediump const mat3 normalMatrix = draws[drawId].normalMatrix;
#endif #endif
#ifdef TEXTURE_TRANSFORMATION #ifdef TEXTURE_TRANSFORMATION
mediump const mat3 textureMatrix = mat3(textureTransformations[drawOffset].rotationScaling.xy, 0.0, textureTransformations[drawOffset].rotationScaling.zw, 0.0, textureTransformations[drawOffset].textureTransformation_offset, 1.0); mediump const mat3 textureMatrix = mat3(textureTransformations[drawId].rotationScaling.xy, 0.0, textureTransformations[drawId].rotationScaling.zw, 0.0, textureTransformations[drawId].textureTransformation_offset, 1.0);
#endif #endif
#if LIGHT_COUNT #if LIGHT_COUNT
mediump const uint lightOffset = draws[drawOffset].draw_lightOffset; mediump const uint lightOffset = draws[drawId].draw_lightOffset;
#endif #endif
#endif #endif
@ -328,7 +352,7 @@ void main() {
#ifndef UNIFORM_BUFFERS #ifndef UNIFORM_BUFFERS
for(int i = 0; i < LIGHT_COUNT; ++i) for(int i = 0; i < LIGHT_COUNT; ++i)
#else #else
for(uint i = 0u, actualLightCount = min(uint(LIGHT_COUNT), draws[drawOffset].draw_lightCount); i < actualLightCount; ++i) for(uint i = 0u, actualLightCount = min(uint(LIGHT_COUNT), draws[drawId].draw_lightCount); i < actualLightCount; ++i)
#endif #endif
{ {
highp const vec4 lightPosition = highp const vec4 lightPosition =

15
src/Magnum/Shaders/PhongGL.cpp

@ -105,6 +105,17 @@ PhongGL::PhongGL(const Flags flags, const UnsignedInt lightCount
if(flags >= Flag::UniformBuffers) if(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_GLES2
if(flags >= Flag::MultiDraw) {
#ifndef MAGNUM_TARGET_GLES
MAGNUM_ASSERT_GL_EXTENSION_SUPPORTED(GL::Extensions::ARB::shader_draw_parameters);
#elif !defined(MAGNUM_TARGET_WEBGL)
MAGNUM_ASSERT_GL_EXTENSION_SUPPORTED(GL::Extensions::ANGLE::multi_draw);
#else
MAGNUM_ASSERT_GL_EXTENSION_SUPPORTED(GL::Extensions::WEBGL::multi_draw);
#endif
}
#endif
#ifdef MAGNUM_BUILD_STATIC #ifdef MAGNUM_BUILD_STATIC
/* Import resources on static build, if not already */ /* Import resources on static build, if not already */
@ -199,6 +210,7 @@ PhongGL::PhongGL(const Flags flags, const UnsignedInt lightCount
"#define LIGHT_COUNT {}\n", "#define LIGHT_COUNT {}\n",
drawCount, drawCount,
lightCount)); lightCount));
vert.addSource(flags >= Flag::MultiDraw ? "#define MULTI_DRAW\n" : "");
} }
#endif #endif
#ifndef MAGNUM_TARGET_GLES #ifndef MAGNUM_TARGET_GLES
@ -229,6 +241,7 @@ PhongGL::PhongGL(const Flags flags, const UnsignedInt lightCount
drawCount, drawCount,
materialCount, materialCount,
lightCount)); lightCount));
frag.addSource(flags >= Flag::MultiDraw ? "#define MULTI_DRAW\n" : "");
} else } else
#endif #endif
{ {
@ -809,6 +822,7 @@ Debug& operator<<(Debug& debug, const PhongGL::Flag value) {
_c(InstancedTextureOffset) _c(InstancedTextureOffset)
#ifndef MAGNUM_TARGET_GLES2 #ifndef MAGNUM_TARGET_GLES2
_c(UniformBuffers) _c(UniformBuffers)
_c(MultiDraw)
#endif #endif
#undef _c #undef _c
/* LCOV_EXCL_STOP */ /* LCOV_EXCL_STOP */
@ -834,6 +848,7 @@ Debug& operator<<(Debug& debug, const PhongGL::Flags value) {
#endif #endif
PhongGL::Flag::InstancedTransformation, PhongGL::Flag::InstancedTransformation,
#ifndef MAGNUM_TARGET_GLES2 #ifndef MAGNUM_TARGET_GLES2
PhongGL::Flag::MultiDraw, /* Superset of UniformBuffers */
PhongGL::Flag::UniformBuffers PhongGL::Flag::UniformBuffers
#endif #endif
}); });

31
src/Magnum/Shaders/PhongGL.h

@ -577,7 +577,31 @@ class MAGNUM_SHADERS_EXPORT PhongGL: public GL::AbstractShaderProgram {
* 1.0. * 1.0.
* @m_since_latest * @m_since_latest
*/ */
UniformBuffers = 1 << 12 UniformBuffers = 1 << 12,
/**
* Enable multidraw functionality. Implies @ref Flag::UniformBuffers
* and adds the value from @ref setDrawOffset() with the
* @glsl gl_DrawID @ce builtin, which makes draws submitted via
* @ref GL::AbstractShaderProgram::draw(Containers::ArrayView<const Containers::Reference<MeshView>>)
* pick up per-draw parameters directly, without having to rebind
* the uniform buffers or specify @ref setDrawOffset() before each
* draw. In a non-multidraw scenario, @glsl gl_DrawID @ce is
* @cpp 0 @ce, which means a shader with this flag enabled can be
* used for regular draws as well.
* @requires_gl46 Extension @gl_extension{ARB,uniform_buffer_object}
* and @gl_extension{ARB,shader_draw_parameters}
* @requires_es_extension OpenGL ES 3.0 and extension @m_class{m-doc-external} [ANGLE_multi_draw](https://chromium.googlesource.com/angle/angle/+/master/extensions/ANGLE_multi_draw.txt) (unlisted).
* While the extension alone needs only OpenGL ES 2.0, the
* shader implementation relies on uniform buffers, which
* require OpenGL ES 3.0.
* @requires_webgl_extension WebGL 2.0 Extension @webgl_extension{ANGLE,multi_draw}.
* While the extension alone needs only WebGL 1.0, the shader
* implementation relies on uniform buffers, which require
* WebGL 2.0.
* @m_since_latest
*/
MultiDraw = UniformBuffers|(1 << 13)
#endif #endif
}; };
@ -1162,6 +1186,11 @@ class MAGNUM_SHADERS_EXPORT PhongGL: public GL::AbstractShaderProgram {
* and @ref bindTextureTransformationBuffer() should be used for * and @ref bindTextureTransformationBuffer() should be used for
* current draw. Expects that @ref Flag::UniformBuffers is set and * current draw. Expects that @ref Flag::UniformBuffers is set and
* @p offset is less than @ref drawCount(). Initial value is @cpp 0 @ce. * @p offset is less than @ref drawCount(). Initial value is @cpp 0 @ce.
*
* If @ref Flag::MultiDraw is set, @glsl gl_DrawID @ce is added to this
* value, which makes each draw submitted via
* @ref GL::AbstractShaderProgram::draw(Containers::ArrayView<const Containers::Reference<MeshView>>)
* pick up its own per-draw parameters.
* @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 2.0. * @requires_gles30 Uniform buffers are not available in OpenGL ES 2.0.
* @requires_webgl20 Uniform buffers are not available in WebGL 1.0. * @requires_webgl20 Uniform buffers are not available in WebGL 1.0.

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

@ -129,24 +129,27 @@ struct DistanceFieldVectorGLTest: GL::OpenGLTester {
Rendering tests done: Rendering tests done:
[B] base [B] base
[O] draw offset [O] UBOs + draw offset
[M] multidraw
Mesa Intel BO Mesa Intel BOM
ES2 x ES2 xx
ES3 BO ES3 BOx
Mesa AMD B Mesa AMD B
Mesa llvmpipe B Mesa llvmpipe B
SwiftShader ES2 Bx SwiftShader ES2 Bxx
ES3 B ES3 B
ARM Mali (Huawei P10) ES2 Bx ANGLE ES2 xx
ES3 BO ES3 BOM
WebGL (on Mesa Intel) 1.0 Bx ARM Mali (Huawei P10) ES2 Bxx
2.0 BO ES3 BOx
WebGL (on Mesa Intel) 1.0 Bxx
2.0 BOM
NVidia NVidia
Intel Windows Intel Windows
AMD macOS AMD macOS x
Intel macOS BO Intel macOS BOx
iPhone 6 w/ iOS 12.4 ES3 B iPhone 6 w/ iOS 12.4 ES3 B x
*/ */
using namespace Math::Literals; using namespace Math::Literals;
@ -171,6 +174,7 @@ 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}
}; };
constexpr struct { constexpr struct {
@ -213,16 +217,21 @@ constexpr struct {
const char* name; const char* name;
const char* expected2D; const char* expected2D;
const char* expected3D; const char* expected3D;
DistanceFieldVectorGL2D::Flags flags;
UnsignedInt materialCount, drawCount; UnsignedInt materialCount, drawCount;
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, 16,
/* Minor differences on ARM Mali */ /* Minor differences on ARM Mali */
1.67f, 0.012f}, 1.67f, 0.012f},
{"draw offset", "multidraw2D-distancefield.tga", "multidraw3D-distancefield.tga", {"draw offset", "multidraw2D-distancefield.tga", "multidraw3D-distancefield.tga",
2, 3, 1, {}, 2, 3, 1,
/* Minor differences on ARM Mali */
1.67f, 0.012f},
{"multidraw", "multidraw2D-distancefield.tga", "multidraw3D-distancefield.tga",
DistanceFieldVectorGL2D::Flag::MultiDraw, 2, 3, 1,
/* Minor differences on ARM Mali */ /* Minor differences on ARM Mali */
1.67f, 0.012f}, 1.67f, 0.012f},
}; };
@ -369,6 +378,19 @@ 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
if(data.flags >= DistanceFieldVectorGL2D::Flag::MultiDraw) {
#ifndef MAGNUM_TARGET_GLES
if(!GL::Context::current().isExtensionSupported<GL::Extensions::ARB::shader_draw_parameters>())
CORRADE_SKIP(GL::Extensions::ARB::shader_draw_parameters::string() << "is not supported.");
#elif !defined(MAGNUM_TARGET_WEBGL)
if(!GL::Context::current().isExtensionSupported<GL::Extensions::ANGLE::multi_draw>())
CORRADE_SKIP(GL::Extensions::ANGLE::multi_draw::string() << "is not supported.");
#else
if(!GL::Context::current().isExtensionSupported<GL::Extensions::WEBGL::multi_draw>())
CORRADE_SKIP(GL::Extensions::WEBGL::multi_draw::string() << "is not supported.");
#endif
}
DistanceFieldVectorGL<dimensions> shader{data.flags, data.materialCount, data.drawCount}; DistanceFieldVectorGL<dimensions> shader{data.flags, data.materialCount, data.drawCount};
CORRADE_COMPARE(shader.flags(), data.flags); CORRADE_COMPARE(shader.flags(), data.flags);
CORRADE_COMPARE(shader.materialCount(), data.materialCount); CORRADE_COMPARE(shader.materialCount(), data.materialCount);
@ -1036,6 +1058,19 @@ 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
if(data.flags >= DistanceFieldVectorGL2D::Flag::MultiDraw) {
#ifndef MAGNUM_TARGET_GLES
if(!GL::Context::current().isExtensionSupported<GL::Extensions::ARB::shader_draw_parameters>())
CORRADE_SKIP(GL::Extensions::ARB::shader_draw_parameters::string() << "is not supported.");
#elif !defined(MAGNUM_TARGET_WEBGL)
if(!GL::Context::current().isExtensionSupported<GL::Extensions::ANGLE::multi_draw>())
CORRADE_SKIP(GL::Extensions::ANGLE::multi_draw::string() << "is not supported.");
#else
if(!GL::Context::current().isExtensionSupported<GL::Extensions::WEBGL::multi_draw>())
CORRADE_SKIP(GL::Extensions::WEBGL::multi_draw::string() << "is not supported.");
#endif
}
if(!(_manager.loadState("AnyImageImporter") & PluginManager::LoadState::Loaded) || if(!(_manager.loadState("AnyImageImporter") & PluginManager::LoadState::Loaded) ||
!(_manager.loadState("TgaImporter") & PluginManager::LoadState::Loaded)) !(_manager.loadState("TgaImporter") & PluginManager::LoadState::Loaded))
CORRADE_SKIP("AnyImageImporter / TgaImporter plugins not found."); CORRADE_SKIP("AnyImageImporter / TgaImporter plugins not found.");
@ -1131,7 +1166,7 @@ void DistanceFieldVectorGLTest::renderMulti2D() {
.setMaterialId(data.drawCount == 1 ? 0 : 0); .setMaterialId(data.drawCount == 1 ? 0 : 0);
GL::Buffer drawUniform{GL::Buffer::TargetHint::Uniform, drawData}; GL::Buffer drawUniform{GL::Buffer::TargetHint::Uniform, drawData};
DistanceFieldVectorGL2D shader{DistanceFieldVectorGL2D::Flag::UniformBuffers|DistanceFieldVectorGL2D::Flag::TextureTransformation, data.materialCount, data.drawCount}; DistanceFieldVectorGL2D shader{DistanceFieldVectorGL2D::Flag::UniformBuffers|DistanceFieldVectorGL2D::Flag::TextureTransformation|data.flags, data.materialCount, data.drawCount};
shader.bindVectorTexture(vector); shader.bindVectorTexture(vector);
/* Just one draw, rebinding UBOs each time */ /* Just one draw, rebinding UBOs each time */
@ -1178,18 +1213,23 @@ void DistanceFieldVectorGLTest::renderMulti2D() {
sizeof(TextureTransformationUniform)); sizeof(TextureTransformationUniform));
shader.draw(triangle); shader.draw(triangle);
/* Otherwise using the draw offset */ /* Otherwise using the draw offset / multidraw */
} else { } else {
shader.bindTransformationProjectionBuffer(transformationProjectionUniform) shader.bindTransformationProjectionBuffer(transformationProjectionUniform)
.bindDrawBuffer(drawUniform) .bindDrawBuffer(drawUniform)
.bindMaterialBuffer(materialUniform) .bindMaterialBuffer(materialUniform)
.bindTextureTransformationBuffer(textureTransformationUniform); .bindTextureTransformationBuffer(textureTransformationUniform);
shader.setDrawOffset(0)
.draw(circle); if(data.flags >= DistanceFieldVectorGL2D::Flag::MultiDraw)
shader.setDrawOffset(1) shader.draw({circle, square, triangle});
.draw(square); else {
shader.setDrawOffset(2) shader.setDrawOffset(0)
.draw(triangle); .draw(circle);
shader.setDrawOffset(1)
.draw(square);
shader.setDrawOffset(2)
.draw(triangle);
}
} }
/* /*
@ -1214,6 +1254,19 @@ 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
if(data.flags >= DistanceFieldVectorGL2D::Flag::MultiDraw) {
#ifndef MAGNUM_TARGET_GLES
if(!GL::Context::current().isExtensionSupported<GL::Extensions::ARB::shader_draw_parameters>())
CORRADE_SKIP(GL::Extensions::ARB::shader_draw_parameters::string() << "is not supported.");
#elif !defined(MAGNUM_TARGET_WEBGL)
if(!GL::Context::current().isExtensionSupported<GL::Extensions::ANGLE::multi_draw>())
CORRADE_SKIP(GL::Extensions::ANGLE::multi_draw::string() << "is not supported.");
#else
if(!GL::Context::current().isExtensionSupported<GL::Extensions::WEBGL::multi_draw>())
CORRADE_SKIP(GL::Extensions::WEBGL::multi_draw::string() << "is not supported.");
#endif
}
if(!(_manager.loadState("AnyImageImporter") & PluginManager::LoadState::Loaded) || if(!(_manager.loadState("AnyImageImporter") & PluginManager::LoadState::Loaded) ||
!(_manager.loadState("TgaImporter") & PluginManager::LoadState::Loaded)) !(_manager.loadState("TgaImporter") & PluginManager::LoadState::Loaded))
CORRADE_SKIP("AnyImageImporter / TgaImporter plugins not found."); CORRADE_SKIP("AnyImageImporter / TgaImporter plugins not found.");
@ -1314,7 +1367,7 @@ void DistanceFieldVectorGLTest::renderMulti3D() {
.setMaterialId(data.drawCount == 1 ? 0 : 0); .setMaterialId(data.drawCount == 1 ? 0 : 0);
GL::Buffer drawUniform{GL::Buffer::TargetHint::Uniform, drawData}; GL::Buffer drawUniform{GL::Buffer::TargetHint::Uniform, drawData};
DistanceFieldVectorGL3D shader{DistanceFieldVectorGL3D::Flag::UniformBuffers|DistanceFieldVectorGL3D::Flag::TextureTransformation, data.materialCount, data.drawCount}; DistanceFieldVectorGL3D shader{DistanceFieldVectorGL3D::Flag::UniformBuffers|DistanceFieldVectorGL3D::Flag::TextureTransformation|data.flags, data.materialCount, data.drawCount};
shader.bindVectorTexture(vector); shader.bindVectorTexture(vector);
/* Just one draw, rebinding UBOs each time */ /* Just one draw, rebinding UBOs each time */
@ -1361,18 +1414,23 @@ void DistanceFieldVectorGLTest::renderMulti3D() {
sizeof(TextureTransformationUniform)); sizeof(TextureTransformationUniform));
shader.draw(cone); shader.draw(cone);
/* Otherwise using the draw offset */ /* Otherwise using the draw offset / multidraw */
} else { } else {
shader.bindTransformationProjectionBuffer(transformationProjectionUniform) shader.bindTransformationProjectionBuffer(transformationProjectionUniform)
.bindDrawBuffer(drawUniform) .bindDrawBuffer(drawUniform)
.bindMaterialBuffer(materialUniform) .bindMaterialBuffer(materialUniform)
.bindTextureTransformationBuffer(textureTransformationUniform); .bindTextureTransformationBuffer(textureTransformationUniform);
shader.setDrawOffset(0)
.draw(sphere); if(data.flags >= DistanceFieldVectorGL3D::Flag::MultiDraw)
shader.setDrawOffset(1) shader.draw({sphere, plane, cone});
.draw(plane); else {
shader.setDrawOffset(2) shader.setDrawOffset(0)
.draw(cone); .draw(sphere);
shader.setDrawOffset(1)
.draw(plane);
shader.setDrawOffset(2)
.draw(cone);
}
} }
/* /*

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

@ -41,17 +41,25 @@ struct DistanceFieldVectorGL_Test: TestSuite::Tester {
void debugFlag(); void debugFlag();
void debugFlags(); void debugFlags();
#ifndef MAGNUM_TARGET_GLES2
void debugFlagsSupersets();
#endif
}; };
DistanceFieldVectorGL_Test::DistanceFieldVectorGL_Test() { DistanceFieldVectorGL_Test::DistanceFieldVectorGL_Test() {
addTests({&DistanceFieldVectorGL_Test::constructNoCreate<2>, addTests({
&DistanceFieldVectorGL_Test::constructNoCreate<3>, &DistanceFieldVectorGL_Test::constructNoCreate<2>,
&DistanceFieldVectorGL_Test::constructNoCreate<3>,
&DistanceFieldVectorGL_Test::constructCopy<2>,
&DistanceFieldVectorGL_Test::constructCopy<3>, &DistanceFieldVectorGL_Test::constructCopy<2>,
&DistanceFieldVectorGL_Test::constructCopy<3>,
&DistanceFieldVectorGL_Test::debugFlag,
&DistanceFieldVectorGL_Test::debugFlags}); &DistanceFieldVectorGL_Test::debugFlag,
&DistanceFieldVectorGL_Test::debugFlags,
#ifndef MAGNUM_TARGET_GLES2
&DistanceFieldVectorGL_Test::debugFlagsSupersets
#endif
});
} }
template<UnsignedInt dimensions> void DistanceFieldVectorGL_Test::constructNoCreate() { template<UnsignedInt dimensions> void DistanceFieldVectorGL_Test::constructNoCreate() {
@ -87,6 +95,15 @@ void DistanceFieldVectorGL_Test::debugFlags() {
CORRADE_COMPARE(out.str(), "Shaders::DistanceFieldVectorGL::Flag::TextureTransformation|Shaders::DistanceFieldVectorGL::Flag(0xf0) Shaders::DistanceFieldVectorGL::Flags{}\n"); CORRADE_COMPARE(out.str(), "Shaders::DistanceFieldVectorGL::Flag::TextureTransformation|Shaders::DistanceFieldVectorGL::Flag(0xf0) Shaders::DistanceFieldVectorGL::Flags{}\n");
} }
#ifndef MAGNUM_TARGET_GLES2
void DistanceFieldVectorGL_Test::debugFlagsSupersets() {
/* MultiDraw is a superset of UniformBuffers so only one should be printed */
std::ostringstream out;
Debug{&out} << (DistanceFieldVectorGL3D::Flag::MultiDraw|DistanceFieldVectorGL3D::Flag::UniformBuffers);
CORRADE_COMPARE(out.str(), "Shaders::DistanceFieldVectorGL::Flag::MultiDraw\n");
}
#endif
}}}} }}}}
CORRADE_TEST_MAIN(Magnum::Shaders::Test::DistanceFieldVectorGL_Test) CORRADE_TEST_MAIN(Magnum::Shaders::Test::DistanceFieldVectorGL_Test)

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

@ -161,24 +161,27 @@ struct FlatGLTest: GL::OpenGLTester {
[A] alpha mask [A] alpha mask
[D] object ID [D] object ID
[I] instancing [I] instancing
[O] draw offset [O] UBOs + draw offset
[M] multidraw
Mesa Intel BADIO Mesa Intel BADIOM
ES2 x ES2 xx
ES3 BADIO ES3 BADIOx
Mesa AMD BADI Mesa AMD BADI
Mesa llvmpipe BADI Mesa llvmpipe BADI
SwiftShader ES2 BADIx SwiftShader ES2 BADIxx
ES3 BADI ES3 BADI
ARM Mali (Huawei P10) ES2 BAD x ANGLE ES2 xx
ES3 BADIO ES3 BADIOM
WebGL (on Mesa Intel) 1.0 BAD x ARM Mali (Huawei P10) ES2 BAD xx
2.0 BADIO ES3 BADIOx
WebGL (on Mesa Intel) 1.0 BAD xx
2.0 BADIOM
NVidia BAD NVidia BAD
Intel Windows BAD Intel Windows BAD
AMD macOS BAD AMD macOS BAD
Intel macOS BADIO Intel macOS BADIOx
iPhone 6 w/ iOS 12.4 ES3 BAD iPhone 6 w/ iOS 12.4 ES3 BAD x
*/ */
using namespace Math::Literals; using namespace Math::Literals;
@ -216,7 +219,8 @@ constexpr struct {
{"multiple draws", FlatGL2D::Flag::UniformBuffers, 42}, {"multiple draws", FlatGL2D::Flag::UniformBuffers, 42},
{"texture transformation", FlatGL2D::Flag::UniformBuffers|FlatGL2D::Flag::Textured|FlatGL2D::Flag::TextureTransformation, 1}, {"texture transformation", FlatGL2D::Flag::UniformBuffers|FlatGL2D::Flag::Textured|FlatGL2D::Flag::TextureTransformation, 1},
{"alpha mask", FlatGL2D::Flag::UniformBuffers|FlatGL2D::Flag::AlphaMask, 1}, {"alpha mask", FlatGL2D::Flag::UniformBuffers|FlatGL2D::Flag::AlphaMask, 1},
{"object ID", FlatGL2D::Flag::UniformBuffers|FlatGL2D::Flag::ObjectId, 1} {"object ID", FlatGL2D::Flag::UniformBuffers|FlatGL2D::Flag::ObjectId, 1},
{"multidraw with all the things", FlatGL2D::Flag::MultiDraw|FlatGL2D::Flag::TextureTransformation|FlatGL2D::Flag::Textured|FlatGL2D::Flag::AlphaMask|FlatGL2D::Flag::ObjectId|FlatGL2D::Flag::InstancedTextureOffset|FlatGL2D::Flag::InstancedTransformation|FlatGL2D::Flag::InstancedObjectId, 42}
}; };
#endif #endif
@ -290,11 +294,19 @@ constexpr struct {
/* Minor differences on ARM Mali */ /* Minor differences on ARM Mali */
2.34f, 0.01f}, 2.34f, 0.01f},
{"draw offset, colored", "multidraw2D.tga", "multidraw3D.tga", {"draw offset, colored", "multidraw2D.tga", "multidraw3D.tga",
{}, 3, 1, 0.0f, 0.0f}, {},
3, 1, 0.0f, 0.0f},
{"draw offset, textured", "multidraw-textured2D.tga", "multidraw-textured3D.tga", {"draw offset, textured", "multidraw-textured2D.tga", "multidraw-textured3D.tga",
FlatGL2D::Flag::TextureTransformation|FlatGL2D::Flag::Textured, FlatGL2D::Flag::TextureTransformation|FlatGL2D::Flag::Textured,
3, 1, 3, 1,
/* Minor differences on ARM Mali */ /* Minor differences on ARM Mali */
2.34f, 0.01f},
{"multidraw, colored", "multidraw2D.tga", "multidraw3D.tga",
FlatGL2D::Flag::MultiDraw, 3, 1, 0.0f, 0.0f},
{"multidraw, textured", "multidraw-textured2D.tga", "multidraw-textured3D.tga",
FlatGL2D::Flag::MultiDraw|FlatGL2D::Flag::TextureTransformation|FlatGL2D::Flag::Textured,
3, 1,
/* Minor differences on ARM Mali */
2.34f, 0.01f} 2.34f, 0.01f}
}; };
#endif #endif
@ -532,6 +544,19 @@ template<UnsignedInt dimensions> void FlatGLTest::constructUniformBuffers() {
CORRADE_SKIP(GL::Extensions::EXT::gpu_shader4::string() << "is not supported."); CORRADE_SKIP(GL::Extensions::EXT::gpu_shader4::string() << "is not supported.");
#endif #endif
if(data.flags >= FlatGL2D::Flag::MultiDraw) {
#ifndef MAGNUM_TARGET_GLES
if(!GL::Context::current().isExtensionSupported<GL::Extensions::ARB::shader_draw_parameters>())
CORRADE_SKIP(GL::Extensions::ARB::shader_draw_parameters::string() << "is not supported.");
#elif !defined(MAGNUM_TARGET_WEBGL)
if(!GL::Context::current().isExtensionSupported<GL::Extensions::ANGLE::multi_draw>())
CORRADE_SKIP(GL::Extensions::ANGLE::multi_draw::string() << "is not supported.");
#else
if(!GL::Context::current().isExtensionSupported<GL::Extensions::WEBGL::multi_draw>())
CORRADE_SKIP(GL::Extensions::WEBGL::multi_draw::string() << "is not supported.");
#endif
}
FlatGL<dimensions> shader{data.flags, data.drawCount}; FlatGL<dimensions> shader{data.flags, data.drawCount};
CORRADE_COMPARE(shader.flags(), data.flags); CORRADE_COMPARE(shader.flags(), data.flags);
CORRADE_COMPARE(shader.drawCount(), data.drawCount); CORRADE_COMPARE(shader.drawCount(), data.drawCount);
@ -2266,6 +2291,19 @@ void FlatGLTest::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
if(data.flags >= FlatGL2D::Flag::MultiDraw) {
#ifndef MAGNUM_TARGET_GLES
if(!GL::Context::current().isExtensionSupported<GL::Extensions::ARB::shader_draw_parameters>())
CORRADE_SKIP(GL::Extensions::ARB::shader_draw_parameters::string() << "is not supported.");
#elif !defined(MAGNUM_TARGET_WEBGL)
if(!GL::Context::current().isExtensionSupported<GL::Extensions::ANGLE::multi_draw>())
CORRADE_SKIP(GL::Extensions::ANGLE::multi_draw::string() << "is not supported.");
#else
if(!GL::Context::current().isExtensionSupported<GL::Extensions::WEBGL::multi_draw>())
CORRADE_SKIP(GL::Extensions::WEBGL::multi_draw::string() << "is not supported.");
#endif
}
GL::Texture2D texture; GL::Texture2D texture;
if(data.flags & FlatGL2D::Flag::Textured) { if(data.flags & FlatGL2D::Flag::Textured) {
if(!(_manager.loadState("AnyImageImporter") & PluginManager::LoadState::Loaded) || if(!(_manager.loadState("AnyImageImporter") & PluginManager::LoadState::Loaded) ||
@ -2402,18 +2440,23 @@ void FlatGLTest::renderMulti2D() {
sizeof(TextureTransformationUniform)); sizeof(TextureTransformationUniform));
shader.draw(triangle); shader.draw(triangle);
/* Otherwise using the draw offset */ /* Otherwise using the draw offset / multidraw */
} else { } else {
shader.bindTransformationProjectionBuffer(transformationProjectionUniform) shader.bindTransformationProjectionBuffer(transformationProjectionUniform)
.bindDrawBuffer(drawUniform); .bindDrawBuffer(drawUniform);
if(data.flags & FlatGL2D::Flag::TextureTransformation) if(data.flags & FlatGL2D::Flag::TextureTransformation)
shader.bindTextureTransformationBuffer(textureTransformationUniform); shader.bindTextureTransformationBuffer(textureTransformationUniform);
shader.setDrawOffset(0)
.draw(circle); if(data.flags >= FlatGL2D::Flag::MultiDraw)
shader.setDrawOffset(1) shader.draw({circle, square, triangle});
.draw(square); else {
shader.setDrawOffset(2) shader.setDrawOffset(0)
.draw(triangle); .draw(circle);
shader.setDrawOffset(1)
.draw(square);
shader.setDrawOffset(2)
.draw(triangle);
}
} }
MAGNUM_VERIFY_NO_GL_ERROR(); MAGNUM_VERIFY_NO_GL_ERROR();
@ -2469,6 +2512,19 @@ void FlatGLTest::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
if(data.flags >= FlatGL3D::Flag::MultiDraw) {
#ifndef MAGNUM_TARGET_GLES
if(!GL::Context::current().isExtensionSupported<GL::Extensions::ARB::shader_draw_parameters>())
CORRADE_SKIP(GL::Extensions::ARB::shader_draw_parameters::string() << "is not supported.");
#elif !defined(MAGNUM_TARGET_WEBGL)
if(!GL::Context::current().isExtensionSupported<GL::Extensions::ANGLE::multi_draw>())
CORRADE_SKIP(GL::Extensions::ANGLE::multi_draw::string() << "is not supported.");
#else
if(!GL::Context::current().isExtensionSupported<GL::Extensions::WEBGL::multi_draw>())
CORRADE_SKIP(GL::Extensions::WEBGL::multi_draw::string() << "is not supported.");
#endif
}
GL::Texture2D texture; GL::Texture2D texture;
if(data.flags & FlatGL3D::Flag::Textured) { if(data.flags & FlatGL3D::Flag::Textured) {
if(!(_manager.loadState("AnyImageImporter") & PluginManager::LoadState::Loaded) || if(!(_manager.loadState("AnyImageImporter") & PluginManager::LoadState::Loaded) ||
@ -2611,18 +2667,23 @@ void FlatGLTest::renderMulti3D() {
sizeof(TextureTransformationUniform)); sizeof(TextureTransformationUniform));
shader.draw(cone); shader.draw(cone);
/* Otherwise using the draw offset */ /* Otherwise using the draw offset / multidraw */
} else { } else {
shader.bindTransformationProjectionBuffer(transformationProjectionUniform) shader.bindTransformationProjectionBuffer(transformationProjectionUniform)
.bindDrawBuffer(drawUniform); .bindDrawBuffer(drawUniform);
if(data.flags & FlatGL3D::Flag::TextureTransformation) if(data.flags & FlatGL3D::Flag::TextureTransformation)
shader.bindTextureTransformationBuffer(textureTransformationUniform); shader.bindTextureTransformationBuffer(textureTransformationUniform);
shader.setDrawOffset(0)
.draw(sphere); if(data.flags >= FlatGL3D::Flag::MultiDraw)
shader.setDrawOffset(1) shader.draw({sphere, plane, cone});
.draw(plane); else {
shader.setDrawOffset(2) shader.setDrawOffset(0)
.draw(cone); .draw(sphere);
shader.setDrawOffset(1)
.draw(plane);
shader.setDrawOffset(2)
.draw(cone);
}
} }
MAGNUM_VERIFY_NO_GL_ERROR(); MAGNUM_VERIFY_NO_GL_ERROR();

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

@ -102,9 +102,20 @@ void FlatGL_Test::debugFlagsSupersets() {
/* InstancedTextureOffset is a superset of TextureTransformation so only /* InstancedTextureOffset is a superset of TextureTransformation so only
one should be printed */ one should be printed */
std::ostringstream out; {
Debug{&out} << (FlatGL3D::Flag::InstancedTextureOffset|FlatGL3D::Flag::TextureTransformation); std::ostringstream out;
CORRADE_COMPARE(out.str(), "Shaders::FlatGL::Flag::InstancedTextureOffset\n"); Debug{&out} << (FlatGL3D::Flag::InstancedTextureOffset|FlatGL3D::Flag::TextureTransformation);
CORRADE_COMPARE(out.str(), "Shaders::FlatGL::Flag::InstancedTextureOffset\n");
}
#ifndef MAGNUM_TARGET_GLES2
/* MultiDraw is a superset of UniformBuffers so only one should be printed */
{
std::ostringstream out;
Debug{&out} << (FlatGL3D::Flag::MultiDraw|FlatGL3D::Flag::UniformBuffers);
CORRADE_COMPARE(out.str(), "Shaders::FlatGL::Flag::MultiDraw\n");
}
#endif
} }
}}}} }}}}

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

@ -180,23 +180,26 @@ struct MeshVisualizerGLTest: GL::OpenGLTester {
[D] primitive/vertex/object ID [D] primitive/vertex/object ID
[T] TBN visualization [T] TBN visualization
[O] draw offset [O] draw offset
[M] multidraw
Mesa Intel WDTO Mesa Intel WDTOM
ES2 x ES2 xx
ES3 ES3 x
Mesa AMD WDT Mesa AMD WDT
Mesa llvmpipe WDT Mesa llvmpipe WDT
SwiftShader ES2 WDxx SwiftShader ES2 WDxxx
ES3 WDx ES3 WDx
ARM Mali (Huawei P10) ES2 W xx ANGLE ES2 xx
ES3 W O (WDT big diffs, needs investigation) ES3 WDxOM
WebGL (on Mesa Intel) 1.0 W xx ARM Mali (Huawei P10) ES2 W xxx
2.0 W x ES3 W Ox (WDT big diffs, needs investigation)
WebGL (on Mesa Intel) 1.0 W xxx
2.0 W x M
NVidia NVidia
Intel Windows Intel Windows
AMD macOS AMD macOS
Intel macOS WDTO Intel macOS WDTOx
iPhone 6 w/ iOS 12.4 ES3 W x iPhone 6 w/ iOS 12.4 ES3 W x x
*/ */
using namespace Math::Literals; using namespace Math::Literals;
@ -232,6 +235,10 @@ constexpr struct {
/* SwiftShader has 256 uniform vectors at most, per-2D-draw is 4, /* SwiftShader has 256 uniform vectors at most, per-2D-draw is 4,
per-material 4, two need to be left for drawOffset + viewportSize */ per-material 4, two need to be left for drawOffset + viewportSize */
{"multiple materials, draws", MeshVisualizerGL2D::Flag::UniformBuffers|MeshVisualizerGL2D::Flag::Wireframe|MeshVisualizerGL2D::Flag::NoGeometryShader, 8, 55}, {"multiple materials, draws", MeshVisualizerGL2D::Flag::UniformBuffers|MeshVisualizerGL2D::Flag::Wireframe|MeshVisualizerGL2D::Flag::NoGeometryShader, 8, 55},
{"multidraw with wireframe w/o GS and vertex ID", MeshVisualizerGL2D::Flag::MultiDraw|MeshVisualizerGL2D::Flag::Wireframe|MeshVisualizerGL2D::Flag::NoGeometryShader|MeshVisualizerGL2D::Flag::VertexId, 8, 55},
#ifndef MAGNUM_TARGET_WEBGL
{"multidraw with wireframe and primitive ID", MeshVisualizerGL2D::Flag::MultiDraw|MeshVisualizerGL2D::Flag::Wireframe|MeshVisualizerGL2D::Flag::PrimitiveId, 8, 55},
#endif
/* The rest is basically a copy of ConstructData2D with UniformBuffers /* The rest is basically a copy of ConstructData2D with UniformBuffers
added */ added */
#ifndef MAGNUM_TARGET_WEBGL #ifndef MAGNUM_TARGET_WEBGL
@ -293,6 +300,10 @@ constexpr struct {
/* SwiftShader has 256 uniform vectors at most, per-3D-draw is 4+4, /* SwiftShader has 256 uniform vectors at most, per-3D-draw is 4+4,
per-material 4, plus 4 for projection */ per-material 4, plus 4 for projection */
{"multiple materials, draws", MeshVisualizerGL3D::Flag::UniformBuffers|MeshVisualizerGL3D::Flag::Wireframe|MeshVisualizerGL3D::Flag::NoGeometryShader, 6, 28}, {"multiple materials, draws", MeshVisualizerGL3D::Flag::UniformBuffers|MeshVisualizerGL3D::Flag::Wireframe|MeshVisualizerGL3D::Flag::NoGeometryShader, 6, 28},
{"multidraw with wireframe w/o GS and vertex ID", MeshVisualizerGL3D::Flag::MultiDraw|MeshVisualizerGL3D::Flag::Wireframe|MeshVisualizerGL3D::Flag::NoGeometryShader|MeshVisualizerGL3D::Flag::VertexId, 6, 28},
#ifndef MAGNUM_TARGET_WEBGL
{"multidraw with wireframe, primitive ID and TBN", MeshVisualizerGL3D::Flag::MultiDraw|MeshVisualizerGL3D::Flag::Wireframe|MeshVisualizerGL3D::Flag::PrimitiveId|MeshVisualizerGL3D::Flag::TangentDirection|MeshVisualizerGL3D::Flag::BitangentDirection|MeshVisualizerGL3D::Flag::NormalDirection, 6, 28},
#endif
/* The rest is basically a copy of ConstructData2D with UniformBuffers /* The rest is basically a copy of ConstructData2D with UniformBuffers
added */ added */
#ifndef MAGNUM_TARGET_WEBGL #ifndef MAGNUM_TARGET_WEBGL
@ -605,6 +616,23 @@ constexpr struct {
2, 3, 1, 2, 3, 1,
/* Minor differences on ARM Mali */ /* Minor differences on ARM Mali */
0.67f, 0.01f}, 0.67f, 0.01f},
#ifndef MAGNUM_TARGET_WEBGL
{"multidraw, wireframe", "multidraw-wireframe2D.tga",
MeshVisualizerGL2D::Flag::MultiDraw|MeshVisualizerGL2D::Flag::Wireframe,
2, 3, 1,
/* Minor differences on ARM Mali */
0.67f, 0.01f},
#endif
{"multidraw, wireframe w/o GS", "multidraw-wireframe-nogeo2D.tga",
MeshVisualizerGL2D::Flag::MultiDraw|MeshVisualizerGL2D::Flag::Wireframe|MeshVisualizerGL2D::Flag::NoGeometryShader,
2, 3, 1,
/* Minor differences on ARM Mali */
0.67f, 0.02f},
{"multidraw, vertex ID", "multidraw-vertexid2D.tga",
MeshVisualizerGL2D::Flag::MultiDraw|MeshVisualizerGL2D::Flag::VertexId,
2, 3, 1,
/* Minor differences on ARM Mali */
0.67f, 0.01f},
}; };
constexpr struct { constexpr struct {
@ -651,6 +679,24 @@ constexpr struct {
2, 3, 1, 2, 3, 1,
/* Minor differences on ARM Mali */ /* Minor differences on ARM Mali */
0.67f, 0.01f}, 0.67f, 0.01f},
#ifndef MAGNUM_TARGET_WEBGL
{"multidraw, wireframe", "multidraw-wireframe3D.tga",
MeshVisualizerGL3D::Flag::MultiDraw|MeshVisualizerGL3D::Flag::Wireframe,
2, 3, 1, 0.0f, 0.0f},
{"multidraw, wireframe + TBN", "multidraw-wireframe-tbn3D.tga",
MeshVisualizerGL3D::Flag::MultiDraw|MeshVisualizerGL3D::Flag::Wireframe|MeshVisualizerGL3D::Flag::TangentDirection|MeshVisualizerGL3D::Flag::BitangentFromTangentDirection|MeshVisualizerGL3D::Flag::NormalDirection,
2, 3, 1, 0.0f, 0.0f},
#endif
{"multidraw, wireframe w/o GS", "multidraw-wireframe-nogeo3D.tga",
MeshVisualizerGL3D::Flag::MultiDraw|MeshVisualizerGL3D::Flag::Wireframe|MeshVisualizerGL3D::Flag::NoGeometryShader,
2, 3, 1,
/* Minor differences on ARM Mali */
6.0f, 0.04f},
{"multidraw, vertex ID", "multidraw-vertexid3D.tga",
MeshVisualizerGL3D::Flag::MultiDraw|MeshVisualizerGL3D::Flag::VertexId,
2, 3, 1,
/* Minor differences on ARM Mali */
0.67f, 0.01f},
}; };
#endif #endif
@ -998,6 +1044,19 @@ void MeshVisualizerGLTest::constructUniformBuffers2D() {
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
if(data.flags >= MeshVisualizerGL2D::Flag::MultiDraw) {
#ifndef MAGNUM_TARGET_GLES
if(!GL::Context::current().isExtensionSupported<GL::Extensions::ARB::shader_draw_parameters>())
CORRADE_SKIP(GL::Extensions::ARB::shader_draw_parameters::string() << "is not supported.");
#elif !defined(MAGNUM_TARGET_WEBGL)
if(!GL::Context::current().isExtensionSupported<GL::Extensions::ANGLE::multi_draw>())
CORRADE_SKIP(GL::Extensions::ANGLE::multi_draw::string() << "is not supported.");
#else
if(!GL::Context::current().isExtensionSupported<GL::Extensions::WEBGL::multi_draw>())
CORRADE_SKIP(GL::Extensions::WEBGL::multi_draw::string() << "is not supported.");
#endif
}
MeshVisualizerGL2D shader{data.flags, data.materialCount, data.drawCount}; MeshVisualizerGL2D shader{data.flags, data.materialCount, data.drawCount};
CORRADE_COMPARE(shader.flags(), data.flags); CORRADE_COMPARE(shader.flags(), data.flags);
CORRADE_VERIFY(shader.id()); CORRADE_VERIFY(shader.id());
@ -1123,6 +1182,19 @@ void MeshVisualizerGLTest::constructUniformBuffers3D() {
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
if(data.flags >= MeshVisualizerGL3D::Flag::MultiDraw) {
#ifndef MAGNUM_TARGET_GLES
if(!GL::Context::current().isExtensionSupported<GL::Extensions::ARB::shader_draw_parameters>())
CORRADE_SKIP(GL::Extensions::ARB::shader_draw_parameters::string() << "is not supported.");
#elif !defined(MAGNUM_TARGET_WEBGL)
if(!GL::Context::current().isExtensionSupported<GL::Extensions::ANGLE::multi_draw>())
CORRADE_SKIP(GL::Extensions::ANGLE::multi_draw::string() << "is not supported.");
#else
if(!GL::Context::current().isExtensionSupported<GL::Extensions::WEBGL::multi_draw>())
CORRADE_SKIP(GL::Extensions::WEBGL::multi_draw::string() << "is not supported.");
#endif
}
MeshVisualizerGL3D shader{data.flags, data.materialCount, data.drawCount}; MeshVisualizerGL3D shader{data.flags, data.materialCount, data.drawCount};
CORRADE_COMPARE(shader.flags(), data.flags); CORRADE_COMPARE(shader.flags(), data.flags);
CORRADE_VERIFY(shader.id()); CORRADE_VERIFY(shader.id());
@ -3158,6 +3230,19 @@ void MeshVisualizerGLTest::renderMulti2D() {
} }
#endif #endif
if(data.flags >= MeshVisualizerGL2D::Flag::MultiDraw) {
#ifndef MAGNUM_TARGET_GLES
if(!GL::Context::current().isExtensionSupported<GL::Extensions::ARB::shader_draw_parameters>())
CORRADE_SKIP(GL::Extensions::ARB::shader_draw_parameters::string() << "is not supported.");
#elif !defined(MAGNUM_TARGET_WEBGL)
if(!GL::Context::current().isExtensionSupported<GL::Extensions::ANGLE::multi_draw>())
CORRADE_SKIP(GL::Extensions::ANGLE::multi_draw::string() << "is not supported.");
#else
if(!GL::Context::current().isExtensionSupported<GL::Extensions::WEBGL::multi_draw>())
CORRADE_SKIP(GL::Extensions::WEBGL::multi_draw::string() << "is not supported.");
#endif
}
/* Circle is a fan, plane is a strip, make it indexed first */ /* Circle is a fan, plane is a strip, make it indexed first */
Trade::MeshData circleData = MeshTools::generateIndices(Primitives::circle2DSolid(8)); Trade::MeshData circleData = MeshTools::generateIndices(Primitives::circle2DSolid(8));
Trade::MeshData squareData = MeshTools::generateIndices(Primitives::squareSolid()); Trade::MeshData squareData = MeshTools::generateIndices(Primitives::squareSolid());
@ -3273,17 +3358,22 @@ void MeshVisualizerGLTest::renderMulti2D() {
sizeof(MeshVisualizerDrawUniform2D)); sizeof(MeshVisualizerDrawUniform2D));
shader.draw(triangle); shader.draw(triangle);
/* Otherwise using the draw offset */ /* Otherwise using the draw offset / multidraw */
} else { } else {
shader.bindMaterialBuffer(materialUniform) shader.bindMaterialBuffer(materialUniform)
.bindTransformationProjectionBuffer(transformationProjectionUniform) .bindTransformationProjectionBuffer(transformationProjectionUniform)
.bindDrawBuffer(drawUniform); .bindDrawBuffer(drawUniform);
shader.setDrawOffset(0)
.draw(circle); if(data.flags >= MeshVisualizerGL2D::Flag::MultiDraw)
shader.setDrawOffset(1) shader.draw({circle, square, triangle});
.draw(square); else {
shader.setDrawOffset(2) shader.setDrawOffset(0)
.draw(triangle); .draw(circle);
shader.setDrawOffset(1)
.draw(square);
shader.setDrawOffset(2)
.draw(triangle);
}
}; };
MAGNUM_VERIFY_NO_GL_ERROR(); MAGNUM_VERIFY_NO_GL_ERROR();
@ -3333,6 +3423,19 @@ void MeshVisualizerGLTest::renderMulti3D() {
} }
#endif #endif
if(data.flags >= MeshVisualizerGL3D::Flag::MultiDraw) {
#ifndef MAGNUM_TARGET_GLES
if(!GL::Context::current().isExtensionSupported<GL::Extensions::ARB::shader_draw_parameters>())
CORRADE_SKIP(GL::Extensions::ARB::shader_draw_parameters::string() << "is not supported.");
#elif !defined(MAGNUM_TARGET_WEBGL)
if(!GL::Context::current().isExtensionSupported<GL::Extensions::ANGLE::multi_draw>())
CORRADE_SKIP(GL::Extensions::ANGLE::multi_draw::string() << "is not supported.");
#else
if(!GL::Context::current().isExtensionSupported<GL::Extensions::WEBGL::multi_draw>())
CORRADE_SKIP(GL::Extensions::WEBGL::multi_draw::string() << "is not supported.");
#endif
}
Trade::MeshData sphereData = MeshTools::interleave(Primitives::icosphereSolid(0), { Trade::MeshData sphereData = MeshTools::interleave(Primitives::icosphereSolid(0), {
/* The icosphere doesn't have tangents and we don't use them, but /* The icosphere doesn't have tangents and we don't use them, but
concatenate() will ignore the tangents of others if the first mesh concatenate() will ignore the tangents of others if the first mesh
@ -3462,17 +3565,22 @@ void MeshVisualizerGLTest::renderMulti3D() {
sizeof(MeshVisualizerDrawUniform3D)); sizeof(MeshVisualizerDrawUniform3D));
shader.draw(cone); shader.draw(cone);
/* Otherwise using the draw offset */ /* Otherwise using the draw offset / multidraw */
} else { } else {
shader.bindMaterialBuffer(materialUniform) shader.bindMaterialBuffer(materialUniform)
.bindTransformationBuffer(transformationUniform) .bindTransformationBuffer(transformationUniform)
.bindDrawBuffer(drawUniform); .bindDrawBuffer(drawUniform);
shader.setDrawOffset(0)
.draw(sphere); if(data.flags >= MeshVisualizerGL3D::Flag::MultiDraw)
shader.setDrawOffset(1) shader.draw({sphere, plane, cone});
.draw(plane); else {
shader.setDrawOffset(2) shader.setDrawOffset(0)
.draw(cone); .draw(sphere);
shader.setDrawOffset(1)
.draw(plane);
shader.setDrawOffset(2)
.draw(cone);
}
}; };
MAGNUM_VERIFY_NO_GL_ERROR(); MAGNUM_VERIFY_NO_GL_ERROR();

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

@ -48,21 +48,31 @@ struct MeshVisualizerGL_Test: TestSuite::Tester {
void debugFlag3D(); void debugFlag3D();
void debugFlags2D(); void debugFlags2D();
void debugFlags3D(); void debugFlags3D();
#ifndef MAGNUM_TARGET_GLES2
void debugFlagsSupersets2D();
void debugFlagsSupersets3D();
#endif
}; };
MeshVisualizerGL_Test::MeshVisualizerGL_Test() { MeshVisualizerGL_Test::MeshVisualizerGL_Test() {
addTests({&MeshVisualizerGL_Test::constructNoCreate2D, addTests({
&MeshVisualizerGL_Test::constructNoCreate3D, &MeshVisualizerGL_Test::constructNoCreate2D,
&MeshVisualizerGL_Test::constructNoCreate3D,
&MeshVisualizerGL_Test::constructCopy2D,
&MeshVisualizerGL_Test::constructCopy3D, &MeshVisualizerGL_Test::constructCopy2D,
&MeshVisualizerGL_Test::constructCopy3D,
&MeshVisualizerGL_Test::vertexIndexSameAsObjectId,
&MeshVisualizerGL_Test::vertexIndexSameAsObjectId,
&MeshVisualizerGL_Test::debugFlag2D,
&MeshVisualizerGL_Test::debugFlag3D, &MeshVisualizerGL_Test::debugFlag2D,
&MeshVisualizerGL_Test::debugFlags2D, &MeshVisualizerGL_Test::debugFlag3D,
&MeshVisualizerGL_Test::debugFlags3D}); &MeshVisualizerGL_Test::debugFlags2D,
&MeshVisualizerGL_Test::debugFlags3D,
#ifndef MAGNUM_TARGET_GLES2
&MeshVisualizerGL_Test::debugFlagsSupersets2D,
&MeshVisualizerGL_Test::debugFlagsSupersets3D,
#endif
});
} }
void MeshVisualizerGL_Test::constructNoCreate2D() { void MeshVisualizerGL_Test::constructNoCreate2D() {
@ -140,6 +150,22 @@ void MeshVisualizerGL_Test::debugFlags3D() {
#endif #endif
} }
#ifndef MAGNUM_TARGET_GLES2
void MeshVisualizerGL_Test::debugFlagsSupersets2D() {
/* MultiDraw is a superset of UniformBuffers so only one should be printed */
std::ostringstream out;
Debug{&out} << (MeshVisualizerGL2D::Flag::MultiDraw|MeshVisualizerGL2D::Flag::UniformBuffers);
CORRADE_COMPARE(out.str(), "Shaders::MeshVisualizerGL2D::Flag::MultiDraw\n");
}
void MeshVisualizerGL_Test::debugFlagsSupersets3D() {
/* MultiDraw is a superset of UniformBuffers so only one should be printed */
std::ostringstream out;
Debug{&out} << (MeshVisualizerGL3D::Flag::MultiDraw|MeshVisualizerGL3D::Flag::UniformBuffers);
CORRADE_COMPARE(out.str(), "Shaders::MeshVisualizerGL3D::Flag::MultiDraw\n");
}
#endif
}}}} }}}}
CORRADE_TEST_MAIN(Magnum::Shaders::Test::MeshVisualizerGL_Test) CORRADE_TEST_MAIN(Magnum::Shaders::Test::MeshVisualizerGL_Test)

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

@ -168,24 +168,27 @@ struct PhongGLTest: GL::OpenGLTester {
[D] object ID [D] object ID
[L] point lights [L] point lights
[I] instancing [I] instancing
[O] draw offset [O] UBOs + draw offset
[M] multidraw
Mesa Intel BADLIO Mesa Intel BADLIOM
ES2 x ES2 xx
ES3 BADLIO ES3 BADLIOx
Mesa AMD BAD I Mesa AMD BAD I
Mesa llvmpipe BAD I Mesa llvmpipe BAD I
SwiftShader ES2 BADLIx SwiftShader ES2 BADLIxx
ES3 BADLI ES3 BADLI
ARM Mali (Huawei P10) ES2 BAD x ANGLE ES2 xx
ES3 BADLIO ES3 BADLIOM
WebGL (on Mesa Intel) 1.0 BAD x ARM Mali (Huawei P10) ES2 BAD xx
2.0 BADLIO ES3 BADLIOx
WebGL (on Mesa Intel) 1.0 BAD xx
2.0 BADLIOM
NVidia BAD NVidia BAD
Intel Windows BAD Intel Windows BAD
AMD macOS BAD AMD macOS BAD
Intel macOS BADLIO Intel macOS BADLIOx
iPhone 6 w/ iOS 12.4 ES3 BAD iPhone 6 w/ iOS 12.4 ES3 BAD x
*/ */
constexpr struct { constexpr struct {
@ -244,7 +247,8 @@ constexpr struct {
{"normal texture", PhongGL::Flag::UniformBuffers|PhongGL::Flag::NormalTexture, 1, 1, 1}, {"normal texture", PhongGL::Flag::UniformBuffers|PhongGL::Flag::NormalTexture, 1, 1, 1},
{"normal texture + separate bitangents", PhongGL::Flag::UniformBuffers|PhongGL::Flag::NormalTexture|PhongGL::Flag::Bitangent, 1, 1, 1}, {"normal texture + separate bitangents", PhongGL::Flag::UniformBuffers|PhongGL::Flag::NormalTexture|PhongGL::Flag::Bitangent, 1, 1, 1},
{"alpha mask", PhongGL::Flag::UniformBuffers|PhongGL::Flag::AlphaMask, 1, 1, 1}, {"alpha mask", PhongGL::Flag::UniformBuffers|PhongGL::Flag::AlphaMask, 1, 1, 1},
{"object ID", PhongGL::Flag::UniformBuffers|PhongGL::Flag::ObjectId, 1, 1, 1} {"object ID", PhongGL::Flag::UniformBuffers|PhongGL::Flag::ObjectId, 1, 1, 1},
{"multidraw with all the things", PhongGL::Flag::MultiDraw|PhongGL::Flag::TextureTransformation|PhongGL::Flag::DiffuseTexture|PhongGL::Flag::AmbientTexture|PhongGL::Flag::SpecularTexture|PhongGL::Flag::NormalTexture|PhongGL::Flag::AlphaMask|PhongGL::Flag::ObjectId|PhongGL::Flag::InstancedTextureOffset|PhongGL::Flag::InstancedTransformation|PhongGL::Flag::InstancedObjectId, 8, 16, 24}
}; };
#endif #endif
@ -617,6 +621,16 @@ constexpr struct {
4, 2, 3, 1, 4, 2, 3, 1,
/* Minor differences on ARM Mali */ /* Minor differences on ARM Mali */
4.67f, 0.02f}, 4.67f, 0.02f},
{"multidraw, colored", "multidraw.tga",
PhongGL::Flag::MultiDraw,
4, 2, 3, 1,
/* Minor differences on ARM Mali */
3.34f, 0.01f},
{"multidraw, textured", "multidraw-textured.tga",
PhongGL::Flag::MultiDraw|PhongGL::Flag::TextureTransformation|PhongGL::Flag::DiffuseTexture,
4, 2, 3, 1,
/* Minor differences on ARM Mali */
4.67f, 0.02f},
}; };
#endif #endif
@ -875,6 +889,19 @@ void PhongGLTest::constructUniformBuffers() {
CORRADE_SKIP(GL::Extensions::EXT::gpu_shader4::string() << "is not supported."); CORRADE_SKIP(GL::Extensions::EXT::gpu_shader4::string() << "is not supported.");
#endif #endif
if(data.flags >= PhongGL::Flag::MultiDraw) {
#ifndef MAGNUM_TARGET_GLES
if(!GL::Context::current().isExtensionSupported<GL::Extensions::ARB::shader_draw_parameters>())
CORRADE_SKIP(GL::Extensions::ARB::shader_draw_parameters::string() << "is not supported.");
#elif !defined(MAGNUM_TARGET_WEBGL)
if(!GL::Context::current().isExtensionSupported<GL::Extensions::ANGLE::multi_draw>())
CORRADE_SKIP(GL::Extensions::ANGLE::multi_draw::string() << "is not supported.");
#else
if(!GL::Context::current().isExtensionSupported<GL::Extensions::WEBGL::multi_draw>())
CORRADE_SKIP(GL::Extensions::WEBGL::multi_draw::string() << "is not supported.");
#endif
}
PhongGL shader{data.flags, data.lightCount, data.materialCount, data.drawCount}; PhongGL shader{data.flags, data.lightCount, data.materialCount, data.drawCount};
CORRADE_COMPARE(shader.flags(), data.flags); CORRADE_COMPARE(shader.flags(), data.flags);
CORRADE_COMPARE(shader.lightCount(), data.lightCount); CORRADE_COMPARE(shader.lightCount(), data.lightCount);
@ -2971,6 +2998,19 @@ void PhongGLTest::renderMulti() {
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
if(data.flags >= PhongGL::Flag::MultiDraw) {
#ifndef MAGNUM_TARGET_GLES
if(!GL::Context::current().isExtensionSupported<GL::Extensions::ARB::shader_draw_parameters>())
CORRADE_SKIP(GL::Extensions::ARB::shader_draw_parameters::string() << "is not supported.");
#elif !defined(MAGNUM_TARGET_WEBGL)
if(!GL::Context::current().isExtensionSupported<GL::Extensions::ANGLE::multi_draw>())
CORRADE_SKIP(GL::Extensions::ANGLE::multi_draw::string() << "is not supported.");
#else
if(!GL::Context::current().isExtensionSupported<GL::Extensions::WEBGL::multi_draw>())
CORRADE_SKIP(GL::Extensions::WEBGL::multi_draw::string() << "is not supported.");
#endif
}
GL::Texture2D diffuse; GL::Texture2D diffuse;
if(data.flags & PhongGL::Flag::DiffuseTexture) { if(data.flags & PhongGL::Flag::DiffuseTexture) {
if(!(_manager.loadState("AnyImageImporter") & PluginManager::LoadState::Loaded) || if(!(_manager.loadState("AnyImageImporter") & PluginManager::LoadState::Loaded) ||
@ -3176,7 +3216,7 @@ void PhongGLTest::renderMulti() {
sizeof(TextureTransformationUniform)); sizeof(TextureTransformationUniform));
shader.draw(cone); shader.draw(cone);
/* Otherwise using the draw offset */ /* Otherwise using the draw offset / multidraw */
} else { } else {
shader.bindTransformationBuffer(transformationUniform) shader.bindTransformationBuffer(transformationUniform)
.bindDrawBuffer(drawUniform) .bindDrawBuffer(drawUniform)
@ -3184,12 +3224,17 @@ void PhongGLTest::renderMulti() {
.bindLightBuffer(lightUniform); .bindLightBuffer(lightUniform);
if(data.flags & PhongGL::Flag::TextureTransformation) if(data.flags & PhongGL::Flag::TextureTransformation)
shader.bindTextureTransformationBuffer(textureTransformationUniform); shader.bindTextureTransformationBuffer(textureTransformationUniform);
shader.setDrawOffset(0)
.draw(sphere); if(data.flags >= PhongGL::Flag::MultiDraw)
shader.setDrawOffset(1) shader.draw({sphere, plane, cone});
.draw(plane); else {
shader.setDrawOffset(2) shader.setDrawOffset(0)
.draw(cone); .draw(sphere);
shader.setDrawOffset(1)
.draw(plane);
shader.setDrawOffset(2)
.draw(cone);
}
} }
/* /*

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

@ -96,9 +96,20 @@ void PhongGL_Test::debugFlagsSupersets() {
/* InstancedTextureOffset is a superset of TextureTransformation so only /* InstancedTextureOffset is a superset of TextureTransformation so only
one should be printed */ one should be printed */
std::ostringstream out; {
Debug{&out} << (PhongGL::Flag::InstancedTextureOffset|PhongGL::Flag::TextureTransformation); std::ostringstream out;
CORRADE_COMPARE(out.str(), "Shaders::PhongGL::Flag::InstancedTextureOffset\n"); Debug{&out} << (PhongGL::Flag::InstancedTextureOffset|PhongGL::Flag::TextureTransformation);
CORRADE_COMPARE(out.str(), "Shaders::PhongGL::Flag::InstancedTextureOffset\n");
}
#ifndef MAGNUM_TARGET_GLES2
/* MultiDraw is a superset of UniformBuffers so only one should be printed */
{
std::ostringstream out;
Debug{&out} << (PhongGL::Flag::MultiDraw|PhongGL::Flag::UniformBuffers);
CORRADE_COMPARE(out.str(), "Shaders::PhongGL::Flag::MultiDraw\n");
}
#endif
} }
}}}} }}}}

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

@ -128,24 +128,27 @@ struct VectorGLTest: GL::OpenGLTester {
Rendering tests done: Rendering tests done:
[B] base [B] base
[O] draw offset [O] UBOs + draw offset
[M] multidraw
Mesa Intel BO Mesa Intel BOM
ES2 x ES2 xx
ES3 BO ES3 BOx
Mesa AMD B Mesa AMD B
Mesa llvmpipe B Mesa llvmpipe B
SwiftShader ES2 Bx SwiftShader ES2 Bxx
ES3 B ES3 B
ARM Mali (Huawei P10) ES2 Bx ANGLE ES2 xx
ES3 BO ES3 BOM
WebGL (on Mesa Intel) 1.0 Bx ARM Mali (Huawei P10) ES2 Bxx
2.0 BO ES3 BOx
WebGL (on Mesa Intel) 1.0 Bxx
2.0 BOM
NVidia NVidia
Intel Windows Intel Windows
AMD macOS AMD macOS x
Intel macOS BO Intel macOS BOx
iPhone 6 w/ iOS 12.4 ES3 B iPhone 6 w/ iOS 12.4 ES3 B x
*/ */
using namespace Math::Literals; using namespace Math::Literals;
@ -170,6 +173,7 @@ constexpr struct {
/* SwiftShader has 256 uniform vectors at most, per-draw is 4+3 in 3D case /* SwiftShader has 256 uniform vectors at most, per-draw is 4+3 in 3D case
and 3+3 in 2D */ and 3+3 in 2D */
{"multiple draws", VectorGL2D::Flag::UniformBuffers, 36}, {"multiple draws", VectorGL2D::Flag::UniformBuffers, 36},
{"multidraw with all the things", VectorGL2D::Flag::MultiDraw|VectorGL2D::Flag::TextureTransformation, 36}
}; };
#endif #endif
@ -195,16 +199,21 @@ constexpr struct {
const char* name; const char* name;
const char* expected2D; const char* expected2D;
const char* expected3D; const char* expected3D;
VectorGL2D::Flags flags;
UnsignedInt drawCount; UnsignedInt drawCount;
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, 16,
/* Minor differences on ARM Mali */ /* Minor differences on ARM Mali */
1.34f, 0.02f}, 1.34f, 0.02f},
{"draw offset", "multidraw2D.tga", "multidraw3D.tga", {"draw offset", "multidraw2D.tga", "multidraw3D.tga",
3, 1, {}, 3, 1,
/* Minor differences on ARM Mali */
1.34f, 0.02f},
{"multidraw", "multidraw2D.tga", "multidraw3D.tga",
VectorGL2D::Flag::MultiDraw, 3, 1,
/* Minor differences on ARM Mali */ /* Minor differences on ARM Mali */
1.34f, 0.02f}, 1.34f, 0.02f},
}; };
@ -347,6 +356,19 @@ 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
if(data.flags >= VectorGL2D::Flag::MultiDraw) {
#ifndef MAGNUM_TARGET_GLES
if(!GL::Context::current().isExtensionSupported<GL::Extensions::ARB::shader_draw_parameters>())
CORRADE_SKIP(GL::Extensions::ARB::shader_draw_parameters::string() << "is not supported.");
#elif !defined(MAGNUM_TARGET_WEBGL)
if(!GL::Context::current().isExtensionSupported<GL::Extensions::ANGLE::multi_draw>())
CORRADE_SKIP(GL::Extensions::ANGLE::multi_draw::string() << "is not supported.");
#else
if(!GL::Context::current().isExtensionSupported<GL::Extensions::WEBGL::multi_draw>())
CORRADE_SKIP(GL::Extensions::WEBGL::multi_draw::string() << "is not supported.");
#endif
}
VectorGL<dimensions> shader{data.flags, data.drawCount}; VectorGL<dimensions> shader{data.flags, data.drawCount};
CORRADE_COMPARE(shader.flags(), data.flags); CORRADE_COMPARE(shader.flags(), data.flags);
CORRADE_COMPARE(shader.drawCount(), data.drawCount); CORRADE_COMPARE(shader.drawCount(), data.drawCount);
@ -958,6 +980,19 @@ 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
if(data.flags >= VectorGL2D::Flag::MultiDraw) {
#ifndef MAGNUM_TARGET_GLES
if(!GL::Context::current().isExtensionSupported<GL::Extensions::ARB::shader_draw_parameters>())
CORRADE_SKIP(GL::Extensions::ARB::shader_draw_parameters::string() << "is not supported.");
#elif !defined(MAGNUM_TARGET_WEBGL)
if(!GL::Context::current().isExtensionSupported<GL::Extensions::ANGLE::multi_draw>())
CORRADE_SKIP(GL::Extensions::ANGLE::multi_draw::string() << "is not supported.");
#else
if(!GL::Context::current().isExtensionSupported<GL::Extensions::WEBGL::multi_draw>())
CORRADE_SKIP(GL::Extensions::WEBGL::multi_draw::string() << "is not supported.");
#endif
}
if(!(_manager.loadState("AnyImageImporter") & PluginManager::LoadState::Loaded) || if(!(_manager.loadState("AnyImageImporter") & PluginManager::LoadState::Loaded) ||
!(_manager.loadState("TgaImporter") & PluginManager::LoadState::Loaded)) !(_manager.loadState("TgaImporter") & PluginManager::LoadState::Loaded))
CORRADE_SKIP("AnyImageImporter / TgaImporter plugins not found."); CORRADE_SKIP("AnyImageImporter / TgaImporter plugins not found.");
@ -1045,7 +1080,7 @@ void VectorGLTest::renderMulti2D() {
.setBackgroundColor(0xccffcc_rgbf); .setBackgroundColor(0xccffcc_rgbf);
GL::Buffer drawUniform{GL::Buffer::TargetHint::Uniform, drawData}; GL::Buffer drawUniform{GL::Buffer::TargetHint::Uniform, drawData};
VectorGL2D shader{VectorGL2D::Flag::UniformBuffers|VectorGL2D::Flag::TextureTransformation, data.drawCount}; VectorGL2D shader{VectorGL2D::Flag::UniformBuffers|VectorGL2D::Flag::TextureTransformation|data.flags, data.drawCount};
shader.bindVectorTexture(vector); shader.bindVectorTexture(vector);
/* Just one draw, rebinding UBOs each time */ /* Just one draw, rebinding UBOs each time */
@ -1083,17 +1118,22 @@ void VectorGLTest::renderMulti2D() {
sizeof(TextureTransformationUniform)); sizeof(TextureTransformationUniform));
shader.draw(triangle); shader.draw(triangle);
/* Otherwise using the draw offset */ /* Otherwise using the draw offset / multidraw */
} else { } else {
shader.bindTransformationProjectionBuffer(transformationProjectionUniform) shader.bindTransformationProjectionBuffer(transformationProjectionUniform)
.bindDrawBuffer(drawUniform) .bindDrawBuffer(drawUniform)
.bindTextureTransformationBuffer(textureTransformationUniform); .bindTextureTransformationBuffer(textureTransformationUniform);
shader.setDrawOffset(0)
.draw(circle); if(data.flags >= VectorGL2D::Flag::MultiDraw)
shader.setDrawOffset(1) shader.draw({circle, square, triangle});
.draw(square); else {
shader.setDrawOffset(2) shader.setDrawOffset(0)
.draw(triangle); .draw(circle);
shader.setDrawOffset(1)
.draw(square);
shader.setDrawOffset(2)
.draw(triangle);
}
} }
/* /*
@ -1118,6 +1158,19 @@ 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
if(data.flags >= VectorGL3D::Flag::MultiDraw) {
#ifndef MAGNUM_TARGET_GLES
if(!GL::Context::current().isExtensionSupported<GL::Extensions::ARB::shader_draw_parameters>())
CORRADE_SKIP(GL::Extensions::ARB::shader_draw_parameters::string() << "is not supported.");
#elif !defined(MAGNUM_TARGET_WEBGL)
if(!GL::Context::current().isExtensionSupported<GL::Extensions::ANGLE::multi_draw>())
CORRADE_SKIP(GL::Extensions::ANGLE::multi_draw::string() << "is not supported.");
#else
if(!GL::Context::current().isExtensionSupported<GL::Extensions::WEBGL::multi_draw>())
CORRADE_SKIP(GL::Extensions::WEBGL::multi_draw::string() << "is not supported.");
#endif
}
if(!(_manager.loadState("AnyImageImporter") & PluginManager::LoadState::Loaded) || if(!(_manager.loadState("AnyImageImporter") & PluginManager::LoadState::Loaded) ||
!(_manager.loadState("TgaImporter") & PluginManager::LoadState::Loaded)) !(_manager.loadState("TgaImporter") & PluginManager::LoadState::Loaded))
CORRADE_SKIP("AnyImageImporter / TgaImporter plugins not found."); CORRADE_SKIP("AnyImageImporter / TgaImporter plugins not found.");
@ -1210,7 +1263,7 @@ void VectorGLTest::renderMulti3D() {
.setBackgroundColor(0xccffcc_rgbf); .setBackgroundColor(0xccffcc_rgbf);
GL::Buffer drawUniform{GL::Buffer::TargetHint::Uniform, drawData}; GL::Buffer drawUniform{GL::Buffer::TargetHint::Uniform, drawData};
VectorGL3D shader{VectorGL3D::Flag::UniformBuffers|VectorGL3D::Flag::TextureTransformation, data.drawCount}; VectorGL3D shader{VectorGL3D::Flag::UniformBuffers|VectorGL3D::Flag::TextureTransformation|data.flags, data.drawCount};
shader.bindVectorTexture(vector); shader.bindVectorTexture(vector);
/* Just one draw, rebinding UBOs each time */ /* Just one draw, rebinding UBOs each time */
@ -1248,17 +1301,22 @@ void VectorGLTest::renderMulti3D() {
sizeof(TextureTransformationUniform)); sizeof(TextureTransformationUniform));
shader.draw(cone); shader.draw(cone);
/* Otherwise using the draw offset */ /* Otherwise using the draw offset / multidraw */
} else { } else {
shader.bindTransformationProjectionBuffer(transformationProjectionUniform) shader.bindTransformationProjectionBuffer(transformationProjectionUniform)
.bindDrawBuffer(drawUniform) .bindDrawBuffer(drawUniform)
.bindTextureTransformationBuffer(textureTransformationUniform); .bindTextureTransformationBuffer(textureTransformationUniform);
shader.setDrawOffset(0)
.draw(sphere); if(data.flags >= VectorGL3D::Flag::MultiDraw)
shader.setDrawOffset(1) shader.draw({sphere, plane, cone});
.draw(plane); else {
shader.setDrawOffset(2) shader.setDrawOffset(0)
.draw(cone); .draw(sphere);
shader.setDrawOffset(1)
.draw(plane);
shader.setDrawOffset(2)
.draw(cone);
}
} }
/* /*

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

@ -41,17 +41,25 @@ struct VectorGL_Test: TestSuite::Tester {
void debugFlag(); void debugFlag();
void debugFlags(); void debugFlags();
#ifndef MAGNUM_TARGET_GLES2
void debugFlagsSupersets();
#endif
}; };
VectorGL_Test::VectorGL_Test() { VectorGL_Test::VectorGL_Test() {
addTests({&VectorGL_Test::constructNoCreate<2>, addTests({
&VectorGL_Test::constructNoCreate<3>, &VectorGL_Test::constructNoCreate<2>,
&VectorGL_Test::constructNoCreate<3>,
&VectorGL_Test::constructCopy<2>,
&VectorGL_Test::constructCopy<3>, &VectorGL_Test::constructCopy<2>,
&VectorGL_Test::constructCopy<3>,
&VectorGL_Test::debugFlag,
&VectorGL_Test::debugFlags}); &VectorGL_Test::debugFlag,
&VectorGL_Test::debugFlags,
#ifndef MAGNUM_TARGET_GLES2
&VectorGL_Test::debugFlagsSupersets
#endif
});
} }
template<UnsignedInt dimensions> void VectorGL_Test::constructNoCreate() { template<UnsignedInt dimensions> void VectorGL_Test::constructNoCreate() {
@ -87,6 +95,15 @@ void VectorGL_Test::debugFlags() {
CORRADE_COMPARE(out.str(), "Shaders::VectorGL::Flag::TextureTransformation|Shaders::VectorGL::Flag(0xf0) Shaders::VectorGL::Flags{}\n"); CORRADE_COMPARE(out.str(), "Shaders::VectorGL::Flag::TextureTransformation|Shaders::VectorGL::Flag(0xf0) Shaders::VectorGL::Flags{}\n");
} }
#ifndef MAGNUM_TARGET_GLES2
void VectorGL_Test::debugFlagsSupersets() {
/* MultiDraw is a superset of UniformBuffers so only one should be printed */
std::ostringstream out;
Debug{&out} << (VectorGL3D::Flag::MultiDraw|VectorGL3D::Flag::UniformBuffers);
CORRADE_COMPARE(out.str(), "Shaders::VectorGL::Flag::MultiDraw\n");
}
#endif
}}}} }}}}
CORRADE_TEST_MAIN(Magnum::Shaders::Test::VectorGL_Test) CORRADE_TEST_MAIN(Magnum::Shaders::Test::VectorGL_Test)

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

@ -115,24 +115,27 @@ struct VertexColorGLTest: GL::OpenGLTester {
Rendering tests done: Rendering tests done:
[B] base [B] base
[O] draw offset [O] UBOs + draw offset
[M] multidraw
Mesa Intel BO Mesa Intel BOM
ES2 x ES2 xx
ES3 BO ES3 BOx
Mesa AMD B Mesa AMD B
Mesa llvmpipe B Mesa llvmpipe B
SwiftShader ES2 Bx SwiftShader ES2 Bxx
ES3 B ES3 B
ARM Mali (Huawei P10) ES2 Bx ANGLE ES2 xx
ES3 BO ES3 BOM
WebGL (on Mesa Intel) 1.0 Bx ARM Mali (Huawei P10) ES2 Bxx
2.0 BO ES3 BOx
WebGL (on Mesa Intel) 1.0 Bxx
2.0 BOM
NVidia NVidia
Intel Windows Intel Windows
AMD macOS AMD macOS x
Intel macOS BO Intel macOS BOx
iPhone 6 w/ iOS 12.4 ES3 B iPhone 6 w/ iOS 12.4 ES3 B x
*/ */
using namespace Math::Literals; using namespace Math::Literals;
@ -147,7 +150,8 @@ constexpr struct {
{"", VertexColorGL2D::Flag::UniformBuffers, 1}, {"", VertexColorGL2D::Flag::UniformBuffers, 1},
/* 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}
}; };
#endif #endif
@ -156,18 +160,23 @@ constexpr struct {
const char* name; const char* name;
const char* expected2D; const char* expected2D;
const char* expected3D; const char* expected3D;
VertexColorGL2D::Flags flags;
UnsignedInt drawCount; UnsignedInt drawCount;
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, 16,
/* Minor differences on ARM Mali */ /* Minor differences on ARM Mali */
0.34f, 0.01f}, 0.34f, 0.01f},
{"draw offset", "multidraw2D.tga", "multidraw3D.tga", {"draw offset", "multidraw2D.tga", "multidraw3D.tga",
3, 1, {}, 3, 1,
/* Minor differences on ARM Mali */ /* Minor differences on ARM Mali */
0.34f, 0.01f}, 0.34f, 0.01f},
{"multidraw", "multidraw2D.tga", "multidraw3D.tga",
VertexColorGL2D::Flag::MultiDraw, 3, 1,
/* Minor differences on ARM Mali */
0.34f, 0.01f}
}; };
#endif #endif
@ -305,6 +314,19 @@ 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
if(data.flags >= VertexColorGL2D::Flag::MultiDraw) {
#ifndef MAGNUM_TARGET_GLES
if(!GL::Context::current().isExtensionSupported<GL::Extensions::ARB::shader_draw_parameters>())
CORRADE_SKIP(GL::Extensions::ARB::shader_draw_parameters::string() << "is not supported.");
#elif !defined(MAGNUM_TARGET_WEBGL)
if(!GL::Context::current().isExtensionSupported<GL::Extensions::ANGLE::multi_draw>())
CORRADE_SKIP(GL::Extensions::ANGLE::multi_draw::string() << "is not supported.");
#else
if(!GL::Context::current().isExtensionSupported<GL::Extensions::WEBGL::multi_draw>())
CORRADE_SKIP(GL::Extensions::WEBGL::multi_draw::string() << "is not supported.");
#endif
}
VertexColorGL<dimensions> shader{data.flags, data.drawCount}; VertexColorGL<dimensions> shader{data.flags, data.drawCount};
CORRADE_COMPARE(shader.flags(), data.flags); CORRADE_COMPARE(shader.flags(), data.flags);
CORRADE_COMPARE(shader.drawCount(), data.drawCount); CORRADE_COMPARE(shader.drawCount(), data.drawCount);
@ -758,6 +780,19 @@ 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
if(data.flags >= VertexColorGL2D::Flag::MultiDraw) {
#ifndef MAGNUM_TARGET_GLES
if(!GL::Context::current().isExtensionSupported<GL::Extensions::ARB::shader_draw_parameters>())
CORRADE_SKIP(GL::Extensions::ARB::shader_draw_parameters::string() << "is not supported.");
#elif !defined(MAGNUM_TARGET_WEBGL)
if(!GL::Context::current().isExtensionSupported<GL::Extensions::ANGLE::multi_draw>())
CORRADE_SKIP(GL::Extensions::ANGLE::multi_draw::string() << "is not supported.");
#else
if(!GL::Context::current().isExtensionSupported<GL::Extensions::WEBGL::multi_draw>())
CORRADE_SKIP(GL::Extensions::WEBGL::multi_draw::string() << "is not supported.");
#endif
}
/* Circle is a fan, plane is a strip, make it indexed first */ /* Circle is a fan, plane is a strip, make it indexed first */
Trade::MeshData circleData = MeshTools::generateIndices(Primitives::circle2DSolid(32)); Trade::MeshData circleData = MeshTools::generateIndices(Primitives::circle2DSolid(32));
Trade::MeshData squareData = MeshTools::generateIndices(Primitives::squareSolid()); Trade::MeshData squareData = MeshTools::generateIndices(Primitives::squareSolid());
@ -806,7 +841,7 @@ void VertexColorGLTest::renderMulti2D() {
); );
GL::Buffer transformationProjectionUniform{GL::Buffer::TargetHint::Uniform, transformationProjectionData}; GL::Buffer transformationProjectionUniform{GL::Buffer::TargetHint::Uniform, transformationProjectionData};
VertexColorGL2D shader{VertexColorGL2D::Flag::UniformBuffers, data.drawCount}; VertexColorGL2D shader{VertexColorGL2D::Flag::UniformBuffers|data.flags, data.drawCount};
/* Just one draw, rebinding UBOs each time */ /* Just one draw, rebinding UBOs each time */
if(data.drawCount == 1) { if(data.drawCount == 1) {
@ -825,15 +860,20 @@ void VertexColorGLTest::renderMulti2D() {
sizeof(TransformationProjectionUniform2D)); sizeof(TransformationProjectionUniform2D));
shader.draw(triangle); shader.draw(triangle);
/* Otherwise using the draw offset */ /* Otherwise using the draw offset / multidraw */
} else { } else {
shader.bindTransformationProjectionBuffer(transformationProjectionUniform); shader.bindTransformationProjectionBuffer(transformationProjectionUniform);
shader.setDrawOffset(0)
.draw(circle); if(data.flags >= VertexColorGL2D::Flag::MultiDraw)
shader.setDrawOffset(1) shader.draw({circle, square, triangle});
.draw(square); else {
shader.setDrawOffset(2) shader.setDrawOffset(0)
.draw(triangle); .draw(circle);
shader.setDrawOffset(1)
.draw(square);
shader.setDrawOffset(2)
.draw(triangle);
}
} }
MAGNUM_VERIFY_NO_GL_ERROR(); MAGNUM_VERIFY_NO_GL_ERROR();
@ -863,6 +903,19 @@ 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
if(data.flags >= VertexColorGL3D::Flag::MultiDraw) {
#ifndef MAGNUM_TARGET_GLES
if(!GL::Context::current().isExtensionSupported<GL::Extensions::ARB::shader_draw_parameters>())
CORRADE_SKIP(GL::Extensions::ARB::shader_draw_parameters::string() << "is not supported.");
#elif !defined(MAGNUM_TARGET_WEBGL)
if(!GL::Context::current().isExtensionSupported<GL::Extensions::ANGLE::multi_draw>())
CORRADE_SKIP(GL::Extensions::ANGLE::multi_draw::string() << "is not supported.");
#else
if(!GL::Context::current().isExtensionSupported<GL::Extensions::WEBGL::multi_draw>())
CORRADE_SKIP(GL::Extensions::WEBGL::multi_draw::string() << "is not supported.");
#endif
}
Trade::MeshData sphereData = Primitives::uvSphereSolid(16, 32); Trade::MeshData sphereData = Primitives::uvSphereSolid(16, 32);
/* Plane is a strip, make it indexed first */ /* Plane is a strip, make it indexed first */
Trade::MeshData planeData = MeshTools::generateIndices(Primitives::planeSolid()); Trade::MeshData planeData = MeshTools::generateIndices(Primitives::planeSolid());
@ -914,7 +967,7 @@ void VertexColorGLTest::renderMulti3D() {
); );
GL::Buffer transformationProjectionUniform{GL::Buffer::TargetHint::Uniform, transformationProjectionData}; GL::Buffer transformationProjectionUniform{GL::Buffer::TargetHint::Uniform, transformationProjectionData};
VertexColorGL3D shader{VertexColorGL3D::Flag::UniformBuffers, data.drawCount}; VertexColorGL3D shader{VertexColorGL3D::Flag::UniformBuffers|data.flags, data.drawCount};
/* Just one draw, rebinding UBOs each time */ /* Just one draw, rebinding UBOs each time */
if(data.drawCount == 1) { if(data.drawCount == 1) {
@ -933,15 +986,20 @@ void VertexColorGLTest::renderMulti3D() {
sizeof(TransformationProjectionUniform3D)); sizeof(TransformationProjectionUniform3D));
shader.draw(cone); shader.draw(cone);
/* Otherwise using the draw offset */ /* Otherwise using the draw offset / multidraw */
} else { } else {
shader.bindTransformationProjectionBuffer(transformationProjectionUniform); shader.bindTransformationProjectionBuffer(transformationProjectionUniform);
shader.setDrawOffset(0)
.draw(sphere); if(data.flags >= VertexColorGL3D::Flag::MultiDraw)
shader.setDrawOffset(1) shader.draw({sphere, plane, cone});
.draw(plane); else {
shader.setDrawOffset(2) shader.setDrawOffset(0)
.draw(cone); .draw(sphere);
shader.setDrawOffset(1)
.draw(plane);
shader.setDrawOffset(2)
.draw(cone);
}
} }
MAGNUM_VERIFY_NO_GL_ERROR(); MAGNUM_VERIFY_NO_GL_ERROR();

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

@ -41,6 +41,9 @@ struct VertexColorGL_Test: TestSuite::Tester {
void debugFlag(); void debugFlag();
void debugFlags(); void debugFlags();
#ifndef MAGNUM_TARGET_GLES2
void debugFlagsSupersets();
#endif
}; };
VertexColorGL_Test::VertexColorGL_Test() { VertexColorGL_Test::VertexColorGL_Test() {
@ -52,7 +55,11 @@ VertexColorGL_Test::VertexColorGL_Test() {
&VertexColorGL_Test::constructCopy<3>, &VertexColorGL_Test::constructCopy<3>,
&VertexColorGL_Test::debugFlag, &VertexColorGL_Test::debugFlag,
&VertexColorGL_Test::debugFlags}); &VertexColorGL_Test::debugFlags,
#ifndef MAGNUM_TARGET_GLES2
&VertexColorGL_Test::debugFlagsSupersets
#endif
});
} }
template<UnsignedInt dimensions> void VertexColorGL_Test::constructNoCreate() { template<UnsignedInt dimensions> void VertexColorGL_Test::constructNoCreate() {
@ -97,6 +104,15 @@ void VertexColorGL_Test::debugFlags() {
#endif #endif
} }
#ifndef MAGNUM_TARGET_GLES2
void VertexColorGL_Test::debugFlagsSupersets() {
/* MultiDraw is a superset of UniformBuffers so only one should be printed */
std::ostringstream out;
Debug{&out} << (VertexColorGL3D::Flag::MultiDraw|VertexColorGL3D::Flag::UniformBuffers);
CORRADE_COMPARE(out.str(), "Shaders::VertexColorGL::Flag::MultiDraw\n");
}
#endif
}}}} }}}}
CORRADE_TEST_MAIN(Magnum::Shaders::Test::VertexColorGL_Test) CORRADE_TEST_MAIN(Magnum::Shaders::Test::VertexColorGL_Test)

11
src/Magnum/Shaders/Vector.frag

@ -53,6 +53,7 @@ uniform lowp vec4 color
/* Uniform buffers */ /* Uniform buffers */
#else #else
#ifndef MULTI_DRAW
#ifdef EXPLICIT_UNIFORM_LOCATION #ifdef EXPLICIT_UNIFORM_LOCATION
layout(location = 0) layout(location = 0)
#endif #endif
@ -61,6 +62,8 @@ uniform highp uint drawOffset
= 0u = 0u
#endif #endif
; ;
#define drawId drawOffset
#endif
struct DrawUniform { struct DrawUniform {
lowp vec4 color; lowp vec4 color;
@ -88,6 +91,10 @@ uniform lowp sampler2D vectorTexture;
in mediump vec2 interpolatedTextureCoordinates; in mediump vec2 interpolatedTextureCoordinates;
#ifdef MULTI_DRAW
flat in highp uint drawId;
#endif
/* Outputs */ /* Outputs */
#ifdef NEW_GLSL #ifdef NEW_GLSL
@ -99,8 +106,8 @@ out lowp vec4 fragmentColor;
void main() { void main() {
#ifdef UNIFORM_BUFFERS #ifdef UNIFORM_BUFFERS
lowp const vec4 color = draws[drawOffset].color; lowp const vec4 color = draws[drawId].color;
lowp const vec4 backgroundColor = draws[drawOffset].backgroundColor; lowp const vec4 backgroundColor = draws[drawId].backgroundColor;
#endif #endif
lowp float intensity = texture(vectorTexture, interpolatedTextureCoordinates).r; lowp float intensity = texture(vectorTexture, interpolatedTextureCoordinates).r;

28
src/Magnum/Shaders/Vector.vert

@ -23,6 +23,14 @@
DEALINGS IN THE SOFTWARE. DEALINGS IN THE SOFTWARE.
*/ */
#ifdef MULTI_DRAW
#ifndef GL_ES
#extension GL_ARB_shader_draw_parameters: require
#else /* covers WebGL as well */
#extension GL_ANGLE_multi_draw: require
#endif
#endif
#ifndef NEW_GLSL #ifndef NEW_GLSL
#define in attribute #define in attribute
#define out varying #define out varying
@ -132,8 +140,24 @@ in mediump vec2 textureCoordinates;
out mediump vec2 interpolatedTextureCoordinates; out mediump vec2 interpolatedTextureCoordinates;
#ifdef MULTI_DRAW
flat out highp uint drawId;
#endif
void main() { void main() {
#ifdef UNIFORM_BUFFERS #ifdef UNIFORM_BUFFERS
#ifdef MULTI_DRAW
drawId = drawOffset + uint(
#ifndef GL_ES
gl_DrawIDARB /* Using GL_ARB_shader_draw_parameters, not GLSL 4.6 */
#else
gl_DrawID
#endif
);
#else
#define drawId drawOffset
#endif
highp const highp const
#ifdef TWO_DIMENSIONS #ifdef TWO_DIMENSIONS
mat3 mat3
@ -142,9 +166,9 @@ void main() {
#else #else
#error #error
#endif #endif
transformationProjectionMatrix = transformationProjectionMatrices[drawOffset]; transformationProjectionMatrix = transformationProjectionMatrices[drawId];
#ifdef TEXTURE_TRANSFORMATION #ifdef TEXTURE_TRANSFORMATION
mediump const mat3 textureMatrix = mat3(textureTransformations[drawOffset].rotationScaling.xy, 0.0, textureTransformations[drawOffset].rotationScaling.zw, 0.0, textureTransformations[drawOffset].textureTransformation_offset, 1.0); mediump const mat3 textureMatrix = mat3(textureTransformations[drawId].rotationScaling.xy, 0.0, textureTransformations[drawId].rotationScaling.zw, 0.0, textureTransformations[drawId].textureTransformation_offset, 1.0);
#endif #endif
#endif #endif

15
src/Magnum/Shaders/VectorGL.cpp

@ -81,6 +81,17 @@ template<UnsignedInt dimensions> VectorGL<dimensions>::VectorGL(const Flags flag
if(flags >= Flag::UniformBuffers) if(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_GLES2
if(flags >= Flag::MultiDraw) {
#ifndef MAGNUM_TARGET_GLES
MAGNUM_ASSERT_GL_EXTENSION_SUPPORTED(GL::Extensions::ARB::shader_draw_parameters);
#elif !defined(MAGNUM_TARGET_WEBGL)
MAGNUM_ASSERT_GL_EXTENSION_SUPPORTED(GL::Extensions::ANGLE::multi_draw);
#else
MAGNUM_ASSERT_GL_EXTENSION_SUPPORTED(GL::Extensions::WEBGL::multi_draw);
#endif
}
#endif
#ifdef MAGNUM_BUILD_STATIC #ifdef MAGNUM_BUILD_STATIC
/* Import resources on static build, if not already */ /* Import resources on static build, if not already */
@ -108,6 +119,7 @@ template<UnsignedInt dimensions> VectorGL<dimensions>::VectorGL(const Flags flag
"#define UNIFORM_BUFFERS\n" "#define UNIFORM_BUFFERS\n"
"#define DRAW_COUNT {}\n", "#define DRAW_COUNT {}\n",
drawCount)); drawCount));
vert.addSource(flags >= Flag::MultiDraw ? "#define MULTI_DRAW\n" : "");
} }
#endif #endif
vert.addSource(rs.get("generic.glsl")) vert.addSource(rs.get("generic.glsl"))
@ -118,6 +130,7 @@ template<UnsignedInt dimensions> VectorGL<dimensions>::VectorGL(const Flags flag
"#define UNIFORM_BUFFERS\n" "#define UNIFORM_BUFFERS\n"
"#define DRAW_COUNT {}\n", "#define DRAW_COUNT {}\n",
drawCount)); drawCount));
frag.addSource(flags >= Flag::MultiDraw ? "#define MULTI_DRAW\n" : "");
} }
#endif #endif
frag.addSource(rs.get("generic.glsl")) frag.addSource(rs.get("generic.glsl"))
@ -308,6 +321,7 @@ Debug& operator<<(Debug& debug, const VectorGLFlag value) {
_c(TextureTransformation) _c(TextureTransformation)
#ifndef MAGNUM_TARGET_GLES2 #ifndef MAGNUM_TARGET_GLES2
_c(UniformBuffers) _c(UniformBuffers)
_c(MultiDraw)
#endif #endif
#undef _c #undef _c
/* LCOV_EXCL_STOP */ /* LCOV_EXCL_STOP */
@ -320,6 +334,7 @@ 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
VectorGLFlag::MultiDraw, /* Superset of UniformBuffers */
VectorGLFlag::UniformBuffers VectorGLFlag::UniformBuffers
#endif #endif
}); });

34
src/Magnum/Shaders/VectorGL.h

@ -41,7 +41,8 @@ namespace Implementation {
enum class VectorGLFlag: UnsignedByte { enum class VectorGLFlag: UnsignedByte {
TextureTransformation = 1 << 0, TextureTransformation = 1 << 0,
#ifndef MAGNUM_TARGET_GLES2 #ifndef MAGNUM_TARGET_GLES2
UniformBuffers = 1 << 1 UniformBuffers = 1 << 1,
MultiDraw = UniformBuffers|(1 << 2)
#endif #endif
}; };
typedef Containers::EnumSet<VectorGLFlag> VectorGLFlags; typedef Containers::EnumSet<VectorGLFlag> VectorGLFlags;
@ -135,7 +136,31 @@ template<UnsignedInt dimensions> class MAGNUM_SHADERS_EXPORT VectorGL: public GL
* 1.0. * 1.0.
* @m_since_latest * @m_since_latest
*/ */
UniformBuffers = 1 << 1 UniformBuffers = 1 << 1,
/**
* Enable multidraw functionality. Implies @ref Flag::UniformBuffers
* and adds the value from @ref setDrawOffset() with the
* @glsl gl_DrawID @ce builtin, which makes draws submitted via
* @ref GL::AbstractShaderProgram::draw(Containers::ArrayView<const Containers::Reference<MeshView>>)
* pick up per-draw parameters directly, without having to rebind
* the uniform buffers or specify @ref setDrawOffset() before each
* draw. In a non-multidraw scenario, @glsl gl_DrawID @ce is
* @cpp 0 @ce, which means a shader with this flag enabled can be
* used for regular draws as well.
* @requires_gl46 Extension @gl_extension{ARB,uniform_buffer_object}
* and @gl_extension{ARB,shader_draw_parameters}
* @requires_es_extension OpenGL ES 3.0 and extension @m_class{m-doc-external} [ANGLE_multi_draw](https://chromium.googlesource.com/angle/angle/+/master/extensions/ANGLE_multi_draw.txt) (unlisted).
* While the extension alone needs only OpenGL ES 2.0, the
* shader implementation relies on uniform buffers, which
* require OpenGL ES 3.0.
* @requires_webgl_extension WebGL 2.0 Extension @webgl_extension{ANGLE,multi_draw}.
* While the extension alone needs only WebGL 1.0, the shader
* implementation relies on uniform buffers, which require
* WebGL 2.0.
* @m_since_latest
*/
MultiDraw = UniformBuffers|(1 << 2)
#endif #endif
}; };
@ -327,6 +352,11 @@ template<UnsignedInt dimensions> class MAGNUM_SHADERS_EXPORT VectorGL: public GL
* should be used for current draw. Expects that * should be used for current draw. Expects that
* @ref Flag::UniformBuffers is set and @p offset is less than * @ref Flag::UniformBuffers is set and @p offset is less than
* @ref drawCount(). Initial value is @cpp 0 @ce. * @ref drawCount(). Initial value is @cpp 0 @ce.
*
* If @ref Flag::MultiDraw is set, @glsl gl_DrawID @ce is added to this
* value, which makes each draw submitted via
* @ref GL::AbstractShaderProgram::draw(Containers::ArrayView<const Containers::Reference<MeshView>>)
* pick up its own per-draw parameters.
* @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 2.0. * @requires_gles30 Uniform buffers are not available in OpenGL ES 2.0.
* @requires_webgl20 Uniform buffers are not available in WebGL 1.0. * @requires_webgl20 Uniform buffers are not available in WebGL 1.0.

22
src/Magnum/Shaders/VertexColor.vert

@ -23,6 +23,14 @@
DEALINGS IN THE SOFTWARE. DEALINGS IN THE SOFTWARE.
*/ */
#ifdef MULTI_DRAW
#ifndef GL_ES
#extension GL_ARB_shader_draw_parameters: require
#else /* covers WebGL as well */
#extension GL_ANGLE_multi_draw: require
#endif
#endif
#ifndef NEW_GLSL #ifndef NEW_GLSL
#define in attribute #define in attribute
#define out varying #define out varying
@ -107,6 +115,18 @@ out lowp vec4 interpolatedColor;
void main() { void main() {
#ifdef UNIFORM_BUFFERS #ifdef UNIFORM_BUFFERS
#ifdef MULTI_DRAW
highp uint drawId = drawOffset + uint(
#ifndef GL_ES
gl_DrawIDARB /* Using GL_ARB_shader_draw_parameters, not GLSL 4.6 */
#else
gl_DrawID
#endif
);
#else
#define drawId drawOffset
#endif
highp const highp const
#ifdef TWO_DIMENSIONS #ifdef TWO_DIMENSIONS
mat3 mat3
@ -115,7 +135,7 @@ void main() {
#else #else
#error #error
#endif #endif
transformationProjectionMatrix = transformationProjectionMatrices[drawOffset]; transformationProjectionMatrix = transformationProjectionMatrices[drawId];
#endif #endif
#ifdef TWO_DIMENSIONS #ifdef TWO_DIMENSIONS

14
src/Magnum/Shaders/VertexColorGL.cpp

@ -76,6 +76,17 @@ template<UnsignedInt dimensions> VertexColorGL<dimensions>::VertexColorGL(const
if(flags >= Flag::UniformBuffers) if(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_GLES2
if(flags >= Flag::MultiDraw) {
#ifndef MAGNUM_TARGET_GLES
MAGNUM_ASSERT_GL_EXTENSION_SUPPORTED(GL::Extensions::ARB::shader_draw_parameters);
#elif !defined(MAGNUM_TARGET_WEBGL)
MAGNUM_ASSERT_GL_EXTENSION_SUPPORTED(GL::Extensions::ANGLE::multi_draw);
#else
MAGNUM_ASSERT_GL_EXTENSION_SUPPORTED(GL::Extensions::WEBGL::multi_draw);
#endif
}
#endif
#ifdef MAGNUM_BUILD_STATIC #ifdef MAGNUM_BUILD_STATIC
/* Import resources on static build, if not already */ /* Import resources on static build, if not already */
@ -102,6 +113,7 @@ template<UnsignedInt dimensions> VertexColorGL<dimensions>::VertexColorGL(const
"#define UNIFORM_BUFFERS\n" "#define UNIFORM_BUFFERS\n"
"#define DRAW_COUNT {}\n", "#define DRAW_COUNT {}\n",
drawCount)); drawCount));
vert.addSource(flags >= Flag::MultiDraw ? "#define MULTI_DRAW\n" : "");
} }
#endif #endif
vert.addSource(rs.get("generic.glsl")) vert.addSource(rs.get("generic.glsl"))
@ -214,6 +226,7 @@ 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)
_c(MultiDraw)
#endif #endif
#undef _c #undef _c
/* LCOV_EXCL_STOP */ /* LCOV_EXCL_STOP */
@ -225,6 +238,7 @@ 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
VertexColorGLFlag::MultiDraw, /* Superset of UniformBuffers */
VertexColorGLFlag::UniformBuffers VertexColorGLFlag::UniformBuffers
#endif #endif
}); });

34
src/Magnum/Shaders/VertexColorGL.h

@ -40,7 +40,8 @@ namespace Magnum { namespace Shaders {
namespace Implementation { namespace Implementation {
enum class VertexColorGLFlag: UnsignedByte { enum class VertexColorGLFlag: UnsignedByte {
#ifndef MAGNUM_TARGET_GLES2 #ifndef MAGNUM_TARGET_GLES2
UniformBuffers = 1 << 0 UniformBuffers = 1 << 0,
MultiDraw = UniformBuffers|(1 << 1)
#endif #endif
}; };
typedef Containers::EnumSet<VertexColorGLFlag> VertexColorGLFlags; typedef Containers::EnumSet<VertexColorGLFlag> VertexColorGLFlags;
@ -136,7 +137,31 @@ template<UnsignedInt dimensions> class MAGNUM_SHADERS_EXPORT VertexColorGL: publ
* 1.0. * 1.0.
* @m_since_latest * @m_since_latest
*/ */
UniformBuffers = 1 << 0 UniformBuffers = 1 << 0,
/**
* Enable multidraw functionality. Implies @ref Flag::UniformBuffers
* and adds the value from @ref setDrawOffset() with the
* @glsl gl_DrawID @ce builtin, which makes draws submitted via
* @ref GL::AbstractShaderProgram::draw(Containers::ArrayView<const Containers::Reference<MeshView>>)
* pick up per-draw parameters directly, without having to rebind
* the uniform buffers or specify @ref setDrawOffset() before each
* draw. In a non-multidraw scenario, @glsl gl_DrawID @ce is
* @cpp 0 @ce, which means a shader with this flag enabled can be
* used for regular draws as well.
* @requires_gl46 Extension @gl_extension{ARB,uniform_buffer_object}
* and @gl_extension{ARB,shader_draw_parameters}
* @requires_es_extension OpenGL ES 3.0 and extension @m_class{m-doc-external} [ANGLE_multi_draw](https://chromium.googlesource.com/angle/angle/+/master/extensions/ANGLE_multi_draw.txt) (unlisted).
* While the extension alone needs only OpenGL ES 2.0, the
* shader implementation relies on uniform buffers, which
* require OpenGL ES 3.0.
* @requires_webgl_extension WebGL 2.0 Extension @webgl_extension{ANGLE,multi_draw}.
* While the extension alone needs only WebGL 1.0, the shader
* implementation relies on uniform buffers, which require
* WebGL 2.0.
* @m_since_latest
*/
MultiDraw = UniformBuffers|(1 << 1)
#endif #endif
}; };
@ -279,6 +304,11 @@ template<UnsignedInt dimensions> class MAGNUM_SHADERS_EXPORT VertexColorGL: publ
* @ref bindTransformationProjectionBuffer() should be used for current * @ref bindTransformationProjectionBuffer() should be used for current
* draw. Expects that @ref Flag::UniformBuffers is set and @p offset is * draw. Expects that @ref Flag::UniformBuffers is set and @p offset is
* less than @ref drawCount(). Initial value is @cpp 0 @ce. * less than @ref drawCount(). Initial value is @cpp 0 @ce.
*
* If @ref Flag::MultiDraw is set, @glsl gl_DrawID @ce is added to this
* value, which makes each draw submitted via
* @ref GL::AbstractShaderProgram::draw(Containers::ArrayView<const Containers::Reference<MeshView>>)
* pick up its own per-draw parameters.
* @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 2.0. * @requires_gles30 Uniform buffers are not available in OpenGL ES 2.0.
* @requires_webgl20 Uniform buffers are not available in WebGL 1.0. * @requires_webgl20 Uniform buffers are not available in WebGL 1.0.

Loading…
Cancel
Save