Browse Source

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.
pull/499/head
Vladimír Vondruš 3 years ago
parent
commit
c2a18f290d
  1. 16
      src/Magnum/Shaders/Phong.frag
  2. 32
      src/Magnum/Shaders/Phong.h
  3. 9
      src/Magnum/Shaders/Phong.vert
  4. 24
      src/Magnum/Shaders/Test/PhongTest.cpp

16
src/Magnum/Shaders/Phong.frag

@ -183,11 +183,10 @@ uniform highp uint drawOffset
struct DrawUniform { struct DrawUniform {
/* Can't be a mat3 because of ANGLE, see Phong.vert for details */ /* Can't be a mat3 because of ANGLE, see Phong.vert for details */
mediump mat3x4 normalMatrix; mediump mat3x4 normalMatrix;
highp uvec4 materialIdReservedObjectIdLightOffsetLightCount; highp uvec4 materialIdReservedObjectIdLightOffsetLightCountReserved;
#define draw_materialIdReserved materialIdReservedObjectIdLightOffsetLightCount.x #define draw_materialIdReserved materialIdReservedObjectIdLightOffsetLightCountReserved.x
#define draw_objectId materialIdReservedObjectIdLightOffsetLightCount.y #define draw_objectId materialIdReservedObjectIdLightOffsetLightCountReserved.y
#define draw_lightOffset materialIdReservedObjectIdLightOffsetLightCount.z #define draw_lightOffsetLightCount materialIdReservedObjectIdLightOffsetLightCountReserved.z
#define draw_lightCount materialIdReservedObjectIdLightOffsetLightCount.w
}; };
layout(std140 layout(std140
@ -382,7 +381,10 @@ void main() {
lowp const float alphaMask = materials[materialId].material_alphaMask; lowp const float alphaMask = materials[materialId].material_alphaMask;
#endif #endif
#if LIGHT_COUNT #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
#endif #endif
@ -444,7 +446,7 @@ void main() {
#ifndef LIGHT_CULLING #ifndef LIGHT_CULLING
for(int i = 0; i < LIGHT_COUNT; ++i) for(int i = 0; i < LIGHT_COUNT; ++i)
#else #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 #endif
{ {
lowp const vec3 lightColor = lowp const vec3 lightColor =

32
src/Magnum/Shaders/Phong.h

@ -55,7 +55,13 @@ separate @ref PhongMaterialUniform structure, referenced by @ref materialId.
*/ */
struct PhongDrawUniform { struct PhongDrawUniform {
/** @brief Construct with default parameters */ /** @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 */ /** @brief Construct without initializing the contents */
explicit PhongDrawUniform(NoInitT) noexcept: normalMatrix{NoInit} {} explicit PhongDrawUniform(NoInitT) noexcept: normalMatrix{NoInit} {}
@ -168,7 +174,7 @@ struct PhongDrawUniform {
*/ */
UnsignedInt objectId; UnsignedInt objectId;
/** /** @var lightOffset
* @brief Light offset * @brief Light offset
* *
* References the first light in the @ref PhongLightUniform array. Should * 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 * Used only if @ref PhongGL::Flag::LightCulling is enabled, otherwise
* light offset is implicitly @cpp 0 @ce. * light offset is implicitly @cpp 0 @ce.
*/ */
UnsignedInt lightOffset;
/** /** @var lightCount
* @brief Light count * @brief Light count
* *
* Specifies how many lights after the @p lightOffset are used from the * Specifies how many lights after the @p lightOffset are used from the
* @ref PhongLightUniform array. Gets clamped by the shader so it's * @ref PhongLightUniform array. Gets clamped by the shader so it's
* together with @ref lightOffset not larger than the light count passed to * 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 * Used only if @ref PhongGL::Flag::LightCulling is enabled, otherwise
* light count is implicitly @ref PhongGL::lightCount(). * 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
}; };
/** /**

9
src/Magnum/Shaders/Phong.vert

@ -132,11 +132,10 @@ struct DrawUniform {
2. Forget to actually implement and test the damn thing. 2. Forget to actually implement and test the damn thing.
*/ */
mediump mat3x4 normalMatrix; mediump mat3x4 normalMatrix;
highp uvec4 materialIdReservedObjectIdLightOffsetLightCount; highp uvec4 materialIdReservedObjectIdLightOffsetLightCountReserved;
#define draw_materialIdReserved materialIdReservedObjectIdLightOffsetLightCount.x #define draw_materialIdReserved materialIdReservedObjectIdLightOffsetLightCountReserved.x
#define draw_objectId materialIdReservedObjectIdLightOffsetLightCount.y #define draw_objectId materialIdReservedObjectIdLightOffsetLightCountReserved.y
#define draw_lightOffset materialIdReservedObjectIdLightOffsetLightCount.z #define draw_lightOffsetLightCount materialIdReservedObjectIdLightOffsetLightCountReserved.z
#define draw_lightCount materialIdReservedObjectIdLightOffsetLightCount.w
}; };
layout(std140 layout(std140

24
src/Magnum/Shaders/Test/PhongTest.cpp

@ -39,7 +39,7 @@ struct PhongTest: TestSuite::Tester {
void drawUniformConstructDefault(); void drawUniformConstructDefault();
void drawUniformConstructNoInit(); void drawUniformConstructNoInit();
void drawUniformSetters(); void drawUniformSetters();
void drawUniformMaterialIdPacking(); void drawUniformPacking();
void materialUniformConstructDefault(); void materialUniformConstructDefault();
void materialUniformConstructNoInit(); void materialUniformConstructNoInit();
@ -58,7 +58,7 @@ PhongTest::PhongTest() {
&PhongTest::drawUniformConstructDefault, &PhongTest::drawUniformConstructDefault,
&PhongTest::drawUniformConstructNoInit, &PhongTest::drawUniformConstructNoInit,
&PhongTest::drawUniformSetters, &PhongTest::drawUniformSetters,
&PhongTest::drawUniformMaterialIdPacking, &PhongTest::drawUniformPacking,
&PhongTest::materialUniformConstructDefault, &PhongTest::materialUniformConstructDefault,
&PhongTest::materialUniformConstructNoInit, &PhongTest::materialUniformConstructNoInit,
@ -115,8 +115,8 @@ void PhongTest::drawUniformConstructDefault() {
CORRADE_COMPARE(b.objectId, 0); CORRADE_COMPARE(b.objectId, 0);
CORRADE_COMPARE(a.lightOffset, 0); CORRADE_COMPARE(a.lightOffset, 0);
CORRADE_COMPARE(b.lightOffset, 0); CORRADE_COMPARE(b.lightOffset, 0);
CORRADE_COMPARE(a.lightCount, 0xffffffffu); CORRADE_COMPARE(a.lightCount, 0xffffu);
CORRADE_COMPARE(b.lightCount, 0xffffffffu); CORRADE_COMPARE(b.lightCount, 0xffffu);
constexpr PhongDrawUniform ca; constexpr PhongDrawUniform ca;
constexpr PhongDrawUniform cb{DefaultInit}; constexpr PhongDrawUniform cb{DefaultInit};
@ -136,8 +136,8 @@ void PhongTest::drawUniformConstructDefault() {
CORRADE_COMPARE(cb.objectId, 0); CORRADE_COMPARE(cb.objectId, 0);
CORRADE_COMPARE(ca.lightOffset, 0); CORRADE_COMPARE(ca.lightOffset, 0);
CORRADE_COMPARE(cb.lightOffset, 0); CORRADE_COMPARE(cb.lightOffset, 0);
CORRADE_COMPARE(ca.lightCount, 0xffffffffu); CORRADE_COMPARE(ca.lightCount, 0xffffu);
CORRADE_COMPARE(cb.lightCount, 0xffffffffu); CORRADE_COMPARE(cb.lightCount, 0xffffu);
CORRADE_VERIFY(std::is_nothrow_default_constructible<PhongDrawUniform>::value); CORRADE_VERIFY(std::is_nothrow_default_constructible<PhongDrawUniform>::value);
CORRADE_VERIFY(std::is_nothrow_constructible<PhongDrawUniform, DefaultInitT>::value); CORRADE_VERIFY(std::is_nothrow_constructible<PhongDrawUniform, DefaultInitT>::value);
@ -189,12 +189,20 @@ void PhongTest::drawUniformSetters() {
CORRADE_COMPARE(a.lightCount, 13); CORRADE_COMPARE(a.lightCount, 13);
} }
void PhongTest::drawUniformMaterialIdPacking() { void PhongTest::drawUniformPacking() {
PhongDrawUniform a; 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 /* The normalMatrix field is 3x4 floats, materialId should be right after
in the low 16 bits on both LE and BE */ in the low 16 bits on both LE and BE */
CORRADE_COMPARE(reinterpret_cast<UnsignedInt*>(&a)[12] & 0xffff, 13765); CORRADE_COMPARE(reinterpret_cast<UnsignedInt*>(&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<UnsignedInt*>(&a)[14] & 0xffff, 13766);
CORRADE_COMPARE((reinterpret_cast<UnsignedInt*>(&a)[14] >> 16) & 0xffff, 63573);
} }
void PhongTest::materialUniformConstructDefault() { void PhongTest::materialUniformConstructDefault() {

Loading…
Cancel
Save