diff --git a/filament/src/Froxelizer.cpp b/filament/src/Froxelizer.cpp index df87fbfe1c..cd5b56076f 100644 --- a/filament/src/Froxelizer.cpp +++ b/filament/src/Froxelizer.cpp @@ -43,8 +43,21 @@ using namespace driver; namespace details { +/* + * This enables froxels to be rectangular which allows us to use a but more froxel + * with the same amount of memory in the GPU. + * This requires backward compatibility breaking changes in the shaders. + */ static constexpr bool SUPPORTS_NON_SQUARE_FROXELS = false; +/* + * This changes the layout of the froxel info on the GPU such that it is more cache friendly, + * i.e. the major axis is Z instead of X, because in a given froxel there is more chance to + * hit another froxel at the same x,y coordinate. + * This requires backward compatibility breaking changes in the shaders. + */ +static constexpr bool SUPPORTS_REMAPPED_FROXELS = false; + // The Froxel buffer is set to FROXEL_BUFFER_WIDTH x n // With n limited by the supported texture dimension, which is guaranteed to be at least 2048 // in all version of GLES. @@ -153,10 +166,9 @@ bool Froxelizer::prepare( */ // froxel buffer (~32 KiB) - const uint32_t maxFroxelCount = FROXEL_BUFFER_WIDTH * FROXEL_BUFFER_HEIGHT; mFroxelBufferUser = { - driverApi.allocatePod(maxFroxelCount, CACHELINE_SIZE), - maxFroxelCount }; + driverApi.allocatePod(FROXEL_BUFFER_ENTRY_COUNT_MAX, CACHELINE_SIZE), + FROXEL_BUFFER_ENTRY_COUNT_MAX }; // record buffer (~64 KiB) mRecordBufferUser = { @@ -184,9 +196,9 @@ bool Froxelizer::prepare( assert(mFroxelShardedData.begin()); #ifndef NDEBUG - memset(mFroxelBufferUser.data(), 0x55, mFroxelBufferUser.sizeInBytes()); - memset(mRecordBufferUser.data(), 0xEB, mRecordBufferUser.sizeInBytes()); - memset(mFroxelShardedData.data(), 0xAA, mFroxelShardedData.sizeInBytes()); + memset(mFroxelBufferUser.data(), 0x55, mFroxelBufferUser.sizeInBytes()); + memset(mRecordBufferUser.data(), 0xEB, mRecordBufferUser.sizeInBytes()); + memset(mFroxelShardedData.data(), 0xFD, mFroxelShardedData.sizeInBytes()); #endif return uniformsNeedUpdating; @@ -266,6 +278,7 @@ bool Froxelizer::update() noexcept { mFroxelCountZ = froxelCountZ; // froxel count must fit on 16 bits const uint16_t froxelCount = uint16_t(froxelCountX * froxelCountY * froxelCountZ); + mFroxelCount = froxelCount; if (mDistancesZ) { // this is a LinearAllocator arena, use rewind() instead of free (which is a no op). @@ -307,8 +320,15 @@ bool Froxelizer::update() noexcept { mParamsZ[1] = 0; // updated when camera changes mParamsZ[2] = -mLinearizer; mParamsZ[3] = mFroxelCountZ; - mParamsF[0] = uint32_t(mFroxelCountX); - mParamsF[1] = uint32_t(mFroxelCountX * mFroxelCountY); + if (SUPPORTS_REMAPPED_FROXELS) { + mParamsF.x = uint32_t(mFroxelCountZ); + mParamsF.y = uint32_t(mFroxelCountX * mFroxelCountZ); + mParamsF.z = 1; + } else { + mParamsF[0] = 1; + mParamsF[1] = uint32_t(mFroxelCountX); + mParamsF[2] = uint32_t(mFroxelCountX * mFroxelCountY); + } } if (UTILS_UNLIKELY(mDirtyFlags & (PROJECTION_CHANGED | VIEWPORT_CHANGED))) { @@ -523,8 +543,10 @@ void Froxelizer::froxelizeLights(FEngine& engine, #ifndef NDEBUG if (lightData.size()) { // go through every froxel - auto const& gpuFroxelEntries(mFroxelBufferUser); auto const& recordBufferUser(mRecordBufferUser); + auto gpuFroxelEntries(mFroxelBufferUser); + gpuFroxelEntries.set(gpuFroxelEntries.begin(), + mFroxelCountX * mFroxelCountY * mFroxelCountZ); for (auto const& entry : gpuFroxelEntries) { // go through every lights for that froxel for (size_t i = 0; i < entry.pointLightCount + entry.spotLightCount; i++) { @@ -639,14 +661,22 @@ void Froxelizer::froxelizeAssignRecordsCompress() noexcept { } uint16_t offset = 0; - Slice gpuFroxelEntries(mFroxelBufferUser); - FroxelEntry* const UTILS_RESTRICT froxels = gpuFroxelEntries.data(); - RecordBufferType* UTILS_RESTRICT froxelRecords = mRecordBufferUser.data(); + FroxelEntry* const UTILS_RESTRICT froxels = mFroxelBufferUser.data(); + + auto remap = [stride = size_t(mFroxelCountX * mFroxelCountY)](size_t i) { + if (SUPPORTS_REMAPPED_FROXELS) { + // TODO: with the non-square froxel change these would be mask ops instead of divide. + i = (i % stride) * FEngine::CONFIG_FROXEL_SLICE_COUNT + (i / stride); + } + return i; + }; + + RecordBufferType* const UTILS_RESTRICT froxelRecords = mRecordBufferUser.data(); // how many froxel record entries were reused (for debugging) UTILS_UNUSED size_t reused = FROXEL_BUFFER_ENTRY_COUNT_MAX; - for (size_t i = 0, c = records.size(); i < c;) { + for (size_t i = 0, c = getFroxelCount(); i < c;) { #ifndef NDEBUG reused--; #endif @@ -665,8 +695,8 @@ void Froxelizer::froxelizeAssignRecordsCompress() noexcept { #endif // note: instead of dropping froxels we could look for similar records we've already // filed up. - do { // this compiles to memset() - froxels[i++].u32 = 0; + do { // this compiles to memset() when remap() is identity + froxels[remap(i++)].u32 = 0; } while(i < c); goto out_of_memory; } @@ -697,7 +727,7 @@ void Froxelizer::froxelizeAssignRecordsCompress() noexcept { // note: we can't use partition_point() here because we're not sorted do { - froxels[i++].u32 = entry.u32; + froxels[remap(i++)].u32 = entry.u32; } while(i < c && records[i].lights == b.lights); } out_of_memory: diff --git a/filament/src/details/Engine.h b/filament/src/details/Engine.h index 78ea1dc4ec..0101585ef9 100644 --- a/filament/src/details/Engine.h +++ b/filament/src/details/Engine.h @@ -129,14 +129,14 @@ public: math::float4 sun; // cos(sunAngle), sin(sunAngle), 1/(sunAngle*HALO_SIZE-sunAngle), HALO_EXP math::float3 lightDirection; - float padding1; + uint32_t fParamsX; // stride-x math::float3 shadowBias; // constant bias, normal bias, unused float oneOverFroxelDimensionY; math::float4 zParams; // froxel Z parameters - math::uint2 fParams; // froxelCountX, froxelCountX * froxelCountY + math::uint2 fParams; // stride-y, stride-z math::float2 origin; // viewport left, viewport bottom float oneOverFroxelDimensionX; diff --git a/filament/src/details/Froxelizer.h b/filament/src/details/Froxelizer.h index 01f70f713d..0a6ccdd1cd 100644 --- a/filament/src/details/Froxelizer.h +++ b/filament/src/details/Froxelizer.h @@ -117,6 +117,7 @@ public: size_t getFroxelCountX() const noexcept { return mFroxelCountX; } size_t getFroxelCountY() const noexcept { return mFroxelCountY; } size_t getFroxelCountZ() const noexcept { return mFroxelCountZ; } + size_t getFroxelCount() const noexcept { return mFroxelCount; } // update Records and Froxels texture with lights data. this is thread-safe. void froxelizeLights(FEngine& engine, math::mat4f const& viewMatrix, @@ -124,7 +125,8 @@ public: void updateUniforms(UniformBuffer& u) { u.setUniform(offsetof(FEngine::PerViewUib, zParams), mParamsZ); - u.setUniform(offsetof(FEngine::PerViewUib, fParams), mParamsF); + u.setUniform(offsetof(FEngine::PerViewUib, fParams), mParamsF.yz); + u.setUniform(offsetof(FEngine::PerViewUib, fParamsX), mParamsF.x); u.setUniform(offsetof(FEngine::PerViewUib, oneOverFroxelDimensionX), mOneOverDimension.x); u.setUniform(offsetof(FEngine::PerViewUib, oneOverFroxelDimensionY), mOneOverDimension.y); } @@ -224,6 +226,7 @@ private: uint16_t mFroxelCountX = 0; uint16_t mFroxelCountY = 0; uint16_t mFroxelCountZ = 0; + uint16_t mFroxelCount = 0; math::uint2 mFroxelDimension = {}; math::mat4f mProjection; @@ -238,7 +241,7 @@ private: // needed for update() Viewport mViewport; math::float4 mParamsZ = {}; - math::uint4 mParamsF = {}; + math::uint3 mParamsF = {}; float mNear = 0.0f; // camera near float mZLightFar = FEngine::CONFIG_Z_LIGHT_FAR; float mZLightNear = FEngine::CONFIG_Z_LIGHT_NEAR; // light near (first slice) diff --git a/libs/filabridge/src/UibGenerator.cpp b/libs/filabridge/src/UibGenerator.cpp index 9767ab0576..83a9c6f5c2 100644 --- a/libs/filabridge/src/UibGenerator.cpp +++ b/libs/filabridge/src/UibGenerator.cpp @@ -43,7 +43,7 @@ UniformInterfaceBlock& UibGenerator::getPerViewUib() noexcept { .add("lightColorIntensity", 1, UniformInterfaceBlock::Type::FLOAT4) .add("sun", 1, UniformInterfaceBlock::Type::FLOAT4) .add("lightDirection", 1, UniformInterfaceBlock::Type::FLOAT3) - .add("padding1", 1, UniformInterfaceBlock::Type::FLOAT) + .add("fParamsX", 1, UniformInterfaceBlock::Type::UINT) // shadow .add("shadowBias", 1, UniformInterfaceBlock::Type::FLOAT3) .add("oneOverFroxelDimensionY", 1, UniformInterfaceBlock::Type::FLOAT)