Skip to content

Commit

Permalink
Hydra emulation: making tasks also go through emulation. More precise…
Browse files Browse the repository at this point in the history
…ly, the emulated scene index driven by legacy scene delegates.

This fixes the crash reported in #3471 caused by change 2351061.

The problem was that the HdxTaskController added a task without going through emulation. But when we received a removed notice (in this case UsdImagingStageSceneIndex removing /), we removed the task without re-adding it. That is, the merging scene index is removing and re-adding prims. But because the task was not properly emulated, it was never re-added when the merging scene index send the prims added notice.

Fixes #3471

(Internal change: 2353415)
  • Loading branch information
unhyperbolic authored and pixar-oss committed Jan 13, 2025
1 parent 7579b91 commit 5973111
Show file tree
Hide file tree
Showing 13 changed files with 281 additions and 21 deletions.
1 change: 1 addition & 0 deletions pxr/imaging/hd/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ pxr_library(hd
dataSource
dataSourceHash
dataSourceLegacyPrim
dataSourceLegacyTaskPrim
dataSourceLocator
dataSourceMaterialNetworkInterface
debugCodes
Expand Down
20 changes: 20 additions & 0 deletions pxr/imaging/hd/changeTracker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -401,6 +401,26 @@ HdChangeTracker::MarkTaskDirty(SdfPath const& id, HdDirtyBits bits)
return;
}

if (_emulationSceneIndex) {
HdDataSourceLocatorSet locators;
HdDirtyBitsTranslator::TaskDirtyBitsToLocatorSet(
bits, &locators);
if (!locators.IsEmpty()) {
_emulationSceneIndex->DirtyPrims({{id, locators}});
}
} else {
_MarkTaskDirty(id, bits);
}
}

