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

182
src/Magnum/Shaders/Flat.h

@ -26,7 +26,7 @@
*/ */
/** @file /** @file
* @brief Struct @ref Magnum::Shaders::FlatDrawUniform * @brief Struct @ref Magnum::Shaders::FlatDrawUniform, @ref Magnum::Shaders::FlatMaterialUniform
*/ */
#include "Magnum/Magnum.h" #include "Magnum/Magnum.h"
@ -47,24 +47,29 @@ namespace Magnum { namespace Shaders {
Together with the generic @ref TransformationProjectionUniform2D / Together with the generic @ref TransformationProjectionUniform2D /
@ref TransformationProjectionUniform3D contains parameters that are specific to @ref TransformationProjectionUniform3D contains parameters that are specific to
each draw call. Texture transformation, if needed, is supplied separately in a 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() @see @ref FlatGL::bindDrawBuffer()
*/ */
struct FlatDrawUniform { struct FlatDrawUniform {
/** @brief Construct with default parameters */ /** @brief Construct with default parameters */
constexpr explicit FlatDrawUniform(DefaultInitT = DefaultInit) noexcept: color{1.0f, 1.0f, 1.0f, 1.0f}, objectId{0}, constexpr explicit FlatDrawUniform(DefaultInitT = DefaultInit) noexcept:
#if (defined(CORRADE_TARGET_CLANG) && __clang_major__ < 4) || (defined(CORRADE_TARGET_APPLE_CLANG) && __clang_major__ < 8) #if ((defined(CORRADE_TARGET_CLANG) && __clang_major__ < 4) || (defined(CORRADE_TARGET_APPLE_CLANG) && __clang_major__ < 8)) && defined(CORRADE_TARGET_BIG_ENDIAN)
/* Otherwise it refuses to constexpr, on 3.8 at least */ _pad0{}, /* Otherwise it refuses to constexpr, on 3.8 at least */
_pad0{}, _pad1{}, #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 #endif
alphaMask{0.5f} objectId{0}
#if (defined(CORRADE_TARGET_CLANG) && __clang_major__ < 4) || (defined(CORRADE_TARGET_APPLE_CLANG) && __clang_major__ < 8) #if (defined(CORRADE_TARGET_CLANG) && __clang_major__ < 4) || (defined(CORRADE_TARGET_APPLE_CLANG) && __clang_major__ < 8)
, _pad2{} , _pad1{}, _pad2{}
#endif #endif
{} {}
/** @brief Construct without initializing the contents */ /** @brief Construct without initializing the contents */
explicit FlatDrawUniform(NoInitT) noexcept: color{NoInit} {} explicit FlatDrawUniform(NoInitT) noexcept {}
/** @{ /** @{
* @name Convenience setters * @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) * @return Reference to self (for method chaining)
*/ */
FlatDrawUniform& setObjectId(UnsignedInt id) { FlatDrawUniform& setMaterialId(UnsignedInt id) {
objectId = id; materialId = id;
return *this; return *this;
} }
/** /**
* @brief Set the @ref alphaMask field * @brief Set the @ref objectId field
* @return Reference to self (for method chaining)
*/
FlatDrawUniform& setAlphaMask(Float alphaMask) {
this->alphaMask = alphaMask;
return *this;
}
/**
* @brief Set the @ref color field
* @return Reference to self (for method chaining) * @return Reference to self (for method chaining)
*/ */
FlatDrawUniform& setColor(const Color4& color) { FlatDrawUniform& setObjectId(UnsignedInt id) {
this->color = color; objectId = id;
return *this; return *this;
} }
@ -106,17 +102,37 @@ struct FlatDrawUniform {
* @} * @}
*/ */
/** /** @var materialId
* @brief Color * @brief Material ID
*
* Default value is @cpp 0xffffffff_rgbaf @ce.
* *
* If @ref FlatGL::Flag::VertexColor is enabled, the color is multiplied * References a particular material from a @ref FlatMaterialUniform array.
* with a color coming from the @ref FlatGL::Color3 / @ref FlatGL::Color4 * Useful when an UBO with more than one material is supplied or in a
* attribute. * multi-draw scenario. Should be less than the material count passed to
* @see @ref FlatGL::setColor() * 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 * @brief Object ID
@ -131,35 +147,83 @@ struct FlatDrawUniform {
*/ */
UnsignedInt objectId; 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 */ I MADE THOSE UNNAMED, YOU DUMB FOOL */
#ifndef DOXYGEN_GENERATING_OUTPUT #ifndef DOXYGEN_GENERATING_OUTPUT
/* This field is an UnsignedInt in the shader and skinOffset is extracted Int
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
#if (defined(CORRADE_TARGET_CLANG) && __clang_major__ < 4) || (defined(CORRADE_TARGET_APPLE_CLANG) && __clang_major__ < 8) #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 */ _pad1 /* Otherwise it refuses to constexpr, on 3.8 at least */
#endif #endif
:16; /* reserved for skinOffset */ :32;
#else Int
UnsignedShort
#if (defined(CORRADE_TARGET_CLANG) && __clang_major__ < 4) || (defined(CORRADE_TARGET_APPLE_CLANG) && __clang_major__ < 8) #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 #endif
:16; /* reserved for skinOffset */ :32;
UnsignedShort #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) #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 #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 * @brief Alpha mask value
@ -172,9 +236,19 @@ struct FlatDrawUniform {
*/ */
Float alphaMask; 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 */ I MADE THOSE UNNAMED, YOU DUMB FOOL */
#ifndef DOXYGEN_GENERATING_OUTPUT #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 Int
#if (defined(CORRADE_TARGET_CLANG) && __clang_major__ < 4) || (defined(CORRADE_TARGET_APPLE_CLANG) && __clang_major__ < 8) #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 */ _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 */ bound to the same buffer for the whole time */
TransformationProjectionBufferBinding = 1, TransformationProjectionBufferBinding = 1,
DrawBufferBinding = 2, DrawBufferBinding = 2,
TextureTransformationBufferBinding = 3 TextureTransformationBufferBinding = 3,
MaterialBufferBinding = 4
}; };
#endif #endif
} }
template<UnsignedInt dimensions> FlatGL<dimensions>::FlatGL(const Flags flags template<UnsignedInt dimensions> FlatGL<dimensions>::FlatGL(const Flags flags
#ifndef MAGNUM_TARGET_GLES2 #ifndef MAGNUM_TARGET_GLES2
, const UnsignedInt drawCount , const UnsignedInt materialCount, const UnsignedInt drawCount
#endif #endif
): ):
_flags{flags} _flags{flags}
#ifndef MAGNUM_TARGET_GLES2 #ifndef MAGNUM_TARGET_GLES2
, _drawCount{drawCount} , _materialCount{materialCount}, _drawCount{drawCount}
#endif #endif
{ {
CORRADE_ASSERT(!(flags & Flag::TextureTransformation) || (flags & Flag::Textured), CORRADE_ASSERT(!(flags & Flag::TextureTransformation) || (flags & Flag::Textured),
"Shaders::FlatGL: texture transformation enabled but the shader is not textured", ); "Shaders::FlatGL: texture transformation enabled but the shader is not textured", );
#ifndef MAGNUM_TARGET_GLES2 #ifndef MAGNUM_TARGET_GLES2
CORRADE_ASSERT(!(flags >= Flag::UniformBuffers) || materialCount,
"Shaders::FlatGL: material count can't be zero", );
CORRADE_ASSERT(!(flags >= Flag::UniformBuffers) || drawCount, CORRADE_ASSERT(!(flags >= Flag::UniformBuffers) || drawCount,
"Shaders::FlatGL: draw count can't be zero", ); "Shaders::FlatGL: draw count can't be zero", );
#endif #endif
@ -146,8 +149,10 @@ template<UnsignedInt dimensions> FlatGL<dimensions>::FlatGL(const Flags flags
if(flags >= Flag::UniformBuffers) { if(flags >= Flag::UniformBuffers) {
frag.addSource(Utility::formatString( frag.addSource(Utility::formatString(
"#define UNIFORM_BUFFERS\n" "#define UNIFORM_BUFFERS\n"
"#define DRAW_COUNT {}\n", "#define DRAW_COUNT {}\n"
drawCount)); "#define MATERIAL_COUNT {}\n",
drawCount,
materialCount));
frag.addSource(flags >= Flag::MultiDraw ? "#define MULTI_DRAW\n" : ""); frag.addSource(flags >= Flag::MultiDraw ? "#define MULTI_DRAW\n" : "");
} }
#endif #endif
@ -219,6 +224,7 @@ template<UnsignedInt dimensions> FlatGL<dimensions>::FlatGL(const Flags flags
setUniformBlockBinding(uniformBlockIndex("Draw"), DrawBufferBinding); setUniformBlockBinding(uniformBlockIndex("Draw"), DrawBufferBinding);
if(flags & Flag::TextureTransformation) if(flags & Flag::TextureTransformation)
setUniformBlockBinding(uniformBlockIndex("TextureTransformation"), TextureTransformationBufferBinding); setUniformBlockBinding(uniformBlockIndex("TextureTransformation"), TextureTransformationBufferBinding);
setUniformBlockBinding(uniformBlockIndex("Material"), MaterialBufferBinding);
} }
#endif #endif
} }
@ -242,7 +248,7 @@ template<UnsignedInt dimensions> FlatGL<dimensions>::FlatGL(const Flags flags
} }
#ifndef MAGNUM_TARGET_GLES2 #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 #endif
template<UnsignedInt dimensions> FlatGL<dimensions>& FlatGL<dimensions>::setTransformationProjectionMatrix(const MatrixTypeFor<dimensions, Float>& matrix) { 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); buffer.bind(GL::Buffer::Target::Uniform, TextureTransformationBufferBinding, offset, size);
return *this; 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 #endif
template<UnsignedInt dimensions> FlatGL<dimensions>& FlatGL<dimensions>::bindTexture(GL::Texture2D& texture) { 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 * Use uniform buffers. Expects that uniform data are supplied via
* @ref bindTransformationProjectionBuffer(), * @ref bindTransformationProjectionBuffer(),
* @ref bindDrawBuffer() and @ref bindTextureTransformationBuffer() * @ref bindDrawBuffer(), @ref bindTextureTransformationBuffer()
* instead of direct uniform setters. * and @ref bindMaterialBuffer() instead of direct uniform setters.
* @requires_gl31 Extension @gl_extension{ARB,uniform_buffer_object} * @requires_gl31 Extension @gl_extension{ARB,uniform_buffer_object}
* @requires_gles30 Uniform buffers are not available in OpenGL ES * @requires_gles30 Uniform buffers are not available in OpenGL ES
* 2.0. * 2.0.
@ -437,32 +437,44 @@ template<UnsignedInt dimensions> class MAGNUM_SHADERS_EXPORT FlatGL: public GL::
* *
* While this function is meant mainly for the classic uniform * While this function is meant mainly for the classic uniform
* scenario (without @ref Flag::UniformBuffers set), it's equivalent to * 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 = {}); explicit FlatGL(Flags flags = {});
#ifndef MAGNUM_TARGET_GLES2 #ifndef MAGNUM_TARGET_GLES2
/** /**
* @brief Construct for a multi-draw scenario * @brief Construct for a multi-draw scenario
* @param flags Flags * @param flags Flags
* @param drawCount Size of a @ref TransformationProjectionUniform2D / * @param materialCount Size of a @ref FlatMaterialUniform buffer
* @ref TransformationProjectionUniform3D / @ref FlatDrawUniform / * bound with @ref bindMaterialBuffer()
* @ref TextureTransformationUniform buffer bound with * @param drawCount Size of a @ref TransformationProjectionUniform2D
* / @ref TransformationProjectionUniform3D / @ref FlatDrawUniform
* / @ref TextureTransformationUniform buffer bound with
* @ref bindTransformationProjectionBuffer(), @ref bindDrawBuffer() * @ref bindTransformationProjectionBuffer(), @ref bindDrawBuffer()
* and @ref bindTextureTransformationBuffer() * and @ref bindTextureTransformationBuffer()
* *
* If @p flags contains @ref Flag::UniformBuffers, @p drawCount * If @p flags contains @ref Flag::UniformBuffers, @p materialCount and
* describes the uniform buffer sizes as these are required to have a * @p drawCount describe the uniform buffer sizes as these are required
* statically defined size. The draw offset is then set via * to have a statically defined size. The draw offset is then set via
* @ref setDrawOffset(). * @ref setDrawOffset() and the per-draw materials specified via
* @ref FlatDrawUniform::materialId.
* *
* If @p flags don't contain @ref Flag::UniformBuffers, @p drawCount is * If @p flags don't contain @ref Flag::UniformBuffers,
* ignored and the constructor behaves the same as @ref FlatGL(Flags). * @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_gl31 Extension @gl_extension{ARB,uniform_buffer_object}
* @requires_gles30 Uniform buffers are not available in OpenGL ES 2.0. * @requires_gles30 Uniform buffers are not available in OpenGL ES 2.0.
* @requires_webgl20 Uniform buffers are not available in WebGL 1.0. * @requires_webgl20 Uniform buffers are not available in WebGL 1.0.
*/ */
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 #endif
/** /**
@ -495,6 +507,18 @@ template<UnsignedInt dimensions> class MAGNUM_SHADERS_EXPORT FlatGL: public GL::
Flags flags() const { return _flags; } Flags flags() const { return _flags; }
#ifndef MAGNUM_TARGET_GLES2 #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 * @brief Draw count
* @m_since_latest * @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. * coming from the @ref Color3 / @ref Color4 attribute.
* *
* Expects that @ref Flag::UniformBuffers is not set, in that case fill * 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() * @see @ref bindTexture()
*/ */
FlatGL<dimensions>& setColor(const Magnum::Color4& color); FlatGL<dimensions>& setColor(const Magnum::Color4& color);
@ -578,8 +603,8 @@ template<UnsignedInt dimensions> class MAGNUM_SHADERS_EXPORT FlatGL: public GL::
* in classic OpenGL. * in classic OpenGL.
* *
* Expects that @ref Flag::UniformBuffers is not set, in that case fill * Expects that @ref Flag::UniformBuffers is not set, in that case fill
* @ref FlatDrawUniform::alphaMask and call @ref bindDrawBuffer() * @ref FlatMaterialUniform::alphaMask and call
* instead. * @ref bindMaterialBuffer() instead.
* @m_keywords{glAlphaFunc()} * @m_keywords{glAlphaFunc()}
*/ */
FlatGL<dimensions>& setAlphaMask(Float mask); 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 * expected to contain @ref drawCount() instances of
* @ref TransformationProjectionUniform2D / * @ref TransformationProjectionUniform2D /
* @ref TransformationProjectionUniform3D. At the very least you need * @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_gl31 Extension @gl_extension{ARB,uniform_buffer_object}
* @requires_gles30 Uniform buffers are not available in OpenGL ES 2.0. * @requires_gles30 Uniform buffers are not available in OpenGL ES 2.0.
* @requires_webgl20 Uniform buffers are not available in WebGL 1.0. * @requires_webgl20 Uniform buffers are not available in WebGL 1.0.
@ -668,7 +693,8 @@ template<UnsignedInt dimensions> class MAGNUM_SHADERS_EXPORT FlatGL: public GL::
* Expects that @ref Flag::UniformBuffers is set. The buffer is * Expects that @ref Flag::UniformBuffers is set. The buffer is
* expected to contain @ref drawCount() instances of * expected to contain @ref drawCount() instances of
* @ref FlatDrawUniform. At the very least you need to call also * @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_gl31 Extension @gl_extension{ARB,uniform_buffer_object}
* @requires_gles30 Uniform buffers are not available in OpenGL ES 2.0. * @requires_gles30 Uniform buffers are not available in OpenGL ES 2.0.
* @requires_webgl20 Uniform buffers are not available in WebGL 1.0. * @requires_webgl20 Uniform buffers are not available in WebGL 1.0.
@ -700,6 +726,26 @@ template<UnsignedInt dimensions> class MAGNUM_SHADERS_EXPORT FlatGL: public GL::
*/ */
FlatGL<dimensions>& bindTextureTransformationBuffer(GL::Buffer& buffer, GLintptr offset, GLsizeiptr size); FlatGL<dimensions>& bindTextureTransformationBuffer(GL::Buffer& buffer, GLintptr offset, GLsizeiptr size);
/**
* @brief 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; Flags _flags;
#ifndef MAGNUM_TARGET_GLES2 #ifndef MAGNUM_TARGET_GLES2
UnsignedInt _drawCount{}; UnsignedInt _materialCount{}, _drawCount{};
#endif #endif
Int _transformationProjectionMatrixUniform{0}, Int _transformationProjectionMatrixUniform{0},
_textureMatrixUniform{1}, _textureMatrixUniform{1},

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

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

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

@ -38,14 +38,25 @@ struct FlatTest: TestSuite::Tester {
void drawUniformConstructDefault(); void drawUniformConstructDefault();
void drawUniformConstructNoInit(); void drawUniformConstructNoInit();
void drawUniformSetters(); void drawUniformSetters();
void drawUniformMaterialIdPacking();
void materialUniformConstructDefault();
void materialUniformConstructNoInit();
void materialUniformSetters();
}; };
FlatTest::FlatTest() { FlatTest::FlatTest() {
addTests({&FlatTest::uniformSizeAlignment<FlatDrawUniform>, addTests({&FlatTest::uniformSizeAlignment<FlatDrawUniform>,
&FlatTest::uniformSizeAlignment<FlatMaterialUniform>,
&FlatTest::drawUniformConstructDefault, &FlatTest::drawUniformConstructDefault,
&FlatTest::drawUniformConstructNoInit, &FlatTest::drawUniformConstructNoInit,
&FlatTest::drawUniformSetters}); &FlatTest::drawUniformSetters,
&FlatTest::drawUniformMaterialIdPacking,
&FlatTest::materialUniformConstructDefault,
&FlatTest::materialUniformConstructNoInit,
&FlatTest::materialUniformSetters});
} }
using namespace Math::Literals; using namespace Math::Literals;
@ -54,6 +65,9 @@ template<class> struct UniformTraits;
template<> struct UniformTraits<FlatDrawUniform> { template<> struct UniformTraits<FlatDrawUniform> {
static const char* name() { return "FlatDrawUniform"; } static const char* name() { return "FlatDrawUniform"; }
}; };
template<> struct UniformTraits<FlatMaterialUniform> {
static const char* name() { return "FlatMaterialUniform"; }
};
template<class T> void FlatTest::uniformSizeAlignment() { template<class T> void FlatTest::uniformSizeAlignment() {
setTestCaseTemplateName(UniformTraits<T>::name()); setTestCaseTemplateName(UniformTraits<T>::name());
@ -72,21 +86,17 @@ template<class T> void FlatTest::uniformSizeAlignment() {
void FlatTest::drawUniformConstructDefault() { void FlatTest::drawUniformConstructDefault() {
FlatDrawUniform a; FlatDrawUniform a;
FlatDrawUniform b{DefaultInit}; FlatDrawUniform b{DefaultInit};
CORRADE_COMPARE(a.color, 0xffffffff_rgbaf); CORRADE_COMPARE(a.materialId, 0);
CORRADE_COMPARE(b.color, 0xffffffff_rgbaf); CORRADE_COMPARE(b.materialId, 0);
CORRADE_COMPARE(a.objectId, 0); CORRADE_COMPARE(a.objectId, 0);
CORRADE_COMPARE(b.objectId, 0); CORRADE_COMPARE(b.objectId, 0);
CORRADE_COMPARE(a.alphaMask, 0.5f);
CORRADE_COMPARE(b.alphaMask, 0.5f);
constexpr FlatDrawUniform ca; constexpr FlatDrawUniform ca;
constexpr FlatDrawUniform cb{DefaultInit}; constexpr FlatDrawUniform cb{DefaultInit};
CORRADE_COMPARE(ca.color, 0xffffffff_rgbaf); CORRADE_COMPARE(ca.materialId, 0);
CORRADE_COMPARE(cb.color, 0xffffffff_rgbaf); CORRADE_COMPARE(cb.materialId, 0);
CORRADE_COMPARE(ca.objectId, 0); CORRADE_COMPARE(ca.objectId, 0);
CORRADE_COMPARE(cb.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_default_constructible<FlatDrawUniform>::value);
CORRADE_VERIFY(std::is_nothrow_constructible<FlatDrawUniform, DefaultInitT>::value); CORRADE_VERIFY(std::is_nothrow_constructible<FlatDrawUniform, DefaultInitT>::value);
@ -98,16 +108,16 @@ void FlatTest::drawUniformConstructDefault() {
void FlatTest::drawUniformConstructNoInit() { void FlatTest::drawUniformConstructNoInit() {
/* Testing only some fields, should be enough */ /* Testing only some fields, should be enough */
FlatDrawUniform a; FlatDrawUniform a;
a.color = 0x354565fc_rgbaf; a.materialId = 5;
a.alphaMask = 0.7f; a.objectId = 7;
new(&a) FlatDrawUniform{NoInit}; new(&a) FlatDrawUniform{NoInit};
{ {
#if defined(__GNUC__) && __GNUC__*100 + __GNUC_MINOR__ >= 601 && __OPTIMIZE__ #if defined(__GNUC__) && __GNUC__*100 + __GNUC_MINOR__ >= 601 && __OPTIMIZE__
CORRADE_EXPECT_FAIL("GCC 6.1+ misoptimizes and overwrites the value."); CORRADE_EXPECT_FAIL("GCC 6.1+ misoptimizes and overwrites the value.");
#endif #endif
CORRADE_COMPARE(a.color, 0x354565fc_rgbaf); CORRADE_COMPARE(a.materialId, 5);
CORRADE_COMPARE(a.alphaMask, 0.7f); CORRADE_COMPARE(a.objectId, 7);
} }
CORRADE_VERIFY(std::is_nothrow_constructible<FlatDrawUniform, NoInitT>::value); CORRADE_VERIFY(std::is_nothrow_constructible<FlatDrawUniform, NoInitT>::value);
@ -118,11 +128,68 @@ void FlatTest::drawUniformConstructNoInit() {
void FlatTest::drawUniformSetters() { void FlatTest::drawUniformSetters() {
FlatDrawUniform a; 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) a.setColor(0x354565fc_rgbaf)
.setObjectId(7)
.setAlphaMask(0.7f); .setAlphaMask(0.7f);
CORRADE_COMPARE(a.color, 0x354565fc_rgbaf); CORRADE_COMPARE(a.color, 0x354565fc_rgbaf);
CORRADE_COMPARE(a.objectId, 7);
CORRADE_COMPARE(a.alphaMask, 0.7f); 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 struct {
const char* name; const char* name;
FlatGL2D::Flags flags; FlatGL2D::Flags flags;
UnsignedInt drawCount; UnsignedInt materialCount, drawCount;
} FlatData[] { } FlatData[] {
{"", {}, 1}, {"", {}, 1, 1},
{"vertex color", FlatGL2D::Flag::VertexColor, 1}, {"vertex color", FlatGL2D::Flag::VertexColor, 1, 1},
#ifndef MAGNUM_TARGET_GLES2 #ifndef MAGNUM_TARGET_GLES2
{"object ID", FlatGL2D::Flag::ObjectId, 1}, {"object ID", FlatGL2D::Flag::ObjectId, 1, 1},
#endif #endif
{"textured", FlatGL2D::Flag::Textured, 1}, {"textured", FlatGL2D::Flag::Textured, 1, 1},
{"textured + alpha mask", FlatGL2D::Flag::Textured|FlatGL2D::Flag::AlphaMask, 1}, {"textured + alpha mask", FlatGL2D::Flag::Textured|FlatGL2D::Flag::AlphaMask, 1, 1},
{"texture transformation", FlatGL2D::Flag::Textured|FlatGL2D::Flag::TextureTransformation, 1}, {"texture transformation", FlatGL2D::Flag::Textured|FlatGL2D::Flag::TextureTransformation, 1, 1},
{"instanced transformation", FlatGL2D::Flag::InstancedTransformation, 1}, {"instanced transformation", FlatGL2D::Flag::InstancedTransformation, 1, 1},
{"instanced transformation + color", FlatGL2D::Flag::InstancedTransformation|FlatGL2D::Flag::VertexColor, 1}, {"instanced transformation + color", FlatGL2D::Flag::InstancedTransformation|FlatGL2D::Flag::VertexColor, 1, 1},
#ifndef MAGNUM_TARGET_GLES2 #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 #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 #ifndef MAGNUM_TARGET_GLES2
{"UBO single", FlatGL2D::Flag::UniformBuffers, 1}, {"UBO single", FlatGL2D::Flag::UniformBuffers, 1, 1},
{"UBO single, texture transformation", FlatGL2D::Flag::UniformBuffers|FlatGL2D::Flag::Textured|FlatGL2D::Flag::TextureTransformation, 1}, {"UBO single, texture transformation", FlatGL2D::Flag::UniformBuffers|FlatGL2D::Flag::Textured|FlatGL2D::Flag::TextureTransformation, 1, 1},
{"UBO multi", FlatGL2D::Flag::UniformBuffers, 128}, {"UBO multi", FlatGL2D::Flag::UniformBuffers, 32, 128},
{"multidraw", FlatGL2D::Flag::MultiDraw, 128}, {"multidraw", FlatGL2D::Flag::MultiDraw, 32, 128},
#endif #endif
}; };
@ -541,7 +541,7 @@ template<UnsignedInt dimensions> void ShadersGLBenchmark::flat() {
FlatGL<dimensions> shader{data.flags FlatGL<dimensions> shader{data.flags
#ifndef MAGNUM_TARGET_GLES2 #ifndef MAGNUM_TARGET_GLES2
, data.drawCount , data.materialCount, data.drawCount
#endif #endif
}; };
@ -549,13 +549,16 @@ template<UnsignedInt dimensions> void ShadersGLBenchmark::flat() {
GL::Buffer transformationProjectionUniform{NoCreate}; GL::Buffer transformationProjectionUniform{NoCreate};
GL::Buffer drawUniform{NoCreate}; GL::Buffer drawUniform{NoCreate};
GL::Buffer textureTransformationUniform{NoCreate}; GL::Buffer textureTransformationUniform{NoCreate};
GL::Buffer materialUniform{NoCreate};
if(data.flags & FlatGL2D::Flag::UniformBuffers) { if(data.flags & FlatGL2D::Flag::UniformBuffers) {
transformationProjectionUniform = GL::Buffer{GL::Buffer::TargetHint::Uniform, Containers::Array<typename UniformTraits<dimensions>::TransformationProjection>{data.drawCount}}; transformationProjectionUniform = GL::Buffer{GL::Buffer::TargetHint::Uniform, Containers::Array<typename UniformTraits<dimensions>::TransformationProjection>{data.drawCount}};
Containers::Array<FlatDrawUniform> drawData{data.drawCount}; drawUniform = GL::Buffer{GL::Buffer::TargetHint::Uniform, Containers::Array<FlatDrawUniform>{data.drawCount}};
drawData[0].setAlphaMask(0.0f); Containers::Array<FlatMaterialUniform> materialData{data.materialCount};
drawUniform = GL::Buffer{GL::Buffer::TargetHint::Uniform, drawData}; materialData[0].setAlphaMask(0.0f);
materialUniform = GL::Buffer{GL::Buffer::TargetHint::Uniform, materialData};
shader.bindTransformationProjectionBuffer(transformationProjectionUniform) shader.bindTransformationProjectionBuffer(transformationProjectionUniform)
.bindDrawBuffer(drawUniform); .bindDrawBuffer(drawUniform)
.bindMaterialBuffer(materialUniform);
if(data.flags & FlatGL2D::Flag::TextureTransformation) { if(data.flags & FlatGL2D::Flag::TextureTransformation) {
textureTransformationUniform = GL::Buffer{GL::Buffer::TargetHint::Uniform, Containers::Array<TextureTransformationUniform>{data.drawCount}}; textureTransformationUniform = GL::Buffer{GL::Buffer::TargetHint::Uniform, Containers::Array<TextureTransformationUniform>{data.drawCount}};
shader.bindTextureTransformationBuffer(textureTransformationUniform); shader.bindTextureTransformationBuffer(textureTransformationUniform);

Loading…
Cancel
Save