Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

New object management #161

Draft
wants to merge 3 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 8 additions & 2 deletions plugin/hdCycles/objectSource.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,19 +23,25 @@

#include <graph/node.h>
#include <render/object.h>
#include <render/geometry.h>

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
Expand Down
3 changes: 2 additions & 1 deletion plugin/hdCycles/objectSource.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -62,6 +62,7 @@ class HdCyclesObjectSource : public HdBufferSource {

ccl::Object* m_object;
SdfPath m_id;
bool m_isReference;

TfHashMap<TfToken, HdBufferSourceSharedPtr, TfHash> m_pending_sources;
};
Expand Down
24 changes: 5 additions & 19 deletions plugin/hdCycles/renderDelegate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -119,19 +114,10 @@ HdCyclesRenderDelegate::_Initialize(HdRenderSettingsMap const& settingsMap)
if (!m_renderParam->Initialize(settingsMap))
return;

// -- Initialize Render Delegate components
std::lock_guard<std::mutex> guard{m_resource_registry_mutex};
if(m_resource_registry_counter.fetch_add(1) == 0) {
m_resourceRegistry = std::make_shared<HdCyclesResourceRegistry>();
}

m_resourceRegistry->UpdateScene(m_renderParam->GetCyclesScene());
m_resourceRegistry = std::make_shared<HdCyclesResourceRegistry>(this);
}

HdCyclesRenderDelegate::~HdCyclesRenderDelegate()
{
m_renderParam->StopRender();
}
HdCyclesRenderDelegate::~HdCyclesRenderDelegate() { m_renderParam->StopRender(); }

TfTokenVector const&
HdCyclesRenderDelegate::GetSupportedRprimTypes() const
Expand Down Expand Up @@ -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*
Expand Down
6 changes: 2 additions & 4 deletions plugin/hdCycles/renderDelegate.h
Original file line number Diff line number Diff line change
Expand Up @@ -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<HdCyclesRenderParam> m_renderParam;
bool m_hasStarted;

HdCyclesResourceRegistrySharedPtr m_resourceRegistry;

///
/// Auto add/remove cycles diagnostic delegate
///
Expand Down
212 changes: 190 additions & 22 deletions plugin/hdCycles/resourceRegistry.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,61 +18,229 @@
// limitations under the License.

#include "resourceRegistry.h"
#include "renderDelegate.h"
#include "renderParam.h"

#include <pxr/base/work/loops.h>
#include <pxr/usd/sdf/path.h>

#include <render/geometry.h>
#include <render/object.h>
#include <render/scene.h>

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<HdCyclesObjectSourceSharedPtr>::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<const ccl::Object*> unique_objects;
std::unordered_set<const ccl::Geometry*> 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<HdCyclesObjectSourceSharedPtr>
HdCyclesResourceRegistry::GetObjectInstance(const SdfPath& id)
{
return m_object_sources.GetInstance(id.GetHash());
return m_objects.GetInstance(id.GetHash());
}

HdCyclesResourceRegistry::~HdCyclesResourceRegistry() { _GarbageCollect(); }
Loading