void
HdChangeTracker::_MarkTaskDirty(SdfPath const& id, HdDirtyBits bits)
{
if (ARCH_UNLIKELY(bits == HdChangeTracker::Clean)) {
TF_CODING_ERROR("MarkTaskDirty called with bits == clean!");
return;
}

_IDStateMap::iterator it = _taskState.find(id);
if (!TF_VERIFY(it != _taskState.end(), "Task Id = %s", id.GetText())) {
return;
Expand Down
1 change: 1 addition & 0 deletions pxr/imaging/hd/changeTracker.h
Original file line number Diff line number Diff line change
Expand Up @@ -670,6 +670,7 @@ class HdChangeTracker
void _MarkSprimDirty(SdfPath const& id, HdDirtyBits bits=AllDirty);
void _MarkBprimDirty(SdfPath const& id, HdDirtyBits bits=AllDirty);
void _MarkInstancerDirty(SdfPath const& id, HdDirtyBits bits=AllDirty);
void _MarkTaskDirty(SdfPath const& id, HdDirtyBits bits=AllDirty);
};


Expand Down
126 changes: 126 additions & 0 deletions pxr/imaging/hd/dataSourceLegacyTaskPrim.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
//
// Copyright 2025 Pixar
//
// Licensed under the terms set forth in the LICENSE.txt file available at
// https://openusd.org/license.
//
#include "pxr/imaging/hd/dataSourceLegacyTaskPrim.h"

#include "pxr/imaging/hd/legacyTaskSchema.h"
#include "pxr/imaging/hd/retainedDataSource.h"
#include "pxr/imaging/hd/sceneDelegate.h"

PXR_NAMESPACE_OPEN_SCOPE

namespace {

class _LegacyTaskSchemaDataSource : public HdContainerDataSource
{
public:
HD_DECLARE_DATASOURCE(_LegacyTaskSchemaDataSource);

TfTokenVector GetNames() override {
static const TfTokenVector result = {
HdLegacyTaskSchemaTokens->factory,
HdLegacyTaskSchemaTokens->parameters,
HdLegacyTaskSchemaTokens->collection,
HdLegacyTaskSchemaTokens->renderTags
};
return result;
}

HdDataSourceBaseHandle Get(const TfToken &name) override {
if (name == HdLegacyTaskSchemaTokens->factory) {
return _ToTypedDataSource(_factory);
}

if (name == HdLegacyTaskSchemaTokens->parameters) {
return HdRetainedSampledDataSource::New(
_sceneDelegate->Get(_id, HdTokens->params));
}

if (name == HdLegacyTaskSchemaTokens->collection) {
return _Get<HdRprimCollection>(HdTokens->collection);
}

if (name == HdLegacyTaskSchemaTokens->renderTags) {
return _Get<TfTokenVector>(HdTokens->renderTags);
}

return nullptr;
}

private:
_LegacyTaskSchemaDataSource(
const SdfPath& id,
HdSceneDelegate * const sceneDelegate,
HdLegacyTaskFactorySharedPtr factory)
: _id(id)
, _sceneDelegate(sceneDelegate)
, _factory(std::move(factory))
{
}

template<typename T>
static
HdDataSourceBaseHandle
_ToTypedDataSource(const T &v)
{
return HdRetainedTypedSampledDataSource<T>::New(v);
}

template<typename T>
HdDataSourceBaseHandle
_Get(const TfToken &key) const {
const VtValue value = _sceneDelegate->Get(_id, key);
if (!value.IsHolding<T>()) {
return nullptr;
}
return _ToTypedDataSource(value.UncheckedGet<T>());
}

const SdfPath _id;
HdSceneDelegate * const _sceneDelegate;
HdLegacyTaskFactorySharedPtr const _factory;
};

}

HdDataSourceLegacyTaskPrim::HdDataSourceLegacyTaskPrim(
const SdfPath& id,
HdSceneDelegate * const sceneDelegate,
HdLegacyTaskFactorySharedPtr factory)
: _id(id)
, _sceneDelegate(sceneDelegate)
, _factory(std::move(factory))
{
}

HdDataSourceLegacyTaskPrim::~HdDataSourceLegacyTaskPrim() = default;

TfTokenVector
HdDataSourceLegacyTaskPrim::GetNames()
{
static const TfTokenVector result = {
HdLegacyTaskSchemaTokens->task
};
return result;
}

HdDataSourceBaseHandle
HdDataSourceLegacyTaskPrim::Get(const TfToken &name)
{
if (!TF_VERIFY(_sceneDelegate)) {
return nullptr;
}

if (name == HdLegacyTaskSchemaTokens->task) {
return _LegacyTaskSchemaDataSource::New(_id, _sceneDelegate, _factory);
}

return nullptr;
}



PXR_NAMESPACE_CLOSE_SCOPE
53 changes: 53 additions & 0 deletions pxr/imaging/hd/dataSourceLegacyTaskPrim.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
//
// Copyright 2025 Pixar
//
// Licensed under the terms set forth in the LICENSE.txt file available at
// https://openusd.org/license.
//
#ifndef PXR_IMAGING_HD_DATA_SOURCE_LEGACY_TASK_PRIM_H
#define PXR_IMAGING_HD_DATA_SOURCE_LEGACY_TASK_PRIM_H

#include "pxr/usd/sdf/path.h"

#include "pxr/imaging/hd/api.h"
#include "pxr/imaging/hd/dataSource.h"

#include "pxr/pxr.h"

PXR_NAMESPACE_OPEN_SCOPE

using HdLegacyTaskFactorySharedPtr = std::shared_ptr<class HdLegacyTaskFactory>;
class HdSceneDelegate;

/// \class HdDataSourceLegacyTaskPrim
///
/// This is an HdContainerDataSource which represents a prim-level data source
/// for a task for adapting HdSceneDelegate calls into the forms defined by
/// HdSchemas during emulation of legacy scene delegates.
///
class HdDataSourceLegacyTaskPrim : public HdContainerDataSource
{
public:
HD_DECLARE_DATASOURCE(HdDataSourceLegacyTaskPrim);

~HdDataSourceLegacyTaskPrim() override;

TfTokenVector GetNames() override;
HdDataSourceBaseHandle Get(const TfToken &name) override;

private:
HdDataSourceLegacyTaskPrim(
const SdfPath& id,
HdSceneDelegate *sceneDelegate,
HdLegacyTaskFactorySharedPtr factory);

const SdfPath _id;
HdSceneDelegate * const _sceneDelegate;
HdLegacyTaskFactorySharedPtr const _factory;
};

HD_DECLARE_DATASOURCE_HANDLES(HdDataSourceLegacyTaskPrim);

PXR_NAMESPACE_CLOSE_SCOPE

#endif
20 changes: 20 additions & 0 deletions pxr/imaging/hd/dirtyBitsTranslator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -457,6 +457,26 @@ HdDirtyBitsTranslator::BprimDirtyBitsToLocatorSet(TfToken const& primType,
}
}

/* static */
void
HdDirtyBitsTranslator::TaskDirtyBitsToLocatorSet(
const HdDirtyBits bits, HdDataSourceLocatorSet *set)
{
if (ARCH_UNLIKELY(set == nullptr)) {
return;
}

if (bits & HdChangeTracker::DirtyCollection) {
set->append(HdLegacyTaskSchema::GetCollectionLocator());
}
if (bits & HdChangeTracker::DirtyParams) {
set->append(HdLegacyTaskSchema::GetParametersLocator());
}
if (bits & HdChangeTracker::DirtyRenderTags) {
set->append(HdLegacyTaskSchema::GetRenderTagsLocator());
}
}

// ----------------------------------------------------------------------------

