void HdRenderPass::SetRprimCollection(HdRprimCollection const& col) { if (col == _collection){ return; } _collection = col; // Force any cached data based on collection to be refreshed. _collectionChanged = true; // reset the cached collection version _collectionVersion = 0; // update dirty list subscription for the new collection. // holding shared_ptr for the lifetime of the dirty list. bool isMinorChange = true; if (!_dirtyList || !_dirtyList->ApplyEdit(col)) { _dirtyList.reset(new HdDirtyList(_collection, *_renderIndex)); isMinorChange = false; } if (TfDebug::IsEnabled(HD_DIRTY_LIST)) { std::stringstream s; s << " Include: \n"; for (auto i : col.GetRootPaths()) { s << " - " << i << "\n"; } s << " Exclude: \n"; for (auto i : col.GetExcludePaths()) { s << " - " << i << "\n"; } s << " Repr: " << col.GetReprName() << "\n"; s << " Render Tags: \n"; for (auto i : col.GetRenderTags()) { s << " - " << i << "\n"; } TF_DEBUG(HD_DIRTY_LIST).Msg("RenderPass(%p)::SetRprimCollection (%s) - " "constructing new DirtyList(%p) minorChange(%d) \n%s\n", (void*)this, col.GetName().GetText(), (void*)&*_dirtyList, isMinorChange, s.str().c_str()); } }
bool HdDirtyList::ApplyEdit(HdRprimCollection const& col) { HD_TRACE_FUNCTION(); // Don't attempt to transition dirty lists where the collection // fundamentally changed, we can't reused filtered paths in those cases. // // when repr changes, don't reuse the dirty list, since the required // DirtyBits may change. if (col.GetName() != _collection.GetName() || col.GetReprName() != _collection.GetReprName() || col.IsForcedRepr() != _collection.IsForcedRepr() || col.GetRenderTags() != _collection.GetRenderTags()) { return false; } // Also don't attempt to fix-up dirty lists when the collection is radically // different in terms of root paths; here a heuristic of 100 root paths is // used as a threshold for when we will stop attempting to fix the list. if (std::abs(int(col.GetRootPaths().size()) - int(_collection.GetRootPaths().size())) > 100) { return false; } // If the either the old or new collection has Exclude paths do // the full rebuild. if (!col.GetExcludePaths().empty() || !_collection.GetExcludePaths().empty()) { return false; } // If the varying state has changed - Rebuild the base list // before adding the new items HdChangeTracker &changeTracker = _renderIndex.GetChangeTracker(); unsigned int currentVaryingStateVersion = changeTracker.GetVaryingStateVersion(); if (_varyingStateVersion != currentVaryingStateVersion) { TF_DEBUG(HD_DIRTY_LIST).Msg("DirtyList(%p): varying state changed " "(%s, %d -> %d)\n", (void*)this, _collection.GetName().GetText(), _varyingStateVersion, currentVaryingStateVersion); // populate only varying prims in the collection _UpdateIDs(&_dirtyIds, HdChangeTracker::Varying); _varyingStateVersion = currentVaryingStateVersion; } SdfPathVector added, removed; typedef SdfPathVector::const_iterator ITR; ITR newI = col.GetRootPaths().cbegin(); ITR newEnd = col.GetRootPaths().cend(); ITR oldI = _collection.GetRootPaths().cbegin(); ITR oldEnd = _collection.GetRootPaths().cend(); HdRenderIndex& index = _renderIndex; TfToken const & repr = col.GetReprName(); TF_DEBUG(HD_DIRTY_LIST).Msg("DirtyList(%p): ApplyEdit\n", (void*)this); if (TfDebug::IsEnabled(HD_DIRTY_LIST)) { std::cout << " Old Collection: " << std::endl; for (auto const& i : _collection.GetRootPaths()) { std::cout << " " << i << std::endl; } std::cout << " Old _dirtyIds: " << std::endl; for (auto const& i : _dirtyIds) { std::cout << " " << i << std::endl; } } const SdfPathVector &paths = _renderIndex.GetRprimIds(); while (newI != newEnd || oldI != oldEnd) { if (newI != newEnd && oldI != oldEnd && *newI == *oldI) { ++newI; ++oldI; continue; } // If any paths in the two sets are prefixed by one another, the logic // below doesn't work, since the subtree has to be fixed up (it's not // just a simple prefix scan). In these cases, we'll just rebuild the // entire list. if (newI != newEnd && oldI != oldEnd && newI->HasPrefix(*oldI)) { return false; } if (newI != newEnd && oldI != oldEnd && oldI->HasPrefix(*newI)) { return false; } if (newI != newEnd && (oldI == oldEnd || *newI < *oldI)) { HdPrimGather gather; SdfPathVector newPaths; gather.Subtree(paths, *newI, &newPaths); size_t numNewPaths = newPaths.size(); for (size_t newPathNum = 0; newPathNum < numNewPaths; ++newPathNum) { const SdfPath &newPath = newPaths[newPathNum]; if (col.HasRenderTag(index.GetRenderTag(newPath, repr))) { _dirtyIds.push_back(newPath); changeTracker.MarkRprimDirty(newPath, HdChangeTracker::InitRepr); } } ++newI; } else if (oldI != oldEnd) { // oldI < newI: Item removed in new list SdfPath const& oldPath = *oldI; _dirtyIds.erase(std::remove_if(_dirtyIds.begin(), _dirtyIds.end(), [&oldPath](SdfPath const& p){return p.HasPrefix(oldPath);}), _dirtyIds.end()); ++oldI; } } _collection = col; _collectionVersion = changeTracker.GetCollectionVersion(_collection.GetName()); // make sure the next GetDirtyRprims() picks up the updated list. _isEmpty = false; if (TfDebug::IsEnabled(HD_DIRTY_LIST)) { std::cout << " New Collection: " << std::endl; for (auto const& i : _collection.GetRootPaths()) { std::cout << " " << i << std::endl; } std::cout << " New _dirtyIds: " << std::endl; for (auto const& i : _dirtyIds) { std::cout << " " << i << std::endl; } } return true; }