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.
This commit is contained in:
Mathias Agopian
2018-12-07 12:24:28 -08:00
committed by Mathias Agopian
parent 5bbdc673f2
commit 4d9788ffb9
3 changed files with 41 additions and 42 deletions

View File

@@ -72,6 +72,10 @@ public:
return static_cast<char*>(mBuffer) + offset;
}
void* invalidate() noexcept {
return invalidateUniforms(0, mSize);
}
// pointer to the uniform buffer
void const* getBuffer() const noexcept { return mBuffer; }

View File

@@ -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<Bones> 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<Visibility&>(manager[ci].visibility).skinning = builder->mSkinningBoneCount > 0;
setSkinning(ci, false);
if (!canReuse) {
if (builder->mSkinningBoneCount) {
std::unique_ptr<Bones>& 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<Bones> const& bones = manager[ci].bones;
const size_t count = builder->mSkinningBoneCount;
if (UTILS_UNLIKELY(count)) {
std::unique_ptr<Bones>& bones = manager[ci].bones;
bones = std::unique_ptr<Bones>(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{});
}
}
}
}

View File

@@ -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<FRenderPrimitive> 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> aabb;
Field<LAYERS> layers;
Field<VISIBILITY> visibility;
Field<PRIMITIVES> primitives;
Field<BONES> bones;
Field<AABB> aabb;
Field<LAYERS> layers;
Field<VISIBILITY> visibility;
Field<PRIMITIVES> primitives;
Field<BONES> 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<FRenderPrimitive> const& primitives) noexcept {
if (instance) {