Browse Source

Shaders: decouple light array size and per-draw light count.

So it's possible to have light culling enabled on, say, 64 lights, but
with only at most 3 applied each draw, allowing the shader compiler to
unroll the loop if it makes sense. This also better prepares for SSBO
support where the total light count would be unbounded and thus the
value ignored, and thus the value can be 0.
pull/617/head
Vladimír Vondruš 3 years ago
parent
commit
fdd9d798b3
  1. 18
      src/Magnum/Shaders/Phong.frag
  2. 53
      src/Magnum/Shaders/PhongGL.cpp
  3. 141
      src/Magnum/Shaders/PhongGL.h
  4. 278
      src/Magnum/Shaders/Test/PhongGLTest.cpp
  5. 34
      src/Magnum/Shaders/Test/PhongGL_Test.cpp

18
src/Magnum/Shaders/Phong.frag

@ -53,7 +53,7 @@ uniform lowp vec4 ambientColor
#endif
;
#if LIGHT_COUNT
#if PER_DRAW_LIGHT_COUNT
#ifdef EXPLICIT_UNIFORM_LOCATION
layout(location = 6)
#endif
@ -252,7 +252,7 @@ uniform lowp
ambientTexture;
#endif
#if LIGHT_COUNT
#if PER_DRAW_LIGHT_COUNT
#ifdef DIFFUSE_TEXTURE
#ifdef EXPLICIT_BINDING
layout(binding = 1)
@ -308,7 +308,7 @@ uniform lowp
/* Inputs */
#if LIGHT_COUNT
#if PER_DRAW_LIGHT_COUNT
in mediump vec3 transformedNormal;
#ifdef NORMAL_TEXTURE
#ifndef BITANGENT
@ -370,7 +370,7 @@ void main() {
#define materialId 0u
#endif
lowp const vec4 ambientColor = materials[materialId].ambientColor;
#if LIGHT_COUNT
#if PER_DRAW_LIGHT_COUNT
lowp const vec4 diffuseColor = materials[materialId].diffuseColor;
lowp const vec4 specularColor = materials[materialId].specularColor;
mediump const float shininess = materials[materialId].material_shininess;
@ -381,7 +381,7 @@ void main() {
#ifdef ALPHA_MASK
lowp const float alphaMask = materials[materialId].material_alphaMask;
#endif
#if LIGHT_COUNT
#if PER_DRAW_LIGHT_COUNT
mediump const uint lightOffset = draws[drawId].draw_lightOffsetLightCount & 0xffffu;
#ifdef LIGHT_CULLING
mediump const uint lightCount = draws[drawId].draw_lightOffsetLightCount >> 16 & 0xffffu;
@ -397,7 +397,7 @@ void main() {
interpolatedVertexColor*
#endif
ambientColor;
#if LIGHT_COUNT
#if PER_DRAW_LIGHT_COUNT
lowp const vec4 finalDiffuseColor =
#ifdef DIFFUSE_TEXTURE
texture(diffuseTexture, interpolatedTextureCoordinates)*
@ -418,7 +418,7 @@ void main() {
/* Ambient color */
fragmentColor = finalAmbientColor;
#if LIGHT_COUNT
#if PER_DRAW_LIGHT_COUNT
/* Normal */
mediump vec3 normalizedTransformedNormal = normalize(transformedNormal);
#ifdef NORMAL_TEXTURE
@ -445,9 +445,9 @@ void main() {
/* Add diffuse color for each light */
#ifndef LIGHT_CULLING
for(int i = 0; i < LIGHT_COUNT; ++i)
for(int i = 0; i < PER_DRAW_LIGHT_COUNT; ++i)
#else
for(uint i = 0u, actualLightCount = min(uint(LIGHT_COUNT), lightCount); i < actualLightCount; ++i)
for(uint i = 0u, actualLightCount = min(uint(PER_DRAW_LIGHT_COUNT), lightCount); i < actualLightCount; ++i)
#endif
{
lowp const vec3 lightColor =

53
src/Magnum/Shaders/PhongGL.cpp

@ -170,6 +170,7 @@ PhongGL::CompileState PhongGL::compile(const Configuration& configuration) {
PhongGL out{NoInit};
out._flags = configuration.flags();
out._lightCount = configuration.lightCount();
out._perDrawLightCount = configuration.perDrawLightCount();
#ifndef MAGNUM_TARGET_GLES2
out._jointCount = configuration.jointCount();
out._perVertexJointCount = configuration.perVertexJointCount();
@ -215,7 +216,7 @@ PhongGL::CompileState PhongGL::compile(const Configuration& configuration) {
#ifndef MAGNUM_TARGET_GLES2
.addSource(configuration.flags() & Flag::TextureArrays ? "#define TEXTURE_ARRAYS\n"_s : ""_s)
#endif
.addSource(configuration.lightCount() ? "#define HAS_LIGHTS\n"_s : ""_s)
.addSource(configuration.perDrawLightCount() ? "#define HAS_LIGHTS\n"_s : ""_s)
#ifndef MAGNUM_TARGET_GLES2
.addSource(configuration.flags() >= Flag::InstancedObjectId ? "#define INSTANCED_OBJECT_ID\n"_s : ""_s)
#endif
@ -286,10 +287,12 @@ PhongGL::CompileState PhongGL::compile(const Configuration& configuration) {
"#define UNIFORM_BUFFERS\n"
"#define DRAW_COUNT {}\n"
"#define MATERIAL_COUNT {}\n"
"#define LIGHT_COUNT {}\n",
"#define LIGHT_COUNT {}\n"
"#define PER_DRAW_LIGHT_COUNT {}\n",
configuration.drawCount(),
configuration.materialCount(),
configuration.lightCount()));
configuration.lightCount(),
configuration.perDrawLightCount()));
frag.addSource(configuration.flags() >= Flag::MultiDraw ? "#define MULTI_DRAW\n"_s : ""_s)
.addSource(configuration.flags() >= Flag::LightCulling ? "#define LIGHT_CULLING\n"_s : ""_s);
} else
@ -297,10 +300,12 @@ PhongGL::CompileState PhongGL::compile(const Configuration& configuration) {
{
frag.addSource(Utility::format(
"#define LIGHT_COUNT {}\n"
"#define PER_DRAW_LIGHT_COUNT {}\n"
"#define LIGHT_COLORS_LOCATION {}\n"
"#define LIGHT_SPECULAR_COLORS_LOCATION {}\n"
"#define LIGHT_RANGES_LOCATION {}\n",
configuration.lightCount(),
configuration.perDrawLightCount(),
out._lightColorsUniform,
out._lightSpecularColorsUniform,
out._lightRangesUniform));
@ -323,9 +328,9 @@ PhongGL::CompileState PhongGL::compile(const Configuration& configuration) {
#endif
{
out.bindAttributeLocation(Position::Location, "position"_s);
if(configuration.lightCount())
if(configuration.perDrawLightCount())
out.bindAttributeLocation(Normal::Location, "normal"_s);
if((configuration.flags() & Flag::NormalTexture) && configuration.lightCount()) {
if((configuration.flags() & Flag::NormalTexture) && configuration.perDrawLightCount()) {
out.bindAttributeLocation(Tangent::Location, "tangent"_s);
if(configuration.flags() & Flag::Bitangent)
out.bindAttributeLocation(Bitangent::Location, "bitangent"_s);
@ -348,7 +353,7 @@ PhongGL::CompileState PhongGL::compile(const Configuration& configuration) {
#endif
if(configuration.flags() & Flag::InstancedTransformation) {
out.bindAttributeLocation(TransformationMatrix::Location, "instancedTransformationMatrix"_s);
if(configuration.lightCount())
if(configuration.perDrawLightCount())
out.bindAttributeLocation(NormalMatrix::Location, "instancedNormalMatrix"_s);
}
if(configuration.flags() >= Flag::InstancedTextureOffset)
@ -431,7 +436,7 @@ PhongGL::PhongGL(CompileState&& state): PhongGL{static_cast<PhongGL&&>(std::move
#endif
_projectionMatrixUniform = uniformLocation("projectionMatrix"_s);
_ambientColorUniform = uniformLocation("ambientColor"_s);
if(_lightCount) {
if(_perDrawLightCount) {
_normalMatrixUniform = uniformLocation("normalMatrix"_s);
_diffuseColorUniform = uniformLocation("diffuseColor"_s);
if(!(_flags & Flag::NoSpecular)) {
@ -464,7 +469,7 @@ PhongGL::PhongGL(CompileState&& state): PhongGL{static_cast<PhongGL&&>(std::move
#endif
{
if(_flags & Flag::AmbientTexture) setUniform(uniformLocation("ambientTexture"_s), AmbientTextureUnit);
if(_lightCount) {
if(_perDrawLightCount) {
if(_flags & Flag::DiffuseTexture) setUniform(uniformLocation("diffuseTexture"_s), DiffuseTextureUnit);
if(_flags & Flag::SpecularTexture) setUniform(uniformLocation("specularTexture"_s), SpecularTextureUnit);
if(_flags & Flag::NormalTexture) setUniform(uniformLocation("normalTexture"_s), NormalTextureUnit);
@ -580,7 +585,7 @@ PhongGL& PhongGL::setDiffuseColor(const Magnum::Color4& color) {
CORRADE_ASSERT(!(_flags >= Flag::UniformBuffers),
"Shaders::PhongGL::setDiffuseColor(): the shader was created with uniform buffers enabled", *this);
#endif
if(_lightCount) setUniform(_diffuseColorUniform, color);
if(_perDrawLightCount) setUniform(_diffuseColorUniform, color);
return *this;
}
@ -591,7 +596,7 @@ PhongGL& PhongGL::setSpecularColor(const Magnum::Color4& color) {
#endif
CORRADE_ASSERT(!(_flags >= Flag::NoSpecular),
"Shaders::PhongGL::setSpecularColor(): the shader was created with specular disabled", *this);
if(_lightCount) setUniform(_specularColorUniform, color);
if(_perDrawLightCount) setUniform(_specularColorUniform, color);
return *this;
}
@ -602,7 +607,7 @@ PhongGL& PhongGL::setShininess(Float shininess) {
#endif
CORRADE_ASSERT(!(_flags >= Flag::NoSpecular),
"Shaders::PhongGL::setShininess(): the shader was created with specular disabled", *this);
if(_lightCount) setUniform(_shininessUniform, shininess);
if(_perDrawLightCount) setUniform(_shininessUniform, shininess);
return *this;
}
@ -613,7 +618,7 @@ PhongGL& PhongGL::setNormalTextureScale(const Float scale) {
#endif
CORRADE_ASSERT(_flags & Flag::NormalTexture,
"Shaders::PhongGL::setNormalTextureScale(): the shader was not created with normal texture enabled", *this);
if(_lightCount) setUniform(_normalTextureScaleUniform, scale);
if(_perDrawLightCount) setUniform(_normalTextureScaleUniform, scale);
return *this;
}
@ -653,7 +658,7 @@ PhongGL& PhongGL::setNormalMatrix(const Matrix3x3& matrix) {
CORRADE_ASSERT(!(_flags >= Flag::UniformBuffers),
"Shaders::PhongGL::setNormalMatrix(): the shader was created with uniform buffers enabled", *this);
#endif
if(_lightCount) setUniform(_normalMatrixUniform, matrix);
if(_perDrawLightCount) setUniform(_normalMatrixUniform, matrix);
return *this;
}
@ -1025,7 +1030,7 @@ PhongGL& PhongGL::bindDiffuseTexture(GL::Texture2D& texture) {
CORRADE_ASSERT(!(_flags & Flag::TextureArrays),
"Shaders::PhongGL::bindDiffuseTexture(): the shader was created with texture arrays enabled, use a Texture2DArray instead", *this);
#endif
if(_lightCount) texture.bind(DiffuseTextureUnit);
if(_perDrawLightCount) texture.bind(DiffuseTextureUnit);
return *this;
}
@ -1035,7 +1040,7 @@ PhongGL& PhongGL::bindDiffuseTexture(GL::Texture2DArray& texture) {
"Shaders::PhongGL::bindDiffuseTexture(): the shader was not created with diffuse texture enabled", *this);
CORRADE_ASSERT(_flags & Flag::TextureArrays,
"Shaders::PhongGL::bindDiffuseTexture(): the shader was not created with texture arrays enabled, use a Texture2D instead", *this);
if(_lightCount) texture.bind(DiffuseTextureUnit);
if(_perDrawLightCount) texture.bind(DiffuseTextureUnit);
return *this;
}
#endif
@ -1047,7 +1052,7 @@ PhongGL& PhongGL::bindSpecularTexture(GL::Texture2D& texture) {
CORRADE_ASSERT(!(_flags & Flag::TextureArrays),
"Shaders::PhongGL::bindSpecularTexture(): the shader was created with texture arrays enabled, use a Texture2DArray instead", *this);
#endif
if(_lightCount) texture.bind(SpecularTextureUnit);
if(_perDrawLightCount) texture.bind(SpecularTextureUnit);
return *this;
}
@ -1057,7 +1062,7 @@ PhongGL& PhongGL::bindSpecularTexture(GL::Texture2DArray& texture) {
"Shaders::PhongGL::bindSpecularTexture(): the shader was not created with specular texture enabled", *this);
CORRADE_ASSERT(_flags & Flag::TextureArrays,
"Shaders::PhongGL::bindSpecularTexture(): the shader was not created with texture arrays enabled, use a Texture2D instead", *this);
if(_lightCount) texture.bind(SpecularTextureUnit);
if(_perDrawLightCount) texture.bind(SpecularTextureUnit);
return *this;
}
#endif
@ -1069,7 +1074,7 @@ PhongGL& PhongGL::bindNormalTexture(GL::Texture2D& texture) {
CORRADE_ASSERT(!(_flags & Flag::TextureArrays),
"Shaders::PhongGL::bindNormalTexture(): the shader was created with texture arrays enabled, use a Texture2DArray instead", *this);
#endif
if(_lightCount) texture.bind(NormalTextureUnit);
if(_perDrawLightCount) texture.bind(NormalTextureUnit);
return *this;
}
@ -1079,7 +1084,7 @@ PhongGL& PhongGL::bindNormalTexture(GL::Texture2DArray& texture) {
"Shaders::PhongGL::bindNormalTexture(): the shader was not created with normal texture enabled", *this);
CORRADE_ASSERT(_flags & Flag::TextureArrays,
"Shaders::PhongGL::bindNormalTexture(): the shader was not created with texture arrays enabled, use a Texture2D instead", *this);
if(_lightCount) texture.bind(NormalTextureUnit);
if(_perDrawLightCount) texture.bind(NormalTextureUnit);
return *this;
}
#endif
@ -1117,6 +1122,16 @@ PhongGL& PhongGL::bindTextures(GL::Texture2D* ambient, GL::Texture2D* diffuse, G
return *this;
}
PhongGL::Configuration& PhongGL::Configuration::setLightCount(const UnsignedInt count, const UnsignedInt perDrawCount) {
CORRADE_ASSERT(!count == !perDrawCount,
"Shaders::PhongGL::Configuration::setLightCount(): count has to be non-zero iff per-draw count is non-zero", *this);
CORRADE_ASSERT(perDrawCount <= count,
"Shaders::PhongGL::Configuration::setLightCount(): per-draw light count expected to be not larger than total count of" << count << Debug::nospace << ", got" << perDrawCount, *this);
_lightCount = count;
_perDrawLightCount = perDrawCount;
return *this;
}
#ifndef MAGNUM_TARGET_GLES2
PhongGL::Configuration& PhongGL::Configuration::setJointCount(UnsignedInt count, UnsignedInt perVertexCount, UnsignedInt secondaryPerVertexCount) {
CORRADE_ASSERT(perVertexCount <= 4,

141
src/Magnum/Shaders/PhongGL.h

@ -365,8 +365,8 @@ class MAGNUM_SHADERS_EXPORT PhongGL: public GL::AbstractShaderProgram {
* @brief Normal direction
*
* @ref shaders-generic "Generic attribute",
* @relativeref{Magnum,Vector3}. Used only if @ref lightCount() isn't
* @cpp 0 @ce.
* @relativeref{Magnum,Vector3}. Used only if @ref perDrawLightCount()
* isn't @cpp 0 @ce.
*/
typedef GenericGL3D::Normal Normal;
@ -380,7 +380,7 @@ class MAGNUM_SHADERS_EXPORT PhongGL: public GL::AbstractShaderProgram {
* @ref Flag::Bitangent is not enabled, it's the same as if
* @ref Tangent4 was specified with the fourth component always being
* @cpp 1.0f @ce. Used only if @ref Flag::NormalTexture is set and
* @ref lightCount() isn't @cpp 0 @ce.
* @ref perDrawLightCount() isn't @cpp 0 @ce.
* @see @ref Shaders-PhongGL-normal-mapping
*/
typedef GenericGL3D::Tangent Tangent;
@ -394,7 +394,7 @@ class MAGNUM_SHADERS_EXPORT PhongGL: public GL::AbstractShaderProgram {
* attribute. If @ref Flag::Bitangent is set, the fourth component is
* ignored and bitangents are taken from the @ref Bitangent attribute
* instead. Used only if @ref Flag::NormalTexture is set and
* @ref lightCount() isn't @cpp 0 @ce.
* @ref perDrawLightCount() isn't @cpp 0 @ce.
* @see @ref Shaders-PhongGL-normal-mapping
*/
typedef GenericGL3D::Tangent4 Tangent4;
@ -406,7 +406,8 @@ class MAGNUM_SHADERS_EXPORT PhongGL: public GL::AbstractShaderProgram {
* @ref shaders-generic "Generic attribute",
* @relativeref{Magnum,Vector3}. Use either this or the @ref Tangent4
* attribute. Used only if both @ref Flag::NormalTexture and
* @ref Flag::Bitangent are set and @ref lightCount() isn't @cpp 0 @ce.
* @ref Flag::Bitangent are set and @ref perDrawLightCount() isn't
* @cpp 0 @ce.
* @see @ref Shaders-PhongGL-normal-mapping
*/
typedef GenericGL3D::Bitangent Bitangent;
@ -851,8 +852,8 @@ class MAGNUM_SHADERS_EXPORT PhongGL: public GL::AbstractShaderProgram {
* Enable light culling in uniform buffer workflows using the
* @ref PhongDrawUniform::lightOffset and
* @ref PhongDrawUniform::lightCount fields. If not enabled, all
* @ref lightCount() lights are used for every draw. Expects that
* @ref Flag::UniformBuffers is enabled as well.
* @ref perDrawLightCount() lights are used for every draw. Expects
* that @ref Flag::UniformBuffers is enabled as well.
* @requires_gl31 Extension @gl_extension{ARB,uniform_buffer_object}
* @requires_gles30 Uniform buffers are not available in OpenGL ES
* 2.0.
@ -1032,10 +1033,24 @@ class MAGNUM_SHADERS_EXPORT PhongGL: public GL::AbstractShaderProgram {
* If @ref Flag::UniformBuffers is set, this is the statically defined
* size of the @ref PhongLightUniform uniform buffer bound with
* @ref bindLightBuffer().
* @see @ref Configuration::setLightCount()
* @see @ref perDrawLightCount(), @ref Configuration::setLightCount()
*/
UnsignedInt lightCount() const { return _lightCount; }
/**
* @brief Per-draw light count
* @m_since_latest
*
* Number of lights out of @ref lightCount() applied per draw. If
* @ref Flag::LightCulling is enabled, this is only an upper bound on
* the light count applied per draw, with the actual count supplied via
* @ref PhongDrawUniform::lightCount. If @cpp 0 @ce, no lighting
* calculations are performed and only the ambient contribution to the
* color is used.
* @see @ref Configuration::setLightCount()
*/
UnsignedInt perDrawLightCount() const { return _perDrawLightCount; }
#ifndef MAGNUM_TARGET_GLES2
/**
* @brief Joint count
@ -1164,10 +1179,10 @@ class MAGNUM_SHADERS_EXPORT PhongGL: public GL::AbstractShaderProgram {
*
* Initial value is @cpp 0xffffffff_rgbaf @ce. If
* @ref Flag::DiffuseTexture is set, the color will be multiplied with
* the texture. If @ref lightCount() is zero, this function is a no-op,
* as diffuse color doesn't contribute to the output in that case.
* If @ref Flag::VertexColor is set, the color is multiplied with a
* color coming from the @ref Color3 / @ref Color4 attribute.
* the texture. If @ref perDrawLightCount() is zero, this function is a
* no-op, as diffuse color doesn't contribute to the output in that
* case. If @ref Flag::VertexColor is set, the color is multiplied with
* a color coming from the @ref Color3 / @ref Color4 attribute.
*
* Expects that @ref Flag::UniformBuffers is not set, in that case fill
* @ref PhongMaterialUniform::diffuseColor and call
@ -1187,8 +1202,8 @@ class MAGNUM_SHADERS_EXPORT PhongGL: public GL::AbstractShaderProgram {
* altogether.
*
* Expects that the shader was created with @ref Flag::NormalTexture
* enabled. If @ref lightCount() is zero, this function is a no-op, as
* normals don't contribute to the output in that case.
* enabled. If @ref perDrawLightCount() is zero, this function is a
* no-op, as normals don't contribute to the output in that case.
*
* Expects that @ref Flag::UniformBuffers is not set, in that case fill
* @ref PhongMaterialUniform::normalTextureScale and call
@ -1209,8 +1224,8 @@ class MAGNUM_SHADERS_EXPORT PhongGL: public GL::AbstractShaderProgram {
* recommended to disable the specular contribution altogether with
* @ref Flag::NoSpecular. If having a dedicated shader variant is not
* possible, set the specular color to @cpp 0x00000000_rgbaf @ce. If
* @ref lightCount() is zero, this function is a no-op, as specular
* color doesn't contribute to the output in that case.
* @ref perDrawLightCount() is zero, this function is a no-op, as
* specular color doesn't contribute to the output in that case.
*
* Expects that @ref Flag::UniformBuffers is not set, in that case fill
* @ref PhongMaterialUniform::specularColor and call
@ -1224,9 +1239,9 @@ class MAGNUM_SHADERS_EXPORT PhongGL: public GL::AbstractShaderProgram {
* @return Reference to self (for method chaining)
*
* The larger value, the harder surface (smaller specular highlight).
* Initial value is @cpp 80.0f @ce. If @ref lightCount() is zero, this
* function is a no-op, as specular color doesn't contribute to the
* output in that case.
* Initial value is @cpp 80.0f @ce. If @ref perDrawLightCount() is
* zero, this function is a no-op, as specular color doesn't contribute
* to the output in that case.
*
* Expects that @ref Flag::UniformBuffers is not set, in that case fill
* @ref PhongMaterialUniform::shininess and call
@ -1301,9 +1316,9 @@ class MAGNUM_SHADERS_EXPORT PhongGL: public GL::AbstractShaderProgram {
* The matrix doesn't need to be normalized, as renormalization is done
* per-fragment anyway. You need to set also
* @ref setTransformationMatrix() with a corresponding value. Initial
* value is an identity matrix. If @ref lightCount() is zero, this
* function is a no-op, as normals don't contribute to the output in
* that case. If @ref Flag::InstancedTransformation is set, the
* value is an identity matrix. If @ref perDrawLightCount() is zero,
* this function is a no-op, as normals don't contribute to the output
* in that case. If @ref Flag::InstancedTransformation is set, the
* per-instance normal matrix coming from the @ref NormalMatrix
* attribute is applied first, before this one.
*
@ -1895,8 +1910,8 @@ class MAGNUM_SHADERS_EXPORT PhongGL: public GL::AbstractShaderProgram {
* Expects that the shader was created with @ref Flag::DiffuseTexture
* enabled. If @ref Flag::TextureArrays is enabled as well, use
* @ref bindDiffuseTexture(GL::Texture2DArray&) instead. If
* @ref lightCount() is zero, this function is a no-op, as diffuse
* color doesn't contribute to the output in that case.
* @ref perDrawLightCount() is zero, this function is a no-op, as
* diffuse color doesn't contribute to the output in that case.
* @see @ref bindTextures(), @ref setDiffuseColor()
*/
PhongGL& bindDiffuseTexture(GL::Texture2D& texture);
@ -1913,8 +1928,8 @@ class MAGNUM_SHADERS_EXPORT PhongGL: public GL::AbstractShaderProgram {
* set via @ref setTextureLayer(); if @ref Flag::UniformBuffers is
* enabled, @ref Flag::TextureTransformation has to be enabled as well
* and the layer is set via @ref TextureTransformationUniform::layer.
* If @ref lightCount() is zero, this function is a no-op, as diffuse
* color doesn't contribute to the output in that case.
* If @ref perDrawLightCount() is zero, this function is a no-op, as
* diffuse color doesn't contribute to the output in that case.
* @see @ref setDiffuseColor()
* @requires_gl30 Extension @gl_extension{EXT,texture_array}
* @requires_gles30 Texture arrays are not available in OpenGL ES 2.0.
@ -1931,8 +1946,8 @@ class MAGNUM_SHADERS_EXPORT PhongGL: public GL::AbstractShaderProgram {
* enabled and that @ref Flag::NoSpecular is not set. If
* @ref Flag::TextureArrays is enabled as well, use
* @ref bindSpecularTexture(GL::Texture2DArray&) instead. If
* @ref lightCount() is zero, this function is a no-op, as specular
* color doesn't contribute to the output in that case.
* @ref perDrawLightCount() is zero, this function is a no-op, as
* specular color doesn't contribute to the output in that case.
* @see @ref bindTextures(), @ref setSpecularColor()
*/
PhongGL& bindSpecularTexture(GL::Texture2D& texture);
@ -1950,8 +1965,8 @@ class MAGNUM_SHADERS_EXPORT PhongGL: public GL::AbstractShaderProgram {
* @ref Flag::UniformBuffers is enabled,
* @ref Flag::TextureTransformation has to be enabled as well and the
* layer is set via @ref TextureTransformationUniform::layer. If
* @ref lightCount() is zero, this function is a no-op, as specular
* color doesn't contribute to the output in that case.
* @ref perDrawLightCount() is zero, this function is a no-op, as
* specular color doesn't contribute to the output in that case.
* @see @ref setSpecularColor()
* @requires_gl30 Extension @gl_extension{EXT,texture_array}
* @requires_gles30 Texture arrays are not available in OpenGL ES 2.0.
@ -1969,8 +1984,8 @@ class MAGNUM_SHADERS_EXPORT PhongGL: public GL::AbstractShaderProgram {
* enabled and the @ref Tangent attribute was supplied. If
* @ref Flag::TextureArrays is enabled as well, use
* @ref bindNormalTexture(GL::Texture2DArray&) instead. If
* @ref lightCount() is zero, this function is a no-op, as normals
* don't contribute to the output in that case.
* @ref perDrawLightCount() is zero, this function is a no-op, as
* normals don't contribute to the output in that case.
* @see @ref Shaders-PhongGL-normal-mapping,
* @ref bindTextures(), @ref setNormalTextureScale()
*/
@ -1984,9 +1999,9 @@ class MAGNUM_SHADERS_EXPORT PhongGL: public GL::AbstractShaderProgram {
*
* Expects that the shader was created with both
* @ref Flag::NormalTexture and @ref Flag::TextureArrays enabled and
* the @ref Tangent attribute was supplied. If @ref lightCount() is
* zero, this function is a no-op, as normals don't contribute to the
* output in that case.
* the @ref Tangent attribute was supplied. If @ref perDrawLightCount()
* is zero, this function is a no-op, as normals don't contribute to
* the output in that case.
* @see @ref Shaders-PhongGL-normal-mapping,
* @ref setNormalTextureScale()
*/
@ -2070,7 +2085,8 @@ class MAGNUM_SHADERS_EXPORT PhongGL: public GL::AbstractShaderProgram {
explicit PhongGL(NoInitT) {}
Flags _flags;
UnsignedInt _lightCount{};
UnsignedInt _lightCount{},
_perDrawLightCount{};
#ifndef MAGNUM_TARGET_GLES2
UnsignedInt _jointCount{},
_perVertexJointCount{},
@ -2136,33 +2152,50 @@ class MAGNUM_SHADERS_EXPORT PhongGL::Configuration {
/** @brief Light count */
UnsignedInt lightCount() const { return _lightCount; }
/** @brief Per-draw light count */
UnsignedInt perDrawLightCount() const { return _perDrawLightCount; }
/**
* @brief Set light count
*
* If @ref Flag::UniformBuffers isn't set, describes how many lights
* get applied to each draw, and corresponds to the range / array size
* accepted by @ref setLightPosition() / @ref setLightPositions(),
* @ref setLightColor() / @ref setLightColors(),
* @ref setLightSpecularColor() / @ref setLightSpecularColors() and
* @ref setLightRange() / @ref setLightRanges(). If
* @ref Flag::UniformBuffers is set, describes size of a
* If @ref Flag::UniformBuffers isn't set, @p count corresponds to the
* range / array size accepted by @ref setLightPosition() /
* @ref setLightPositions(), @ref setLightColor() /
* @ref setLightColors(), @ref setLightSpecularColor() /
* @ref setLightSpecularColors() and @ref setLightRange() /
* @ref setLightRanges().
*
* If @ref Flag::UniformBuffers is set, @p count describes size of a
* @ref PhongLightUniform buffer bound with @ref bindLightBuffer().
* Uniform buffers have a statically defined size and
* @cpp count*sizeof(PhongLightUniform) @ce has to be within
* @ref GL::AbstractShaderProgram::maxUniformBlockSize().
*
* The per-draw lights are then specified via
* @ref PhongDrawUniform::lightOffset and
* @ref GL::AbstractShaderProgram::maxUniformBlockSize(). The per-draw
* lights are then specified via @ref PhongDrawUniform::lightOffset and
* @ref PhongDrawUniform::lightCount.
*
* Can be set to @cpp 0 @ce, in which case only the ambient
* contribution to the color is used. Default value is @cpp 1 @ce.
* The @p perDrawCount parameter describes how many lights out of
* @p count get applied to each draw. Useful mainly in combination with
* @ref Flag::LightCulling, without it can be used for conveniently
* reducing the light count without having to reduce sizes of the light
* arrays as well. It's expected to not be larger than @p count. If set
* to @cpp 0 @ce, no lighting calculations are performed and only the
* ambient contribution to the color is used. If @p perDrawCount is
* @cpp 0 @ce, @p count is expected to be zero as well.
*
* Default value is @cpp 1 @ce for both.
* @see @ref setFlags(), @ref setMaterialCount(), @ref setDrawCount(),
* @ref PhongGL::lightCount()
* @ref PhongGL::lightCount(), @ref PhongGL::perDrawLightCount()
*/
Configuration& setLightCount(UnsignedInt count, UnsignedInt perDrawCount);
/**
* @brief Set light count
*
* Same as calling @ref setLightCount(UnsignedInt, UnsignedInt) with
* both parameters set to @p count.
*/
Configuration& setLightCount(UnsignedInt count) {
_lightCount = count;
return *this;
return setLightCount(count, count);
}
#ifndef MAGNUM_TARGET_GLES2
@ -2302,7 +2335,9 @@ class MAGNUM_SHADERS_EXPORT PhongGL::Configuration {
Flags _flags;
UnsignedInt _lightCount = 1;
#ifndef MAGNUM_TARGET_GLES2
UnsignedInt _jointCount = 0,
UnsignedInt
_perDrawLightCount = 1,
_jointCount = 0,
_perVertexJointCount = 0,
_secondaryPerVertexJointCount = 0,
_materialCount = 1,

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

@ -230,54 +230,55 @@ struct PhongGLTest: GL::OpenGLTester {
constexpr struct {
const char* name;
PhongGL::Flags flags;
UnsignedInt lightCount;
UnsignedInt lightCount, perDrawLightCount;
} ConstructData[]{
{"", {}, 1},
{"ambient texture", PhongGL::Flag::AmbientTexture, 1},
{"diffuse texture", PhongGL::Flag::DiffuseTexture, 1},
{"diffuse texture + texture transform", PhongGL::Flag::DiffuseTexture|PhongGL::Flag::TextureTransformation, 1},
{"specular texture", PhongGL::Flag::SpecularTexture, 1},
{"normal texture", PhongGL::Flag::NormalTexture, 1},
{"normal texture + separate bitangents", PhongGL::Flag::NormalTexture|PhongGL::Flag::Bitangent, 1},
{"separate bitangents alone", PhongGL::Flag::Bitangent, 1},
{"ambient + diffuse texture", PhongGL::Flag::AmbientTexture|PhongGL::Flag::DiffuseTexture, 1},
{"ambient + specular texture", PhongGL::Flag::AmbientTexture|PhongGL::Flag::SpecularTexture, 1},
{"diffuse + specular texture", PhongGL::Flag::DiffuseTexture|PhongGL::Flag::SpecularTexture, 1},
{"ambient + diffuse + specular texture", PhongGL::Flag::AmbientTexture|PhongGL::Flag::DiffuseTexture|PhongGL::Flag::SpecularTexture, 1},
{"ambient + diffuse + specular + normal texture", PhongGL::Flag::AmbientTexture|PhongGL::Flag::DiffuseTexture|PhongGL::Flag::SpecularTexture|PhongGL::Flag::NormalTexture, 1},
{"", {}, 1, 1},
{"ambient texture", PhongGL::Flag::AmbientTexture, 1, 1},
{"diffuse texture", PhongGL::Flag::DiffuseTexture, 1, 1},
{"diffuse texture + texture transform", PhongGL::Flag::DiffuseTexture|PhongGL::Flag::TextureTransformation, 1, 1},
{"specular texture", PhongGL::Flag::SpecularTexture, 1, 1},
{"normal texture", PhongGL::Flag::NormalTexture, 1, 1},
{"normal texture + separate bitangents", PhongGL::Flag::NormalTexture|PhongGL::Flag::Bitangent, 1, 1},
{"separate bitangents alone", PhongGL::Flag::Bitangent, 1, 1},
{"ambient + diffuse texture", PhongGL::Flag::AmbientTexture|PhongGL::Flag::DiffuseTexture, 1, 1},
{"ambient + specular texture", PhongGL::Flag::AmbientTexture|PhongGL::Flag::SpecularTexture, 1, 1},
{"diffuse + specular texture", PhongGL::Flag::DiffuseTexture|PhongGL::Flag::SpecularTexture, 1, 1},
{"ambient + diffuse + specular texture", PhongGL::Flag::AmbientTexture|PhongGL::Flag::DiffuseTexture|PhongGL::Flag::SpecularTexture, 1, 1},
{"ambient + diffuse + specular + normal texture", PhongGL::Flag::AmbientTexture|PhongGL::Flag::DiffuseTexture|PhongGL::Flag::SpecularTexture|PhongGL::Flag::NormalTexture, 1, 1},
#ifndef MAGNUM_TARGET_GLES2
{"ambient + diffuse + specular + normal texture arrays", PhongGL::Flag::AmbientTexture|PhongGL::Flag::DiffuseTexture|PhongGL::Flag::SpecularTexture|PhongGL::Flag::NormalTexture|PhongGL::Flag::TextureArrays, 1},
{"ambient + diffuse + specular + normal texture arrays + texture transformation", PhongGL::Flag::AmbientTexture|PhongGL::Flag::DiffuseTexture|PhongGL::Flag::SpecularTexture|PhongGL::Flag::NormalTexture|PhongGL::Flag::TextureArrays|PhongGL::Flag::TextureTransformation, 1},
{"ambient + diffuse + specular + normal texture arrays", PhongGL::Flag::AmbientTexture|PhongGL::Flag::DiffuseTexture|PhongGL::Flag::SpecularTexture|PhongGL::Flag::NormalTexture|PhongGL::Flag::TextureArrays, 1, 1},
{"ambient + diffuse + specular + normal texture arrays + texture transformation", PhongGL::Flag::AmbientTexture|PhongGL::Flag::DiffuseTexture|PhongGL::Flag::SpecularTexture|PhongGL::Flag::NormalTexture|PhongGL::Flag::TextureArrays|PhongGL::Flag::TextureTransformation, 1, 1},
#endif
{"alpha mask", PhongGL::Flag::AlphaMask, 1},
{"alpha mask + diffuse texture", PhongGL::Flag::AlphaMask|PhongGL::Flag::DiffuseTexture, 1},
{"vertex colors", PhongGL::Flag::VertexColor, 1},
{"vertex colors + diffuse texture", PhongGL::Flag::VertexColor|PhongGL::Flag::DiffuseTexture, 1},
{"alpha mask", PhongGL::Flag::AlphaMask, 1, 1},
{"alpha mask + diffuse texture", PhongGL::Flag::AlphaMask|PhongGL::Flag::DiffuseTexture, 1, 1},
{"vertex colors", PhongGL::Flag::VertexColor, 1, 1},
{"vertex colors + diffuse texture", PhongGL::Flag::VertexColor|PhongGL::Flag::DiffuseTexture, 1, 1},
#ifndef MAGNUM_TARGET_GLES2
{"object ID", PhongGL::Flag::ObjectId, 1},
{"object ID", PhongGL::Flag::ObjectId, 1, 1},
/* This is fine, InstancedObjectId isn't (check in ConstructInvalidData) */
{"object ID + separate bitangent", PhongGL::Flag::ObjectId|PhongGL::Flag::Bitangent, 1},
{"instanced object ID", PhongGL::Flag::InstancedObjectId, 1},
{"object ID + alpha mask + specular texture", PhongGL::Flag::ObjectId|PhongGL::Flag::AlphaMask|PhongGL::Flag::SpecularTexture, 1},
{"object ID texture", PhongGL::Flag::ObjectIdTexture, 1},
{"object ID texture array", PhongGL::Flag::ObjectIdTexture|PhongGL::Flag::TextureArrays, 1},
{"object ID texture + instanced texture transformation", PhongGL::Flag::ObjectIdTexture|PhongGL::Flag::InstancedTextureOffset, 1},
{"object ID texture array + instanced texture transformation", PhongGL::Flag::ObjectIdTexture|PhongGL::Flag::TextureArrays|PhongGL::Flag::InstancedTextureOffset, 1},
{"instanced object ID texture array + texture transformation", PhongGL::Flag::ObjectIdTexture|PhongGL::Flag::InstancedObjectId|PhongGL::Flag::TextureArrays|PhongGL::Flag::TextureTransformation, 1},
{"object ID texture + diffuse texture", PhongGL::Flag::ObjectIdTexture|PhongGL::Flag::DiffuseTexture, 1},
{"object ID texture, zero lights", PhongGL::Flag::ObjectIdTexture, 0},
{"object ID + separate bitangent", PhongGL::Flag::ObjectId|PhongGL::Flag::Bitangent, 1, 1},
{"instanced object ID", PhongGL::Flag::InstancedObjectId, 1, 1},
{"object ID + alpha mask + specular texture", PhongGL::Flag::ObjectId|PhongGL::Flag::AlphaMask|PhongGL::Flag::SpecularTexture, 1, 1},
{"object ID texture", PhongGL::Flag::ObjectIdTexture, 1, 1},
{"object ID texture array", PhongGL::Flag::ObjectIdTexture|PhongGL::Flag::TextureArrays, 1, 1},
{"object ID texture + instanced texture transformation", PhongGL::Flag::ObjectIdTexture|PhongGL::Flag::InstancedTextureOffset, 1, 1},
{"object ID texture array + instanced texture transformation", PhongGL::Flag::ObjectIdTexture|PhongGL::Flag::TextureArrays|PhongGL::Flag::InstancedTextureOffset, 1, 1},
{"instanced object ID texture array + texture transformation", PhongGL::Flag::ObjectIdTexture|PhongGL::Flag::InstancedObjectId|PhongGL::Flag::TextureArrays|PhongGL::Flag::TextureTransformation, 1, 1},
{"object ID texture + diffuse texture", PhongGL::Flag::ObjectIdTexture|PhongGL::Flag::DiffuseTexture, 1, 1},
{"object ID texture, zero lights", PhongGL::Flag::ObjectIdTexture, 0, 0},
#endif
{"no specular", PhongGL::Flag::NoSpecular, 1},
{"five lights", {}, 5},
{"zero lights", {}, 0},
{"instanced transformation", PhongGL::Flag::InstancedTransformation, 3},
{"instanced transformation, zero lights", PhongGL::Flag::InstancedTransformation, 0},
{"instanced specular texture offset", PhongGL::Flag::SpecularTexture|PhongGL::Flag::InstancedTextureOffset, 3},
{"instanced normal texture offset", PhongGL::Flag::NormalTexture|PhongGL::Flag::InstancedTextureOffset, 3},
{"no specular", PhongGL::Flag::NoSpecular, 1, 1},
{"five lights", {}, 5, 5},
{"fifteen lights, five used", {}, 15, 5},
{"zero lights", {}, 0, 0},
{"instanced transformation", PhongGL::Flag::InstancedTransformation, 3, 3},
{"instanced transformation, zero lights", PhongGL::Flag::InstancedTransformation, 0, 0},
{"instanced specular texture offset", PhongGL::Flag::SpecularTexture|PhongGL::Flag::InstancedTextureOffset, 3, 3},
{"instanced normal texture offset", PhongGL::Flag::NormalTexture|PhongGL::Flag::InstancedTextureOffset, 3, 3},
#ifndef MAGNUM_TARGET_GLES2
/* InstancedObjectId|Bitangent is disallowed (checked in
ConstructInvalidData), but this should work */
{"object ID + normal texture with bitangent from tangent", PhongGL::Flag::InstancedObjectId|PhongGL::Flag::NormalTexture, 1}
{"object ID + normal texture with bitangent from tangent", PhongGL::Flag::InstancedObjectId|PhongGL::Flag::NormalTexture, 1, 1}
#endif
};
@ -311,57 +312,57 @@ const struct {
constexpr struct {
const char* name;
PhongGL::Flags flags;
UnsignedInt lightCount, materialCount, drawCount;
UnsignedInt lightCount, perDrawLightCount, materialCount, drawCount;
UnsignedInt jointCount, perVertexJointCount, secondaryPerVertexJointCount;
} ConstructUniformBuffersData[]{
{"classic fallback", {},
1, 1, 1, 0, 0, 0},
1, 1, 1, 1, 0, 0, 0},
{"", PhongGL::Flag::UniformBuffers,
1, 1, 1, 0, 0, 0},
1, 1, 1, 1, 0, 0, 0},
/* SwiftShader has 256 uniform vectors at most, per-3D-draw is 4+4,
per-material 4, per-light 4 plus 4 for projection */
{"multiple lights, materials, draws", PhongGL::Flag::UniformBuffers,
8, 8, 24, 0, 0, 0},
8, 8, 8, 24, 0, 0, 0},
{"multiple lights, materials, draws + light culling", PhongGL::Flag::UniformBuffers|PhongGL::Flag::LightCulling,
8, 8, 24, 0, 0, 0},
8, 4, 8, 24, 0, 0, 0},
{"zero lights", PhongGL::Flag::UniformBuffers,
0, 16, 24, 0, 0, 0},
0, 0, 16, 24, 0, 0, 0},
{"ambient + diffuse + specular texture", PhongGL::Flag::UniformBuffers|PhongGL::Flag::AmbientTexture|PhongGL::Flag::DiffuseTexture|PhongGL::Flag::SpecularTexture,
1, 1, 1, 0, 0, 0},
1, 1, 1, 1, 0, 0, 0},
{"ambient + diffuse + specular texture + texture transformation", PhongGL::Flag::UniformBuffers|PhongGL::Flag::AmbientTexture|PhongGL::Flag::DiffuseTexture|PhongGL::Flag::SpecularTexture|PhongGL::Flag::TextureTransformation,
1, 1, 1, 0, 0, 0},
1, 1, 1, 1, 0, 0, 0},
{"ambient + diffuse + specular texture array + texture transformation", PhongGL::Flag::UniformBuffers|PhongGL::Flag::AmbientTexture|PhongGL::Flag::DiffuseTexture|PhongGL::Flag::SpecularTexture|PhongGL::Flag::TextureArrays|PhongGL::Flag::TextureTransformation,
1, 1, 1, 0, 0, 0},
1, 1, 1, 1, 0, 0, 0},
{"normal texture", PhongGL::Flag::UniformBuffers|PhongGL::Flag::NormalTexture,
1, 1, 1, 0, 0, 0},
1, 1, 1, 1, 0, 0, 0},
{"normal texture + separate bitangents", PhongGL::Flag::UniformBuffers|PhongGL::Flag::NormalTexture|PhongGL::Flag::Bitangent,
1, 1, 1, 0, 0, 0},
1, 1, 1, 1, 0, 0, 0},
{"alpha mask", PhongGL::Flag::UniformBuffers|PhongGL::Flag::AlphaMask,
1, 1, 1, 0, 0, 0},
1, 1, 1, 1, 0, 0, 0},
{"object ID", PhongGL::Flag::UniformBuffers|PhongGL::Flag::ObjectId,
1, 1, 1, 0, 0, 0},
1, 1, 1, 1, 0, 0, 0},
{"object ID texture", PhongGL::Flag::UniformBuffers|PhongGL::Flag::ObjectIdTexture,
1, 1, 1, 0, 0, 0},
1, 1, 1, 1, 0, 0, 0},
{"object ID texture array", PhongGL::Flag::UniformBuffers|PhongGL::Flag::ObjectIdTexture|PhongGL::Flag::TextureArrays|PhongGL::Flag::TextureTransformation,
1, 1, 1, 0, 0, 0},
1, 1, 1, 1, 0, 0, 0},
{"object ID texture + instanced texture transformation", PhongGL::Flag::UniformBuffers|PhongGL::Flag::ObjectIdTexture|PhongGL::Flag::InstancedTextureOffset,
1, 1, 1, 0, 0, 0},
1, 1, 1, 1, 0, 0, 0},
{"object ID texture array + instanced texture transformation", PhongGL::Flag::UniformBuffers|PhongGL::Flag::ObjectIdTexture|PhongGL::Flag::TextureArrays|PhongGL::Flag::InstancedTextureOffset,
1, 1, 1, 0, 0, 0},
1, 1, 1, 1, 0, 0, 0},
{"instanced object ID texture array + texture transformation", PhongGL::Flag::UniformBuffers|PhongGL::Flag::ObjectIdTexture|PhongGL::Flag::InstancedObjectId|PhongGL::Flag::TextureArrays|PhongGL::Flag::TextureTransformation,
1, 1, 1, 0, 0, 0},
1, 1, 1, 1, 0, 0, 0},
{"object ID texture + diffuse texture", PhongGL::Flag::UniformBuffers|PhongGL::Flag::ObjectIdTexture|PhongGL::Flag::DiffuseTexture,
1, 1, 1, 0, 0, 0},
1, 1, 1, 1, 0, 0, 0},
{"no specular", PhongGL::Flag::UniformBuffers|PhongGL::Flag::NoSpecular,
1, 1, 1, 0, 0, 0},
1, 1, 1, 1, 0, 0, 0},
{"skinning", PhongGL::Flag::UniformBuffers,
1, 1, 1, 32, 3, 2},
1, 1, 1, 1, 32, 3, 2},
{"skinning, dynamic per-vertex sets", PhongGL::Flag::UniformBuffers|PhongGL::Flag::DynamicPerVertexJointCount,
1, 1, 1, 32, 3, 4},
1, 1, 1, 1, 32, 3, 4},
{"multidraw with all the things except secondary per-vertex sets", PhongGL::Flag::MultiDraw|PhongGL::Flag::TextureTransformation|PhongGL::Flag::DiffuseTexture|PhongGL::Flag::AmbientTexture|PhongGL::Flag::SpecularTexture|PhongGL::Flag::NormalTexture|PhongGL::Flag::TextureArrays|PhongGL::Flag::AlphaMask|PhongGL::Flag::ObjectId|PhongGL::Flag::InstancedTextureOffset|PhongGL::Flag::InstancedTransformation|PhongGL::Flag::InstancedObjectId|PhongGL::Flag::LightCulling|PhongGL::Flag::DynamicPerVertexJointCount,
8, 16, 24, 16, 4, 0},
8, 4, 16, 24, 16, 4, 0},
{"multidraw with all the things except instancing", PhongGL::Flag::MultiDraw|PhongGL::Flag::TextureTransformation|PhongGL::Flag::DiffuseTexture|PhongGL::Flag::AmbientTexture|PhongGL::Flag::SpecularTexture|PhongGL::Flag::NormalTexture|PhongGL::Flag::TextureArrays|PhongGL::Flag::AlphaMask|PhongGL::Flag::ObjectId|PhongGL::Flag::LightCulling|PhongGL::Flag::DynamicPerVertexJointCount,
8, 16, 24, 16, 3, 4},
8, 4, 16, 24, 16, 3, 4},
};
#endif
@ -489,13 +490,15 @@ using namespace Math::Literals;
const struct {
const char* name;
UnsignedInt lightCount, perDrawLightCount;
Deg rotation;
Color3 lightColor1, lightColor2;
Float lightPosition1, lightPosition2;
} RenderColoredData[]{
{"", {}, 0x993366_rgbf, 0x669933_rgbf, -3.0f, 3.0f},
{"flip lights", {}, 0x669933_rgbf, 0x993366_rgbf, 3.0f, -3.0f},
{"rotated", 45.0_degf, 0x993366_rgbf, 0x669933_rgbf, -3.0f, 3.0f}
{"", 2, 2, {}, 0x993366_rgbf, 0x669933_rgbf, -3.0f, 3.0f},
{"per-draw light count less than total", 4, 2, {}, 0x993366_rgbf, 0x669933_rgbf, -3.0f, 3.0f},
{"flip lights", 2, 2, {}, 0x669933_rgbf, 0x993366_rgbf, 3.0f, -3.0f},
{"rotated", 2, 2, 45.0_degf, 0x993366_rgbf, 0x669933_rgbf, -3.0f, 3.0f}
};
constexpr struct {
@ -795,6 +798,16 @@ const struct {
1.0f, 0.0f, {}}
};
#ifndef MAGNUM_TARGET_GLES2
const struct {
const char* name;
UnsignedInt count, perDrawCount;
} RenderLightCullingData[]{
{"same count and per-draw count", 64, 64},
{"per-draw count lower", 64, 2}
};
#endif
#ifndef MAGNUM_TARGET_GLES2
const struct {
const char* name;
@ -976,118 +989,130 @@ constexpr struct {
const char* expected;
UnsignedInt expectedId[3];
PhongGL::Flags flags;
UnsignedInt lightCount, materialCount, drawCount;
UnsignedInt lightCount, perDrawLightCount, materialCount, drawCount;
UnsignedInt uniformIncrement;
Float maxThreshold, meanThreshold;
} RenderMultiData[] {
{"bind with offset, colored",
"multidraw.tga", {},
{},
2, 1, 1, 16,
2, 2, 1, 1, 16,
/* Minor differences on ARM Mali */
3.34f, 0.01f},
{"bind with offset, colored + object ID",
"multidraw.tga", {1211, 5627, 36363},
PhongGL::Flag::ObjectId,
2, 1, 1, 16,
2, 2, 1, 1, 16,
/* Minor differences on ARM Mali */
3.34f, 0.01f},
{"bind with offset, colored + textured object ID",
"multidraw.tga", {3211, 8627, 40363},
PhongGL::Flag::TextureTransformation|PhongGL::Flag::ObjectIdTexture,
2, 1, 1, 16,
2, 2, 1, 1, 16,
/* Minor differences on ARM Mali */
3.34f, 0.01f},
{"bind with offset, colored + textured array object ID",
"multidraw.tga", {3211, 8627, 40363},
PhongGL::Flag::TextureTransformation|PhongGL::Flag::ObjectIdTexture|PhongGL::Flag::TextureArrays,
2, 1, 1, 16,
2, 2, 1, 1, 16,
/* Minor differences on ARM Mali */
3.34f, 0.01f},
{"bind with offset, textured",
"multidraw-textured.tga", {},
PhongGL::Flag::TextureTransformation|PhongGL::Flag::DiffuseTexture,
2, 1, 1, 16,
2, 2, 1, 1, 16,
/* Minor differences on ARM Mali */
4.67f, 0.02f},
{"bind with offset, texture array",
"multidraw-textured.tga", {},
PhongGL::Flag::TextureTransformation|PhongGL::Flag::DiffuseTexture|PhongGL::Flag::TextureArrays,
2, 1, 1, 16,
2, 2, 1, 1, 16,
/* Some difference at the UV edge (texture is wrapping in the 2D case
while the 2D array has a black area around) */
50.34f, 0.131f},
{"draw offset, colored",
"multidraw.tga", {},
{},
4, 2, 3, 1,
4, 4, 2, 3, 1,
/* Minor differences on ARM Mali */
3.34f, 0.01f},
{"draw offset, colore, less per-draw lights",
"multidraw.tga", {},
{},
4, 2, 2, 3, 1,
/* Minor differences on ARM Mali */
3.34f, 0.01f},
{"draw offset, colored + object ID",
"multidraw.tga", {1211, 5627, 36363},
PhongGL::Flag::ObjectId,
4, 2, 3, 1,
4, 4, 2, 3, 1,
/* Minor differences on ARM Mali */
3.34f, 0.01f},
{"draw offset, colored + textured object ID",
"multidraw.tga", {3211, 8627, 40363},
PhongGL::Flag::TextureTransformation|PhongGL::Flag::ObjectIdTexture,
4, 2, 3, 1,
4, 4, 2, 3, 1,
/* Minor differences on ARM Mali */
3.34f, 0.01f},
{"draw offset, colored + textured array object ID",
"multidraw.tga", {3211, 8627, 40363},
PhongGL::Flag::TextureTransformation|PhongGL::Flag::ObjectIdTexture|PhongGL::Flag::TextureArrays,
4, 2, 3, 1,
4, 4, 2, 3, 1,
/* Minor differences on ARM Mali */
3.34f, 0.01f},
{"draw offset, textured",
"multidraw-textured.tga", {},
PhongGL::Flag::TextureTransformation|PhongGL::Flag::DiffuseTexture,
4, 2, 3, 1,
4, 4, 2, 3, 1,
/* Minor differences on ARM Mali */
4.67f, 0.02f},
{"draw offset, texture array",
"multidraw-textured.tga", {},
PhongGL::Flag::TextureTransformation|PhongGL::Flag::DiffuseTexture|PhongGL::Flag::TextureArrays,
4, 2, 3, 1,
4, 4, 2, 3, 1,
/* Some difference at the UV edge (texture is wrapping in the 2D case
while the 2D array has a black area around) */
50.34f, 0.131f},
{"multidraw, colored",
"multidraw.tga", {},
PhongGL::Flag::MultiDraw,
4, 2, 3, 1,
4, 4, 2, 3, 1,
/* Minor differences on ARM Mali */
3.34f, 0.01f},
{"multidraw, colored, less per-draw lights",
"multidraw.tga", {},
PhongGL::Flag::MultiDraw,
4, 2, 2, 3, 1,
/* Minor differences on ARM Mali */
3.34f, 0.01f},
{"multidraw, colored + object ID",
"multidraw.tga", {1211, 5627, 36363},
PhongGL::Flag::MultiDraw|PhongGL::Flag::ObjectId,
4, 2, 3, 1,
4, 4, 2, 3, 1,
/* Minor differences on ARM Mali */
3.34f, 0.01f},
{"multidraw, colored + textured object ID",
"multidraw.tga", {3211, 8627, 40363},
PhongGL::Flag::MultiDraw|PhongGL::Flag::TextureTransformation|PhongGL::Flag::ObjectIdTexture,
4, 2, 3, 1,
4, 4, 2, 3, 1,
/* Minor differences on ARM Mali */
3.34f, 0.01f},
{"multidraw, colored + textured array object ID",
"multidraw.tga", {3211, 8627, 40363},
PhongGL::Flag::MultiDraw|PhongGL::Flag::TextureTransformation|PhongGL::Flag::ObjectIdTexture|PhongGL::Flag::TextureArrays,
4, 2, 3, 1,
4, 4, 2, 3, 1,
/* Minor differences on ARM Mali */
3.34f, 0.01f},
{"multidraw, textured",
"multidraw-textured.tga", {},
PhongGL::Flag::MultiDraw|PhongGL::Flag::TextureTransformation|PhongGL::Flag::DiffuseTexture,
4, 2, 3, 1,
4, 4, 2, 3, 1,
/* Minor differences on ARM Mali */
4.67f, 0.02f},
{"multidraw, texture array",
"multidraw-textured.tga", {},
PhongGL::Flag::MultiDraw|PhongGL::Flag::TextureTransformation|PhongGL::Flag::DiffuseTexture|PhongGL::Flag::TextureArrays,
4, 2, 3, 1,
4, 4, 2, 3, 1,
/* Some difference at the UV edge (texture is wrapping in the 2D case
while the 2D array has a black area around) */
50.34f, 0.131f},
@ -1292,16 +1317,18 @@ PhongGLTest::PhongGLTest() {
&PhongGLTest::renderSetup,
&PhongGLTest::renderTeardown);
addTests({
&PhongGLTest::renderLightsSetOneByOne,
&PhongGLTest::renderLowLightAngle,
#ifndef MAGNUM_TARGET_GLES2
&PhongGLTest::renderLightCulling
#endif
},
addTests({&PhongGLTest::renderLightsSetOneByOne,
&PhongGLTest::renderLowLightAngle},
&PhongGLTest::renderSetup,
&PhongGLTest::renderTeardown);
#ifndef MAGNUM_TARGET_GLES2
addInstancedTests({&PhongGLTest::renderLightCulling},
Containers::arraySize(RenderLightCullingData),
&PhongGLTest::renderSetup,
&PhongGLTest::renderTeardown);
#endif
/* MSVC needs explicit type due to default template args */
addTests<PhongGLTest>({
&PhongGLTest::renderZeroLights,
@ -1391,9 +1418,10 @@ void PhongGLTest::construct() {
PhongGL shader{PhongGL::Configuration{}
.setFlags(data.flags)
.setLightCount(data.lightCount)};
.setLightCount(data.lightCount, data.perDrawLightCount)};
CORRADE_COMPARE(shader.flags(), data.flags);
CORRADE_COMPARE(shader.lightCount(), data.lightCount);
CORRADE_COMPARE(shader.perDrawLightCount(), data.perDrawLightCount);
CORRADE_VERIFY(shader.id());
{
#if defined(CORRADE_TARGET_APPLE) && !defined(MAGNUM_TARGET_GLES)
@ -1438,12 +1466,13 @@ void PhongGLTest::constructSkinning() {
void PhongGLTest::constructAsync() {
PhongGL::CompileState state = PhongGL::compile(PhongGL::Configuration{}
.setFlags(PhongGL::Flag::SpecularTexture|PhongGL::Flag::InstancedTextureOffset)
.setLightCount(3)
.setLightCount(3, 2)
/* Skinning properties tested in constructUniformBuffersAsync(), as
there we don't need to bother with ES2 */
);
CORRADE_COMPARE(state.flags(), PhongGL::Flag::SpecularTexture|PhongGL::Flag::InstancedTextureOffset);
CORRADE_COMPARE(state.lightCount(), 3);
CORRADE_COMPARE(state.perDrawLightCount(), 2);
while(!state.isLinkFinished())
Utility::System::sleep(100);
@ -1451,6 +1480,7 @@ void PhongGLTest::constructAsync() {
PhongGL shader{std::move(state)};
CORRADE_COMPARE(shader.flags(), PhongGL::Flag::SpecularTexture|PhongGL::Flag::InstancedTextureOffset);
CORRADE_COMPARE(shader.lightCount(), 3);
CORRADE_COMPARE(shader.perDrawLightCount(), 2);
CORRADE_VERIFY(shader.isLinkFinished());
CORRADE_VERIFY(shader.id());
{
@ -1492,12 +1522,13 @@ void PhongGLTest::constructUniformBuffers() {
PhongGL shader{PhongGL::Configuration{}
.setFlags(data.flags)
.setLightCount(data.lightCount)
.setLightCount(data.lightCount, data.perDrawLightCount)
.setMaterialCount(data.materialCount)
.setDrawCount(data.drawCount)
.setJointCount(data.jointCount, data.perVertexJointCount, data.secondaryPerVertexJointCount)};
CORRADE_COMPARE(shader.flags(), data.flags);
CORRADE_COMPARE(shader.lightCount(), data.lightCount);
CORRADE_COMPARE(shader.perDrawLightCount(), data.perDrawLightCount);
CORRADE_COMPARE(shader.materialCount(), data.materialCount);
CORRADE_COMPARE(shader.drawCount(), data.drawCount);
CORRADE_COMPARE(shader.jointCount(), data.jointCount);
@ -1526,12 +1557,13 @@ void PhongGLTest::constructUniformBuffersAsync() {
.setFlags(PhongGL::Flag::UniformBuffers|PhongGL::Flag::LightCulling)
/* SwiftShader has 256 uniform vectors at most, per-3D-draw is 4+4,
per-material 4, per-light 4, per joint 4 plus 4 for projection */
.setLightCount(2)
.setLightCount(2, 1)
.setMaterialCount(5)
.setDrawCount(24)
.setJointCount(7, 3, 4));
CORRADE_COMPARE(state.flags(), PhongGL::Flag::UniformBuffers|PhongGL::Flag::LightCulling);
CORRADE_COMPARE(state.lightCount(), 2);
CORRADE_COMPARE(state.perDrawLightCount(), 1);
CORRADE_COMPARE(state.materialCount(), 5);
CORRADE_COMPARE(state.drawCount(), 24);
CORRADE_COMPARE(state.jointCount(), 7);
@ -1544,6 +1576,7 @@ void PhongGLTest::constructUniformBuffersAsync() {
PhongGL shader{std::move(state)};
CORRADE_COMPARE(shader.flags(), PhongGL::Flag::UniformBuffers|PhongGL::Flag::LightCulling);
CORRADE_COMPARE(shader.lightCount(), 2);
CORRADE_COMPARE(shader.perDrawLightCount(), 1);
CORRADE_COMPARE(shader.materialCount(), 5);
CORRADE_COMPARE(shader.drawCount(), 24);
CORRADE_COMPARE(shader.jointCount(), 7);
@ -1564,7 +1597,7 @@ void PhongGLTest::constructUniformBuffersAsync() {
void PhongGLTest::constructMove() {
PhongGL a{PhongGL::Configuration{}
.setFlags(PhongGL::Flag::AlphaMask)
.setLightCount(3)
.setLightCount(3, 2)
/* Skinning properties tested in constructMoveUniformBuffers(), as
there we don't need to bother with ES2 */
};
@ -1577,6 +1610,7 @@ void PhongGLTest::constructMove() {
CORRADE_COMPARE(b.id(), id);
CORRADE_COMPARE(b.flags(), PhongGL::Flag::AlphaMask);
CORRADE_COMPARE(b.lightCount(), 3);
CORRADE_COMPARE(b.perDrawLightCount(), 2);
CORRADE_VERIFY(!a.id());
PhongGL c{NoCreate};
@ -1584,6 +1618,7 @@ void PhongGLTest::constructMove() {
CORRADE_COMPARE(c.id(), id);
CORRADE_COMPARE(c.flags(), PhongGL::Flag::AlphaMask);
CORRADE_COMPARE(c.lightCount(), 3);
CORRADE_COMPARE(c.perDrawLightCount(), 2);
CORRADE_VERIFY(!b.id());
}
@ -1598,7 +1633,7 @@ void PhongGLTest::constructMoveUniformBuffers() {
PhongGL a{PhongGL::Configuration{}
.setFlags(PhongGL::Flag::UniformBuffers)
.setLightCount(3)
.setLightCount(5, 3)
.setMaterialCount(2)
.setDrawCount(5)
.setJointCount(16, 4, 3)};
@ -1610,7 +1645,8 @@ void PhongGLTest::constructMoveUniformBuffers() {
PhongGL b{std::move(a)};
CORRADE_COMPARE(b.id(), id);
CORRADE_COMPARE(b.flags(), PhongGL::Flag::UniformBuffers);
CORRADE_COMPARE(b.lightCount(), 3);
CORRADE_COMPARE(b.lightCount(), 5);
CORRADE_COMPARE(b.perDrawLightCount(), 3);
CORRADE_COMPARE(b.materialCount(), 2);
CORRADE_COMPARE(b.drawCount(), 5);
CORRADE_COMPARE(b.jointCount(), 16);
@ -1622,7 +1658,8 @@ void PhongGLTest::constructMoveUniformBuffers() {
c = std::move(b);
CORRADE_COMPARE(c.id(), id);
CORRADE_COMPARE(c.flags(), PhongGL::Flag::UniformBuffers);
CORRADE_COMPARE(c.lightCount(), 3);
CORRADE_COMPARE(c.lightCount(), 5);
CORRADE_COMPARE(c.perDrawLightCount(), 3);
CORRADE_COMPARE(c.materialCount(), 2);
CORRADE_COMPARE(c.drawCount(), 5);
CORRADE_COMPARE(c.jointCount(), 16);
@ -2185,13 +2222,27 @@ template<PhongGL::Flag flag> void PhongGLTest::renderColored() {
PhongGL shader{PhongGL::Configuration{}
.setFlags(flag)
.setLightCount(2)};
.setLightCount(data.lightCount, data.perDrawLightCount)};
if(flag == PhongGL::Flag{}) {
Color3 lightColors[]{
data.lightColor1,
data.lightColor2,
{},
{}
};
Vector4 lightPositions[]{
{data.lightPosition1, -3.0f, 2.0f, 0.0f},
{data.lightPosition2, -3.0f, 2.0f, 0.0f},
{},
{}
};
shader
.setLightColors({data.lightColor1, data.lightColor2})
.setLightPositions({{data.lightPosition1, -3.0f, 2.0f, 0.0f},
{data.lightPosition2, -3.0f, 2.0f, 0.0f}})
.setLightColors(Containers::arrayView(lightColors)
.prefix(data.lightCount))
.setLightPositions(Containers::arrayView(lightPositions)
.prefix(data.lightCount))
.setAmbientColor(0x330033_rgbf)
.setDiffuseColor(0xccffcc_rgbf)
.setSpecularColor(0x6666ff_rgbf)
@ -2229,7 +2280,9 @@ template<PhongGL::Flag flag> void PhongGLTest::renderColored() {
.setColor(data.lightColor1),
PhongLightUniform{}
.setPosition({data.lightPosition2, -3.0f, 2.0f, 0.0f})
.setColor(data.lightColor2)
.setColor(data.lightColor2),
PhongLightUniform{},
PhongLightUniform{}
}};
shader
.bindProjectionBuffer(projectionUniform)
@ -2315,6 +2368,7 @@ template<PhongGL::Flag flag> void PhongGLTest::renderSinglePixelTextured() {
#endif
PhongGL shader{PhongGL::Configuration{}
.setFlags(flags)
/* Different count and per-draw count tested in renderColored() */
.setLightCount(2)};
const Color4ub ambientData[]{ 0x330033_rgb };
@ -2503,6 +2557,7 @@ template<PhongGL::Flag flag> void PhongGLTest::renderTextured() {
#endif
PhongGL shader{PhongGL::Configuration{}
.setFlags(flags)
/* Different count and per-draw count tested in renderColored() */
.setLightCount(2)};
Containers::Pointer<Trade::AbstractImporter> importer = _manager.loadAndInstantiate("AnyImageImporter");
@ -2750,6 +2805,7 @@ template<PhongGL::Flag flag> void PhongGLTest::renderTexturedNormal() {
#endif
PhongGL shader{PhongGL::Configuration{}
.setFlags(flags)
/* Different count and per-draw count tested in renderColored() */
.setLightCount(2)};
GL::Texture2D normal{NoCreate};
@ -2953,6 +3009,7 @@ template<class T, PhongGL::Flag flag> void PhongGLTest::renderVertexColor() {
PhongGL shader{PhongGL::Configuration{}
.setFlags(PhongGL::Flag::DiffuseTexture|PhongGL::Flag::VertexColor|flag)
/* Different count and per-draw count tested in renderColored() */
.setLightCount(2)};
shader.bindDiffuseTexture(diffuse);
@ -3240,6 +3297,7 @@ template<PhongGL::Flag flag> void PhongGLTest::renderAlpha() {
PhongGL shader{PhongGL::Configuration{}
.setFlags(data.flags|flag)
/* Different count and per-draw count tested in renderColored() */
.setLightCount(2)};
shader.bindTextures(&ambient, &diffuse, nullptr, nullptr);
@ -3371,6 +3429,7 @@ template<PhongGL::Flag flag> void PhongGLTest::renderObjectId() {
}
PhongGL shader{PhongGL::Configuration{}
.setFlags(PhongGL::Flag::ObjectId|flags)
/* Different count and per-draw count tested in renderColored() */
.setLightCount(2)};
GL::Texture2D texture{NoCreate};
@ -3535,6 +3594,8 @@ template<PhongGL::Flag flag> void PhongGLTest::renderLights() {
PhongGL shader{PhongGL::Configuration{}
.setFlags(flag)
/* Different count and per-draw count tested in renderColored(), here
it's testing mainly the calculation */
.setLightCount(1)};
if(flag == PhongGL::Flag{}) {
shader
@ -3724,6 +3785,9 @@ void PhongGLTest::renderLowLightAngle() {
#ifndef MAGNUM_TARGET_GLES2
void PhongGLTest::renderLightCulling() {
auto&& data = RenderLightCullingData[testCaseInstanceId()];
setTestCaseDescription(data.name);
#ifndef MAGNUM_TARGET_GLES
if(!GL::Context::current().isExtensionSupported<GL::Extensions::ARB::uniform_buffer_object>())
CORRADE_SKIP(GL::Extensions::ARB::uniform_buffer_object::string() << "is not supported.");
@ -3765,7 +3829,7 @@ void PhongGLTest::renderLightCulling() {
PhongGL shader{PhongGL::Configuration{}
.setFlags(PhongGL::Flag::UniformBuffers|PhongGL::Flag::LightCulling)
.setLightCount(64)};
.setLightCount(data.count, data.perDrawCount)};
shader
.bindProjectionBuffer(projectionUniform)
.bindTransformationBuffer(transformationUniform)
@ -4714,7 +4778,7 @@ void PhongGLTest::renderMulti() {
PhongGL shader{PhongGL::Configuration{}
.setFlags(PhongGL::Flag::UniformBuffers|PhongGL::Flag::LightCulling|data.flags)
.setLightCount(data.lightCount)
.setLightCount(data.lightCount, data.perDrawLightCount)
.setMaterialCount(data.materialCount)
.setDrawCount(data.drawCount)};

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

@ -37,6 +37,7 @@ namespace Magnum { namespace Shaders { namespace Test { namespace {
struct PhongGL_Test: TestSuite::Tester {
explicit PhongGL_Test();
void configurationSetLightCountInvalid();
#ifndef MAGNUM_TARGET_GLES2
void configurationSetJointCountInvalid();
#endif
@ -49,6 +50,22 @@ struct PhongGL_Test: TestSuite::Tester {
void debugFlagsSupersets();
};
const struct {
const char* name;
UnsignedInt count, perDrawCount;
const char* message;
} ConfigurationSetLightCountInvalidData[] {
{"per-draw count larger than count",
10, 11,
"per-draw light count expected to be not larger than total count of 10, got 11"},
{"count but no per-draw count",
10, 0,
"count has to be non-zero iff per-draw count is non-zero"},
{"per-draw count but no count",
0, 2,
"count has to be non-zero iff per-draw count is non-zero"},
};
#ifndef MAGNUM_TARGET_GLES2
const struct {
const char* name;
@ -74,6 +91,9 @@ const struct {
#endif
PhongGL_Test::PhongGL_Test() {
addInstancedTests({&PhongGL_Test::configurationSetLightCountInvalid},
Containers::arraySize(ConfigurationSetLightCountInvalidData));
#ifndef MAGNUM_TARGET_GLES2
addInstancedTests({&PhongGL_Test::configurationSetJointCountInvalid},
Containers::arraySize(ConfigurationSetJointCountInvalidData));
@ -87,6 +107,20 @@ PhongGL_Test::PhongGL_Test() {
&PhongGL_Test::debugFlagsSupersets});
}
void PhongGL_Test::configurationSetLightCountInvalid() {
auto&& data = ConfigurationSetLightCountInvalidData[testCaseInstanceId()];
setTestCaseDescription(data.name);
CORRADE_SKIP_IF_NO_ASSERT();
PhongGL::Configuration configuration;
std::ostringstream out;
Error redirectError{&out};
configuration.setLightCount(data.count, data.perDrawCount);
CORRADE_COMPARE(out.str(), Utility::formatString("Shaders::PhongGL::Configuration::setLightCount(): {}\n", data.message));
}
#ifndef MAGNUM_TARGET_GLES2
void PhongGL_Test::configurationSetJointCountInvalid() {
auto&& data = ConfigurationSetJointCountInvalidData[testCaseInstanceId()];

Loading…
Cancel
Save