diff --git a/src/Magnum/Shaders/Phong.frag b/src/Magnum/Shaders/Phong.frag index 37af369ef..61a387292 100644 --- a/src/Magnum/Shaders/Phong.frag +++ b/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 = diff --git a/src/Magnum/Shaders/PhongGL.cpp b/src/Magnum/Shaders/PhongGL.cpp index 098713789..1dd10d82f 100644 --- a/src/Magnum/Shaders/PhongGL.cpp +++ b/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(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(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, diff --git a/src/Magnum/Shaders/PhongGL.h b/src/Magnum/Shaders/PhongGL.h index 5f8d61659..9c17cb8c9 100644 --- a/src/Magnum/Shaders/PhongGL.h +++ b/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, diff --git a/src/Magnum/Shaders/Test/PhongGLTest.cpp b/src/Magnum/Shaders/Test/PhongGLTest.cpp index 55d286cc2..a350473d6 100644 --- a/src/Magnum/Shaders/Test/PhongGLTest.cpp +++ b/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::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 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 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 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 void PhongGLTest::renderTextured() { #endif PhongGL shader{PhongGL::Configuration{} .setFlags(flags) + /* Different count and per-draw count tested in renderColored() */ .setLightCount(2)}; Containers::Pointer importer = _manager.loadAndInstantiate("AnyImageImporter"); @@ -2750,6 +2805,7 @@ template 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 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 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 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 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()) 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)}; diff --git a/src/Magnum/Shaders/Test/PhongGL_Test.cpp b/src/Magnum/Shaders/Test/PhongGL_Test.cpp index 10c638388..f655894c4 100644 --- a/src/Magnum/Shaders/Test/PhongGL_Test.cpp +++ b/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()];