gltfio: Better behavior for releaseSourceData()

This commit is contained in:
Philip Rideout
2022-08-30 15:53:56 -07:00
parent 7337a467b9
commit de7dfc2ea6
5 changed files with 35 additions and 22 deletions

View File

@@ -82,7 +82,10 @@ struct BufferSlot {
MorphTargetBuffer* morphTargetBuffer;
};
// Encapsulates a connection between Texture and MaterialInstance.
// Stores a connection between Texture and MaterialInstance; consumed by resource loader so that it
// can call "setParameter" on the given MaterialInstance after the Texture has been created.
// Since material instances are not typically shared between FilamentInstance, the slots are a
// unified list across all instances that exist before creation of Texture objects.
struct TextureSlot {
size_t sourceTexture; // index into cgltf_texture
MaterialInstance* materialInstance;
@@ -257,9 +260,16 @@ struct FFilamentAsset : public FilamentAsset {
mTextureBindings[tb.sourceTexture] = texture;
}
// If a Filament Texture already exists for the given slot, go ahead and bind it to the
// given material instance. (This can occur when creating new FilamentInstances)
// Otherwise, stash the binding information so that ResourceLoader can trigger the bind.
void addTextureSlot(const TextureSlot& tb) {
if (Texture* texture = mTextureBindings[tb.sourceTexture]; texture) {
if (mResourcesLoaded) {
Texture* texture = mTextureBindings[tb.sourceTexture];
assert_invariant(texture);
tb.materialInstance->setParameter(tb.materialParameter, texture, tb.sampler);
// Intentionally omit adding a dependency graph edge here. We do not need progressive
// reveal for multiple FilamentInstance.
} else {
mTextureSlots.push_back(tb);
mDependencyGraph.addEdge(tb.materialInstance, tb.materialParameter);
@@ -323,13 +333,19 @@ struct FFilamentAsset : public FilamentAsset {
using SourceHandle = std::shared_ptr<SourceAsset>;
SourceHandle mSourceAsset;
// Transient source data that can freed via releaseSourceData:
utils::FixedCapacityVector<Texture*> mTextureBindings; // one element for each cgltf_texture
// Mapping from cgltf_texture to Texture* is required when creating new instances.
utils::FixedCapacityVector<Texture*> mTextureBindings;
// Resource URIs can be queried by the end user.
utils::FixedCapacityVector<const char*> mResourceUris;
// The mapping from cgltf_mesh to VertexBuffer* (etc) is required when creating new instances.
MeshCache mMeshCache;
// Asset information that is produced by AssetLoader and consumed by ResourceLoader:
std::vector<BufferSlot> mBufferSlots;
std::vector<TextureSlot> mTextureSlots;
utils::FixedCapacityVector<const char*> mResourceUris;
std::vector<std::pair<const cgltf_primitive*, VertexBuffer*> > mPrimitives;
MeshCache mMeshCache; // one element for each cgltf_mesh
};
FILAMENT_UPCAST(FilamentAsset)

View File

@@ -80,6 +80,7 @@ struct FFilamentInstance : public FilamentInstance {
// may be sparsely populated. This is used as a simple mapping between cgltf_node and Entity,
// and therefore has the same size as the number of cgltf_node in the original asset. We
// considered using the ECS for this, but we need Node => Entity, not the other way around.
// This is discarded after the animator is created.
utils::FixedCapacityVector<utils::Entity> nodeMap;
Aabb boundingBox;

View File

@@ -160,18 +160,12 @@ Entity FFilamentAsset::getWireframe() noexcept {
void FFilamentAsset::releaseSourceData() noexcept {
// To ensure that all possible memory is freed, we reassign to new containers rather than
// calling clear(). With many container types (such as robin_map), clearing is a fast
// operation that merely frees the storage for the items.
// calling clear(). With many container types, clearing is a fast operation that merely frees
// the storage for the items but not the actual container.
mTextureBindings = {};
mMeshCache = {};
mResourceUris = {};
mPrimitives = {};
mBufferSlots = {};
mTextureSlots = {};
mSourceAsset.reset();
for (FFilamentInstance* instance : mInstances) {
instance->nodeMap = {};
}
}
const char* FFilamentAsset::getName(utils::Entity entity) const noexcept {

View File

@@ -41,6 +41,7 @@ Animator* FFilamentInstance::getAnimator() const noexcept {
void FFilamentInstance::createAnimator() {
assert_invariant(animator == nullptr);
animator = new Animator(owner, this);
nodeMap = {};
}
size_t FFilamentInstance::getSkinCount() const noexcept {

View File

@@ -167,8 +167,7 @@ static void decodeDracoMeshes(FFilamentAsset* asset) {
};
// Go through every primitive and check if it has a Draco mesh.
for (auto& pair : asset->mPrimitives) {
const cgltf_primitive* prim = pair.first;
for (auto& [prim, vertexBuffer] : asset->mPrimitives) {
if (!prim->has_draco_mesh_compression) {
continue;
}
@@ -177,7 +176,6 @@ static void decodeDracoMeshes(FFilamentAsset* asset) {
// If an error occurs, we can simply set the primitive's associated VertexBuffer to null.
// This does not cause a leak because it is a weak reference.
auto& vertexBuffer = pair.second;
// Check if we have already decoded this mesh.
DracoMesh* mesh = dracoCache->findOrCreateMesh(draco.buffer_view);
@@ -494,6 +492,9 @@ bool ResourceLoader::loadResources(FFilamentAsset* asset, bool async) {
// we need to generate the contents of a GPU buffer by processing one or more CPU buffer(s).
pImpl->computeTangents(asset);
asset->mBufferSlots = {};
asset->mPrimitives = {};
// If any decoding jobs are still underway from a previous load, wait for them to finish.
for (const auto& iter : pImpl->mTextureProviders) {
iter.second->waitForCompletion();
@@ -674,11 +675,12 @@ void ResourceLoader::Impl::cancelTextureDecoding() {
void ResourceLoader::Impl::createTextures(FFilamentAsset* asset, bool async) {
// Create new texture objects if they are not cached and kick off decoding jobs.
mRemainingTextureDownloads = 0;
for (auto slot : asset->mTextureSlots) {
for (const TextureSlot& slot : asset->mTextureSlots) {
if (Texture* texture = getOrCreateTexture(asset, slot)) {
asset->bindTexture(slot, texture);
}
}
asset->mTextureSlots = {};
// Non-threaded systems are required to use the asynchronous API.
assert_invariant(UTILS_HAS_THREADING || async);
@@ -711,14 +713,13 @@ void ResourceLoader::Impl::computeTangents(FFilamentAsset* asset) {
// Create a job description for each triangle-based primitive.
using Params = TangentsJob::Params;
std::vector<Params> jobParams;
for (auto pair : asset->mPrimitives) {
if (UTILS_UNLIKELY(pair.first->type != cgltf_primitive_type_triangles)) {
for (auto [prim, vb] : asset->mPrimitives) {
if (UTILS_UNLIKELY(prim->type != cgltf_primitive_type_triangles)) {
continue;
}
VertexBuffer* vb = pair.second;
auto iter = baseTangents.find(vb);
if (iter != baseTangents.end()) {
jobParams.emplace_back(Params {{ pair.first }, {vb, nullptr, iter->second }});
jobParams.emplace_back(Params {{ prim }, {vb, nullptr, iter->second }});
}
}