/* * Copyright (C) 2020 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef GLTFIO_DEPENDENCY_GRAPH_H #define GLTFIO_DEPENDENCY_GRAPH_H #include #include #include #include #include namespace filament { class MaterialInstance; class Texture; } namespace gltfio { /** * Internal graph that enables FilamentAsset to discover "ready-to-render" entities by tracking * the loading status of Texture objects that each entity depends on. * * Renderables connect to a set of material instances, which in turn connect to a set of parameter * names, which in turn connect to a set of texture objects. These relationships are not easily * inspectable using the Filament API or ECS. * * One graph corresponds to a single glTF asset. The graph only contains weak references, it does * not have ownership over any Filament objects. Here's an example: * * Entity Entity Entity Entity * | / \ | / * | / \ | / * Material Material Material * / | \ | * / | \ | * Param Param Param Param * \ / | | * \ / | | * Texture Texture Texture * * Note that the left-most entity in the above graph has no textures, so it becomes ready as soon as * finalize is called. */ class DependencyGraph { public: using Material = filament::MaterialInstance; using Entity = utils::Entity; // Pops up to "count" ready-to-render entities off the queue. // If "result" is non-null, returns the number of written items. // If "result" is null, returns the number of available entities. size_t popRenderables(Entity* result, size_t count) noexcept; // These are called during the initial asset loader phase. void addEdge(Entity entity, Material* material); void addEdge(Material* material, const char* parameter); // This is called at the end of the initial asset loading phase. // Makes a guarantee that no new material nodes or parameter nodes will be added to the graph. void finalize(); // This can be called after finalization to allow for dynamic addition of entities. // It is slower than finalize() because it checks the readiness of existing materials. void refinalize(); // These are called after textures have created and decoded. void addEdge(filament::Texture* texture, Material* material, const char* parameter); void markAsReady(filament::Texture* texture); private: struct TextureNode { filament::Texture* texture; bool ready; }; struct MaterialNode { tsl::robin_map params; }; struct EntityNode { tsl::robin_set materials; size_t numReadyMaterials = 0; }; void checkReadiness(Material* material); void markAsReady(Material* material); TextureNode* getStatus(filament::Texture* texture); // The following maps contain the directed edges in the graph. tsl::robin_map mEntityToMaterial; tsl::robin_map> mMaterialToEntity; tsl::robin_map mMaterialToTexture; tsl::robin_map> mTextureToMaterial; // Each texture (and its readiness flag) can be referenced from multiple nodes, so we own // a collection of wrapper objects in the following map. This uses std::unique_ptr to allow // nodes to refer to a texture wrapper using a stable weak pointer. tsl::robin_map> mTextureNodes; std::queue mReadyRenderables; bool mFinalized = false; }; } // namespace gltfio #endif // GLTFIO_DEPENDENCY_GRAPH_H