static bool
Expand Down
3 changes: 3 additions & 0 deletions pxr/imaging/hd/dirtyBitsTranslator.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@ class HdDirtyBitsTranslator
HD_API
static void InstancerDirtyBitsToLocatorSet(TfToken const& primType,
const HdDirtyBits bits, HdDataSourceLocatorSet *set);
HD_API
static void TaskDirtyBitsToLocatorSet(
const HdDirtyBits bits, HdDataSourceLocatorSet *set);

// Locators to dirty bits.
HD_API
Expand Down
12 changes: 12 additions & 0 deletions pxr/imaging/hd/legacyPrimSceneIndex.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
//
#include "pxr/imaging/hd/legacyPrimSceneIndex.h"
#include "pxr/imaging/hd/dataSourceLegacyPrim.h"
#include "pxr/imaging/hd/dataSourceLegacyTaskPrim.h"
#include "pxr/imaging/hd/tokens.h"
#include "pxr/base/trace/trace.h"

PXR_NAMESPACE_OPEN_SCOPE
Expand All @@ -18,6 +20,16 @@ HdLegacyPrimSceneIndex::AddLegacyPrim(SdfPath const &id, TfToken const &type,
HdDataSourceLegacyPrim::New(id, type, sceneDelegate)}});
}

void
HdLegacyPrimSceneIndex::AddLegacyTask(
SdfPath const &id,
HdSceneDelegate * const sceneDelegate,
HdLegacyTaskFactorySharedPtr factory)
{
AddPrims({{id, HdPrimTypeTokens->task,
HdDataSourceLegacyTaskPrim::New(id, sceneDelegate, factory)}});
}

void
HdLegacyPrimSceneIndex::RemovePrim(SdfPath const &id)
{
Expand Down
12 changes: 10 additions & 2 deletions pxr/imaging/hd/legacyPrimSceneIndex.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
PXR_NAMESPACE_OPEN_SCOPE

class HdSceneDelegate;
using HdLegacyTaskFactorySharedPtr = std::shared_ptr<class HdLegacyTaskFactory>;

TF_DECLARE_REF_PTRS(HdLegacyPrimSceneIndex);

Expand All @@ -31,11 +32,18 @@ class HdLegacyPrimSceneIndex : public HdRetainedSceneIndex
return TfCreateRefPtr(new HdLegacyPrimSceneIndex);
}

/// custom insertion wrapper called by HdRenderIndex during population
/// of legacy HdSceneDelegates
/// Custom insertion wrapper called by HdRenderIndex during population
/// of legacy HdSceneDelegate's.
void AddLegacyPrim(SdfPath const &id, TfToken const &type,
HdSceneDelegate *sceneDelegate);

/// Custom insertion wrapper called by HdRenderIndex::InsertTask<T>
/// during population of legacy HdSceneDelegate's
void AddLegacyTask(
SdfPath const &id,
HdSceneDelegate *sceneDelegate,
HdLegacyTaskFactorySharedPtr factory);

/// Remove only the prim at \p id without affecting children.
///
/// If \p id has children, it is replaced by an entry with no type
Expand Down
26 changes: 22 additions & 4 deletions pxr/imaging/hd/renderIndex.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -600,9 +600,10 @@ HdRenderIndex::_Clear()
// -------------------------------------------------------------------------- //

void
HdRenderIndex::_TrackDelegateTask(HdSceneDelegate* delegate,
SdfPath const& taskId,
HdTaskCreateFnc taskCreateFnc)
HdRenderIndex::_InsertSceneDelegateTask(
HdSceneDelegate* const delegate,
SdfPath const& taskId,
HdLegacyTaskFactorySharedPtr factory)
{
HD_TRACE_FUNCTION();
HF_MALLOC_TAG_FUNCTION();
Expand All @@ -611,7 +612,13 @@ HdRenderIndex::_TrackDelegateTask(HdSceneDelegate* delegate,
return;
}

HdTaskSharedPtr const task = taskCreateFnc(delegate, taskId);
if (_IsEnabledSceneIndexEmulation()) {
_emulationSceneIndex->AddLegacyTask(
taskId, delegate, std::move(factory));
return;
}

HdTaskSharedPtr const task = factory->Create(delegate, taskId);
_InsertTask(delegate, taskId, task);
}

Expand Down Expand Up @@ -640,6 +647,17 @@ HdRenderIndex::GetTask(SdfPath const& id) const {

void
HdRenderIndex::RemoveTask(SdfPath const& id)
{
if (_IsEnabledSceneIndexEmulation()) {
_emulationSceneIndex->RemovePrim(id);
return;
}

_RemoveTask(id);
}

void
HdRenderIndex::_RemoveTask(SdfPath const& id)
{
HD_TRACE_FUNCTION();
HF_MALLOC_TAG_FUNCTION();
Expand Down
Loading

0 comments on commit 5973111

Please sign in to comment.