From 4d9788ffb9bbbb37784116d9307542e37ccc4e31 Mon Sep 17 00:00:00 2001 From: Mathias Agopian Date: Fri, 7 Dec 2018 12:24:28 -0800 Subject: [PATCH] improve skinning memory usage and udpates - use the exact required size for bone data instead of always the max of 256 bones. This also reduces the amount of data to update and copy into the command stream. - also get rid of the "reuse component" optimization, which is less needed now that renderables don't have their own transform UBO. --- filament/src/UniformBuffer.h | 4 ++ filament/src/components/RenderableManager.cpp | 61 ++++++++----------- filament/src/components/RenderableManager.h | 18 ++++-- 3 files changed, 41 insertions(+), 42 deletions(-) diff --git a/filament/src/UniformBuffer.h b/filament/src/UniformBuffer.h index cac637301a..7b5e4c783e 100644 --- a/filament/src/UniformBuffer.h +++ b/filament/src/UniformBuffer.h @@ -72,6 +72,10 @@ public: return static_cast(mBuffer) + offset; } + void* invalidate() noexcept { + return invalidateUniforms(0, mSize); + } + // pointer to the uniform buffer void const* getBuffer() const noexcept { return mBuffer; } diff --git a/filament/src/components/RenderableManager.cpp b/filament/src/components/RenderableManager.cpp index a5028fe10c..28261beba5 100644 --- a/filament/src/components/RenderableManager.cpp +++ b/filament/src/components/RenderableManager.cpp @@ -255,21 +255,10 @@ void FRenderableManager::create( auto& manager = mManager; FEngine::DriverApi& driver = engine.getDriverApi(); - // If we already have an instance we can reuse parts of it without completely - // destroying it. In particular we can reuse the UBO since it's the same for - // all renderables - bool canReuse = false; - Instance ci = getInstance(entity); - if (UTILS_UNLIKELY(ci)) { - canReuse = true; - destroyComponentPrimitives(engine, manager[ci].primitives); - std::unique_ptr const& bones = manager[ci].bones; - if (bones && !builder->mSkinningBoneCount) { - driver.destroyUniformBuffer(bones->handle); - } + if (UTILS_UNLIKELY(manager.hasComponent(entity))) { + destroy(entity); } - - ci = manager.addComponent(entity); + Instance ci = manager.addComponent(entity); assert(ci); if (ci) { @@ -288,31 +277,29 @@ void FRenderableManager::create( setCastShadows(ci, builder->mCastShadows); setReceiveShadows(ci, builder->mReceiveShadows); setCulling(ci, builder->mCulling); - static_cast(manager[ci].visibility).skinning = builder->mSkinningBoneCount > 0; + setSkinning(ci, false); - if (!canReuse) { - if (builder->mSkinningBoneCount) { - std::unique_ptr& bones = manager[ci].bones; - - bones.reset(new Bones); // FIXME: maybe use a pool allocator - bones->bones = UniformBuffer(CONFIG_MAX_BONE_COUNT * sizeof(PerRenderableUibBone)); - bones->handle = driver.createUniformBuffer(CONFIG_MAX_BONE_COUNT * sizeof(PerRenderableUibBone), - driver::BufferUsage::DYNAMIC); - } - } - if (builder->mSkinningBoneCount) { - std::unique_ptr const& bones = manager[ci].bones; + const size_t count = builder->mSkinningBoneCount; + if (UTILS_UNLIKELY(count)) { + std::unique_ptr& bones = manager[ci].bones; + bones = std::unique_ptr(new Bones{ + driver.createUniformBuffer(count * sizeof(PerRenderableUibBone), + driver::BufferUsage::DYNAMIC), + UniformBuffer{ count * sizeof(PerRenderableUibBone) }, + (uint8_t)count + }); assert(bones); - bones->count = (uint8_t)builder->mSkinningBoneCount; - if (builder->mUserBones) { - setBones(ci, builder->mUserBones, bones->count); - } else if (builder->mUserBoneMatrices) { - setBones(ci, builder->mUserBoneMatrices, bones->count); - } else { - // initialize the bones to identity - PerRenderableUibBone* UTILS_RESTRICT out = - (PerRenderableUibBone*)bones->bones.invalidateUniforms(0, bones->count * sizeof(PerRenderableUibBone)); - std::uninitialized_fill_n(out, bones->count, PerRenderableUibBone{}); + if (bones) { + setSkinning(ci, true); + if (builder->mUserBones) { + setBones(ci, builder->mUserBones, count); + } else if (builder->mUserBoneMatrices) { + setBones(ci, builder->mUserBoneMatrices, count); + } else { + // initialize the bones to identity + PerRenderableUibBone* out = (PerRenderableUibBone*)bones->bones.invalidate(); + std::uninitialized_fill_n(out, count, PerRenderableUibBone{}); + } } } } diff --git a/filament/src/components/RenderableManager.h b/filament/src/components/RenderableManager.h index 5c60070f42..e3e572f6d0 100644 --- a/filament/src/components/RenderableManager.h +++ b/filament/src/components/RenderableManager.h @@ -99,6 +99,7 @@ public: inline void setLayerMask(Instance instance, uint8_t layerMask) noexcept; inline void setReceiveShadows(Instance instance, bool enable) noexcept; inline void setCulling(Instance instance, bool enable) noexcept; + inline void setSkinning(Instance instance, bool enable) noexcept; inline void setPrimitives(Instance instance, utils::Slice const& primitives) noexcept; inline void setBones(Instance instance, Bone const* transforms, size_t boneCount, size_t offset = 0) noexcept; inline void setBones(Instance instance, math::mat4f const* transforms, size_t boneCount, size_t offset = 0) noexcept; @@ -175,11 +176,11 @@ private: union { // this specific usage of union is permitted. All fields are identical - Field aabb; - Field layers; - Field visibility; - Field primitives; - Field bones; + Field aabb; + Field layers; + Field visibility; + Field primitives; + Field bones; }; }; @@ -245,6 +246,13 @@ void FRenderableManager::setCulling(Instance instance, bool enable) noexcept { } } +void FRenderableManager::setSkinning(Instance instance, bool enable) noexcept { + if (instance) { + Visibility& visibility = mManager[instance].visibility; + visibility.skinning = enable; + } +} + void FRenderableManager::setPrimitives(Instance instance, utils::Slice const& primitives) noexcept { if (instance) {