Skip to content

Commit

Permalink
[hd] Streamline HdFlatteningSceneIndex PrimsAdded and PrimsDirtied ca…
Browse files Browse the repository at this point in the history
…lls.

- When we get an Added/Dirtied for primPath and invalidate its subtree, don't generate a dirty notice for primPath since that's redundant.
- The wrapper invalidation now takes a locator set, and we filter for relevancy against a locator set.  This reduces the number of times we translate back and forth.
- If we're invalidating a subtree and a prim doesn't have any cached data, don't invalidate its children, on the assumption that they didn't reference this prim for their value computations.  (This particularly helps avoid large invalidations before the scene is populated).

(Internal change: 2186846)
  • Loading branch information
tcauchois authored and pixar-oss committed Sep 13, 2021
1 parent d9b0f28 commit 562750f
Show file tree
Hide file tree
Showing 2 changed files with 79 additions and 54 deletions.
127 changes: 76 additions & 51 deletions pxr/imaging/hd/flatteningSceneIndex.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -94,24 +94,38 @@ HdFlatteningSceneIndex::_PrimsAdded(

for (const HdSceneIndexObserver::AddedPrimEntry &entry : entries) {
// XXX immediately calls GetPrim (for now)
auto wrappedDataSource = _PrimLevelWrappingDataSource::New(
*this, entry.primPath,
_GetInputSceneIndex()->GetPrim(entry.primPath).dataSource);

auto iterBoolPair = _prims.insert({entry.primPath, {{
entry.primType, wrappedDataSource}
}});
HdContainerDataSourceHandle dataSource =
_GetInputSceneIndex()->GetPrim(entry.primPath).dataSource;

// Ensure the prim has an entry in the map.
auto iterBoolPair =
_prims.insert({entry.primPath, {HdSceneIndexPrim()}});
HdSceneIndexPrim &prim = iterBoolPair.first->second.prim;

// Always update the prim type.
prim.primType = entry.primType;

// If the wrapper exists, update the input datasource; otherwise,
// create it. This is both to save an allocation if the PrimsAdded
// message is resyncing a prim, and also to leave the cache intact for
// _DirtyHierarchy to invalidate (since it chooses what to invalidate
// based on what's been cached).
if (prim.dataSource) {
_PrimLevelWrappingDataSource::Cast(prim.dataSource)->
UpdateInputDataSource(dataSource);
} else {
prim.dataSource = _PrimLevelWrappingDataSource::New(
*this, entry.primPath, dataSource);
}

// if it's not newly inserted, we will need to dirty inherited
// attributes everywhere beneath.
// If we're inserting somewhere in the existing hierarchy, we need to
// invalidate descendant flattened attributes.
if (!iterBoolPair.second) {
iterBoolPair.first->second.prim =
{entry.primType, wrappedDataSource};

HdDataSourceLocatorSet locators;
locators.insert(HdXformSchema::GetDefaultLocator());
locators.insert(HdVisibilitySchema::GetDefaultLocator());
locators.insert(HdPurposeSchema::GetDefaultLocator());
static HdDataSourceLocatorSet locators = {
HdXformSchema::GetDefaultLocator(),
HdVisibilitySchema::GetDefaultLocator(),
HdPurposeSchema::GetDefaultLocator(),
};

_DirtyHierarchy(entry.primPath, locators, &dirtyEntries);
}
Expand Down Expand Up @@ -178,10 +192,8 @@ HdFlatteningSceneIndex::_PrimsDirtied(
}
}

if (dirtyEntries.empty()) {
_SendPrimsDirtied(entries);
} else {
dirtyEntries.insert(dirtyEntries.end(), entries.begin(), entries.end());
_SendPrimsDirtied(entries);
if (!dirtyEntries.empty()) {
_SendPrimsDirtied(dirtyEntries);
}
}
Expand All @@ -195,30 +207,29 @@ HdFlatteningSceneIndex::_DirtyHierarchy(
// XXX: here and elsewhere, if a parent xform is dirtied and the child has
// resetXformStack, we could skip dirtying the child...

bool dirtyXform = dirtyLocators.Intersects(
HdXformSchema::GetDefaultLocator());
bool dirtyVis = dirtyLocators.Intersects(
HdVisibilitySchema::GetDefaultLocator());
bool dirtyPurpose = dirtyLocators.Intersects(
HdPurposeSchema::GetDefaultLocator());

auto startEndIt = _prims.FindSubtreeRange(primPath);
auto it = startEndIt.first;
for (; it != startEndIt.second; ++it) {
for (; it != startEndIt.second; ) {
_PrimEntry &entry = it->second;
dirtyEntries->emplace_back(it->first, dirtyLocators);

if (_PrimLevelWrappingDataSourceHandle dataSource =
_PrimLevelWrappingDataSource::Cast(
entry.prim.dataSource)) {
if (dirtyXform) {
dataSource->SetDirtyXform();
}
if (dirtyVis) {
dataSource->SetDirtyVis();
}
if (dirtyPurpose) {
dataSource->SetDirtyPurpose();
if (dataSource->PrimDirtied(dirtyLocators)) {
// If we invalidated any data for any prim besides "primPath"
// (which already has a notice), generate a new PrimsDirtied
// notice.
if (it->first != primPath) {
dirtyEntries->emplace_back(it->first, dirtyLocators);
}
++it;
} else {
// If we didn't invalidate any data, we can safely assume that
// no downstream prims depended on this prim for their
// flattened result, and skip to the next subtree. This is
// an important optimization for (e.g.) scene population,
// where no data is cached yet...
it = it.GetNextSubtree();
}
}
}
Expand All @@ -236,28 +247,42 @@ _PrimLevelWrappingDataSource::_PrimLevelWrappingDataSource(
, _computedVisDataSource(nullptr)
, _computedPurposeDataSource(nullptr)
{

}

void
HdFlatteningSceneIndex::_PrimLevelWrappingDataSource::SetDirtyXform()
HdFlatteningSceneIndex::_PrimLevelWrappingDataSource::UpdateInputDataSource(
HdContainerDataSourceHandle inputDataSource)
{
HdContainerDataSourceHandle null(nullptr);
HdContainerDataSource::AtomicStore(_computedXformDataSource, null);
_inputDataSource = inputDataSource;
}

void
HdFlatteningSceneIndex::_PrimLevelWrappingDataSource::SetDirtyVis()
bool
HdFlatteningSceneIndex::_PrimLevelWrappingDataSource::PrimDirtied(
const HdDataSourceLocatorSet &set)
{
bool anyDirtied = false;
HdContainerDataSourceHandle null(nullptr);
HdContainerDataSource::AtomicStore(_computedVisDataSource, null);
}

void
HdFlatteningSceneIndex::_PrimLevelWrappingDataSource::SetDirtyPurpose()
{
HdContainerDataSourceHandle null(nullptr);
HdContainerDataSource::AtomicStore(_computedPurposeDataSource, null);
if (set.Intersects(HdXformSchema::GetDefaultLocator())) {
if (HdContainerDataSource::AtomicLoad(_computedXformDataSource)) {
anyDirtied = true;
}
HdContainerDataSource::AtomicStore(_computedXformDataSource, null);
}
if (set.Intersects(HdVisibilitySchema::GetDefaultLocator())) {
if (HdContainerDataSource::AtomicLoad(_computedVisDataSource)) {
anyDirtied = true;
}
HdContainerDataSource::AtomicStore(_computedVisDataSource, null);
}
if (set.Intersects(HdPurposeSchema::GetDefaultLocator())) {
if (HdContainerDataSource::AtomicLoad(_computedPurposeDataSource)) {
anyDirtied = true;
}
HdContainerDataSource::AtomicStore(_computedPurposeDataSource, null);
}

return anyDirtied;
}

bool
Expand Down Expand Up @@ -465,7 +490,7 @@ HdFlatteningSceneIndex::_PrimLevelWrappingDataSource::_GetXform()
// If the local xform wants to compose with the parent,
// do so as long as both matrices are provided.
HdMatrixDataSourceHandle parentMatrixDataSource =
parentXform.GetMatrix();
parentXform ? parentXform.GetMatrix() : nullptr;
HdMatrixDataSourceHandle inputMatrixDataSource =
inputXform.GetMatrix();

Expand Down
6 changes: 3 additions & 3 deletions pxr/imaging/hd/flatteningSceneIndex.h
Original file line number Diff line number Diff line change
Expand Up @@ -120,9 +120,9 @@ class HdFlatteningSceneIndex : public HdSingleInputFilteringSceneIndexBase
const SdfPath &primPath,
HdContainerDataSourceHandle inputDataSource);

void SetDirtyXform();
void SetDirtyVis();
void SetDirtyPurpose();
void UpdateInputDataSource(HdContainerDataSourceHandle inputDataSource);

bool PrimDirtied(const HdDataSourceLocatorSet &locators);

bool Has(const TfToken &name) override;
TfTokenVector GetNames() override;
Expand Down

0 comments on commit 562750f

Please sign in to comment.