diff --git a/plugin/hdCycles/objectSource.cpp b/plugin/hdCycles/objectSource.cpp index 16281f59..60764ca5 100644 --- a/plugin/hdCycles/objectSource.cpp +++ b/plugin/hdCycles/objectSource.cpp @@ -23,19 +23,25 @@ #include #include +#include PXR_NAMESPACE_USING_DIRECTIVE -HdCyclesObjectSource::HdCyclesObjectSource(ccl::Object* object, const SdfPath& id) +HdCyclesObjectSource::HdCyclesObjectSource(ccl::Object* object, const SdfPath& id, bool isReference) : m_object { object } , m_id { id } + , m_isReference { isReference } { m_object->name = ccl::ustring { m_id.GetToken().GetText(), m_id.GetToken().size() }; } HdCyclesObjectSource::~HdCyclesObjectSource() { - // TODO unbind from scene? + if (!m_isReference) { + assert(m_object != nullptr); + delete m_object->geometry; + delete m_object; + } } bool diff --git a/plugin/hdCycles/objectSource.h b/plugin/hdCycles/objectSource.h index 8c58c524..20785f96 100644 --- a/plugin/hdCycles/objectSource.h +++ b/plugin/hdCycles/objectSource.h @@ -39,7 +39,7 @@ class SdfPath; /// class HdCyclesObjectSource : public HdBufferSource { public: - explicit HdCyclesObjectSource(ccl::Object* object, const SdfPath& id); + explicit HdCyclesObjectSource(ccl::Object* object, const SdfPath& id, bool isReference = true); ~HdCyclesObjectSource() override; void AddSource(HdBufferSourceSharedPtr source); @@ -62,6 +62,7 @@ class HdCyclesObjectSource : public HdBufferSource { ccl::Object* m_object; SdfPath m_id; + bool m_isReference; TfHashMap m_pending_sources; }; diff --git a/plugin/hdCycles/renderDelegate.cpp b/plugin/hdCycles/renderDelegate.cpp index 04f13576..97ba38cd 100644 --- a/plugin/hdCycles/renderDelegate.cpp +++ b/plugin/hdCycles/renderDelegate.cpp @@ -98,11 +98,6 @@ HdCyclesRenderDelegate::HdCyclesRenderDelegate() _Initialize({}); } - -std::mutex HdCyclesRenderDelegate::m_resource_registry_mutex; -std::atomic_int HdCyclesRenderDelegate::m_resource_registry_counter; -HdCyclesResourceRegistrySharedPtr HdCyclesRenderDelegate::m_resourceRegistry; - HdCyclesRenderDelegate::HdCyclesRenderDelegate(HdRenderSettingsMap const& settingsMap) : HdRenderDelegate(settingsMap) , m_hasStarted(false) @@ -119,19 +114,10 @@ HdCyclesRenderDelegate::_Initialize(HdRenderSettingsMap const& settingsMap) if (!m_renderParam->Initialize(settingsMap)) return; - // -- Initialize Render Delegate components - std::lock_guard guard{m_resource_registry_mutex}; - if(m_resource_registry_counter.fetch_add(1) == 0) { - m_resourceRegistry = std::make_shared(); - } - - m_resourceRegistry->UpdateScene(m_renderParam->GetCyclesScene()); + m_resourceRegistry = std::make_shared(this); } -HdCyclesRenderDelegate::~HdCyclesRenderDelegate() -{ - m_renderParam->StopRender(); -} +HdCyclesRenderDelegate::~HdCyclesRenderDelegate() { m_renderParam->StopRender(); } TfTokenVector const& HdCyclesRenderDelegate::GetSupportedRprimTypes() const @@ -217,12 +203,12 @@ HdCyclesRenderDelegate::CommitResources(HdChangeTracker* tracker) // commit resource to the scene m_resourceRegistry->Commit(); - if(tracker->IsGarbageCollectionNeeded()) { + m_renderParam->CommitResources(); + + if (tracker->IsGarbageCollectionNeeded()) { m_resourceRegistry->GarbageCollect(); tracker->ClearGarbageCollectionNeeded(); } - - m_renderParam->CommitResources(); } HdRprim* diff --git a/plugin/hdCycles/renderDelegate.h b/plugin/hdCycles/renderDelegate.h index 2824a555..d7ce302b 100644 --- a/plugin/hdCycles/renderDelegate.h +++ b/plugin/hdCycles/renderDelegate.h @@ -242,13 +242,11 @@ class HdCyclesRenderDelegate : public HdRenderDelegate { HdCyclesRenderPass* m_renderPass; HdRenderSettingDescriptorList m_settingDescriptors; - static std::mutex m_resource_registry_mutex; - static std::atomic_int m_resource_registry_counter; - static HdCyclesResourceRegistrySharedPtr m_resourceRegistry; - std::unique_ptr m_renderParam; bool m_hasStarted; + HdCyclesResourceRegistrySharedPtr m_resourceRegistry; + /// /// Auto add/remove cycles diagnostic delegate /// diff --git a/plugin/hdCycles/resourceRegistry.cpp b/plugin/hdCycles/resourceRegistry.cpp index 14eacf64..86ebeffe 100644 --- a/plugin/hdCycles/resourceRegistry.cpp +++ b/plugin/hdCycles/resourceRegistry.cpp @@ -18,61 +18,229 @@ // limitations under the License. #include "resourceRegistry.h" +#include "renderDelegate.h" +#include "renderParam.h" #include #include +#include +#include #include PXR_NAMESPACE_USING_DIRECTIVE +namespace { +struct HdCyclesSessionAutoPause { + explicit HdCyclesSessionAutoPause(ccl::Session* s) + : session(s) + { + session->set_pause(true); + } + + ~HdCyclesSessionAutoPause() { session->set_pause(false); } + + ccl::Session* session; +}; +} // namespace + void HdCyclesResourceRegistry::_Commit() { + // + // *** WARNING *** + // // This function is under heavy wip. In ideal situation committing all resources to cycles should happen in one // place only. - ccl::thread_scoped_lock scene_lock { m_scene->mutex }; - // TODO: acquire display lock + auto session = m_renderDelegate->GetCyclesRenderParam()->GetCyclesSession(); + auto scene = m_renderDelegate->GetCyclesRenderParam()->GetCyclesScene(); + + // Pause rendering for committing + HdCyclesSessionAutoPause session_auto_pause { session }; // State used to control session/scene update reset - std::atomic_bool requires_reset { false }; + std::atomic_size_t num_new_objects { 0 }; + std::atomic_size_t num_new_geometries { 0 }; + std::atomic_size_t num_new_sources { 0 }; + + // scene must be locked before any modifications + ccl::thread_scoped_lock scene_lock { scene->mutex }; + + // + // * bind lights + // + + // + // * bind shaders + // + + // + // * bind objects and geometries to the scene + // + for (auto& object_source : m_objects) { // TODO: preallocate objects + HdCyclesObjectSource* source_ptr = object_source.second.value.get(); + + if (!source_ptr->IsValid()) { + continue; + } + + if (source_ptr->IsResolved()) { + continue; + } + + // resolve and bind + source_ptr->Resolve(); + + ccl::Object* object = source_ptr->GetObject(); + if (!object) { + continue; + } + scene->objects.push_back(object); + object->tag_update(scene); + ++num_new_objects; - // * bind objects to the scene - for (auto& object_source : m_object_sources) { - if (!object_source.second.value->IsValid()) { + ccl::Geometry* geometry = object->geometry; + if (!geometry) { continue; } - object_source.second.value->Resolve(); + scene->geometry.push_back(geometry); + geometry->tag_update(scene, true); // new object bvh has to be rebuild + ++num_new_geometries; } - // * commit all pending object resources + // + // * commit all pending object sources + // using ValueType = HdInstanceRegistry::const_iterator::value_type; - WorkParallelForEach(m_object_sources.begin(), m_object_sources.end(), - [&requires_reset](const ValueType& object_source) { - // resolve per object - size_t num_resolved_sources = object_source.second.value->ResolvePendingSources(); - if (num_resolved_sources > 0) { - requires_reset = true; - } - }); - - // * notify session that new resources have been committed and reset is required + WorkParallelForEach(m_objects.begin(), m_objects.end(), [&num_new_sources, scene](const ValueType& object_source) { + // resolve per object + size_t num_resolved_sources = object_source.second.value->ResolvePendingSources(); + if (num_resolved_sources > 0) { + ++num_new_sources; + object_source.second.value->GetObject()->tag_update(scene); + } + }); + + // + // * notify cycles about the changes + // + std::atomic_bool requires_reset { false }; + + if (num_new_objects > 0) { + scene->object_manager->tag_update(scene); + requires_reset = true; + } + + if (num_new_geometries > 0) { + scene->geometry_manager->tag_update(scene); + requires_reset = true; + } + + if (num_new_sources > 0) { + requires_reset = true; + } + + // + // * restart if necessary + // if (requires_reset) { - // TODO: After we are done removing scene and session mutations from *::Sync. We can request update and reset + m_renderDelegate->GetCyclesRenderParam()->CyclesReset(true); + } +} + + +void +HdCyclesResourceRegistry::_GarbageCollectObjectAndGeometry() +{ + auto scene = m_renderDelegate->GetCyclesRenderParam()->GetCyclesScene(); + + // Design note: + // Unique instances of shared pointer are considered not used in the scene and should be detached from the scene + // before removal. Instead of removing objects from the scene during RPrim destructor or Finalize calls, + // we group them into unordered set of pointers, then we sweep through all objects once and remove those that are + // unique. + + std::unordered_set unique_objects; + std::unordered_set unique_geometries; + + // + // * collect unique objects and geometries + // + for (const auto& object_instance : m_objects) { + if (!object_instance.second.value.unique()) { + continue; + } + + const ccl::Object* object = object_instance.second.value->GetObject(); + if (!object) { + continue; + } + + // Mark for unbinding + unique_objects.insert(object); + const ccl::Geometry* geometry = object->geometry; + if (geometry) { + unique_geometries.insert(geometry); + } + } + + // + // * unbind objects and geometries + // + if (unique_objects.empty()) { + return; + } + + // remove geometries + for (auto it = scene->geometry.begin(); it != scene->geometry.end();) { + if (unique_geometries.find(*it) != unique_geometries.end()) { + it = scene->geometry.erase(it); + } else { + ++it; + } + } + + // remove objects + for (auto it = scene->objects.begin(); it != scene->objects.end();) { + if (unique_objects.find(*it) != unique_objects.end()) { + it = scene->objects.erase(it); + } else { + ++it; + } } } void HdCyclesResourceRegistry::_GarbageCollect() { - ccl::thread_scoped_lock scene_lock { m_scene->mutex }; + auto scene = m_renderDelegate->GetCyclesRenderParam()->GetCyclesScene(); + ccl::thread_scoped_lock scene_lock { scene->mutex }; - m_object_sources.GarbageCollect(); + // Design note: + // One might think that following OOP pattern would be the best choice of action, and deletion of the objects should + // happen in HdCyclesObjectSource. It turns out it's better to collect all unique objects and remove them in one + // iteration. + + // + // * Unbind unique instances of Geometry and Object from the Scene + // + { + _GarbageCollectObjectAndGeometry(); + } + + // + // * delete unique objects + // + { + m_objects.GarbageCollect(); + } } HdInstance HdCyclesResourceRegistry::GetObjectInstance(const SdfPath& id) { - return m_object_sources.GetInstance(id.GetHash()); + return m_objects.GetInstance(id.GetHash()); } + +HdCyclesResourceRegistry::~HdCyclesResourceRegistry() { _GarbageCollect(); } diff --git a/plugin/hdCycles/resourceRegistry.h b/plugin/hdCycles/resourceRegistry.h index 97d32532..0a56aed4 100644 --- a/plugin/hdCycles/resourceRegistry.h +++ b/plugin/hdCycles/resourceRegistry.h @@ -22,24 +22,25 @@ #include "objectSource.h" -#include #include #include #include -namespace ccl { -class Scene; -} - PXR_NAMESPACE_OPEN_SCOPE +class HdCyclesRenderDelegate; + class HdCyclesResourceRegistry final : public HdResourceRegistry { public: + explicit HdCyclesResourceRegistry(HdCyclesRenderDelegate* renderDelegate) + : m_renderDelegate { renderDelegate } + { + } - HdCyclesResourceRegistry() = default; + ~HdCyclesResourceRegistry(); - void UpdateScene(ccl::Scene* scene) { m_scene = scene; } + void Update(HdCyclesRenderDelegate* renderDelegate) { m_renderDelegate = renderDelegate; } HdInstance GetObjectInstance(const SdfPath& id); @@ -47,8 +48,10 @@ class HdCyclesResourceRegistry final : public HdResourceRegistry { void _Commit() override; void _GarbageCollect() override; - ccl::Scene* m_scene{}; - HdInstanceRegistry m_object_sources; + void _GarbageCollectObjectAndGeometry(); + + HdCyclesRenderDelegate* m_renderDelegate; + HdInstanceRegistry m_objects; }; using HdCyclesResourceRegistrySharedPtr = std::shared_ptr;