Browse Source

Shaders: supply Flat material information in a separate UBO as well.

While it's one additional indirection (that has an extra cost on Intel
GPUs apparently, like with Phong and MeshVisualizer and
DistanceFieldVector already), with the assumption that draws usually
share the material info it allows to cram more draws into the 16/64k UBO
limit as the per-draw data are now one vec4 smaller.

For the indirection overhead I can imagine adding a new flag which makes
material mapping implicit (materialId == drawId). That seems to put the
benchmark numbers back to the original speed. Same could be done for
other shaders.
pull/518/head
Vladimír Vondruš 5 years ago
parent
commit
a2f8a920da
  1. 30
      src/Magnum/Shaders/Flat.frag
  2. 182
      src/Magnum/Shaders/Flat.h
  3. 32
      src/Magnum/Shaders/FlatGL.cpp
  4. 86
      src/Magnum/Shaders/FlatGL.h
  5. 233
      src/Magnum/Shaders/Test/FlatGLTest.cpp
  6. 97
      src/Magnum/Shaders/Test/FlatTest.cpp
  7. 43
      src/Magnum/Shaders/Test/ShadersGLBenchmark.cpp

30
src/Magnum/Shaders/Flat.frag

@ -27,10 +27,6 @@
#extension GL_EXT_gpu_shader4: require
#endif
#if defined(UNIFORM_BUFFERS) && defined(ALPHA_MASK) && !defined(GL_ES)
#extension GL_ARB_shader_bit_encoding: require
#endif
#ifndef NEW_GLSL
#define fragmentColor gl_FragColor
#define texture texture2D
@ -88,10 +84,9 @@ uniform highp uint drawOffset
#endif
struct DrawUniform {
lowp vec4 color;
highp uvec4 objectIdReservedAlphaMaskReserved;
#define draw_objectId objectIdReservedAlphaMaskReserved.x
#define draw_alphaMask objectIdReservedAlphaMaskReserved.z
highp uvec4 materialIdReservedObjectIdReservedReserved;
#define draw_materialIdReserved materialIdReservedObjectIdReservedReserved.x
#define draw_objectId materialIdReservedObjectIdReservedReserved.y
};
layout(std140
@ -101,6 +96,20 @@ layout(std140
) uniform Draw {
DrawUniform draws[DRAW_COUNT];
};
struct MaterialUniform {
lowp vec4 color;
highp vec4 alphaMaskReservedReservedReserved;
#define material_alphaMask alphaMaskReservedReservedReserved.x
};
layout(std140
#ifdef EXPLICIT_BINDING
, binding = 4
#endif
) uniform Material {
MaterialUniform materials[MATERIAL_COUNT];
};
#endif
/* Textures */
@ -148,12 +157,13 @@ flat in highp uint drawId;
void main() {
#ifdef UNIFORM_BUFFERS
lowp const vec4 color = draws[drawId].color;
#ifdef OBJECT_ID
highp const uint objectId = draws[drawId].draw_objectId;
#endif
mediump const uint materialId = draws[drawId].draw_materialIdReserved & 0xffffu;
lowp const vec4 color = materials[materialId].color;
#ifdef ALPHA_MASK
lowp const float alphaMask = uintBitsToFloat(draws[drawId].draw_alphaMask);
lowp const float alphaMask = materials[materialId].material_alphaMask;
#endif
#endif

182
src/Magnum/Shaders/Flat.h

@ -26,7 +26,7 @@
*/
/** @file
* @brief Struct @ref Magnum::Shaders::FlatDrawUniform
* @brief Struct @ref Magnum::Shaders::FlatDrawUniform, @ref Magnum::Shaders::FlatMaterialUniform
*/
#include "Magnum/Magnum.h"
@ -47,24 +47,29 @@ namespace Magnum { namespace Shaders {
Together with the generic @ref TransformationProjectionUniform2D /
@ref TransformationProjectionUniform3D contains parameters that are specific to
each draw call. Texture transformation, if needed, is supplied separately in a
@ref TextureTransformationUniform.
@ref TextureTransformationUniform; material-related properties are expected to
be shared among multiple draw calls and thus are provided in a separate
@ref FlatMaterialUniform structure, referenced by @ref materialId.
@see @ref FlatGL::bindDrawBuffer()
*/
struct FlatDrawUniform {
/** @brief Construct with default parameters */
constexpr explicit FlatDrawUniform(DefaultInitT = DefaultInit) noexcept: color{1.0f, 1.0f, 1.0f, 1.0f}, objectId{0},
#if (defined(CORRADE_TARGET_CLANG) && __clang_major__ < 4) || (defined(CORRADE_TARGET_APPLE_CLANG) && __clang_major__ < 8)
/* Otherwise it refuses to constexpr, on 3.8 at least */
_pad0{}, _pad1{},
constexpr explicit FlatDrawUniform(DefaultInitT = DefaultInit) noexcept:
#if ((defined(CORRADE_TARGET_CLANG) && __clang_major__ < 4) || (defined(CORRADE_TARGET_APPLE_CLANG) && __clang_major__ < 8)) && defined(CORRADE_TARGET_BIG_ENDIAN)
_pad0{}, /* Otherwise it refuses to constexpr, on 3.8 at least */
#endif
materialId{0},
#if (defined(CORRADE_TARGET_CLANG) && __clang_major__ < 4) || (defined(CORRADE_TARGET_APPLE_CLANG) && __clang_major__ < 8) && !defined(CORRADE_TARGET_BIG_ENDIAN)
_pad0{},
#endif
alphaMask{0.5f}
objectId{0}
#if (defined(CORRADE_TARGET_CLANG) && __clang_major__ < 4) || (defined(CORRADE_TARGET_APPLE_CLANG) && __clang_major__ < 8)
, _pad2{}
, _pad1{}, _pad2{}
#endif
{}
/** @brief Construct without initializing the contents */
explicit FlatDrawUniform(NoInitT) noexcept: color{NoInit} {}
explicit FlatDrawUniform(NoInitT) noexcept {}
/** @{
* @name Convenience setters
@ -76,29 +81,20 @@ struct FlatDrawUniform {
*/
/**
* @brief Set the @ref objectId field
* @brief Set the @ref materialId field
* @return Reference to self (for method chaining)
*/
FlatDrawUniform& setObjectId(UnsignedInt id) {
objectId = id;
FlatDrawUniform& setMaterialId(UnsignedInt id) {
materialId = id;
return *this;
}
/**
* @brief Set the @ref alphaMask field
* @return Reference to self (for method chaining)
*/
FlatDrawUniform& setAlphaMask(Float alphaMask) {
this->alphaMask = alphaMask;
return *this;
}
/**
* @brief Set the @ref color field
* @brief Set the @ref objectId field
* @return Reference to self (for method chaining)
*/
FlatDrawUniform& setColor(const Color4& color) {
this->color = color;
FlatDrawUniform& setObjectId(UnsignedInt id) {
objectId = id;
return *this;
}
@ -106,17 +102,37 @@ struct FlatDrawUniform {
* @}
*/
/**
* @brief Color
*
* Default value is @cpp 0xffffffff_rgbaf @ce.
/** @var materialId
* @brief Material ID
*
* If @ref FlatGL::Flag::VertexColor is enabled, the color is multiplied
* with a color coming from the @ref FlatGL::Color3 / @ref FlatGL::Color4
* attribute.
* @see @ref FlatGL::setColor()
* References a particular material from a @ref FlatMaterialUniform array.
* Useful when an UBO with more than one material is supplied or in a
* multi-draw scenario. Should be less than the material count passed to
* the @ref FlatGL::FlatGL(Flags, UnsignedInt, UnsignedInt) constructor.
* Default value is @cpp 0 @ce, meaning the first material gets used.
*/
Color4 color;
/* This field is an UnsignedInt in the shader and materialId is extracted
as (value & 0xffff), so the order has to be different on BE */
#ifndef CORRADE_TARGET_BIG_ENDIAN
UnsignedShort materialId;
/* warning: Member __pad0__ is not documented. FFS DOXYGEN WHY DO YOU THINK
I MADE THOSE UNNAMED, YOU DUMB FOOL */
#ifndef DOXYGEN_GENERATING_OUTPUT
UnsignedShort
#if (defined(CORRADE_TARGET_CLANG) && __clang_major__ < 4) || (defined(CORRADE_TARGET_APPLE_CLANG) && __clang_major__ < 8)
_pad0 /* Otherwise it refuses to constexpr, on 3.8 at least */
#endif
:16; /* reserved for skinOffset */
#endif
#else
UnsignedShort
#if (defined(CORRADE_TARGET_CLANG) && __clang_major__ < 4) || (defined(CORRADE_TARGET_APPLE_CLANG) && __clang_major__ < 8)
_pad0 /* Otherwise it refuses to constexpr, on 3.8 at least */
#endif
:16; /* reserved for skinOffset */
UnsignedShort materialId;
#endif
/**
* @brief Object ID
@ -131,35 +147,83 @@ struct FlatDrawUniform {
*/
UnsignedInt objectId;
/* warning: Member __pad0__ is not documented. FFS DOXYGEN WHY DO YOU THINK
/* warning: Member __pad1__ is not documented. FFS DOXYGEN WHY DO YOU THINK
I MADE THOSE UNNAMED, YOU DUMB FOOL */
#ifndef DOXYGEN_GENERATING_OUTPUT
/* This field is an UnsignedInt in the shader and skinOffset is extracted
as (value >> 16), so the order has to be different on BE */
#ifndef CORRADE_TARGET_BIG_ENDIAN
UnsignedShort
#if (defined(CORRADE_TARGET_CLANG) && __clang_major__ < 4) || (defined(CORRADE_TARGET_APPLE_CLANG) && __clang_major__ < 8)
_pad0 /* Otherwise it refuses to constexpr, on 3.8 at least */
#endif
:16;
UnsignedShort
Int
#if (defined(CORRADE_TARGET_CLANG) && __clang_major__ < 4) || (defined(CORRADE_TARGET_APPLE_CLANG) && __clang_major__ < 8)
_pad1 /* Otherwise it refuses to constexpr, on 3.8 at least */
#endif
:16; /* reserved for skinOffset */
#else
UnsignedShort
:32;
Int
#if (defined(CORRADE_TARGET_CLANG) && __clang_major__ < 4) || (defined(CORRADE_TARGET_APPLE_CLANG) && __clang_major__ < 8)
_pad0 /* Otherwise it refuses to constexpr, on 3.8 at least */
_pad2 /* Otherwise it refuses to constexpr, on 3.8 at least */
#endif
:16; /* reserved for skinOffset */
UnsignedShort
:32;
#endif
};
/**
@brief Material uniform for flat shaders
@m_since_latest
Describes material properties referenced from
@ref FlatDrawUniform::materialId.
@see @ref FlatGL::bindMaterialBuffer()
*/
struct FlatMaterialUniform {
/** @brief Construct with default parameters */
constexpr explicit FlatMaterialUniform(DefaultInitT = DefaultInit) noexcept: color{1.0f, 1.0f, 1.0f, 1.0f}, alphaMask{0.5f}
#if (defined(CORRADE_TARGET_CLANG) && __clang_major__ < 4) || (defined(CORRADE_TARGET_APPLE_CLANG) && __clang_major__ < 8)
_pad1 /* Otherwise it refuses to constexpr, on 3.8 at least */
, _pad0{}, _pad1{}, _pad2{}
#endif
:16;
#endif
#endif
{}
/** @brief Construct without initializing the contents */
explicit FlatMaterialUniform(NoInitT) noexcept: color{NoInit} {}
/** @{
* @name Convenience setters
*
* Provided to allow the use of method chaining for populating a structure
* in a single expression, otherwise equivalent to accessing the fields
* directly. Also guaranteed to provide backwards compatibility when
* packing of the actual fields changes.
*/
/**
* @brief Set the @ref alphaMask field
* @return Reference to self (for method chaining)
*/
FlatMaterialUniform& setAlphaMask(Float alphaMask) {
this->alphaMask = alphaMask;
return *this;
}
/**
* @brief Set the @ref color field
* @return Reference to self (for method chaining)
*/
FlatMaterialUniform& setColor(const Color4& color) {
this->color = color;
return *this;
}
/**
* @}
*/
/**
* @brief Color
*
* Default value is @cpp 0xffffffff_rgbaf @ce.
*
* If @ref FlatGL::Flag::VertexColor is enabled, the color is multiplied
* with a color coming from the @ref FlatGL::Color3 / @ref FlatGL::Color4
* attribute.
* @see @ref FlatGL::setColor()
*/
Color4 color;
/**
* @brief Alpha mask value
@ -172,9 +236,19 @@ struct FlatDrawUniform {
*/
Float alphaMask;
/* warning: Member __pad2__ is not documented. FFS DOXYGEN WHY DO YOU THINK
/* warning: Member __pad0__ is not documented. FFS DOXYGEN WHY DO YOU THINK
I MADE THOSE UNNAMED, YOU DUMB FOOL */
#ifndef DOXYGEN_GENERATING_OUTPUT
Int
#if (defined(CORRADE_TARGET_CLANG) && __clang_major__ < 4) || (defined(CORRADE_TARGET_APPLE_CLANG) && __clang_major__ < 8)
_pad0 /* Otherwise it refuses to constexpr, on 3.8 at least */
#endif
:32;
Int
#if (defined(CORRADE_TARGET_CLANG) && __clang_major__ < 4) || (defined(CORRADE_TARGET_APPLE_CLANG) && __clang_major__ < 8)
_pad1 /* Otherwise it refuses to constexpr, on 3.8 at least */
#endif
:32;
Int
#if (defined(CORRADE_TARGET_CLANG) && __clang_major__ < 4) || (defined(CORRADE_TARGET_APPLE_CLANG) && __clang_major__ < 8)
_pad2 /* Otherwise it refuses to constexpr, on 3.8 at least */

32
src/Magnum/Shaders/FlatGL.cpp

@ -57,25 +57,28 @@ namespace {
bound to the same buffer for the whole time */
TransformationProjectionBufferBinding = 1,
DrawBufferBinding = 2,
TextureTransformationBufferBinding = 3
TextureTransformationBufferBinding = 3,
MaterialBufferBinding = 4
};
#endif
}
template<UnsignedInt dimensions> FlatGL<dimensions>::FlatGL(const Flags flags
#ifndef MAGNUM_TARGET_GLES2
, const UnsignedInt drawCount
, const UnsignedInt materialCount, const UnsignedInt drawCount
#endif
):
_flags{flags}
#ifndef MAGNUM_TARGET_GLES2
, _drawCount{drawCount}
, _materialCount{materialCount}, _drawCount{drawCount}
#endif
{
CORRADE_ASSERT(!(flags & Flag::TextureTransformation) || (flags & Flag::Textured),
"Shaders::FlatGL: texture transformation enabled but the shader is not textured", );
#ifndef MAGNUM_TARGET_GLES2
CORRADE_ASSERT(!(flags >= Flag::UniformBuffers) || materialCount,
"Shaders::FlatGL: material count can't be zero", );
CORRADE_ASSERT(!(flags >= Flag::UniformBuffers) || drawCount,
"Shaders::FlatGL: draw count can't be zero", );
#endif
@ -146,8 +149,10 @@ template<UnsignedInt dimensions> FlatGL<dimensions>::FlatGL(const Flags flags
if(flags >= Flag::UniformBuffers) {
frag.addSource(Utility::formatString(
"#define UNIFORM_BUFFERS\n"
"#define DRAW_COUNT {}\n",
drawCount));
"#define DRAW_COUNT {}\n"
"#define MATERIAL_COUNT {}\n",
drawCount,
materialCount));
frag.addSource(flags >= Flag::MultiDraw ? "#define MULTI_DRAW\n" : "");
}
#endif
@ -219,6 +224,7 @@ template<UnsignedInt dimensions> FlatGL<dimensions>::FlatGL(const Flags flags
setUniformBlockBinding(uniformBlockIndex("Draw"), DrawBufferBinding);
if(flags & Flag::TextureTransformation)
setUniformBlockBinding(uniformBlockIndex("TextureTransformation"), TextureTransformationBufferBinding);
setUniformBlockBinding(uniformBlockIndex("Material"), MaterialBufferBinding);
}
#endif
}
@ -242,7 +248,7 @@ template<UnsignedInt dimensions> FlatGL<dimensions>::FlatGL(const Flags flags
}
#ifndef MAGNUM_TARGET_GLES2
template<UnsignedInt dimensions> FlatGL<dimensions>::FlatGL(const Flags flags): FlatGL{flags, 1} {}
template<UnsignedInt dimensions> FlatGL<dimensions>::FlatGL(const Flags flags): FlatGL{flags, 1, 1} {}
#endif
template<UnsignedInt dimensions> FlatGL<dimensions>& FlatGL<dimensions>::setTransformationProjectionMatrix(const MatrixTypeFor<dimensions, Float>& matrix) {
@ -351,6 +357,20 @@ template<UnsignedInt dimensions> FlatGL<dimensions>& FlatGL<dimensions>::bindTex
buffer.bind(GL::Buffer::Target::Uniform, TextureTransformationBufferBinding, offset, size);
return *this;
}
template<UnsignedInt dimensions> FlatGL<dimensions>& FlatGL<dimensions>::bindMaterialBuffer(GL::Buffer& buffer) {
CORRADE_ASSERT(_flags >= Flag::UniformBuffers,
"Shaders::FlatGL::bindMaterialBuffer(): the shader was not created with uniform buffers enabled", *this);
buffer.bind(GL::Buffer::Target::Uniform, MaterialBufferBinding);
return *this;
}
template<UnsignedInt dimensions> FlatGL<dimensions>& FlatGL<dimensions>::bindMaterialBuffer(GL::Buffer& buffer, const GLintptr offset, const GLsizeiptr size) {
CORRADE_ASSERT(_flags >= Flag::UniformBuffers,
"Shaders::FlatGL::bindMaterialBuffer(): the shader was not created with uniform buffers enabled", *this);
buffer.bind(GL::Buffer::Target::Uniform, MaterialBufferBinding, offset, size);
return *this;
}
#endif
template<UnsignedInt dimensions> FlatGL<dimensions>& FlatGL<dimensions>::bindTexture(GL::Texture2D& texture) {

86
src/Magnum/Shaders/FlatGL.h

@ -380,8 +380,8 @@ template<UnsignedInt dimensions> class MAGNUM_SHADERS_EXPORT FlatGL: public GL::
/**
* Use uniform buffers. Expects that uniform data are supplied via
* @ref bindTransformationProjectionBuffer(),
* @ref bindDrawBuffer() and @ref bindTextureTransformationBuffer()
* instead of direct uniform setters.
* @ref bindDrawBuffer(), @ref bindTextureTransformationBuffer()
* and @ref bindMaterialBuffer() instead of direct uniform setters.
* @requires_gl31 Extension @gl_extension{ARB,uniform_buffer_object}
* @requires_gles30 Uniform buffers are not available in OpenGL ES
* 2.0.
@ -437,32 +437,44 @@ template<UnsignedInt dimensions> class MAGNUM_SHADERS_EXPORT FlatGL: public GL::
*
* While this function is meant mainly for the classic uniform
* scenario (without @ref Flag::UniformBuffers set), it's equivalent to
* @ref FlatGL(Flags, UnsignedInt) with @p drawCount set to @cpp 1 @ce.
* @ref FlatGL(Flags, UnsignedInt, UnsignedInt) with @p materialCount
* and @p drawCount set to @cpp 1 @ce.
*/
explicit FlatGL(Flags flags = {});
#ifndef MAGNUM_TARGET_GLES2
/**
* @brief Construct for a multi-draw scenario
* @param flags Flags
* @param drawCount Size of a @ref TransformationProjectionUniform2D /
* @ref TransformationProjectionUniform3D / @ref FlatDrawUniform /
* @ref TextureTransformationUniform buffer bound with
* @param flags Flags
* @param materialCount Size of a @ref FlatMaterialUniform buffer
* bound with @ref bindMaterialBuffer()
* @param drawCount Size of a @ref TransformationProjectionUniform2D
* / @ref TransformationProjectionUniform3D / @ref FlatDrawUniform
* / @ref TextureTransformationUniform buffer bound with
* @ref bindTransformationProjectionBuffer(), @ref bindDrawBuffer()
* and @ref bindTextureTransformationBuffer()
*
* If @p flags contains @ref Flag::UniformBuffers, @p drawCount
* describes the uniform buffer sizes as these are required to have a
* statically defined size. The draw offset is then set via
* @ref setDrawOffset().
* If @p flags contains @ref Flag::UniformBuffers, @p materialCount and
* @p drawCount describe the uniform buffer sizes as these are required
* to have a statically defined size. The draw offset is then set via
* @ref setDrawOffset() and the per-draw materials specified via
* @ref FlatDrawUniform::materialId.
*
* If @p flags don't contain @ref Flag::UniformBuffers, @p drawCount is
* ignored and the constructor behaves the same as @ref FlatGL(Flags).
* If @p flags don't contain @ref Flag::UniformBuffers,
* @p materialCount and @p drawCount is ignored and the constructor
* behaves the same as @ref FlatGL(Flags).
* @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.
*/
explicit FlatGL(Flags flags, UnsignedInt drawCount);
/** @todo this constructor will eventually need to have also joint
count, per-vertex weight count, view count for multiview and clip
plane count ... and putting them in arbitrary order next to each
other is too error-prone, so it needs some other solution
(accepting pairs of parameter type and value like in GL context
creation, e.g., which will probably need a new enum as reusing Flag
for this might be too confusing) */
explicit FlatGL(Flags flags, UnsignedInt materialCount, UnsignedInt drawCount);
#endif
/**
@ -495,6 +507,18 @@ template<UnsignedInt dimensions> class MAGNUM_SHADERS_EXPORT FlatGL: public GL::
Flags flags() const { return _flags; }
#ifndef MAGNUM_TARGET_GLES2
/**
* @brief Material count
* @m_since_latest
*
* Statically defined size of the @ref FlatMaterialUniform uniform
* buffer. Has use only if @ref Flag::UniformBuffers is set.
* @see @ref bindMaterialBuffer()
* @requires_gles30 Not defined on OpenGL ES 2.0 builds.
* @requires_webgl20 Not defined on WebGL 1.0 builds.
*/
UnsignedInt materialCount() const { return _materialCount; }
/**
* @brief Draw count
* @m_since_latest
@ -560,7 +584,8 @@ template<UnsignedInt dimensions> class MAGNUM_SHADERS_EXPORT FlatGL: public GL::
* coming from the @ref Color3 / @ref Color4 attribute.
*
* Expects that @ref Flag::UniformBuffers is not set, in that case fill
* @ref FlatDrawUniform::color and call @ref bindDrawBuffer() instead.
* @ref FlatMaterialUniform::color and call @ref bindMaterialBuffer()
* instead.
* @see @ref bindTexture()
*/
FlatGL<dimensions>& setColor(const Magnum::Color4& color);
@ -578,8 +603,8 @@ template<UnsignedInt dimensions> class MAGNUM_SHADERS_EXPORT FlatGL: public GL::
* in classic OpenGL.
*
* Expects that @ref Flag::UniformBuffers is not set, in that case fill
* @ref FlatDrawUniform::alphaMask and call @ref bindDrawBuffer()
* instead.
* @ref FlatMaterialUniform::alphaMask and call
* @ref bindMaterialBuffer() instead.
* @m_keywords{glAlphaFunc()}
*/
FlatGL<dimensions>& setAlphaMask(Float mask);
@ -648,7 +673,7 @@ template<UnsignedInt dimensions> class MAGNUM_SHADERS_EXPORT FlatGL: public GL::
* expected to contain @ref drawCount() instances of
* @ref TransformationProjectionUniform2D /
* @ref TransformationProjectionUniform3D. At the very least you need
* to call also @ref bindDrawBuffer().
* to call also @ref bindDrawBuffer() and @ref bindMaterialBuffer().
* @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.
@ -668,7 +693,8 @@ template<UnsignedInt dimensions> class MAGNUM_SHADERS_EXPORT FlatGL: public GL::
* Expects that @ref Flag::UniformBuffers is set. The buffer is
* expected to contain @ref drawCount() instances of
* @ref FlatDrawUniform. At the very least you need to call also
* @ref bindTransformationProjectionBuffer().
* @ref bindTransformationProjectionBuffer() and
* @ref bindMaterialBuffer().
* @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.
@ -700,6 +726,26 @@ template<UnsignedInt dimensions> class MAGNUM_SHADERS_EXPORT FlatGL: public GL::
*/
FlatGL<dimensions>& bindTextureTransformationBuffer(GL::Buffer& buffer, GLintptr offset, GLsizeiptr size);
/**
* @brief Set a material uniform buffer
* @return Reference to self (for method chaining)
* @m_since_latest
*
* Expects that @ref Flag::UniformBuffers is set. The buffer is
* expected to contain @ref materialCount() instances of
* @ref FlatMaterialUniform. At the very least you need to call also
* @ref bindTransformationProjectionBuffer() and @ref bindDrawBuffer().
* @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.
*/
FlatGL<dimensions>& bindMaterialBuffer(GL::Buffer& buffer);
/**
* @overload
* @m_since_latest
*/
FlatGL<dimensions>& bindMaterialBuffer(GL::Buffer& buffer, GLintptr offset, GLsizeiptr size);
/**
* @}
*/
@ -735,7 +781,7 @@ template<UnsignedInt dimensions> class MAGNUM_SHADERS_EXPORT FlatGL: public GL::
Flags _flags;
#ifndef MAGNUM_TARGET_GLES2
UnsignedInt _drawCount{};
UnsignedInt _materialCount{}, _drawCount{};
#endif
Int _transformationProjectionMatrixUniform{0},
_textureMatrixUniform{1},

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

@ -86,7 +86,7 @@ struct FlatGLTest: GL::OpenGLTester {
template<UnsignedInt dimensions> void constructTextureTransformationNotTextured();
#ifndef MAGNUM_TARGET_GLES2
template<UnsignedInt dimensions> void constructUniformBuffersZeroDraws();
template<UnsignedInt dimensions> void constructUniformBuffersInvalid();
#endif
#ifndef MAGNUM_TARGET_GLES2
@ -210,17 +210,31 @@ constexpr struct {
constexpr struct {
const char* name;
FlatGL2D::Flags flags;
UnsignedInt drawCount;
UnsignedInt materialCount, drawCount;
} ConstructUniformBuffersData[]{
{"classic fallback", {}, 1},
{"", FlatGL2D::Flag::UniformBuffers, 1},
/* SwiftShader has 256 uniform vectors at most, per-draw is 4+2 in 3D case
and 3+2 in 2D */
{"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},
{"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}
{"classic fallback", {}, 1, 1},
{"", FlatGL2D::Flag::UniformBuffers, 1, 1},
/* SwiftShader has 256 uniform vectors at most, per-draw is 4+1 in 3D case
and 3+1 in 2D, per-material 2 */
{"multiple materials, draws", FlatGL2D::Flag::UniformBuffers, 8, 48},
{"texture transformation", FlatGL2D::Flag::UniformBuffers|FlatGL2D::Flag::Textured|FlatGL2D::Flag::TextureTransformation, 1, 1},
{"alpha mask", FlatGL2D::Flag::UniformBuffers|FlatGL2D::Flag::AlphaMask, 1, 1},
{"object ID", FlatGL2D::Flag::UniformBuffers|FlatGL2D::Flag::ObjectId, 1, 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, 8, 48}
};
#endif
#ifndef MAGNUM_TARGET_GLES2
constexpr struct {
const char* name;
FlatGL2D::Flags flags;
UnsignedInt materialCount, drawCount;
const char* message;
} ConstructUniformBuffersInvalidData[]{
{"zero draws", FlatGL2D::Flag::UniformBuffers, 1, 0,
"draw count can't be zero"},
{"zero materials", FlatGL2D::Flag::UniformBuffers, 0, 1,
"material count can't be zero"},
};
#endif
@ -282,30 +296,30 @@ constexpr struct {
const char* expected2D;
const char* expected3D;
FlatGL2D::Flags flags;
UnsignedInt drawCount;
UnsignedInt materialCount, drawCount;
UnsignedInt uniformIncrement;
Float maxThreshold, meanThreshold;
} RenderMultiData[] {
{"bind with offset, colored", "multidraw2D.tga", "multidraw3D.tga",
{}, 1, 16, 0.0f, 0.0f},
{}, 1, 1, 16, 0.0f, 0.0f},
{"bind with offset, textured", "multidraw-textured2D.tga", "multidraw-textured3D.tga",
FlatGL2D::Flag::TextureTransformation|FlatGL2D::Flag::Textured,
1, 16,
1, 1, 16,
/* Minor differences on ARM Mali */
2.34f, 0.01f},
{"draw offset, colored", "multidraw2D.tga", "multidraw3D.tga",
{},
3, 1, 0.0f, 0.0f},
2, 3, 1, 0.0f, 0.0f},
{"draw offset, textured", "multidraw-textured2D.tga", "multidraw-textured3D.tga",
FlatGL2D::Flag::TextureTransformation|FlatGL2D::Flag::Textured,
3, 1,
2, 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},
FlatGL2D::Flag::MultiDraw, 2, 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,
2, 3, 1,
/* Minor differences on ARM Mali */
2.34f, 0.01f}
};
@ -334,12 +348,16 @@ FlatGLTest::FlatGLTest() {
#endif
&FlatGLTest::constructTextureTransformationNotTextured<2>,
&FlatGLTest::constructTextureTransformationNotTextured<3>,
#ifndef MAGNUM_TARGET_GLES2
&FlatGLTest::constructUniformBuffersZeroDraws<2>,
&FlatGLTest::constructUniformBuffersZeroDraws<3>,
#endif
&FlatGLTest::constructTextureTransformationNotTextured<3>});
#ifndef MAGNUM_TARGET_GLES2
addInstancedTests<FlatGLTest>({
&FlatGLTest::constructUniformBuffersInvalid<2>,
&FlatGLTest::constructUniformBuffersInvalid<3>},
Containers::arraySize(ConstructUniformBuffersInvalidData));
#endif
addTests<FlatGLTest>({
#ifndef MAGNUM_TARGET_GLES2
&FlatGLTest::setUniformUniformBuffersEnabled<2>,
&FlatGLTest::setUniformUniformBuffersEnabled<3>,
@ -557,8 +575,9 @@ template<UnsignedInt dimensions> void FlatGLTest::constructUniformBuffers() {
#endif
}
FlatGL<dimensions> shader{data.flags, data.drawCount};
FlatGL<dimensions> shader{data.flags, data.materialCount, data.drawCount};
CORRADE_COMPARE(shader.flags(), data.flags);
CORRADE_COMPARE(shader.materialCount(), data.materialCount);
CORRADE_COMPARE(shader.drawCount(), data.drawCount);
CORRADE_VERIFY(shader.id());
{
@ -602,7 +621,7 @@ template<UnsignedInt dimensions> void FlatGLTest::constructMoveUniformBuffers()
CORRADE_SKIP(GL::Extensions::ARB::uniform_buffer_object::string() << "is not supported.");
#endif
FlatGL<dimensions> a{FlatGL<dimensions>::Flag::UniformBuffers, 5};
FlatGL<dimensions> a{FlatGL<dimensions>::Flag::UniformBuffers, 2, 5};
const GLuint id = a.id();
CORRADE_VERIFY(id);
@ -611,6 +630,7 @@ template<UnsignedInt dimensions> void FlatGLTest::constructMoveUniformBuffers()
FlatGL<dimensions> b{std::move(a)};
CORRADE_COMPARE(b.id(), id);
CORRADE_COMPARE(b.flags(), FlatGL<dimensions>::Flag::UniformBuffers);
CORRADE_COMPARE(b.materialCount(), 2);
CORRADE_COMPARE(b.drawCount(), 5);
CORRADE_VERIFY(!a.id());
@ -618,6 +638,7 @@ template<UnsignedInt dimensions> void FlatGLTest::constructMoveUniformBuffers()
c = std::move(b);
CORRADE_COMPARE(c.id(), id);
CORRADE_COMPARE(c.flags(), FlatGL<dimensions>::Flag::UniformBuffers);
CORRADE_COMPARE(c.materialCount(), 2);
CORRADE_COMPARE(c.drawCount(), 5);
CORRADE_VERIFY(!b.id());
}
@ -638,8 +659,10 @@ template<UnsignedInt dimensions> void FlatGLTest::constructTextureTransformation
}
#ifndef MAGNUM_TARGET_GLES2
template<UnsignedInt dimensions> void FlatGLTest::constructUniformBuffersZeroDraws() {
template<UnsignedInt dimensions> void FlatGLTest::constructUniformBuffersInvalid() {
auto&& data = ConstructUniformBuffersInvalidData[testCaseInstanceId()];
setTestCaseTemplateName(std::to_string(dimensions));
setTestCaseDescription(data.name);
#ifdef CORRADE_NO_ASSERT
CORRADE_SKIP("CORRADE_NO_ASSERT defined, can't test assertions");
@ -652,9 +675,9 @@ template<UnsignedInt dimensions> void FlatGLTest::constructUniformBuffersZeroDra
std::ostringstream out;
Error redirectError{&out};
FlatGL<dimensions>{FlatGL<dimensions>::Flag::UniformBuffers, 0};
CORRADE_COMPARE(out.str(),
"Shaders::FlatGL: draw count can't be zero\n");
FlatGL<dimensions>{data.flags, data.materialCount, data.drawCount};
CORRADE_COMPARE(out.str(), Utility::formatString(
"Shaders::FlatGL: {}\n", data.message));
}
#endif
@ -706,6 +729,8 @@ template<UnsignedInt dimensions> void FlatGLTest::bindBufferUniformBuffersNotEna
.bindDrawBuffer(buffer, 0, 16)
.bindTextureTransformationBuffer(buffer)
.bindTextureTransformationBuffer(buffer, 0, 16)
.bindMaterialBuffer(buffer)
.bindMaterialBuffer(buffer, 0, 16)
.setDrawOffset(0);
CORRADE_COMPARE(out.str(),
"Shaders::FlatGL::bindTransformationProjectionBuffer(): the shader was not created with uniform buffers enabled\n"
@ -714,6 +739,8 @@ template<UnsignedInt dimensions> void FlatGLTest::bindBufferUniformBuffersNotEna
"Shaders::FlatGL::bindDrawBuffer(): the shader was not created with uniform buffers enabled\n"
"Shaders::FlatGL::bindTextureTransformationBuffer(): the shader was not created with uniform buffers enabled\n"
"Shaders::FlatGL::bindTextureTransformationBuffer(): the shader was not created with uniform buffers enabled\n"
"Shaders::FlatGL::bindMaterialBuffer(): the shader was not created with uniform buffers enabled\n"
"Shaders::FlatGL::bindMaterialBuffer(): the shader was not created with uniform buffers enabled\n"
"Shaders::FlatGL::setDrawOffset(): the shader was not created with uniform buffers enabled\n");
}
#endif
@ -829,7 +856,7 @@ template<UnsignedInt dimensions> void FlatGLTest::setWrongDrawOffset() {
std::ostringstream out;
Error redirectError{&out};
FlatGL<dimensions>{FlatGL<dimensions>::Flag::UniformBuffers, 5}
FlatGL<dimensions>{FlatGL<dimensions>::Flag::UniformBuffers, 2, 5}
.setDrawOffset(5);
CORRADE_COMPARE(out.str(),
"Shaders::FlatGL::setDrawOffset(): draw offset 5 is out of bounds for 5 draws\n");
@ -890,9 +917,13 @@ template<FlatGL2D::Flag flag> void FlatGLTest::renderDefaults2D() {
GL::Buffer drawUniform{GL::Buffer::TargetHint::Uniform, {
FlatDrawUniform{}
}};
GL::Buffer materialUniform{GL::Buffer::TargetHint::Uniform, {
FlatMaterialUniform{}
}};
shader
.bindTransformationProjectionBuffer(transformationProjectionUniform)
.bindDrawBuffer(drawUniform)
.bindMaterialBuffer(materialUniform)
.draw(circle);
}
#endif
@ -939,9 +970,13 @@ template<FlatGL3D::Flag flag> void FlatGLTest::renderDefaults3D() {
GL::Buffer drawUniform{GL::Buffer::TargetHint::Uniform, {
FlatDrawUniform{}
}};
GL::Buffer materialUniform{GL::Buffer::TargetHint::Uniform, {
FlatMaterialUniform{}
}};
shader
.bindTransformationProjectionBuffer(transformationProjectionUniform)
.bindDrawBuffer(drawUniform)
.bindMaterialBuffer(materialUniform)
.draw(sphere);
}
#endif
@ -991,11 +1026,15 @@ template<FlatGL2D::Flag flag> void FlatGLTest::renderColored2D() {
}};
GL::Buffer drawUniform{GL::Buffer::TargetHint::Uniform, {
FlatDrawUniform{}
}};
GL::Buffer materialUniform{GL::Buffer::TargetHint::Uniform, {
FlatMaterialUniform{}
.setColor(0x9999ff_rgbf)
}};
shader
.bindTransformationProjectionBuffer(transformationProjectionUniform)
.bindDrawBuffer(drawUniform)
.bindMaterialBuffer(materialUniform)
.draw(circle);
}
#endif
@ -1059,11 +1098,15 @@ template<FlatGL3D::Flag flag> void FlatGLTest::renderColored3D() {
}};
GL::Buffer drawUniform{GL::Buffer::TargetHint::Uniform, {
FlatDrawUniform{}
}};
GL::Buffer materialUniform{GL::Buffer::TargetHint::Uniform, {
FlatMaterialUniform{}
.setColor(0x9999ff_rgbf)
}};
shader
.bindTransformationProjectionBuffer(transformationProjectionUniform)
.bindDrawBuffer(drawUniform)
.bindMaterialBuffer(materialUniform)
.draw(sphere);
}
#endif
@ -1144,8 +1187,12 @@ template<FlatGL2D::Flag flag> void FlatGLTest::renderSinglePixelTextured2D() {
GL::Buffer drawUniform{GL::Buffer::TargetHint::Uniform, {
FlatDrawUniform{}
}};
GL::Buffer materialUniform{GL::Buffer::TargetHint::Uniform, {
FlatMaterialUniform{}
}};
shader.bindTransformationProjectionBuffer(transformationProjectionUniform)
.bindDrawBuffer(drawUniform)
.bindMaterialBuffer(materialUniform)
.draw(circle);
}
#endif
@ -1221,8 +1268,12 @@ template<FlatGL3D::Flag flag> void FlatGLTest::renderSinglePixelTextured3D() {
GL::Buffer drawUniform{GL::Buffer::TargetHint::Uniform, {
FlatDrawUniform{}
}};
GL::Buffer materialUniform{GL::Buffer::TargetHint::Uniform, {
FlatMaterialUniform{}
}};
shader.bindTransformationProjectionBuffer(transformationProjectionUniform)
.bindDrawBuffer(drawUniform)
.bindMaterialBuffer(materialUniform)
.draw(sphere);
}
#endif
@ -1302,16 +1353,20 @@ template<FlatGL2D::Flag flag> void FlatGLTest::renderTextured2D() {
}};
GL::Buffer drawUniform{GL::Buffer::TargetHint::Uniform, {
FlatDrawUniform{}
.setColor(0x9999ff_rgbf)
}};
GL::Buffer textureTransformationUniform{GL::Buffer::TargetHint::Uniform, {
TextureTransformationUniform{}
.setTextureMatrix(data.textureTransformation)
}};
GL::Buffer materialUniform{GL::Buffer::TargetHint::Uniform, {
FlatMaterialUniform{}
.setColor(0x9999ff_rgbf)
}};
if(data.flags & FlatGL2D::Flag::TextureTransformation)
shader.bindTextureTransformationBuffer(textureTransformationUniform);
shader.bindTransformationProjectionBuffer(transformationProjectionUniform)
.bindDrawBuffer(drawUniform)
.bindMaterialBuffer(materialUniform)
.draw(circle);
}
#endif
@ -1401,16 +1456,20 @@ template<FlatGL3D::Flag flag> void FlatGLTest::renderTextured3D() {
}};
GL::Buffer drawUniform{GL::Buffer::TargetHint::Uniform, {
FlatDrawUniform{}
.setColor(0x9999ff_rgbf)
}};
GL::Buffer textureTransformationUniform{GL::Buffer::TargetHint::Uniform, {
TextureTransformationUniform{}
.setTextureMatrix(data.textureTransformation)
}};
GL::Buffer materialUniform{GL::Buffer::TargetHint::Uniform, {
FlatMaterialUniform{}
.setColor(0x9999ff_rgbf)
}};
if(data.flags & FlatGL3D::Flag::TextureTransformation)
shader.bindTextureTransformationBuffer(textureTransformationUniform);
shader.bindTransformationProjectionBuffer(transformationProjectionUniform)
.bindDrawBuffer(drawUniform)
.bindMaterialBuffer(materialUniform)
.draw(sphere);
}
#endif
@ -1496,10 +1555,14 @@ template<class T, FlatGL2D::Flag flag> void FlatGLTest::renderVertexColor2D() {
}};
GL::Buffer drawUniform{GL::Buffer::TargetHint::Uniform, {
FlatDrawUniform{}
}};
GL::Buffer materialUniform{GL::Buffer::TargetHint::Uniform, {
FlatMaterialUniform{}
.setColor(0x9999ff_rgbf)
}};
shader.bindTransformationProjectionBuffer(transformationProjectionUniform)
.bindDrawBuffer(drawUniform)
.bindMaterialBuffer(materialUniform)
.draw(circle);
}
#endif
@ -1590,10 +1653,14 @@ template<class T, FlatGL2D::Flag flag> void FlatGLTest::renderVertexColor3D() {
}};
GL::Buffer drawUniform{GL::Buffer::TargetHint::Uniform, {
FlatDrawUniform{}
}};
GL::Buffer materialUniform{GL::Buffer::TargetHint::Uniform, {
FlatMaterialUniform{}
.setColor(0x9999ff_rgbf)
}};
shader.bindTransformationProjectionBuffer(transformationProjectionUniform)
.bindDrawBuffer(drawUniform)
.bindMaterialBuffer(materialUniform)
.draw(sphere);
}
#endif
@ -1685,11 +1752,15 @@ template<FlatGL2D::Flag flag> void FlatGLTest::renderAlpha2D() {
}};
GL::Buffer drawUniform{GL::Buffer::TargetHint::Uniform, {
FlatDrawUniform{}
}};
GL::Buffer materialUniform{GL::Buffer::TargetHint::Uniform, {
FlatMaterialUniform{}
.setColor(0x9999ff_rgbf)
.setAlphaMask(data.threshold)
}};
shader.bindTransformationProjectionBuffer(transformationProjectionUniform)
.bindDrawBuffer(drawUniform)
.bindMaterialBuffer(materialUniform)
.draw(circle);
}
#endif
@ -1782,11 +1853,15 @@ template<FlatGL3D::Flag flag> void FlatGLTest::renderAlpha3D() {
}};
GL::Buffer drawUniform{GL::Buffer::TargetHint::Uniform, {
FlatDrawUniform{}
}};
GL::Buffer materialUniform{GL::Buffer::TargetHint::Uniform, {
FlatMaterialUniform{}
.setColor(0x9999ff_rgbf)
.setAlphaMask(data.threshold)
}};
shader.bindTransformationProjectionBuffer(transformationProjectionUniform)
.bindDrawBuffer(drawUniform);
.bindDrawBuffer(drawUniform)
.bindMaterialBuffer(materialUniform);
/* For proper Z order draw back faces first and then front faces */
GL::Renderer::setFaceCullingMode(GL::Renderer::PolygonFacing::Front);
@ -1896,11 +1971,15 @@ template<FlatGL2D::Flag flag> void FlatGLTest::renderObjectId2D() {
}};
GL::Buffer drawUniform{GL::Buffer::TargetHint::Uniform, {
FlatDrawUniform{}
.setColor(0x9999ff_rgbf)
.setObjectId(data.uniformId)
}};
GL::Buffer materialUniform{GL::Buffer::TargetHint::Uniform, {
FlatMaterialUniform{}
.setColor(0x9999ff_rgbf)
}};
shader.bindTransformationProjectionBuffer(transformationProjectionUniform)
.bindDrawBuffer(drawUniform)
.bindMaterialBuffer(materialUniform)
.draw(circle);
} else CORRADE_INTERNAL_ASSERT_UNREACHABLE();
@ -1990,11 +2069,15 @@ template<FlatGL3D::Flag flag> void FlatGLTest::renderObjectId3D() {
}};
GL::Buffer drawUniform{GL::Buffer::TargetHint::Uniform, {
FlatDrawUniform{}
.setColor(0x9999ff_rgbf)
.setObjectId(data.uniformId)
}};
GL::Buffer materialUniform{GL::Buffer::TargetHint::Uniform, {
FlatMaterialUniform{}
.setColor(0x9999ff_rgbf)
}};
shader.bindTransformationProjectionBuffer(transformationProjectionUniform)
.bindDrawBuffer(drawUniform)
.bindMaterialBuffer(materialUniform)
.draw(sphere);
} else CORRADE_INTERNAL_ASSERT_UNREACHABLE();
@ -2127,15 +2210,19 @@ template<FlatGL2D::Flag flag> void FlatGLTest::renderInstanced2D() {
}};
GL::Buffer drawUniform{GL::Buffer::TargetHint::Uniform, {
FlatDrawUniform{}
.setColor(0xffff99_rgbf)
}};
GL::Buffer textureTransformationUniform{GL::Buffer::TargetHint::Uniform, {
TextureTransformationUniform{}
.setTextureMatrix(Matrix3::scaling(Vector2{0.5f}))
}};
GL::Buffer materialUniform{GL::Buffer::TargetHint::Uniform, {
FlatMaterialUniform{}
.setColor(0xffff99_rgbf)
}};
shader.bindTransformationProjectionBuffer(transformationProjectionUniform)
.bindDrawBuffer(drawUniform)
.bindTextureTransformationBuffer(textureTransformationUniform)
.bindMaterialBuffer(materialUniform)
.draw(circle);
}
#endif
@ -2251,15 +2338,19 @@ template<FlatGL3D::Flag flag> void FlatGLTest::renderInstanced3D() {
}};
GL::Buffer drawUniform{GL::Buffer::TargetHint::Uniform, {
FlatDrawUniform{}
.setColor(0xffff99_rgbf)
}};
GL::Buffer textureTransformationUniform{GL::Buffer::TargetHint::Uniform, {
TextureTransformationUniform{}
.setTextureMatrix(Matrix3::scaling(Vector2{0.5f}))
}};
GL::Buffer materialUniform{GL::Buffer::TargetHint::Uniform, {
FlatMaterialUniform{}
.setColor(0xffff99_rgbf)
}};
shader.bindTransformationProjectionBuffer(transformationProjectionUniform)
.bindDrawBuffer(drawUniform)
.bindTextureTransformationBuffer(textureTransformationUniform)
.bindMaterialBuffer(materialUniform)
.draw(sphere);
}
#endif
@ -2344,6 +2435,15 @@ void FlatGLTest::renderMulti2D() {
The data.uniformIncrement is set high enough to ensure that, in the
non-offset-bind case this value is 1. */
Containers::Array<FlatMaterialUniform> materialData{data.uniformIncrement + 1};
materialData[0*data.uniformIncrement] = FlatMaterialUniform{}
.setColor(data.flags & FlatGL2D::Flag::Textured ?
0xffffff_rgbf : 0x0000ff_rgbf);
materialData[1*data.uniformIncrement] = FlatMaterialUniform{}
.setColor(data.flags & FlatGL2D::Flag::Textured ?
0xffffff_rgbf : 0xff0000_rgbf);
GL::Buffer materialUniform{GL::Buffer::TargetHint::Uniform, materialData};
Containers::Array<TransformationProjectionUniform2D> transformationProjectionData{2*data.uniformIncrement + 1};
transformationProjectionData[0*data.uniformIncrement] = TransformationProjectionUniform2D{}
.setTransformationProjectionMatrix(
@ -2384,26 +2484,28 @@ void FlatGLTest::renderMulti2D() {
GL::Buffer textureTransformationUniform{GL::Buffer::TargetHint::Uniform, textureTransformationData};
Containers::Array<FlatDrawUniform> drawData{2*data.uniformIncrement + 1};
/* Material offsets are zero if we have single draw, as those are
done with UBO offset bindings instead. */
drawData[0*data.uniformIncrement] = FlatDrawUniform{}
.setColor(data.flags & FlatGL2D::Flag::Textured ?
0xffffff_rgbf : 0xff0000_rgbf)
.setMaterialId(data.drawCount == 1 ? 0 : 1)
.setObjectId(1211);
drawData[1*data.uniformIncrement] = FlatDrawUniform{}
.setColor(data.flags & FlatGL2D::Flag::Textured ?
0xffffff_rgbf : 0x0000ff_rgbf)
.setMaterialId(data.drawCount == 1 ? 0 : 0)
.setObjectId(5627);
drawData[2*data.uniformIncrement] = FlatDrawUniform{}
.setColor(data.flags & FlatGL2D::Flag::Textured ?
0xffffff_rgbf : 0xff0000_rgbf)
.setMaterialId(data.drawCount == 1 ? 0 : 1)
.setObjectId(36363);
GL::Buffer drawUniform{GL::Buffer::TargetHint::Uniform, drawData};
FlatGL2D shader{FlatGL2D::Flag::UniformBuffers|FlatGL2D::Flag::ObjectId|data.flags, data.drawCount};
FlatGL2D shader{FlatGL2D::Flag::UniformBuffers|FlatGL2D::Flag::ObjectId|data.flags, data.materialCount, data.drawCount};
if(data.flags & FlatGL2D::Flag::Textured)
shader.bindTexture(texture);
/* Just one draw, rebinding UBOs each time */
if(data.drawCount == 1) {
shader.bindMaterialBuffer(materialUniform,
1*data.uniformIncrement*sizeof(FlatMaterialUniform),
sizeof(FlatMaterialUniform));
shader.bindTransformationProjectionBuffer(transformationProjectionUniform,
0*data.uniformIncrement*sizeof(TransformationProjectionUniform2D),
sizeof(TransformationProjectionUniform2D));
@ -2416,6 +2518,9 @@ void FlatGLTest::renderMulti2D() {
sizeof(TextureTransformationUniform));
shader.draw(circle);
shader.bindMaterialBuffer(materialUniform,
0*data.uniformIncrement*sizeof(FlatMaterialUniform),
sizeof(FlatMaterialUniform));
shader.bindTransformationProjectionBuffer(transformationProjectionUniform,
1*data.uniformIncrement*sizeof(TransformationProjectionUniform2D),
sizeof(TransformationProjectionUniform2D));
@ -2428,6 +2533,9 @@ void FlatGLTest::renderMulti2D() {
sizeof(TextureTransformationUniform));
shader.draw(square);
shader.bindMaterialBuffer(materialUniform,
1*data.uniformIncrement*sizeof(FlatMaterialUniform),
sizeof(FlatMaterialUniform));
shader.bindTransformationProjectionBuffer(transformationProjectionUniform,
2*data.uniformIncrement*sizeof(TransformationProjectionUniform2D),
sizeof(TransformationProjectionUniform2D));
@ -2443,7 +2551,8 @@ void FlatGLTest::renderMulti2D() {
/* Otherwise using the draw offset / multidraw */
} else {
shader.bindTransformationProjectionBuffer(transformationProjectionUniform)
.bindDrawBuffer(drawUniform);
.bindDrawBuffer(drawUniform)
.bindMaterialBuffer(materialUniform);
if(data.flags & FlatGL2D::Flag::TextureTransformation)
shader.bindTextureTransformationBuffer(textureTransformationUniform);
@ -2565,6 +2674,15 @@ void FlatGLTest::renderMulti3D() {
The data.uniformIncrement is set high enough to ensure that, in the
non-offset-bind case this value is 1. */
Containers::Array<FlatMaterialUniform> materialData{data.uniformIncrement + 1};
materialData[0*data.uniformIncrement] = FlatMaterialUniform{}
.setColor(data.flags & FlatGL2D::Flag::Textured ?
0xffffff_rgbf : 0x0000ff_rgbf);
materialData[1*data.uniformIncrement] = FlatMaterialUniform{}
.setColor(data.flags & FlatGL2D::Flag::Textured ?
0xffffff_rgbf : 0xff0000_rgbf);
GL::Buffer materialUniform{GL::Buffer::TargetHint::Uniform, materialData};
Containers::Array<TransformationProjectionUniform3D> transformationProjectionData{2*data.uniformIncrement + 1};
transformationProjectionData[0*data.uniformIncrement] = TransformationProjectionUniform3D{}
.setTransformationProjectionMatrix(
@ -2611,26 +2729,28 @@ void FlatGLTest::renderMulti3D() {
GL::Buffer textureTransformationUniform{GL::Buffer::TargetHint::Uniform, textureTransformationData};
Containers::Array<FlatDrawUniform> drawData{2*data.uniformIncrement + 1};
/* Material offsets are zero if we have single draw, as those are done with
UBO offset bindings instead. */
drawData[0*data.uniformIncrement] = FlatDrawUniform{}
.setColor(data.flags & FlatGL3D::Flag::Textured ?
0xffffff_rgbf : 0xff0000_rgbf)
.setMaterialId(data.drawCount == 1 ? 0 : 1)
.setObjectId(1211);
drawData[1*data.uniformIncrement] = FlatDrawUniform{}
.setColor(data.flags & FlatGL3D::Flag::Textured ?
0xffffff_rgbf : 0x0000ff_rgbf)
.setMaterialId(data.drawCount == 1 ? 0 : 0)
.setObjectId(5627);
drawData[2*data.uniformIncrement] = FlatDrawUniform{}
.setColor(data.flags & FlatGL3D::Flag::Textured ?
0xffffff_rgbf : 0xff0000_rgbf)
.setMaterialId(data.drawCount == 1 ? 0 : 1)
.setObjectId(36363);
GL::Buffer drawUniform{GL::Buffer::TargetHint::Uniform, drawData};
FlatGL3D shader{FlatGL3D::Flag::UniformBuffers|FlatGL3D::Flag::ObjectId|data.flags, data.drawCount};
FlatGL3D shader{FlatGL3D::Flag::UniformBuffers|FlatGL3D::Flag::ObjectId|data.flags, data.materialCount, data.drawCount};
if(data.flags & FlatGL3D::Flag::Textured)
shader.bindTexture(texture);
/* Just one draw, rebinding UBOs each time */
if(data.drawCount == 1) {
shader.bindMaterialBuffer(materialUniform,
1*data.uniformIncrement*sizeof(FlatMaterialUniform),
sizeof(FlatMaterialUniform));
shader.bindTransformationProjectionBuffer(transformationProjectionUniform,
0*data.uniformIncrement*sizeof(TransformationProjectionUniform3D),
sizeof(TransformationProjectionUniform3D));
@ -2643,6 +2763,9 @@ void FlatGLTest::renderMulti3D() {
sizeof(TextureTransformationUniform));
shader.draw(sphere);
shader.bindMaterialBuffer(materialUniform,
0*data.uniformIncrement*sizeof(FlatMaterialUniform),
sizeof(FlatMaterialUniform));
shader.bindTransformationProjectionBuffer(transformationProjectionUniform,
1*data.uniformIncrement*sizeof(TransformationProjectionUniform3D),
sizeof(TransformationProjectionUniform3D));
@ -2655,6 +2778,9 @@ void FlatGLTest::renderMulti3D() {
sizeof(TextureTransformationUniform));
shader.draw(plane);
shader.bindMaterialBuffer(materialUniform,
1*data.uniformIncrement*sizeof(FlatMaterialUniform),
sizeof(FlatMaterialUniform));
shader.bindTransformationProjectionBuffer(transformationProjectionUniform,
2*data.uniformIncrement*sizeof(TransformationProjectionUniform3D),
sizeof(TransformationProjectionUniform3D));
@ -2670,7 +2796,8 @@ void FlatGLTest::renderMulti3D() {
/* Otherwise using the draw offset / multidraw */
} else {
shader.bindTransformationProjectionBuffer(transformationProjectionUniform)
.bindDrawBuffer(drawUniform);
.bindDrawBuffer(drawUniform)
.bindMaterialBuffer(materialUniform);
if(data.flags & FlatGL3D::Flag::TextureTransformation)
shader.bindTextureTransformationBuffer(textureTransformationUniform);

97
src/Magnum/Shaders/Test/FlatTest.cpp

@ -38,14 +38,25 @@ struct FlatTest: TestSuite::Tester {
void drawUniformConstructDefault();
void drawUniformConstructNoInit();
void drawUniformSetters();
void drawUniformMaterialIdPacking();
void materialUniformConstructDefault();
void materialUniformConstructNoInit();
void materialUniformSetters();
};
FlatTest::FlatTest() {
addTests({&FlatTest::uniformSizeAlignment<FlatDrawUniform>,
&FlatTest::uniformSizeAlignment<FlatMaterialUniform>,
&FlatTest::drawUniformConstructDefault,
&FlatTest::drawUniformConstructNoInit,
&FlatTest::drawUniformSetters});
&FlatTest::drawUniformSetters,
&FlatTest::drawUniformMaterialIdPacking,
&FlatTest::materialUniformConstructDefault,
&FlatTest::materialUniformConstructNoInit,
&FlatTest::materialUniformSetters});
}
using namespace Math::Literals;
@ -54,6 +65,9 @@ template<class> struct UniformTraits;
template<> struct UniformTraits<FlatDrawUniform> {
static const char* name() { return "FlatDrawUniform"; }
};
template<> struct UniformTraits<FlatMaterialUniform> {
static const char* name() { return "FlatMaterialUniform"; }
};
template<class T> void FlatTest::uniformSizeAlignment() {
setTestCaseTemplateName(UniformTraits<T>::name());
@ -72,21 +86,17 @@ template<class T> void FlatTest::uniformSizeAlignment() {
void FlatTest::drawUniformConstructDefault() {
FlatDrawUniform a;
FlatDrawUniform b{DefaultInit};
CORRADE_COMPARE(a.color, 0xffffffff_rgbaf);
CORRADE_COMPARE(b.color, 0xffffffff_rgbaf);
CORRADE_COMPARE(a.materialId, 0);
CORRADE_COMPARE(b.materialId, 0);
CORRADE_COMPARE(a.objectId, 0);
CORRADE_COMPARE(b.objectId, 0);
CORRADE_COMPARE(a.alphaMask, 0.5f);
CORRADE_COMPARE(b.alphaMask, 0.5f);
constexpr FlatDrawUniform ca;
constexpr FlatDrawUniform cb{DefaultInit};
CORRADE_COMPARE(ca.color, 0xffffffff_rgbaf);
CORRADE_COMPARE(cb.color, 0xffffffff_rgbaf);
CORRADE_COMPARE(ca.materialId, 0);
CORRADE_COMPARE(cb.materialId, 0);
CORRADE_COMPARE(ca.objectId, 0);
CORRADE_COMPARE(cb.objectId, 0);
CORRADE_COMPARE(ca.alphaMask, 0.5f);
CORRADE_COMPARE(cb.alphaMask, 0.5f);
CORRADE_VERIFY(std::is_nothrow_default_constructible<FlatDrawUniform>::value);
CORRADE_VERIFY(std::is_nothrow_constructible<FlatDrawUniform, DefaultInitT>::value);
@ -98,16 +108,16 @@ void FlatTest::drawUniformConstructDefault() {
void FlatTest::drawUniformConstructNoInit() {
/* Testing only some fields, should be enough */
FlatDrawUniform a;
a.color = 0x354565fc_rgbaf;
a.alphaMask = 0.7f;
a.materialId = 5;
a.objectId = 7;
new(&a) FlatDrawUniform{NoInit};
{
#if defined(__GNUC__) && __GNUC__*100 + __GNUC_MINOR__ >= 601 && __OPTIMIZE__
CORRADE_EXPECT_FAIL("GCC 6.1+ misoptimizes and overwrites the value.");
#endif
CORRADE_COMPARE(a.color, 0x354565fc_rgbaf);
CORRADE_COMPARE(a.alphaMask, 0.7f);
CORRADE_COMPARE(a.materialId, 5);
CORRADE_COMPARE(a.objectId, 7);
}
CORRADE_VERIFY(std::is_nothrow_constructible<FlatDrawUniform, NoInitT>::value);
@ -118,11 +128,68 @@ void FlatTest::drawUniformConstructNoInit() {
void FlatTest::drawUniformSetters() {
FlatDrawUniform a;
a.setMaterialId(5)
.setObjectId(7);
CORRADE_COMPARE(a.materialId, 5);
CORRADE_COMPARE(a.objectId, 7);
}
void FlatTest::drawUniformMaterialIdPacking() {
FlatDrawUniform a;
a.setMaterialId(13765);
/* materialId should be right at the beginning, in the low 16 bits on both
LE and BE */
CORRADE_COMPARE(reinterpret_cast<UnsignedInt*>(&a)[0] & 0xffff, 13765);
}
void FlatTest::materialUniformConstructDefault() {
FlatMaterialUniform a;
FlatMaterialUniform b{DefaultInit};
CORRADE_COMPARE(a.color, 0xffffffff_rgbaf);
CORRADE_COMPARE(b.color, 0xffffffff_rgbaf);
CORRADE_COMPARE(a.alphaMask, 0.5f);
CORRADE_COMPARE(b.alphaMask, 0.5f);
constexpr FlatMaterialUniform ca;
constexpr FlatMaterialUniform cb{DefaultInit};
CORRADE_COMPARE(ca.color, 0xffffffff_rgbaf);
CORRADE_COMPARE(cb.color, 0xffffffff_rgbaf);
CORRADE_COMPARE(ca.alphaMask, 0.5f);
CORRADE_COMPARE(cb.alphaMask, 0.5f);
CORRADE_VERIFY(std::is_nothrow_default_constructible<FlatDrawUniform>::value);
CORRADE_VERIFY(std::is_nothrow_constructible<FlatDrawUniform, DefaultInitT>::value);
/* Implicit construction is not allowed */
CORRADE_VERIFY(!std::is_convertible<DefaultInitT, FlatDrawUniform>::value);
}
void FlatTest::materialUniformConstructNoInit() {
/* Testing only some fields, should be enough */
FlatMaterialUniform a;
a.color = 0x354565fc_rgbaf;
a.alphaMask = 0.7f;
new(&a) FlatMaterialUniform{NoInit};
{
#if defined(__GNUC__) && __GNUC__*100 + __GNUC_MINOR__ >= 601 && __OPTIMIZE__
CORRADE_EXPECT_FAIL("GCC 6.1+ misoptimizes and overwrites the value.");
#endif
CORRADE_COMPARE(a.color, 0x354565fc_rgbaf);
CORRADE_COMPARE(a.alphaMask, 0.7f);
}
CORRADE_VERIFY(std::is_nothrow_constructible<FlatMaterialUniform, NoInitT>::value);
/* Implicit construction is not allowed */
CORRADE_VERIFY(!std::is_convertible<NoInitT, FlatMaterialUniform>::value);
}
void FlatTest::materialUniformSetters() {
FlatMaterialUniform a;
a.setColor(0x354565fc_rgbaf)
.setObjectId(7)
.setAlphaMask(0.7f);
CORRADE_COMPARE(a.color, 0x354565fc_rgbaf);
CORRADE_COMPARE(a.objectId, 7);
CORRADE_COMPARE(a.alphaMask, 0.7f);
}

43
src/Magnum/Shaders/Test/ShadersGLBenchmark.cpp

@ -130,27 +130,27 @@ constexpr std::size_t BenchmarkRepeats{4};
const struct {
const char* name;
FlatGL2D::Flags flags;
UnsignedInt drawCount;
UnsignedInt materialCount, drawCount;
} FlatData[] {
{"", {}, 1},
{"vertex color", FlatGL2D::Flag::VertexColor, 1},
{"", {}, 1, 1},
{"vertex color", FlatGL2D::Flag::VertexColor, 1, 1},
#ifndef MAGNUM_TARGET_GLES2
{"object ID", FlatGL2D::Flag::ObjectId, 1},
{"object ID", FlatGL2D::Flag::ObjectId, 1, 1},
#endif
{"textured", FlatGL2D::Flag::Textured, 1},
{"textured + alpha mask", FlatGL2D::Flag::Textured|FlatGL2D::Flag::AlphaMask, 1},
{"texture transformation", FlatGL2D::Flag::Textured|FlatGL2D::Flag::TextureTransformation, 1},
{"instanced transformation", FlatGL2D::Flag::InstancedTransformation, 1},
{"instanced transformation + color", FlatGL2D::Flag::InstancedTransformation|FlatGL2D::Flag::VertexColor, 1},
{"textured", FlatGL2D::Flag::Textured, 1, 1},
{"textured + alpha mask", FlatGL2D::Flag::Textured|FlatGL2D::Flag::AlphaMask, 1, 1},
{"texture transformation", FlatGL2D::Flag::Textured|FlatGL2D::Flag::TextureTransformation, 1, 1},
{"instanced transformation", FlatGL2D::Flag::InstancedTransformation, 1, 1},
{"instanced transformation + color", FlatGL2D::Flag::InstancedTransformation|FlatGL2D::Flag::VertexColor, 1, 1},
#ifndef MAGNUM_TARGET_GLES2
{"instanced transformation + object ID", FlatGL2D::Flag::InstancedTransformation|FlatGL2D::Flag::InstancedObjectId, 1},
{"instanced transformation + object ID", FlatGL2D::Flag::InstancedTransformation|FlatGL2D::Flag::InstancedObjectId, 1, 1},
#endif
{"instanced transformation + texture offset", FlatGL2D::Flag::Textured|FlatGL2D::Flag::InstancedTransformation|FlatGL2D::Flag::InstancedTextureOffset, 1},
{"instanced transformation + texture offset", FlatGL2D::Flag::Textured|FlatGL2D::Flag::InstancedTransformation|FlatGL2D::Flag::InstancedTextureOffset, 1, 1},
#ifndef MAGNUM_TARGET_GLES2
{"UBO single", FlatGL2D::Flag::UniformBuffers, 1},
{"UBO single, texture transformation", FlatGL2D::Flag::UniformBuffers|FlatGL2D::Flag::Textured|FlatGL2D::Flag::TextureTransformation, 1},
{"UBO multi", FlatGL2D::Flag::UniformBuffers, 128},
{"multidraw", FlatGL2D::Flag::MultiDraw, 128},
{"UBO single", FlatGL2D::Flag::UniformBuffers, 1, 1},
{"UBO single, texture transformation", FlatGL2D::Flag::UniformBuffers|FlatGL2D::Flag::Textured|FlatGL2D::Flag::TextureTransformation, 1, 1},
{"UBO multi", FlatGL2D::Flag::UniformBuffers, 32, 128},
{"multidraw", FlatGL2D::Flag::MultiDraw, 32, 128},
#endif
};
@ -541,7 +541,7 @@ template<UnsignedInt dimensions> void ShadersGLBenchmark::flat() {
FlatGL<dimensions> shader{data.flags
#ifndef MAGNUM_TARGET_GLES2
, data.drawCount
, data.materialCount, data.drawCount
#endif
};
@ -549,13 +549,16 @@ template<UnsignedInt dimensions> void ShadersGLBenchmark::flat() {
GL::Buffer transformationProjectionUniform{NoCreate};
GL::Buffer drawUniform{NoCreate};
GL::Buffer textureTransformationUniform{NoCreate};
GL::Buffer materialUniform{NoCreate};
if(data.flags & FlatGL2D::Flag::UniformBuffers) {
transformationProjectionUniform = GL::Buffer{GL::Buffer::TargetHint::Uniform, Containers::Array<typename UniformTraits<dimensions>::TransformationProjection>{data.drawCount}};
Containers::Array<FlatDrawUniform> drawData{data.drawCount};
drawData[0].setAlphaMask(0.0f);
drawUniform = GL::Buffer{GL::Buffer::TargetHint::Uniform, drawData};
drawUniform = GL::Buffer{GL::Buffer::TargetHint::Uniform, Containers::Array<FlatDrawUniform>{data.drawCount}};
Containers::Array<FlatMaterialUniform> materialData{data.materialCount};
materialData[0].setAlphaMask(0.0f);
materialUniform = GL::Buffer{GL::Buffer::TargetHint::Uniform, materialData};
shader.bindTransformationProjectionBuffer(transformationProjectionUniform)
.bindDrawBuffer(drawUniform);
.bindDrawBuffer(drawUniform)
.bindMaterialBuffer(materialUniform);
if(data.flags & FlatGL2D::Flag::TextureTransformation) {
textureTransformationUniform = GL::Buffer{GL::Buffer::TargetHint::Uniform, Containers::Array<TextureTransformationUniform>{data.drawCount}};
shader.bindTextureTransformationBuffer(textureTransformationUniform);

Loading…
Cancel
Save