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 {
/* 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 =

32
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
};
/**

9
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

24
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<PhongDrawUniform>::value);
CORRADE_VERIFY(std::is_nothrow_constructible<PhongDrawUniform, DefaultInitT>::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<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() {

Loading…
Cancel
Save