// // Copyright 2016 Pixar // // Licensed under the Apache License, Version 2.0 (the "Apache License") // with the following modification; you may not use this file except in // compliance with the Apache License and the following modification to it: // Section 6. Trademarks. is deleted and replaced with: // // 6. Trademarks. This License does not grant permission to use the trade // names, trademarks, service marks, or product names of the Licensor // and its affiliates, except as required to comply with Section 4(c) of // the License and to reproduce the content of the NOTICE file. // // You may obtain a copy of the Apache License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the Apache License with the above modification is // distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY // KIND, either express or implied. See the Apache License for the specific // language governing permissions and limitations under the Apache License. // #ifndef PXR_IMAGING_HD_RENDER_INDEX_H #define PXR_IMAGING_HD_RENDER_INDEX_H #include "pxr/pxr.h" #include "pxr/imaging/hd/api.h" #include "pxr/imaging/hd/version.h" #include "pxr/imaging/hd/changeTracker.h" #include "pxr/imaging/hd/perfLog.h" #include "pxr/imaging/hd/primTypeIndex.h" #include "pxr/imaging/hd/resourceRegistry.h" #include "pxr/imaging/hd/sortedIds.h" #include "pxr/imaging/hd/textureResource.h" #include "pxr/imaging/hd/tokens.h" #include "pxr/imaging/hf/perfLog.h" #include "pxr/usd/sdf/path.h" #include "pxr/base/gf/vec4i.h" #include "pxr/base/tf/hashmap.h" #include #include #include #include PXR_NAMESPACE_OPEN_SCOPE class HdRprim; class HdSprim; class HdBprim; class HdDrawItem; class HdRprimCollection; class HdSceneDelegate; class HdRenderDelegate; class HdExtComputation; class VtValue; class HdInstancer; class HdDriver; using HdDirtyListSharedPtr = std::shared_ptr; using HdTaskSharedPtr = std::shared_ptr; using HdResourceRegistrySharedPtr = std::shared_ptr; using HdTaskSharedPtrVector = std::vector; using HdTaskContext = std::unordered_map; using HdDriverVector = std::vector; /// \class HdRenderIndex /// /// The Hydra render index is a flattened representation of the client scene /// graph, which may be composed of several self-contained scene graphs, each of /// which provides a HdSceneDelegate adapter for data access. /// /// Thus, multiple HdSceneDelegate's may be tied to the same HdRenderIndex. /// /// The render index, however, is tied to a single HdRenderDelegate, which /// handles the actual creation and deletion of Hydra scene primitives. These /// include geometry and non-drawable objects (such as the camera and texture /// buffers). The render index simply holds a handle to these primitives, and /// tracks any changes to them via the HdChangeTracker. /// It also tracks computations and tasks that may update resources and render a /// subset of the renderable primitives. /// /// The render index orchestrates the "syncing" of scene primitives, by /// providing the relevant scene delegate for data access, and leaves resource /// management to the rendering backend (via HdResourceRegistry). /// /// It also provides "execution" functionality for application facing Hydra /// concepts (such as HdTask/HdRenderPass) in computing the set of HdDrawItems /// for a given HdRprimCollection, for rendering. /// /// \sa /// HdChangeTracker /// HdDrawItem /// HdRenderDelegate /// HdRprimCollection /// HdSceneDelegate /// /// \note /// The current design ties a HdRenderIndex to a HdRenderDelegate. /// However, the HdRenderIndex isn't tied to a viewer (viewport). /// It is common to have multiple viewers image the composed scene (for example, /// with different cameras), in which case the HdRenderIndex and /// HdRenderDelegate are shared by the viewers. /// /// If two viewers use different HdRenderDelegate's, then it may unfortunately /// require populating two HdRenderIndex's. /// class HdRenderIndex final { public: typedef std::vector HdDrawItemPtrVector; /// Create a render index with the given render delegate. /// Returns null if renderDelegate is null. /// The render delegate and render tasks may require access to a renderer's /// device provided by the application. The objects can be /// passed in as 'drivers'. Hgi is an example of a HdDriver. // hgi = Hgi::CreatePlatformDefaultHgi() // hgiDriver = new HdDriver(HgiTokens→renderDriver, hgi) // HdRenderIndex::New(_renderDelegate, {_hgiDriver}) HD_API static HdRenderIndex* New( HdRenderDelegate *renderDelegate, HdDriverVector const& drivers); HD_API ~HdRenderIndex(); /// Clear all r (render), s (state) and b (buffer) prims. HD_API void Clear(); /// Clear all entries in the render index under /// the given root and belong to a specified delegate. /// /// Used for example to unload a delegate. HD_API void RemoveSubtree(const SdfPath &root, HdSceneDelegate* sceneDelegate); // ---------------------------------------------------------------------- // /// Given a prim id, returns the path of the corresponding rprim /// or an empty path if none is found. HD_API SdfPath GetRprimPathFromPrimId(int primId) const; // ---------------------------------------------------------------------- // /// \name Synchronization // ---------------------------------------------------------------------- // /// Adds the dirty list to the sync queue. The actual processing of the /// dirty list happens later in SyncAll(). /// /// This is typically called from HdRenderPass::Sync. However, the current /// call chain ties it to SyncAll, i.e. /// HdRenderIndex::SyncAll > .... > HdRenderPass::Sync > HdRenderIndex::Sync HD_API void EnqueuePrimsToSync( HdDirtyListSharedPtr const &dirtyList, HdRprimCollection const &collection); /// Syncs input tasks, B & S prims, (external) computations and processes /// all pending dirty lists (which syncs the R prims). At the end of this /// step, all the resources that need to be updated have handles to their /// data sources. /// This is the first phase in Hydra's execution. See HdEngine::Execute HD_API void SyncAll(HdTaskSharedPtrVector *tasks, HdTaskContext *taskContext); // ---------------------------------------------------------------------- // /// \name Execution // ---------------------------------------------------------------------- // /// Returns a list of relevant draw items that match the criteria specified // by renderTags and collection. /// The is typically called during render pass execution, which is the /// final phase in the Hydra's execution. See HdRenderPass::Execute HD_API HdDrawItemPtrVector GetDrawItems(HdRprimCollection const& collection, TfTokenVector const& renderTags); // ---------------------------------------------------------------------- // /// \name Change Tracker // ---------------------------------------------------------------------- // HdChangeTracker& GetChangeTracker() { return _tracker; } HdChangeTracker const& GetChangeTracker() const { return _tracker; } // ---------------------------------------------------------------------- // /// \name Renderable prims (e.g. meshes, basis curves) // ---------------------------------------------------------------------- // /// Returns whether the rprim type is supported by this render index. HD_API bool IsRprimTypeSupported(TfToken const& typeId) const; /// Insert a rprim into index HD_API void InsertRprim(TfToken const& typeId, HdSceneDelegate* sceneDelegate, SdfPath const& rprimId, SdfPath const& instancerId = SdfPath()); /// Remove a rprim from index HD_API void RemoveRprim(SdfPath const& id); /// Returns true if rprim \p id exists in index. bool HasRprim(SdfPath const& id) { return _rprimMap.find(id) != _rprimMap.end(); } /// Returns the rprim of id HD_API HdRprim const *GetRprim(SdfPath const &id) const; /// Returns the scene delegate for the given rprim HD_API HdSceneDelegate *GetSceneDelegateForRprim(SdfPath const &id) const; /// Query function to return the id's of the scene delegate and instancer /// associated with the Rprim at the given path. HD_API bool GetSceneDelegateAndInstancerIds(SdfPath const &id, SdfPath* sceneDelegateId, SdfPath* instancerId) const; /// Returns the render tag for the given rprim HD_API TfToken GetRenderTag(SdfPath const& id) const; /// Return the material tag for the given rprim HD_API TfToken GetMaterialTag(SdfPath const& id) const; /// Returns a sorted list of all Rprims in the render index. /// The list is sorted by std::less HD_API const SdfPathVector &GetRprimIds() { return _rprimIds.GetIds(); } /// Returns the subtree rooted under the given path. HD_API SdfPathVector GetRprimSubtree(SdfPath const& root); // ---------------------------------------------------------------------- // /// \name Instancer Support // ---------------------------------------------------------------------- // /// Insert an instancer into index HD_API void InsertInstancer(HdSceneDelegate* delegate, SdfPath const &id, SdfPath const &parentId = SdfPath()); /// Remove an instancer from index HD_API void RemoveInstancer(SdfPath const& id); /// Returns true if instancer \p id exists in index. bool HasInstancer(SdfPath const& id) { return _instancerMap.find(id) != _instancerMap.end(); } /// Returns the instancer of id HD_API HdInstancer *GetInstancer(SdfPath const &id) const; // ---------------------------------------------------------------------- // /// \name Task Support // ---------------------------------------------------------------------- // /// Inserts a new task into the render index with an identifier of \p id. template void InsertTask(HdSceneDelegate* delegate, SdfPath const& id); /// Removes the given task from the RenderIndex. HD_API void RemoveTask(SdfPath const& id); /// Returns true if a task exists in the index with the given \p id. bool HasTask(SdfPath const& id) { return _taskMap.find(id) != _taskMap.end(); } /// Returns the task for the given \p id. HD_API HdTaskSharedPtr const& GetTask(SdfPath const& id) const; // ---------------------------------------------------------------------- // /// \name Scene state prims (e.g. camera, light) // ---------------------------------------------------------------------- // /// Returns whether the sprim type is supported by this render index. HD_API bool IsSprimTypeSupported(TfToken const& typeId) const; /// Insert a sprim into index HD_API void InsertSprim(TfToken const& typeId, HdSceneDelegate* delegate, SdfPath const& sprimId); HD_API void RemoveSprim(TfToken const& typeId, SdfPath const &id); HD_API HdSprim *GetSprim(TfToken const& typeId, SdfPath const &id) const; /// Returns the subtree rooted under the given path for the given sprim /// type. HD_API SdfPathVector GetSprimSubtree(TfToken const& typeId, SdfPath const& root); /// Returns the fullback prim for the Sprim of the given type. HD_API HdSprim *GetFallbackSprim(TfToken const& typeId) const; // ---------------------------------------------------------------------- // /// \name Buffer prims (e.g. textures, buffers) // ---------------------------------------------------------------------- // /// Returns whether the bprim type is supported by this render index. HD_API bool IsBprimTypeSupported(TfToken const& typeId) const; /// Insert a bprim into index HD_API void InsertBprim(TfToken const& typeId, HdSceneDelegate* delegate, SdfPath const& bprimId); HD_API void RemoveBprim(TfToken const& typeId, SdfPath const &id); HD_API HdBprim *GetBprim(TfToken const& typeId, SdfPath const &id) const; /// Returns the subtree rooted under the given path for the given bprim /// type. HD_API SdfPathVector GetBprimSubtree(TfToken const& typeId, SdfPath const& root); /// Returns the fallback prim for the Bprim of the given type. HD_API HdBprim *GetFallbackBprim(TfToken const& typeId) const; /// Helper utility to convert texture resource id's which are unique /// to this render index, into a globally unique texture key HD_API HdResourceRegistry::TextureKey GetTextureKey(HdTextureResource::ID id) const; // ---------------------------------------------------------------------- // /// \name Render Delegate // ---------------------------------------------------------------------- // /// Currently, a render index only supports connection to one type of /// render delegate, due to the inserted information and change tracking /// being specific to that delegate type. HD_API HdRenderDelegate *GetRenderDelegate() const; // The render delegate may require access to a render context / device // that is provided by the application. HD_API HdDriverVector const& GetDrivers() const; /// Returns a shared ptr to the resource registry of the current render /// delegate. HD_API HdResourceRegistrySharedPtr GetResourceRegistry() const; private: // The render index constructor is private so we can check // renderDelegate before construction: see HdRenderIndex::New(...). HdRenderIndex( HdRenderDelegate *renderDelegate, HdDriverVector const& drivers); // ---------------------------------------------------------------------- // // Private Helper methods // ---------------------------------------------------------------------- // // Go through all RPrims and reallocate their instance ids // This is called once we have exhausted all all 24bit instance ids. void _CompactPrimIds(); // Allocate the next available instance id to the prim void _AllocatePrimId(HdRprim* prim); // Inserts the task into the index and updates tracking state. // _TrackDelegateTask is called by the inlined InsertTask, so it needs // to be marked HD_API. HD_API void _TrackDelegateTask(HdSceneDelegate* delegate, SdfPath const& taskId, HdTaskSharedPtr const& task); template static inline const TfToken & _GetTypeId(); void _RemoveRprimSubtree(const SdfPath &root, HdSceneDelegate* sceneDelegate); void _RemoveInstancerSubtree(const SdfPath &root, HdSceneDelegate* sceneDelegate); void _RemoveExtComputationSubtree(const SdfPath &root, HdSceneDelegate* sceneDelegate); void _RemoveTaskSubtree(const SdfPath &root, HdSceneDelegate* sceneDelegate); // ---------------------------------------------------------------------- // // Index State // ---------------------------------------------------------------------- // struct _RprimInfo { HdSceneDelegate *sceneDelegate; HdRprim *rprim; }; struct _TaskInfo { HdSceneDelegate *sceneDelegate; HdTaskSharedPtr task; }; typedef std::unordered_map _TaskMap; typedef TfHashMap _RprimMap; typedef std::vector _RprimPrimIDVector; typedef Hd_PrimTypeIndex _SprimIndex; typedef Hd_PrimTypeIndex _BprimIndex; _RprimMap _rprimMap; Hd_SortedIds _rprimIds; _RprimPrimIDVector _rprimPrimIdMap; _TaskMap _taskMap; _SprimIndex _sprimIndex; _BprimIndex _bprimIndex; HdChangeTracker _tracker; typedef TfHashMap _InstancerMap; _InstancerMap _instancerMap; struct _SyncQueueEntry { HdDirtyListSharedPtr dirtyList; HdRprimCollection collection; }; typedef std::vector<_SyncQueueEntry> _SyncQueue; _SyncQueue _syncQueue; /// With the removal of task-based collection include/exclude path /// filtering, HdDirtyLists were generating their lists of dirty rprim IDs /// by looking through every rprim in the render index. When the number of /// tasks/render passes/dirty lists grew large, this resulted in /// significant overhead and lots of duplication of work. /// Instead, the render index itself now takes care of generating the /// complete list of dirty rprim IDs when requested by the HdDirtyList. /// During SyncAll(), the first HdDirtyList to request the list of dirty /// IDs for a given HdDirtyBits mask triggers the render index to produce /// that list and cache it in a map. Subsequent requests reuse the cached /// list. At the end of SyncAll(), the map is cleared in preparation for /// the next sync. std::unordered_map _dirtyRprimIdsMap; friend class HdDirtyList; const SdfPathVector& _GetDirtyRprimIds(HdDirtyBits mask); HdRenderDelegate *_renderDelegate; HdDriverVector _drivers; // ---------------------------------------------------------------------- // // Sync State // ---------------------------------------------------------------------- // TfTokenVector _activeRenderTags; unsigned int _renderTagVersion; /// Register the render delegate's list of supported prim types. void _InitPrimTypes(); /// Creates fallback prims for each supported prim type. bool _CreateFallbackPrims(); /// Release the fallback prims. void _DestroyFallbackPrims(); void _GatherRenderTags(const HdTaskSharedPtrVector *tasks); typedef tbb::enumerable_thread_specific _ConcurrentDrawItems; void _AppendDrawItems(const SdfPathVector &rprimIds, size_t begin, size_t end, HdRprimCollection const& collection, _ConcurrentDrawItems* result); /// Register core hydra reprs. Only ever called once, the first time /// a render index is created. /// XXX: This code should move to the application layer. static void _ConfigureReprs(); // Remove default constructor HdRenderIndex() = delete; // Don't allow copies HdRenderIndex(const HdRenderIndex &) = delete; HdRenderIndex &operator=(const HdRenderIndex &) = delete; }; template void HdRenderIndex::InsertTask(HdSceneDelegate* delegate, SdfPath const& id) { HD_TRACE_FUNCTION(); HF_MALLOC_TAG_FUNCTION(); HdTaskSharedPtr task = std::make_shared(delegate, id); _TrackDelegateTask(delegate, id, task); } PXR_NAMESPACE_CLOSE_SCOPE #endif //PXR_IMAGING_HD_RENDER_INDEX_H