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
- 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
recently added @ref Trade::MaterialAttribute::NormalTextureScale material
attribute

9
src/Magnum/Shaders/DistanceFieldVector.frag

@ -71,6 +71,7 @@ uniform lowp float smoothness
/* Uniform buffers */
#else
#ifndef MULTI_DRAW
#ifdef EXPLICIT_UNIFORM_LOCATION
layout(location = 0)
#endif
@ -79,6 +80,8 @@ uniform highp uint drawOffset
= 0u
#endif
;
#define drawId drawOffset
#endif
struct DrawUniform {
highp uvec4 materialIdReservedReservedReservedReserved;
@ -122,6 +125,10 @@ uniform lowp sampler2D vectorTexture;
in mediump vec2 interpolatedTextureCoordinates;
#ifdef MULTI_DRAW
flat in highp uint drawId;
#endif
/* OUtput */
#ifdef NEW_GLSL
@ -133,7 +140,7 @@ out lowp vec4 fragmentColor;
void main() {
#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 vec4 color = materials[materialId].color;
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)
MAGNUM_ASSERT_GL_EXTENSION_SUPPORTED(GL::Extensions::ARB::uniform_buffer_object);
#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
/* Import resources on static build, if not already */
@ -112,6 +123,7 @@ template<UnsignedInt dimensions> DistanceFieldVectorGL<dimensions>::DistanceFiel
"#define UNIFORM_BUFFERS\n"
"#define DRAW_COUNT {}\n",
drawCount));
vert.addSource(flags >= Flag::MultiDraw ? "#define MULTI_DRAW\n" : "");
}
#endif
vert.addSource(rs.get("generic.glsl"))
@ -124,6 +136,7 @@ template<UnsignedInt dimensions> DistanceFieldVectorGL<dimensions>::DistanceFiel
"#define DRAW_COUNT {}\n",
materialCount,
drawCount));
frag.addSource(flags >= Flag::MultiDraw ? "#define MULTI_DRAW\n" : "");
}
#endif
frag.addSource(rs.get("generic.glsl"))
@ -351,6 +364,7 @@ Debug& operator<<(Debug& debug, const DistanceFieldVectorGLFlag value) {
_c(TextureTransformation)
#ifndef MAGNUM_TARGET_GLES2
_c(UniformBuffers)
_c(MultiDraw)
#endif
#undef _c
/* LCOV_EXCL_STOP */
@ -363,6 +377,7 @@ Debug& operator<<(Debug& debug, const DistanceFieldVectorGLFlags value) {
return Containers::enumSetDebugOutput(debug, value, "Shaders::DistanceFieldVectorGL::Flags{}", {
DistanceFieldVectorGLFlag::TextureTransformation,
#ifndef MAGNUM_TARGET_GLES2
DistanceFieldVectorGLFlag::MultiDraw, /* Superset of UniformBuffers */
DistanceFieldVectorGLFlag::UniformBuffers
#endif
});

34
src/Magnum/Shaders/DistanceFieldVectorGL.h

@ -41,7 +41,8 @@ namespace Implementation {
enum class DistanceFieldVectorGLFlag: UnsignedByte {
TextureTransformation = 1 << 0,
#ifndef MAGNUM_TARGET_GLES2
UniformBuffers = 1 << 1
UniformBuffers = 1 << 1,
MultiDraw = UniformBuffers|(1 << 2)
#endif
};
typedef Containers::EnumSet<DistanceFieldVectorGLFlag> DistanceFieldVectorGLFlags;
@ -140,7 +141,31 @@ template<UnsignedInt dimensions> class MAGNUM_SHADERS_EXPORT DistanceFieldVector
* 1.0.
* @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
};
@ -387,6 +412,11 @@ template<UnsignedInt dimensions> class MAGNUM_SHADERS_EXPORT DistanceFieldVector
* @ref bindTextureTransformationBuffer() should be used for current
* draw. Expects that @ref Flag::UniformBuffers is set and @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_gles30 Uniform buffers are not available in OpenGL ES 2.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 */
#else
#ifndef MULTI_DRAW
#ifdef EXPLICIT_UNIFORM_LOCATION
layout(location = 0)
#endif
@ -83,6 +84,8 @@ uniform highp uint drawOffset
= 0u
#endif
;
#define drawId drawOffset
#endif
struct DrawUniform {
lowp vec4 color;
@ -139,14 +142,18 @@ layout(location = OBJECT_ID_OUTPUT_ATTRIBUTE_LOCATION)
out highp uint fragmentObjectId;
#endif
#ifdef MULTI_DRAW
flat in highp uint drawId;
#endif
void main() {
#ifdef UNIFORM_BUFFERS
lowp const vec4 color = draws[drawOffset].color;
lowp const vec4 color = draws[drawId].color;
#ifdef OBJECT_ID
highp const uint objectId = draws[drawOffset].draw_objectId;
highp const uint objectId = draws[drawId].draw_objectId;
#endif
#ifdef ALPHA_MASK
lowp const float alphaMask = uintBitsToFloat(draws[drawOffset].draw_alphaMask);
lowp const float alphaMask = uintBitsToFloat(draws[drawId].draw_alphaMask);
#endif
#endif

28
src/Magnum/Shaders/Flat.vert

@ -27,6 +27,14 @@
#extension GL_EXT_gpu_shader4: require
#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
#define in attribute
#define out varying
@ -182,8 +190,24 @@ out lowp vec4 interpolatedVertexColor;
flat out highp uint interpolatedInstanceObjectId;
#endif
#ifdef MULTI_DRAW
flat out highp uint drawId;
#endif
void main() {
#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
#ifdef TWO_DIMENSIONS
mat3
@ -192,9 +216,9 @@ void main() {
#else
#error
#endif
transformationProjectionMatrix = transformationProjectionMatrices[drawOffset];
transformationProjectionMatrix = transformationProjectionMatrices[drawId];
#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

15
src/Magnum/Shaders/FlatGL.cpp

@ -84,6 +84,17 @@ template<UnsignedInt dimensions> FlatGL<dimensions>::FlatGL(const Flags flags
if(flags >= Flag::UniformBuffers)
MAGNUM_ASSERT_GL_EXTENSION_SUPPORTED(GL::Extensions::ARB::uniform_buffer_object);
#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
/* 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 DRAW_COUNT {}\n",
drawCount));
vert.addSource(flags >= Flag::MultiDraw ? "#define MULTI_DRAW\n" : "");
}
#endif
vert.addSource(rs.get("generic.glsl"))
@ -136,6 +148,7 @@ template<UnsignedInt dimensions> FlatGL<dimensions>::FlatGL(const Flags flags
"#define UNIFORM_BUFFERS\n"
"#define DRAW_COUNT {}\n",
drawCount));
frag.addSource(flags >= Flag::MultiDraw ? "#define MULTI_DRAW\n" : "");
}
#endif
frag.addSource(rs.get("generic.glsl"))
@ -370,6 +383,7 @@ Debug& operator<<(Debug& debug, const FlatGLFlag value) {
_c(InstancedTextureOffset)
#ifndef MAGNUM_TARGET_GLES2
_c(UniformBuffers)
_c(MultiDraw)
#endif
#undef _c
/* LCOV_EXCL_STOP */
@ -391,6 +405,7 @@ Debug& operator<<(Debug& debug, const FlatGLFlags value) {
#endif
FlatGLFlag::InstancedTransformation,
#ifndef MAGNUM_TARGET_GLES2
FlatGLFlag::MultiDraw, /* Superset of UniformBuffers */
FlatGLFlag::UniformBuffers
#endif
});

34
src/Magnum/Shaders/FlatGL.h

@ -50,7 +50,8 @@ namespace Implementation {
InstancedTransformation = 1 << 6,
InstancedTextureOffset = (1 << 7)|TextureTransformation,
#ifndef MAGNUM_TARGET_GLES2
UniformBuffers = 1 << 8
UniformBuffers = 1 << 8,
MultiDraw = UniformBuffers|(1 << 9)
#endif
};
typedef Containers::EnumSet<FlatGLFlag> FlatGLFlags;
@ -388,7 +389,31 @@ template<UnsignedInt dimensions> class MAGNUM_SHADERS_EXPORT FlatGL: public GL::
* 1.0.
* @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
};
@ -602,6 +627,11 @@ template<UnsignedInt dimensions> class MAGNUM_SHADERS_EXPORT FlatGL: public GL::
* @ref bindTextureTransformationBuffer() should be used for current
* draw. Expects that @ref Flag::UniformBuffers is set and @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_gles30 Uniform buffers are not available in OpenGL ES 2.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 */
#else
#ifndef MULTI_DRAW
#ifdef EXPLICIT_UNIFORM_LOCATION
layout(location = 1)
#endif
@ -118,6 +119,8 @@ uniform highp uint drawOffset
= 0u
#endif
;
#define drawId drawOffset
#endif
/* Keep in sync with MeshVisualizer.vert and MeshVisualizer.geom. Can't
"outsource" to a common file because the extension directives need to be
@ -202,6 +205,10 @@ in lowp vec4 backgroundColor;
in lowp vec4 lineColor;
#endif
#ifdef MULTI_DRAW
flat in highp uint drawId;
#endif
/* Outputs */
#ifdef NEW_GLSL
@ -213,7 +220,7 @@ out lowp vec4 fragmentColor;
void main() {
#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)
lowp const vec4 color = materials[materialId].color;
lowp const vec4 wireframeColor = materials[materialId].wireframeColor;

18
src/Magnum/Shaders/MeshVisualizer.geom

@ -87,6 +87,7 @@ uniform lowp float smoothness
/* Uniform buffers */
#else
#ifndef MULTI_DRAW
#ifdef EXPLICIT_UNIFORM_LOCATION
layout(location = 1)
#endif
@ -95,6 +96,7 @@ uniform highp uint drawOffset
= 0u
#endif
;
#endif
/* Keep in sync with MeshVisualizer.vert and MeshVisualizer.frag. Can't
"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[];
#endif
#ifdef MULTI_DRAW
flat in highp uint vsDrawId[];
#endif
/* Outputs */
layout(triangle_strip, max_vertices = MAX_VERTICES) out;
@ -186,6 +192,10 @@ out highp float interpolatedMappedVertexId;
flat out highp uint interpolatedPrimitiveId;
#endif
#ifdef MULTI_DRAW
flat out highp uint drawId;
#endif
#if defined(TANGENT_DIRECTION) || defined(BITANGENT_DIRECTION) || defined(NORMAL_DIRECTION)
out lowp vec4 backgroundColor;
out lowp vec4 lineColor;
@ -255,7 +265,13 @@ void emitQuad(
void main() {
#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))
lowp const vec4 color = materials[materialId].color;
lowp const vec4 wireframeColor = materials[materialId].wireframeColor;

44
src/Magnum/Shaders/MeshVisualizer.vert

@ -27,6 +27,14 @@
#extension GL_EXT_gpu_shader4: require
#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
#define in attribute
#define out varying
@ -279,19 +287,47 @@ out highp vec4 bitangentEndpoint;
out highp vec4 normalEndpoint;
#endif
#ifdef MULTI_DRAW
flat out highp uint
#ifdef NO_GEOMETRY_SHADER
drawId
#else
vsDrawId
#endif
;
#endif
void main() {
#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
highp const mat3 transformationProjectionMatrix = transformationProjectionMatrices[drawOffset];
highp const mat3 transformationProjectionMatrix = transformationProjectionMatrices[drawId];
#elif defined(THREE_DIMENSIONS)
highp const mat4 transformationMatrix = transformationMatrices[drawOffset];
highp const mat4 transformationMatrix = transformationMatrices[drawId];
#else
#error
#endif
#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
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 colorMapScale = materials[materialId].material_colorMapScale;
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)
MAGNUM_ASSERT_GL_EXTENSION_SUPPORTED(GL::Extensions::ARB::uniform_buffer_object);
#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
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",
_drawCount,
_materialCount));
vert.addSource(_flags >= FlagBase::MultiDraw ? "#define MULTI_DRAW\n" : "");
}
#endif
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",
_drawCount,
_materialCount));
frag.addSource(_flags >= FlagBase::MultiDraw ? "#define MULTI_DRAW\n" : "");
}
#endif
@ -358,6 +371,7 @@ MeshVisualizerGL2D::MeshVisualizerGL2D(const Flags flags
"#define MATERIAL_COUNT {}\n",
_drawCount,
_materialCount));
geom->addSource(flags >= Flag::MultiDraw ? "#define MULTI_DRAW\n" : "");
}
#endif
geom->addSource(rs.get("MeshVisualizer.geom"));
@ -673,6 +687,7 @@ MeshVisualizerGL3D::MeshVisualizerGL3D(const Flags flags
"#define MATERIAL_COUNT {}\n",
_drawCount,
_materialCount));
geom->addSource(flags >= Flag::MultiDraw ? "#define MULTI_DRAW\n" : "");
}
#endif
geom->addSource(rs.get("MeshVisualizer.geom"));
@ -990,6 +1005,7 @@ Debug& operator<<(Debug& debug, const MeshVisualizerGL2D::Flag value) {
#endif
#ifndef MAGNUM_TARGET_GLES2
_c(UniformBuffers)
_c(MultiDraw)
#endif
#undef _c
/* LCOV_EXCL_STOP */
@ -1022,6 +1038,7 @@ Debug& operator<<(Debug& debug, const MeshVisualizerGL3D::Flag value) {
#endif
#ifndef MAGNUM_TARGET_GLES2
_c(UniformBuffers)
_c(MultiDraw)
#endif
#undef _c
/* LCOV_EXCL_STOP */
@ -1044,6 +1061,7 @@ Debug& operator<<(Debug& debug, const MeshVisualizerGL2D::Flags value) {
MeshVisualizerGL2D::Flag::PrimitiveId,
#endif
#ifndef MAGNUM_TARGET_GLES2
MeshVisualizerGL2D::Flag::MultiDraw, /* Superset of UniformBuffers */
MeshVisualizerGL2D::Flag::UniformBuffers
#endif
#endif
@ -1070,6 +1088,7 @@ Debug& operator<<(Debug& debug, const MeshVisualizerGL3D::Flags value) {
MeshVisualizerGL3D::Flag::PrimitiveId,
#endif
#ifndef MAGNUM_TARGET_GLES2
MeshVisualizerGL3D::Flag::MultiDraw, /* Superset of UniformBuffers */
MeshVisualizerGL3D::Flag::UniformBuffers
#endif
#endif

65
src/Magnum/Shaders/MeshVisualizerGL.h

@ -55,7 +55,8 @@ class MAGNUM_SHADERS_EXPORT MeshVisualizerGLBase: public GL::AbstractShaderProgr
PrimitiveId = 1 << 4,
PrimitiveIdFromVertexId = (1 << 5)|PrimitiveId,
/* bit 6, 7, 8, 9 used by 3D-specific TBN visualization */
UniformBuffers = 1 << 10
UniformBuffers = 1 << 10,
MultiDraw = UniformBuffers|(1 << 11)
#endif
};
typedef Containers::EnumSet<FlagBase> FlagsBase;
@ -236,7 +237,31 @@ class MAGNUM_SHADERS_EXPORT MeshVisualizerGL2D: public Implementation::MeshVisua
* 1.0.
* @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
};
@ -470,6 +495,11 @@ class MAGNUM_SHADERS_EXPORT MeshVisualizerGL2D: public Implementation::MeshVisua
* should be used for current draw. Expects that
* @ref Flag::UniformBuffers is set and @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_gles30 Uniform buffers are not available in OpenGL ES 2.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.
* @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
};
@ -1382,6 +1436,11 @@ class MAGNUM_SHADERS_EXPORT MeshVisualizerGL3D: public Implementation::MeshVisua
* used for current draw. Expects that @ref Flag::UniformBuffers is set
* and @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_gles30 Uniform buffers are not available in OpenGL ES 2.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 */
#else
#ifndef MULTI_DRAW
#ifdef EXPLICIT_UNIFORM_LOCATION
layout(location = 0)
#endif
@ -156,6 +157,8 @@ uniform highp uint drawOffset
= 0u
#endif
;
#define drawId drawOffset
#endif
/* Keep in sync with Phong.vert. Can't "outsource" to a common file because
the #extension directive needs to be always before any code. */
@ -277,6 +280,10 @@ in lowp vec4 interpolatedVertexColor;
flat in highp uint interpolatedInstanceObjectId;
#endif
#ifdef MULTI_DRAW
flat in highp uint drawId;
#endif
/* Outputs */
#ifdef NEW_GLSL
@ -296,9 +303,9 @@ out highp uint fragmentObjectId;
void main() {
#ifdef UNIFORM_BUFFERS
#ifdef OBJECT_ID
highp const uint objectId = draws[drawOffset].draw_objectId;
highp const uint objectId = draws[drawId].draw_objectId;
#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;
#if LIGHT_COUNT
lowp const vec4 diffuseColor = materials[materialId].diffuseColor;
@ -312,7 +319,7 @@ void main() {
lowp const float alphaMask = materials[materialId].material_alphaMask;
#endif
#if LIGHT_COUNT
mediump const uint lightOffset = draws[drawOffset].draw_lightOffset;
mediump const uint lightOffset = draws[drawId].draw_lightOffset;
#endif
#endif
@ -370,7 +377,7 @@ void main() {
#ifndef UNIFORM_BUFFERS
for(int i = 0; i < LIGHT_COUNT; ++i)
#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
{
lowp const vec3 lightColor =

34
src/Magnum/Shaders/Phong.vert

@ -27,6 +27,14 @@
#extension GL_EXT_gpu_shader4: require
#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
#define in attribute
#define out varying
@ -273,17 +281,33 @@ out highp vec4 lightDirections[LIGHT_COUNT];
out highp vec3 cameraDirection;
#endif
#ifdef MULTI_DRAW
flat out highp uint drawId;
#endif
void main() {
#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
mediump const mat3 normalMatrix = draws[drawOffset].normalMatrix;
mediump const mat3 normalMatrix = draws[drawId].normalMatrix;
#endif
#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
#if LIGHT_COUNT
mediump const uint lightOffset = draws[drawOffset].draw_lightOffset;
mediump const uint lightOffset = draws[drawId].draw_lightOffset;
#endif
#endif
@ -328,7 +352,7 @@ void main() {
#ifndef UNIFORM_BUFFERS
for(int i = 0; i < LIGHT_COUNT; ++i)
#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
{
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)
MAGNUM_ASSERT_GL_EXTENSION_SUPPORTED(GL::Extensions::ARB::uniform_buffer_object);
#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
/* Import resources on static build, if not already */
@ -199,6 +210,7 @@ PhongGL::PhongGL(const Flags flags, const UnsignedInt lightCount
"#define LIGHT_COUNT {}\n",
drawCount,
lightCount));
vert.addSource(flags >= Flag::MultiDraw ? "#define MULTI_DRAW\n" : "");
}
#endif
#ifndef MAGNUM_TARGET_GLES
@ -229,6 +241,7 @@ PhongGL::PhongGL(const Flags flags, const UnsignedInt lightCount
drawCount,
materialCount,
lightCount));
frag.addSource(flags >= Flag::MultiDraw ? "#define MULTI_DRAW\n" : "");
} else
#endif
{
@ -809,6 +822,7 @@ Debug& operator<<(Debug& debug, const PhongGL::Flag value) {
_c(InstancedTextureOffset)
#ifndef MAGNUM_TARGET_GLES2
_c(UniformBuffers)
_c(MultiDraw)
#endif
#undef _c
/* LCOV_EXCL_STOP */
@ -834,6 +848,7 @@ Debug& operator<<(Debug& debug, const PhongGL::Flags value) {
#endif
PhongGL::Flag::InstancedTransformation,
#ifndef MAGNUM_TARGET_GLES2
PhongGL::Flag::MultiDraw, /* Superset of UniformBuffers */
PhongGL::Flag::UniformBuffers
#endif
});

31
src/Magnum/Shaders/PhongGL.h

@ -577,7 +577,31 @@ class MAGNUM_SHADERS_EXPORT PhongGL: public GL::AbstractShaderProgram {
* 1.0.
* @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
};
@ -1162,6 +1186,11 @@ class MAGNUM_SHADERS_EXPORT PhongGL: public GL::AbstractShaderProgram {
* and @ref bindTextureTransformationBuffer() should be used for
* current draw. Expects that @ref Flag::UniformBuffers is set and
* @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_gles30 Uniform buffers are not available in OpenGL ES 2.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:
[B] base
[O] draw offset
[O] UBOs + draw offset
[M] multidraw
Mesa Intel BO
ES2 x
ES3 BO
Mesa Intel BOM
ES2 xx
ES3 BOx
Mesa AMD B
Mesa llvmpipe B
SwiftShader ES2 Bx
SwiftShader ES2 Bxx
ES3 B
ARM Mali (Huawei P10) ES2 Bx
ES3 BO
WebGL (on Mesa Intel) 1.0 Bx
2.0 BO
ANGLE ES2 xx
ES3 BOM
ARM Mali (Huawei P10) ES2 Bxx
ES3 BOx
WebGL (on Mesa Intel) 1.0 Bxx
2.0 BOM
NVidia
Intel Windows
AMD macOS
Intel macOS BO
iPhone 6 w/ iOS 12.4 ES3 B
AMD macOS x
Intel macOS BOx
iPhone 6 w/ iOS 12.4 ES3 B x
*/
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
and 3+1 in 2D, per-material 4 */
{"multiple materials, draws", DistanceFieldVectorGL2D::Flag::UniformBuffers, 16, 48},
{"multidraw with all the things", DistanceFieldVectorGL2D::Flag::MultiDraw|DistanceFieldVectorGL2D::Flag::TextureTransformation, 16, 48}
};
constexpr struct {
@ -213,16 +217,21 @@ constexpr struct {
const char* name;
const char* expected2D;
const char* expected3D;
DistanceFieldVectorGL2D::Flags flags;
UnsignedInt materialCount, drawCount;
UnsignedInt uniformIncrement;
Float maxThreshold, meanThreshold;
} RenderMultiData[] {
{"bind with offset", "multidraw2D-distancefield.tga", "multidraw3D-distancefield.tga",
1, 1, 16,
{}, 1, 1, 16,
/* Minor differences on ARM Mali */
1.67f, 0.012f},
{"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 */
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.");
#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};
CORRADE_COMPARE(shader.flags(), data.flags);
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.");
#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) ||
!(_manager.loadState("TgaImporter") & PluginManager::LoadState::Loaded))
CORRADE_SKIP("AnyImageImporter / TgaImporter plugins not found.");
@ -1131,7 +1166,7 @@ void DistanceFieldVectorGLTest::renderMulti2D() {
.setMaterialId(data.drawCount == 1 ? 0 : 0);
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);
/* Just one draw, rebinding UBOs each time */
@ -1178,18 +1213,23 @@ void DistanceFieldVectorGLTest::renderMulti2D() {
sizeof(TextureTransformationUniform));
shader.draw(triangle);
/* Otherwise using the draw offset */
/* Otherwise using the draw offset / multidraw */
} else {
shader.bindTransformationProjectionBuffer(transformationProjectionUniform)
.bindDrawBuffer(drawUniform)
.bindMaterialBuffer(materialUniform)
.bindTextureTransformationBuffer(textureTransformationUniform);
shader.setDrawOffset(0)
.draw(circle);
shader.setDrawOffset(1)
.draw(square);
shader.setDrawOffset(2)
.draw(triangle);
if(data.flags >= DistanceFieldVectorGL2D::Flag::MultiDraw)
shader.draw({circle, square, triangle});
else {
shader.setDrawOffset(0)
.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.");
#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) ||
!(_manager.loadState("TgaImporter") & PluginManager::LoadState::Loaded))
CORRADE_SKIP("AnyImageImporter / TgaImporter plugins not found.");
@ -1314,7 +1367,7 @@ void DistanceFieldVectorGLTest::renderMulti3D() {
.setMaterialId(data.drawCount == 1 ? 0 : 0);
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);
/* Just one draw, rebinding UBOs each time */
@ -1361,18 +1414,23 @@ void DistanceFieldVectorGLTest::renderMulti3D() {
sizeof(TextureTransformationUniform));
shader.draw(cone);
/* Otherwise using the draw offset */
/* Otherwise using the draw offset / multidraw */
} else {
shader.bindTransformationProjectionBuffer(transformationProjectionUniform)
.bindDrawBuffer(drawUniform)
.bindMaterialBuffer(materialUniform)
.bindTextureTransformationBuffer(textureTransformationUniform);
shader.setDrawOffset(0)
.draw(sphere);
shader.setDrawOffset(1)
.draw(plane);
shader.setDrawOffset(2)
.draw(cone);
if(data.flags >= DistanceFieldVectorGL3D::Flag::MultiDraw)
shader.draw({sphere, plane, cone});
else {
shader.setDrawOffset(0)
.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 debugFlags();
#ifndef MAGNUM_TARGET_GLES2
void debugFlagsSupersets();
#endif
};
DistanceFieldVectorGL_Test::DistanceFieldVectorGL_Test() {
addTests({&DistanceFieldVectorGL_Test::constructNoCreate<2>,
&DistanceFieldVectorGL_Test::constructNoCreate<3>,
&DistanceFieldVectorGL_Test::constructCopy<2>,
&DistanceFieldVectorGL_Test::constructCopy<3>,
&DistanceFieldVectorGL_Test::debugFlag,
&DistanceFieldVectorGL_Test::debugFlags});
addTests({
&DistanceFieldVectorGL_Test::constructNoCreate<2>,
&DistanceFieldVectorGL_Test::constructNoCreate<3>,
&DistanceFieldVectorGL_Test::constructCopy<2>,
&DistanceFieldVectorGL_Test::constructCopy<3>,
&DistanceFieldVectorGL_Test::debugFlag,
&DistanceFieldVectorGL_Test::debugFlags,
#ifndef MAGNUM_TARGET_GLES2
&DistanceFieldVectorGL_Test::debugFlagsSupersets
#endif
});
}
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");
}
#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)

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

@ -161,24 +161,27 @@ struct FlatGLTest: GL::OpenGLTester {
[A] alpha mask
[D] object ID
[I] instancing
[O] draw offset
[O] UBOs + draw offset
[M] multidraw
Mesa Intel BADIO
ES2 x
ES3 BADIO
Mesa Intel BADIOM
ES2 xx
ES3 BADIOx
Mesa AMD BADI
Mesa llvmpipe BADI
SwiftShader ES2 BADIx
SwiftShader ES2 BADIxx
ES3 BADI
ARM Mali (Huawei P10) ES2 BAD x
ES3 BADIO
WebGL (on Mesa Intel) 1.0 BAD x
2.0 BADIO
ANGLE ES2 xx
ES3 BADIOM
ARM Mali (Huawei P10) ES2 BAD xx
ES3 BADIOx
WebGL (on Mesa Intel) 1.0 BAD xx
2.0 BADIOM
NVidia BAD
Intel Windows BAD
AMD macOS BAD
Intel macOS BADIO
iPhone 6 w/ iOS 12.4 ES3 BAD
Intel macOS BADIOx
iPhone 6 w/ iOS 12.4 ES3 BAD x
*/
using namespace Math::Literals;
@ -216,7 +219,8 @@ constexpr struct {
{"multiple draws", FlatGL2D::Flag::UniformBuffers, 42},
{"texture transformation", FlatGL2D::Flag::UniformBuffers|FlatGL2D::Flag::Textured|FlatGL2D::Flag::TextureTransformation, 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
@ -290,11 +294,19 @@ constexpr struct {
/* Minor differences on ARM Mali */
2.34f, 0.01f},
{"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",
FlatGL2D::Flag::TextureTransformation|FlatGL2D::Flag::Textured,
3, 1,
/* 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}
};
#endif
@ -532,6 +544,19 @@ template<UnsignedInt dimensions> void FlatGLTest::constructUniformBuffers() {
CORRADE_SKIP(GL::Extensions::EXT::gpu_shader4::string() << "is not supported.");
#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};
CORRADE_COMPARE(shader.flags(), data.flags);
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.");
#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;
if(data.flags & FlatGL2D::Flag::Textured) {
if(!(_manager.loadState("AnyImageImporter") & PluginManager::LoadState::Loaded) ||
@ -2402,18 +2440,23 @@ void FlatGLTest::renderMulti2D() {
sizeof(TextureTransformationUniform));
shader.draw(triangle);
/* Otherwise using the draw offset */
/* Otherwise using the draw offset / multidraw */
} else {
shader.bindTransformationProjectionBuffer(transformationProjectionUniform)
.bindDrawBuffer(drawUniform);
if(data.flags & FlatGL2D::Flag::TextureTransformation)
shader.bindTextureTransformationBuffer(textureTransformationUniform);
shader.setDrawOffset(0)
.draw(circle);
shader.setDrawOffset(1)
.draw(square);
shader.setDrawOffset(2)
.draw(triangle);
if(data.flags >= FlatGL2D::Flag::MultiDraw)
shader.draw({circle, square, triangle});
else {
shader.setDrawOffset(0)
.draw(circle);
shader.setDrawOffset(1)
.draw(square);
shader.setDrawOffset(2)
.draw(triangle);
}
}
MAGNUM_VERIFY_NO_GL_ERROR();
@ -2469,6 +2512,19 @@ void FlatGLTest::renderMulti3D() {
CORRADE_SKIP(GL::Extensions::ARB::uniform_buffer_object::string() << "is not supported.");
#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;
if(data.flags & FlatGL3D::Flag::Textured) {
if(!(_manager.loadState("AnyImageImporter") & PluginManager::LoadState::Loaded) ||
@ -2611,18 +2667,23 @@ void FlatGLTest::renderMulti3D() {
sizeof(TextureTransformationUniform));
shader.draw(cone);
/* Otherwise using the draw offset */
/* Otherwise using the draw offset / multidraw */
} else {
shader.bindTransformationProjectionBuffer(transformationProjectionUniform)
.bindDrawBuffer(drawUniform);
if(data.flags & FlatGL3D::Flag::TextureTransformation)
shader.bindTextureTransformationBuffer(textureTransformationUniform);
shader.setDrawOffset(0)
.draw(sphere);
shader.setDrawOffset(1)
.draw(plane);
shader.setDrawOffset(2)
.draw(cone);
if(data.flags >= FlatGL3D::Flag::MultiDraw)
shader.draw({sphere, plane, cone});
else {
shader.setDrawOffset(0)
.draw(sphere);
shader.setDrawOffset(1)
.draw(plane);
shader.setDrawOffset(2)
.draw(cone);
}
}
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
one should be printed */
std::ostringstream out;
Debug{&out} << (FlatGL3D::Flag::InstancedTextureOffset|FlatGL3D::Flag::TextureTransformation);
CORRADE_COMPARE(out.str(), "Shaders::FlatGL::Flag::InstancedTextureOffset\n");
{
std::ostringstream out;
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
[T] TBN visualization
[O] draw offset
[M] multidraw
Mesa Intel WDTO
ES2 x
ES3
Mesa Intel WDTOM
ES2 xx
ES3 x
Mesa AMD WDT
Mesa llvmpipe WDT
SwiftShader ES2 WDxx
SwiftShader ES2 WDxxx
ES3 WDx
ARM Mali (Huawei P10) ES2 W xx
ES3 W O (WDT big diffs, needs investigation)
WebGL (on Mesa Intel) 1.0 W xx
2.0 W x
ANGLE ES2 xx
ES3 WDxOM
ARM Mali (Huawei P10) ES2 W xxx
ES3 W Ox (WDT big diffs, needs investigation)
WebGL (on Mesa Intel) 1.0 W xxx
2.0 W x M
NVidia
Intel Windows
AMD macOS
Intel macOS WDTO
iPhone 6 w/ iOS 12.4 ES3 W x
Intel macOS WDTOx
iPhone 6 w/ iOS 12.4 ES3 W x x
*/
using namespace Math::Literals;
@ -232,6 +235,10 @@ constexpr struct {
/* SwiftShader has 256 uniform vectors at most, per-2D-draw is 4,
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},
{"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
added */
#ifndef MAGNUM_TARGET_WEBGL
@ -293,6 +300,10 @@ constexpr struct {
/* SwiftShader has 256 uniform vectors at most, per-3D-draw is 4+4,
per-material 4, plus 4 for projection */
{"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
added */
#ifndef MAGNUM_TARGET_WEBGL
@ -605,6 +616,23 @@ constexpr struct {
2, 3, 1,
/* Minor differences on ARM Mali */
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 {
@ -651,6 +679,24 @@ constexpr struct {
2, 3, 1,
/* Minor differences on ARM Mali */
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
@ -998,6 +1044,19 @@ void MeshVisualizerGLTest::constructUniformBuffers2D() {
CORRADE_SKIP(GL::Extensions::ARB::uniform_buffer_object::string() << "is not supported.");
#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};
CORRADE_COMPARE(shader.flags(), data.flags);
CORRADE_VERIFY(shader.id());
@ -1123,6 +1182,19 @@ void MeshVisualizerGLTest::constructUniformBuffers3D() {
CORRADE_SKIP(GL::Extensions::ARB::uniform_buffer_object::string() << "is not supported.");
#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};
CORRADE_COMPARE(shader.flags(), data.flags);
CORRADE_VERIFY(shader.id());
@ -3158,6 +3230,19 @@ void MeshVisualizerGLTest::renderMulti2D() {
}
#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 */
Trade::MeshData circleData = MeshTools::generateIndices(Primitives::circle2DSolid(8));
Trade::MeshData squareData = MeshTools::generateIndices(Primitives::squareSolid());
@ -3273,17 +3358,22 @@ void MeshVisualizerGLTest::renderMulti2D() {
sizeof(MeshVisualizerDrawUniform2D));
shader.draw(triangle);
/* Otherwise using the draw offset */
/* Otherwise using the draw offset / multidraw */
} else {
shader.bindMaterialBuffer(materialUniform)
.bindTransformationProjectionBuffer(transformationProjectionUniform)
.bindDrawBuffer(drawUniform);
shader.setDrawOffset(0)
.draw(circle);
shader.setDrawOffset(1)
.draw(square);
shader.setDrawOffset(2)
.draw(triangle);
if(data.flags >= MeshVisualizerGL2D::Flag::MultiDraw)
shader.draw({circle, square, triangle});
else {
shader.setDrawOffset(0)
.draw(circle);
shader.setDrawOffset(1)
.draw(square);
shader.setDrawOffset(2)
.draw(triangle);
}
};
MAGNUM_VERIFY_NO_GL_ERROR();
@ -3333,6 +3423,19 @@ void MeshVisualizerGLTest::renderMulti3D() {
}
#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), {
/* The icosphere doesn't have tangents and we don't use them, but
concatenate() will ignore the tangents of others if the first mesh
@ -3462,17 +3565,22 @@ void MeshVisualizerGLTest::renderMulti3D() {
sizeof(MeshVisualizerDrawUniform3D));
shader.draw(cone);
/* Otherwise using the draw offset */
/* Otherwise using the draw offset / multidraw */
} else {
shader.bindMaterialBuffer(materialUniform)
.bindTransformationBuffer(transformationUniform)
.bindDrawBuffer(drawUniform);
shader.setDrawOffset(0)
.draw(sphere);
shader.setDrawOffset(1)
.draw(plane);
shader.setDrawOffset(2)
.draw(cone);
if(data.flags >= MeshVisualizerGL3D::Flag::MultiDraw)
shader.draw({sphere, plane, cone});
else {
shader.setDrawOffset(0)
.draw(sphere);
shader.setDrawOffset(1)
.draw(plane);
shader.setDrawOffset(2)
.draw(cone);
}
};
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 debugFlags2D();
void debugFlags3D();
#ifndef MAGNUM_TARGET_GLES2
void debugFlagsSupersets2D();
void debugFlagsSupersets3D();
#endif
};
MeshVisualizerGL_Test::MeshVisualizerGL_Test() {
addTests({&MeshVisualizerGL_Test::constructNoCreate2D,
&MeshVisualizerGL_Test::constructNoCreate3D,
&MeshVisualizerGL_Test::constructCopy2D,
&MeshVisualizerGL_Test::constructCopy3D,
&MeshVisualizerGL_Test::vertexIndexSameAsObjectId,
&MeshVisualizerGL_Test::debugFlag2D,
&MeshVisualizerGL_Test::debugFlag3D,
&MeshVisualizerGL_Test::debugFlags2D,
&MeshVisualizerGL_Test::debugFlags3D});
addTests({
&MeshVisualizerGL_Test::constructNoCreate2D,
&MeshVisualizerGL_Test::constructNoCreate3D,
&MeshVisualizerGL_Test::constructCopy2D,
&MeshVisualizerGL_Test::constructCopy3D,
&MeshVisualizerGL_Test::vertexIndexSameAsObjectId,
&MeshVisualizerGL_Test::debugFlag2D,
&MeshVisualizerGL_Test::debugFlag3D,
&MeshVisualizerGL_Test::debugFlags2D,
&MeshVisualizerGL_Test::debugFlags3D,
#ifndef MAGNUM_TARGET_GLES2
&MeshVisualizerGL_Test::debugFlagsSupersets2D,
&MeshVisualizerGL_Test::debugFlagsSupersets3D,
#endif
});
}
void MeshVisualizerGL_Test::constructNoCreate2D() {
@ -140,6 +150,22 @@ void MeshVisualizerGL_Test::debugFlags3D() {
#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)

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

@ -168,24 +168,27 @@ struct PhongGLTest: GL::OpenGLTester {
[D] object ID
[L] point lights
[I] instancing
[O] draw offset
[O] UBOs + draw offset
[M] multidraw
Mesa Intel BADLIO
ES2 x
ES3 BADLIO
Mesa Intel BADLIOM
ES2 xx
ES3 BADLIOx
Mesa AMD BAD I
Mesa llvmpipe BAD I
SwiftShader ES2 BADLIx
SwiftShader ES2 BADLIxx
ES3 BADLI
ARM Mali (Huawei P10) ES2 BAD x
ES3 BADLIO
WebGL (on Mesa Intel) 1.0 BAD x
2.0 BADLIO
ANGLE ES2 xx
ES3 BADLIOM
ARM Mali (Huawei P10) ES2 BAD xx
ES3 BADLIOx
WebGL (on Mesa Intel) 1.0 BAD xx
2.0 BADLIOM
NVidia BAD
Intel Windows BAD
AMD macOS BAD
Intel macOS BADLIO
iPhone 6 w/ iOS 12.4 ES3 BAD
Intel macOS BADLIOx
iPhone 6 w/ iOS 12.4 ES3 BAD x
*/
constexpr struct {
@ -244,7 +247,8 @@ constexpr struct {
{"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},
{"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
@ -617,6 +621,16 @@ constexpr struct {
4, 2, 3, 1,
/* Minor differences on ARM Mali */
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
@ -875,6 +889,19 @@ void PhongGLTest::constructUniformBuffers() {
CORRADE_SKIP(GL::Extensions::EXT::gpu_shader4::string() << "is not supported.");
#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};
CORRADE_COMPARE(shader.flags(), data.flags);
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.");
#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;
if(data.flags & PhongGL::Flag::DiffuseTexture) {
if(!(_manager.loadState("AnyImageImporter") & PluginManager::LoadState::Loaded) ||
@ -3176,7 +3216,7 @@ void PhongGLTest::renderMulti() {
sizeof(TextureTransformationUniform));
shader.draw(cone);
/* Otherwise using the draw offset */
/* Otherwise using the draw offset / multidraw */
} else {
shader.bindTransformationBuffer(transformationUniform)
.bindDrawBuffer(drawUniform)
@ -3184,12 +3224,17 @@ void PhongGLTest::renderMulti() {
.bindLightBuffer(lightUniform);
if(data.flags & PhongGL::Flag::TextureTransformation)
shader.bindTextureTransformationBuffer(textureTransformationUniform);
shader.setDrawOffset(0)
.draw(sphere);
shader.setDrawOffset(1)
.draw(plane);
shader.setDrawOffset(2)
.draw(cone);
if(data.flags >= PhongGL::Flag::MultiDraw)
shader.draw({sphere, plane, cone});
else {
shader.setDrawOffset(0)
.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
one should be printed */
std::ostringstream out;
Debug{&out} << (PhongGL::Flag::InstancedTextureOffset|PhongGL::Flag::TextureTransformation);
CORRADE_COMPARE(out.str(), "Shaders::PhongGL::Flag::InstancedTextureOffset\n");
{
std::ostringstream out;
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:
[B] base
[O] draw offset
[O] UBOs + draw offset
[M] multidraw
Mesa Intel BO
ES2 x
ES3 BO
Mesa Intel BOM
ES2 xx
ES3 BOx
Mesa AMD B
Mesa llvmpipe B
SwiftShader ES2 Bx
SwiftShader ES2 Bxx
ES3 B
ARM Mali (Huawei P10) ES2 Bx
ES3 BO
WebGL (on Mesa Intel) 1.0 Bx
2.0 BO
ANGLE ES2 xx
ES3 BOM
ARM Mali (Huawei P10) ES2 Bxx
ES3 BOx
WebGL (on Mesa Intel) 1.0 Bxx
2.0 BOM
NVidia
Intel Windows
AMD macOS
Intel macOS BO
iPhone 6 w/ iOS 12.4 ES3 B
AMD macOS x
Intel macOS BOx
iPhone 6 w/ iOS 12.4 ES3 B x
*/
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
and 3+3 in 2D */
{"multiple draws", VectorGL2D::Flag::UniformBuffers, 36},
{"multidraw with all the things", VectorGL2D::Flag::MultiDraw|VectorGL2D::Flag::TextureTransformation, 36}
};
#endif
@ -195,16 +199,21 @@ constexpr struct {
const char* name;
const char* expected2D;
const char* expected3D;
VectorGL2D::Flags flags;
UnsignedInt drawCount;
UnsignedInt uniformIncrement;
Float maxThreshold, meanThreshold;
} RenderMultiData[] {
{"bind with offset", "multidraw2D.tga", "multidraw3D.tga",
1, 16,
{}, 1, 16,
/* Minor differences on ARM Mali */
1.34f, 0.02f},
{"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 */
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.");
#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};
CORRADE_COMPARE(shader.flags(), data.flags);
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.");
#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) ||
!(_manager.loadState("TgaImporter") & PluginManager::LoadState::Loaded))
CORRADE_SKIP("AnyImageImporter / TgaImporter plugins not found.");
@ -1045,7 +1080,7 @@ void VectorGLTest::renderMulti2D() {
.setBackgroundColor(0xccffcc_rgbf);
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);
/* Just one draw, rebinding UBOs each time */
@ -1083,17 +1118,22 @@ void VectorGLTest::renderMulti2D() {
sizeof(TextureTransformationUniform));
shader.draw(triangle);
/* Otherwise using the draw offset */
/* Otherwise using the draw offset / multidraw */
} else {
shader.bindTransformationProjectionBuffer(transformationProjectionUniform)
.bindDrawBuffer(drawUniform)
.bindTextureTransformationBuffer(textureTransformationUniform);
shader.setDrawOffset(0)
.draw(circle);
shader.setDrawOffset(1)
.draw(square);
shader.setDrawOffset(2)
.draw(triangle);
if(data.flags >= VectorGL2D::Flag::MultiDraw)
shader.draw({circle, square, triangle});
else {
shader.setDrawOffset(0)
.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.");
#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) ||
!(_manager.loadState("TgaImporter") & PluginManager::LoadState::Loaded))
CORRADE_SKIP("AnyImageImporter / TgaImporter plugins not found.");
@ -1210,7 +1263,7 @@ void VectorGLTest::renderMulti3D() {
.setBackgroundColor(0xccffcc_rgbf);
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);
/* Just one draw, rebinding UBOs each time */
@ -1248,17 +1301,22 @@ void VectorGLTest::renderMulti3D() {
sizeof(TextureTransformationUniform));
shader.draw(cone);
/* Otherwise using the draw offset */
/* Otherwise using the draw offset / multidraw */
} else {
shader.bindTransformationProjectionBuffer(transformationProjectionUniform)
.bindDrawBuffer(drawUniform)
.bindTextureTransformationBuffer(textureTransformationUniform);
shader.setDrawOffset(0)
.draw(sphere);
shader.setDrawOffset(1)
.draw(plane);
shader.setDrawOffset(2)
.draw(cone);
if(data.flags >= VectorGL3D::Flag::MultiDraw)
shader.draw({sphere, plane, cone});
else {
shader.setDrawOffset(0)
.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 debugFlags();
#ifndef MAGNUM_TARGET_GLES2
void debugFlagsSupersets();
#endif
};
VectorGL_Test::VectorGL_Test() {
addTests({&VectorGL_Test::constructNoCreate<2>,
&VectorGL_Test::constructNoCreate<3>,
&VectorGL_Test::constructCopy<2>,
&VectorGL_Test::constructCopy<3>,
&VectorGL_Test::debugFlag,
&VectorGL_Test::debugFlags});
addTests({
&VectorGL_Test::constructNoCreate<2>,
&VectorGL_Test::constructNoCreate<3>,
&VectorGL_Test::constructCopy<2>,
&VectorGL_Test::constructCopy<3>,
&VectorGL_Test::debugFlag,
&VectorGL_Test::debugFlags,
#ifndef MAGNUM_TARGET_GLES2
&VectorGL_Test::debugFlagsSupersets
#endif
});
}
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");
}
#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)

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

@ -115,24 +115,27 @@ struct VertexColorGLTest: GL::OpenGLTester {
Rendering tests done:
[B] base
[O] draw offset
[O] UBOs + draw offset
[M] multidraw
Mesa Intel BO
ES2 x
ES3 BO
Mesa Intel BOM
ES2 xx
ES3 BOx
Mesa AMD B
Mesa llvmpipe B
SwiftShader ES2 Bx
SwiftShader ES2 Bxx
ES3 B
ARM Mali (Huawei P10) ES2 Bx
ES3 BO
WebGL (on Mesa Intel) 1.0 Bx
2.0 BO
ANGLE ES2 xx
ES3 BOM
ARM Mali (Huawei P10) ES2 Bxx
ES3 BOx
WebGL (on Mesa Intel) 1.0 Bxx
2.0 BOM
NVidia
Intel Windows
AMD macOS
Intel macOS BO
iPhone 6 w/ iOS 12.4 ES3 B
AMD macOS x
Intel macOS BOx
iPhone 6 w/ iOS 12.4 ES3 B x
*/
using namespace Math::Literals;
@ -147,7 +150,8 @@ constexpr struct {
{"", VertexColorGL2D::Flag::UniformBuffers, 1},
/* SwiftShader has 256 uniform vectors at most, per-draw is 4 in 3D case
and 3 in 2D; one needs to be reserved for drawOffset */
{"multiple draws", VertexColorGL2D::Flag::UniformBuffers, 63}
{"multiple draws", VertexColorGL2D::Flag::UniformBuffers, 63},
{"multidraw with all the things", VertexColorGL2D::Flag::MultiDraw, 63}
};
#endif
@ -156,18 +160,23 @@ constexpr struct {
const char* name;
const char* expected2D;
const char* expected3D;
VertexColorGL2D::Flags flags;
UnsignedInt drawCount;
UnsignedInt uniformIncrement;
Float maxThreshold, meanThreshold;
} RenderMultiData[] {
{"bind with offset", "multidraw2D.tga", "multidraw3D.tga",
1, 16,
{}, 1, 16,
/* Minor differences on ARM Mali */
0.34f, 0.01f},
{"draw offset", "multidraw2D.tga", "multidraw3D.tga",
3, 1,
{}, 3, 1,
/* Minor differences on ARM Mali */
0.34f, 0.01f},
{"multidraw", "multidraw2D.tga", "multidraw3D.tga",
VertexColorGL2D::Flag::MultiDraw, 3, 1,
/* Minor differences on ARM Mali */
0.34f, 0.01f}
};
#endif
@ -305,6 +314,19 @@ template<UnsignedInt dimensions> void VertexColorGLTest::constructUniformBuffers
CORRADE_SKIP(GL::Extensions::ARB::uniform_buffer_object::string() << "is not supported.");
#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};
CORRADE_COMPARE(shader.flags(), data.flags);
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.");
#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 */
Trade::MeshData circleData = MeshTools::generateIndices(Primitives::circle2DSolid(32));
Trade::MeshData squareData = MeshTools::generateIndices(Primitives::squareSolid());
@ -806,7 +841,7 @@ void VertexColorGLTest::renderMulti2D() {
);
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 */
if(data.drawCount == 1) {
@ -825,15 +860,20 @@ void VertexColorGLTest::renderMulti2D() {
sizeof(TransformationProjectionUniform2D));
shader.draw(triangle);
/* Otherwise using the draw offset */
/* Otherwise using the draw offset / multidraw */
} else {
shader.bindTransformationProjectionBuffer(transformationProjectionUniform);
shader.setDrawOffset(0)
.draw(circle);
shader.setDrawOffset(1)
.draw(square);
shader.setDrawOffset(2)
.draw(triangle);
if(data.flags >= VertexColorGL2D::Flag::MultiDraw)
shader.draw({circle, square, triangle});
else {
shader.setDrawOffset(0)
.draw(circle);
shader.setDrawOffset(1)
.draw(square);
shader.setDrawOffset(2)
.draw(triangle);
}
}
MAGNUM_VERIFY_NO_GL_ERROR();
@ -863,6 +903,19 @@ void VertexColorGLTest::renderMulti3D() {
CORRADE_SKIP(GL::Extensions::ARB::uniform_buffer_object::string() << "is not supported.");
#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);
/* Plane is a strip, make it indexed first */
Trade::MeshData planeData = MeshTools::generateIndices(Primitives::planeSolid());
@ -914,7 +967,7 @@ void VertexColorGLTest::renderMulti3D() {
);
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 */
if(data.drawCount == 1) {
@ -933,15 +986,20 @@ void VertexColorGLTest::renderMulti3D() {
sizeof(TransformationProjectionUniform3D));
shader.draw(cone);
/* Otherwise using the draw offset */
/* Otherwise using the draw offset / multidraw */
} else {
shader.bindTransformationProjectionBuffer(transformationProjectionUniform);
shader.setDrawOffset(0)
.draw(sphere);
shader.setDrawOffset(1)
.draw(plane);
shader.setDrawOffset(2)
.draw(cone);
if(data.flags >= VertexColorGL3D::Flag::MultiDraw)
shader.draw({sphere, plane, cone});
else {
shader.setDrawOffset(0)
.draw(sphere);
shader.setDrawOffset(1)
.draw(plane);
shader.setDrawOffset(2)
.draw(cone);
}
}
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 debugFlags();
#ifndef MAGNUM_TARGET_GLES2
void debugFlagsSupersets();
#endif
};
VertexColorGL_Test::VertexColorGL_Test() {
@ -52,7 +55,11 @@ VertexColorGL_Test::VertexColorGL_Test() {
&VertexColorGL_Test::constructCopy<3>,
&VertexColorGL_Test::debugFlag,
&VertexColorGL_Test::debugFlags});
&VertexColorGL_Test::debugFlags,
#ifndef MAGNUM_TARGET_GLES2
&VertexColorGL_Test::debugFlagsSupersets
#endif
});
}
template<UnsignedInt dimensions> void VertexColorGL_Test::constructNoCreate() {
@ -97,6 +104,15 @@ void VertexColorGL_Test::debugFlags() {
#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)

11
src/Magnum/Shaders/Vector.frag

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

28
src/Magnum/Shaders/Vector.vert

@ -23,6 +23,14 @@
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
#define in attribute
#define out varying
@ -132,8 +140,24 @@ in mediump vec2 textureCoordinates;
out mediump vec2 interpolatedTextureCoordinates;
#ifdef MULTI_DRAW
flat out highp uint drawId;
#endif
void main() {
#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
#ifdef TWO_DIMENSIONS
mat3
@ -142,9 +166,9 @@ void main() {
#else
#error
#endif
transformationProjectionMatrix = transformationProjectionMatrices[drawOffset];
transformationProjectionMatrix = transformationProjectionMatrices[drawId];
#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

15
src/Magnum/Shaders/VectorGL.cpp

@ -81,6 +81,17 @@ template<UnsignedInt dimensions> VectorGL<dimensions>::VectorGL(const Flags flag
if(flags >= Flag::UniformBuffers)
MAGNUM_ASSERT_GL_EXTENSION_SUPPORTED(GL::Extensions::ARB::uniform_buffer_object);
#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
/* 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 DRAW_COUNT {}\n",
drawCount));
vert.addSource(flags >= Flag::MultiDraw ? "#define MULTI_DRAW\n" : "");
}
#endif
vert.addSource(rs.get("generic.glsl"))
@ -118,6 +130,7 @@ template<UnsignedInt dimensions> VectorGL<dimensions>::VectorGL(const Flags flag
"#define UNIFORM_BUFFERS\n"
"#define DRAW_COUNT {}\n",
drawCount));
frag.addSource(flags >= Flag::MultiDraw ? "#define MULTI_DRAW\n" : "");
}
#endif
frag.addSource(rs.get("generic.glsl"))
@ -308,6 +321,7 @@ Debug& operator<<(Debug& debug, const VectorGLFlag value) {
_c(TextureTransformation)
#ifndef MAGNUM_TARGET_GLES2
_c(UniformBuffers)
_c(MultiDraw)
#endif
#undef _c
/* LCOV_EXCL_STOP */
@ -320,6 +334,7 @@ Debug& operator<<(Debug& debug, const VectorGLFlags value) {
return Containers::enumSetDebugOutput(debug, value, "Shaders::VectorGL::Flags{}", {
VectorGLFlag::TextureTransformation,
#ifndef MAGNUM_TARGET_GLES2
VectorGLFlag::MultiDraw, /* Superset of UniformBuffers */
VectorGLFlag::UniformBuffers
#endif
});

34
src/Magnum/Shaders/VectorGL.h

@ -41,7 +41,8 @@ namespace Implementation {
enum class VectorGLFlag: UnsignedByte {
TextureTransformation = 1 << 0,
#ifndef MAGNUM_TARGET_GLES2
UniformBuffers = 1 << 1
UniformBuffers = 1 << 1,
MultiDraw = UniformBuffers|(1 << 2)
#endif
};
typedef Containers::EnumSet<VectorGLFlag> VectorGLFlags;
@ -135,7 +136,31 @@ template<UnsignedInt dimensions> class MAGNUM_SHADERS_EXPORT VectorGL: public GL
* 1.0.
* @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
};
@ -327,6 +352,11 @@ template<UnsignedInt dimensions> class MAGNUM_SHADERS_EXPORT VectorGL: public GL
* should be used for current draw. Expects that
* @ref Flag::UniformBuffers is set and @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_gles30 Uniform buffers are not available in OpenGL ES 2.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.
*/
#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
#define in attribute
#define out varying
@ -107,6 +115,18 @@ out lowp vec4 interpolatedColor;
void main() {
#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
#ifdef TWO_DIMENSIONS
mat3
@ -115,7 +135,7 @@ void main() {
#else
#error
#endif
transformationProjectionMatrix = transformationProjectionMatrices[drawOffset];
transformationProjectionMatrix = transformationProjectionMatrices[drawId];
#endif
#ifdef TWO_DIMENSIONS

14
src/Magnum/Shaders/VertexColorGL.cpp

@ -76,6 +76,17 @@ template<UnsignedInt dimensions> VertexColorGL<dimensions>::VertexColorGL(const
if(flags >= Flag::UniformBuffers)
MAGNUM_ASSERT_GL_EXTENSION_SUPPORTED(GL::Extensions::ARB::uniform_buffer_object);
#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
/* Import resources on static build, if not already */
@ -102,6 +113,7 @@ template<UnsignedInt dimensions> VertexColorGL<dimensions>::VertexColorGL(const
"#define UNIFORM_BUFFERS\n"
"#define DRAW_COUNT {}\n",
drawCount));
vert.addSource(flags >= Flag::MultiDraw ? "#define MULTI_DRAW\n" : "");
}
#endif
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;
#ifndef MAGNUM_TARGET_GLES2
_c(UniformBuffers)
_c(MultiDraw)
#endif
#undef _c
/* LCOV_EXCL_STOP */
@ -225,6 +238,7 @@ Debug& operator<<(Debug& debug, const VertexColorGLFlag value) {
Debug& operator<<(Debug& debug, const VertexColorGLFlags value) {
return Containers::enumSetDebugOutput(debug, value, "Shaders::VertexColorGL::Flags{}", {
#ifndef MAGNUM_TARGET_GLES2
VertexColorGLFlag::MultiDraw, /* Superset of UniformBuffers */
VertexColorGLFlag::UniformBuffers
#endif
});

34
src/Magnum/Shaders/VertexColorGL.h

@ -40,7 +40,8 @@ namespace Magnum { namespace Shaders {
namespace Implementation {
enum class VertexColorGLFlag: UnsignedByte {
#ifndef MAGNUM_TARGET_GLES2
UniformBuffers = 1 << 0
UniformBuffers = 1 << 0,
MultiDraw = UniformBuffers|(1 << 1)
#endif
};
typedef Containers::EnumSet<VertexColorGLFlag> VertexColorGLFlags;
@ -136,7 +137,31 @@ template<UnsignedInt dimensions> class MAGNUM_SHADERS_EXPORT VertexColorGL: publ
* 1.0.
* @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
};
@ -279,6 +304,11 @@ template<UnsignedInt dimensions> class MAGNUM_SHADERS_EXPORT VertexColorGL: publ
* @ref bindTransformationProjectionBuffer() should be used for current
* draw. Expects that @ref Flag::UniformBuffers is set and @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_gles30 Uniform buffers are not available in OpenGL ES 2.0.
* @requires_webgl20 Uniform buffers are not available in WebGL 1.0.

Loading…
Cancel
Save