From c2a18f290db7f96f5f4b16e66cf1f8435362afbb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Sun, 27 Nov 2022 23:43:24 +0100 Subject: [PATCH] Shaders: pack Phong light offset and count into 16 bits each. To make room for two more 16-bit skinning-related values in the PhongDrawUniform -- joint offset for multidraw and per-instance joint count for instancing. Originally I made those full 32 bits because I wanted to provide an option to have a 64-bit light mask there instead of an offset + count. But the mask is not really driver-friendly as going over the bits and skipping zeros was behaving like if each pixel was affected by 64 lights -- an absolute perf nightmare. I might reconsider this again later, but for now that doesn't seem to make sense, and I need to put the skinning-related info somewhere without inflating the per-draw uniform by another 16-byte vector. --- src/Magnum/Shaders/Phong.frag | 16 ++++++++------ src/Magnum/Shaders/Phong.h | 32 ++++++++++++++++++++++----- src/Magnum/Shaders/Phong.vert | 9 ++++---- src/Magnum/Shaders/Test/PhongTest.cpp | 24 +++++++++++++------- 4 files changed, 55 insertions(+), 26 deletions(-) diff --git a/src/Magnum/Shaders/Phong.frag b/src/Magnum/Shaders/Phong.frag index 0aa6c8db6..58ab39df2 100644 --- a/src/Magnum/Shaders/Phong.frag +++ b/src/Magnum/Shaders/Phong.frag @@ -183,11 +183,10 @@ uniform highp uint drawOffset struct DrawUniform { /* Can't be a mat3 because of ANGLE, see Phong.vert for details */ mediump mat3x4 normalMatrix; - highp uvec4 materialIdReservedObjectIdLightOffsetLightCount; - #define draw_materialIdReserved materialIdReservedObjectIdLightOffsetLightCount.x - #define draw_objectId materialIdReservedObjectIdLightOffsetLightCount.y - #define draw_lightOffset materialIdReservedObjectIdLightOffsetLightCount.z - #define draw_lightCount materialIdReservedObjectIdLightOffsetLightCount.w + highp uvec4 materialIdReservedObjectIdLightOffsetLightCountReserved; + #define draw_materialIdReserved materialIdReservedObjectIdLightOffsetLightCountReserved.x + #define draw_objectId materialIdReservedObjectIdLightOffsetLightCountReserved.y + #define draw_lightOffsetLightCount materialIdReservedObjectIdLightOffsetLightCountReserved.z }; layout(std140 @@ -382,7 +381,10 @@ void main() { lowp const float alphaMask = materials[materialId].material_alphaMask; #endif #if LIGHT_COUNT - mediump const uint lightOffset = draws[drawId].draw_lightOffset; + mediump const uint lightOffset = draws[drawId].draw_lightOffsetLightCount & 0xffffu; + #ifdef LIGHT_CULLING + mediump const uint lightCount = draws[drawId].draw_lightOffsetLightCount >> 16 & 0xffffu; + #endif #endif #endif @@ -444,7 +446,7 @@ void main() { #ifndef LIGHT_CULLING for(int i = 0; i < LIGHT_COUNT; ++i) #else - for(uint i = 0u, actualLightCount = min(uint(LIGHT_COUNT), draws[drawId].draw_lightCount); i < actualLightCount; ++i) + for(uint i = 0u, actualLightCount = min(uint(LIGHT_COUNT), lightCount); i < actualLightCount; ++i) #endif { lowp const vec3 lightColor = diff --git a/src/Magnum/Shaders/Phong.h b/src/Magnum/Shaders/Phong.h index 00f39decb..01afdad48 100644 --- a/src/Magnum/Shaders/Phong.h +++ b/src/Magnum/Shaders/Phong.h @@ -55,7 +55,13 @@ separate @ref PhongMaterialUniform structure, referenced by @ref materialId. */ struct PhongDrawUniform { /** @brief Construct with default parameters */ - constexpr explicit PhongDrawUniform(DefaultInitT = DefaultInit) noexcept: normalMatrix{Math::IdentityInit}, materialId{0}, objectId{0}, lightOffset{0}, lightCount{0xffffffffu} {} + constexpr explicit PhongDrawUniform(DefaultInitT = DefaultInit) noexcept: normalMatrix{Math::IdentityInit}, materialId{0}, objectId{0}, + #ifndef CORRADE_TARGET_BIG_ENDIAN + lightOffset{0}, lightCount{0xffffu} + #else + lightCount{0xffffu}, lightOffset{0} + #endif + {} /** @brief Construct without initializing the contents */ explicit PhongDrawUniform(NoInitT) noexcept: normalMatrix{NoInit} {} @@ -168,7 +174,7 @@ struct PhongDrawUniform { */ UnsignedInt objectId; - /** + /** @var lightOffset * @brief Light offset * * References the first light in the @ref PhongLightUniform array. Should @@ -178,20 +184,34 @@ struct PhongDrawUniform { * Used only if @ref PhongGL::Flag::LightCulling is enabled, otherwise * light offset is implicitly @cpp 0 @ce. */ - UnsignedInt lightOffset; - /** + /** @var lightCount * @brief Light count * * Specifies how many lights after the @p lightOffset are used from the * @ref PhongLightUniform array. Gets clamped by the shader so it's * together with @ref lightOffset not larger than the light count passed to - * @ref PhongGL constructor. Default value is @cpp 0xffffffffu @ce. + * @ref PhongGL constructor. Default value is @cpp 0xffffu @ce. * * Used only if @ref PhongGL::Flag::LightCulling is enabled, otherwise * light count is implicitly @ref PhongGL::lightCount(). */ - UnsignedInt lightCount; + + /* This field is an UnsignedInt in the shader and lightOffset is extracted + as (value & 0xffff), so the order has to be different on BE */ + #ifndef CORRADE_TARGET_BIG_ENDIAN + UnsignedShort lightOffset; + UnsignedShort lightCount; + #else + UnsignedShort lightCount; + UnsignedShort lightOffset; + #endif + + /* warning: Member __pad1__ is not documented. FFS DOXYGEN WHY DO YOU THINK + I MADE THOSE UNNAMED, YOU DUMB FOOL */ + #ifndef DOXYGEN_GENERATING_OUTPUT + Int:32; + #endif }; /** diff --git a/src/Magnum/Shaders/Phong.vert b/src/Magnum/Shaders/Phong.vert index e4e4be0bd..e8d23e2a4 100644 --- a/src/Magnum/Shaders/Phong.vert +++ b/src/Magnum/Shaders/Phong.vert @@ -132,11 +132,10 @@ struct DrawUniform { 2. Forget to actually implement and test the damn thing. */ mediump mat3x4 normalMatrix; - highp uvec4 materialIdReservedObjectIdLightOffsetLightCount; - #define draw_materialIdReserved materialIdReservedObjectIdLightOffsetLightCount.x - #define draw_objectId materialIdReservedObjectIdLightOffsetLightCount.y - #define draw_lightOffset materialIdReservedObjectIdLightOffsetLightCount.z - #define draw_lightCount materialIdReservedObjectIdLightOffsetLightCount.w + highp uvec4 materialIdReservedObjectIdLightOffsetLightCountReserved; + #define draw_materialIdReserved materialIdReservedObjectIdLightOffsetLightCountReserved.x + #define draw_objectId materialIdReservedObjectIdLightOffsetLightCountReserved.y + #define draw_lightOffsetLightCount materialIdReservedObjectIdLightOffsetLightCountReserved.z }; layout(std140 diff --git a/src/Magnum/Shaders/Test/PhongTest.cpp b/src/Magnum/Shaders/Test/PhongTest.cpp index 0950e089b..0a4e4e40d 100644 --- a/src/Magnum/Shaders/Test/PhongTest.cpp +++ b/src/Magnum/Shaders/Test/PhongTest.cpp @@ -39,7 +39,7 @@ struct PhongTest: TestSuite::Tester { void drawUniformConstructDefault(); void drawUniformConstructNoInit(); void drawUniformSetters(); - void drawUniformMaterialIdPacking(); + void drawUniformPacking(); void materialUniformConstructDefault(); void materialUniformConstructNoInit(); @@ -58,7 +58,7 @@ PhongTest::PhongTest() { &PhongTest::drawUniformConstructDefault, &PhongTest::drawUniformConstructNoInit, &PhongTest::drawUniformSetters, - &PhongTest::drawUniformMaterialIdPacking, + &PhongTest::drawUniformPacking, &PhongTest::materialUniformConstructDefault, &PhongTest::materialUniformConstructNoInit, @@ -115,8 +115,8 @@ void PhongTest::drawUniformConstructDefault() { CORRADE_COMPARE(b.objectId, 0); CORRADE_COMPARE(a.lightOffset, 0); CORRADE_COMPARE(b.lightOffset, 0); - CORRADE_COMPARE(a.lightCount, 0xffffffffu); - CORRADE_COMPARE(b.lightCount, 0xffffffffu); + CORRADE_COMPARE(a.lightCount, 0xffffu); + CORRADE_COMPARE(b.lightCount, 0xffffu); constexpr PhongDrawUniform ca; constexpr PhongDrawUniform cb{DefaultInit}; @@ -136,8 +136,8 @@ void PhongTest::drawUniformConstructDefault() { CORRADE_COMPARE(cb.objectId, 0); CORRADE_COMPARE(ca.lightOffset, 0); CORRADE_COMPARE(cb.lightOffset, 0); - CORRADE_COMPARE(ca.lightCount, 0xffffffffu); - CORRADE_COMPARE(cb.lightCount, 0xffffffffu); + CORRADE_COMPARE(ca.lightCount, 0xffffu); + CORRADE_COMPARE(cb.lightCount, 0xffffu); CORRADE_VERIFY(std::is_nothrow_default_constructible::value); CORRADE_VERIFY(std::is_nothrow_constructible::value); @@ -189,12 +189,20 @@ void PhongTest::drawUniformSetters() { CORRADE_COMPARE(a.lightCount, 13); } -void PhongTest::drawUniformMaterialIdPacking() { +void PhongTest::drawUniformPacking() { PhongDrawUniform a; - a.setMaterialId(13765); + a.setMaterialId(13765) + /* second 16 bits unused */ + .setLightOffsetCount(13766, 63573); /* The normalMatrix field is 3x4 floats, materialId should be right after in the low 16 bits on both LE and BE */ CORRADE_COMPARE(reinterpret_cast(&a)[12] & 0xffff, 13765); + /* second 16 bits unused */ + + /* lightOffset should be in the low 16 bits on both LE and BE, lightCount + in the high */ + CORRADE_COMPARE(reinterpret_cast(&a)[14] & 0xffff, 13766); + CORRADE_COMPARE((reinterpret_cast(&a)[14] >> 16) & 0xffff, 63573); } void PhongTest::materialUniformConstructDefault() {