From c3b54ec04af9f183526dac835c0ec79bda63678e Mon Sep 17 00:00:00 2001 From: unhyperbolic Date: Tue, 17 Sep 2024 15:28:18 -0700 Subject: [PATCH] Adding Ext computation/primvar depedency tracking to a scene index, HdsiExtComputationDependencySceneIndex. (Internal change: 2341154) --- pxr/imaging/hdsi/CMakeLists.txt | 1 + .../extComputationDependencySceneIndex.cpp | 370 ++++++++++++++++++ .../hdsi/extComputationDependencySceneIndex.h | 78 ++++ 3 files changed, 449 insertions(+) create mode 100644 pxr/imaging/hdsi/extComputationDependencySceneIndex.cpp create mode 100644 pxr/imaging/hdsi/extComputationDependencySceneIndex.h diff --git a/pxr/imaging/hdsi/CMakeLists.txt b/pxr/imaging/hdsi/CMakeLists.txt index 6dc68e31f6..fb357d4c4d 100644 --- a/pxr/imaging/hdsi/CMakeLists.txt +++ b/pxr/imaging/hdsi/CMakeLists.txt @@ -18,6 +18,7 @@ pxr_library(hdsi PUBLIC_CLASSES computeSceneIndexDiff coordSysPrimSceneIndex + extComputationDependencySceneIndex extComputationPrimvarPruningSceneIndex implicitSurfaceSceneIndex legacyDisplayStyleOverrideSceneIndex diff --git a/pxr/imaging/hdsi/extComputationDependencySceneIndex.cpp b/pxr/imaging/hdsi/extComputationDependencySceneIndex.cpp new file mode 100644 index 0000000000..c30ddf936d --- /dev/null +++ b/pxr/imaging/hdsi/extComputationDependencySceneIndex.cpp @@ -0,0 +1,370 @@ +// +// Copyright 2024 Pixar +// +// Licensed under the terms set forth in the LICENSE.txt file available at +// https://openusd.org/license. +// +#include "pxr/imaging/hdsi/extComputationDependencySceneIndex.h" + +#include "pxr/imaging/hd/overlayContainerDataSource.h" +#include "pxr/imaging/hd/retainedDataSource.h" +#include "pxr/imaging/hd/tokens.h" + +#include "pxr/imaging/hd/dependenciesSchema.h" +#include "pxr/imaging/hd/extComputationSchema.h" +#include "pxr/imaging/hd/extComputationInputComputationSchema.h" +#include "pxr/imaging/hd/extComputationPrimvarsSchema.h" +#include "pxr/imaging/hd/primvarsSchema.h" + +#include "pxr/base/trace/trace.h" + +PXR_NAMESPACE_OPEN_SCOPE + +namespace { + +TF_DEFINE_PRIVATE_TOKENS( + _tokens, + (value) + ((all, "__all__")) + + ((primvarExtComputationDependency, "primvarExtComputationDependency_")) + + (extComputationPrimvarsDependenciesDependency) + + (extComputationInputValuesDependency) + ((extComputationInputDependency, "extComputationInputDependency_")) + ((extComputationOutputDependency, "extComputationOutputDependency_")) + + (extComputationInputComputationsDependenciesDependency) + (extComputationOutputsDependenciesDependency) +); + +// Dependencies change when input computations of computation change. +HdDataSourceBaseHandle const & +_ExtComputationInputComputationsDependenciesDependency() +{ + static HdDataSourceBaseHandle const result = + HdDependencySchema::Builder() + .SetDependedOnDataSourceLocator( + HdRetainedTypedSampledDataSource::New( + HdExtComputationSchema::GetInputComputationsLocator())) + .SetAffectedDataSourceLocator( + HdRetainedTypedSampledDataSource::New( + HdDependenciesSchema::GetDefaultLocator())) + .Build(); + return result; +} + +// Dependencies change when outputs of computation change - since we +// generate a dependency of each output on each input computation. +HdDataSourceBaseHandle const & +_ExtComputationOutputsDependenciesDependency() +{ + static HdDataSourceBaseHandle const result = + HdDependencySchema::Builder() + .SetDependedOnDataSourceLocator( + HdRetainedTypedSampledDataSource::New( + HdExtComputationSchema::GetOutputsLocator())) + .SetAffectedDataSourceLocator( + HdRetainedTypedSampledDataSource::New( + HdDependenciesSchema::GetDefaultLocator())) + .Build(); + return result; +} + +// We have a dependency of each output on each input. To avoid adding +// this many depencencies, we funnel through this dummy locator. +HdLocatorDataSourceHandle const & +_AllOutputValuesLocatorDs() +{ + static HdLocatorDataSourceHandle const result = + HdRetainedTypedSampledDataSource::New( + HdExtComputationSchema::GetOutputsLocator() + .Append(_tokens->all) + .Append(_tokens->value)); + return result; +} + +// Add a dependency of all outputs (through dummy locator) on the +// inputValues of the computation. +HdDataSourceBaseHandle +_ExtComputationInputValuesDependency() +{ + static HdDataSourceBaseHandle const result = + HdDependencySchema::Builder() + .SetDependedOnDataSourceLocator( + HdRetainedTypedSampledDataSource::New( + HdExtComputationSchema::GetInputValuesLocator())) + .SetAffectedDataSourceLocator( + _AllOutputValuesLocatorDs()) + .Build(); + return result; +} + +// Build dependencies schema for an ext computation prim. +HdContainerDataSourceHandle +_BuildExtComputationDependencies(HdContainerDataSourceHandle const &primSource) +{ + TRACE_FUNCTION(); + + TfTokenVector names; + std::vector sources; + + // All outputs depend on inputValues (achieved through dummy locator). + names.push_back(_tokens->extComputationInputValuesDependency); + sources.push_back(_ExtComputationInputValuesDependency()); + + const auto compSchema = + HdExtComputationSchema::GetFromParent(primSource); + + const HdExtComputationInputComputationContainerSchema + inputComputationsSchema = compSchema.GetInputComputations(); + + // Make all outputs depend on each input computation. + for (const TfToken &inputName : inputComputationsSchema.GetNames()) { + const HdExtComputationInputComputationSchema inputComputationSchema = + inputComputationsSchema.Get(inputName); + HdPathDataSourceHandle const sourceComputation = + inputComputationSchema.GetSourceComputation(); + if (!sourceComputation) { + continue; + } + HdTokenDataSourceHandle const sourceComputationOutputName = + inputComputationSchema.GetSourceComputationOutputName(); + if (!sourceComputationOutputName) { + continue; + } + + names.push_back( + TfToken( + _tokens->extComputationInputDependency.GetString() + + inputName.GetString())); + sources.push_back( + HdDependencySchema::Builder() + // The ext computation prim corresponding to the input + // computation. + .SetDependedOnPrimPath( + sourceComputation) + // The value of the output on that ext computation prim. + // + // Note that the locator does not correspond to an actual data + // source in the scene index - but we can still use it to signal + // to clients that the value of the computation (wherever it + // will be executed) has changed. + .SetDependedOnDataSourceLocator( + HdRetainedTypedSampledDataSource::New( + HdExtComputationSchema::GetOutputsLocator() + .Append( + sourceComputationOutputName->GetTypedValue(0.0f)) + .Append(_tokens->value))) + // Use dummy locator to affect the values of all outputs. + .SetAffectedDataSourceLocator( + _AllOutputValuesLocatorDs()) + .Build()); + } + + const HdExtComputationOutputContainerSchema outputsSchema = + compSchema.GetOutputs(); + + // Make the value of each computation output depend on dummy locator. + for (const TfToken &outputName : outputsSchema.GetNames()) { + names.push_back( + TfToken( + _tokens->extComputationOutputDependency.GetString() + + outputName.GetString())); + sources.push_back( + HdDependencySchema::Builder() + .SetDependedOnDataSourceLocator( + _AllOutputValuesLocatorDs()) + .SetAffectedDataSourceLocator( + HdRetainedTypedSampledDataSource::New( + HdExtComputationSchema::GetOutputsLocator() + .Append(outputName) + .Append(_tokens->value))) + .Build()); + } + + // Dependencies for the dependencies. + + names.push_back(_tokens->extComputationInputComputationsDependenciesDependency); + sources.push_back(_ExtComputationInputComputationsDependenciesDependency()); + + names.push_back(_tokens->extComputationOutputsDependenciesDependency); + sources.push_back(_ExtComputationOutputsDependenciesDependency()); + + return HdRetainedContainerDataSource::New( + names.size(), names.data(), sources.data()); +} + +// Depenencies change when ext computation primvars change. +static HdDataSourceBaseHandle const & +_ExtComputationPrimvarsDependenciesDependency() +{ + static HdDataSourceBaseHandle const result = + HdDependencySchema::Builder() + .SetDependedOnDataSourceLocator( + HdRetainedTypedSampledDataSource::New( + HdExtComputationPrimvarsSchema::GetDefaultLocator())) + .SetAffectedDataSourceLocator( + HdRetainedTypedSampledDataSource::New( + HdDependenciesSchema::GetDefaultLocator())) + .Build(); + return result; +} + +HdContainerDataSourceHandle +_BuildPrimvarDependencies(HdContainerDataSourceHandle const &primSource) +{ + TRACE_FUNCTION(); + + const auto compPrimvars = + HdExtComputationPrimvarsSchema::GetFromParent(primSource); + + if (!compPrimvars) { + // No ext computation primvars. But they could be added later. + // So add exactly the dependencies for the dependencies. + static HdContainerDataSourceHandle const result = + HdRetainedContainerDataSource::New( + _tokens->extComputationPrimvarsDependenciesDependency, + _ExtComputationPrimvarsDependenciesDependency()); + return result; + } + + TfTokenVector names; + std::vector sources; + + // The value of the primvar depends on the value of the computation. + for (const TfToken &name : compPrimvars.GetExtComputationPrimvarNames()) { + const HdExtComputationPrimvarSchema compPrimvar = + compPrimvars.GetExtComputationPrimvar(name); + + HdPathDataSourceHandle const sourceComputation = + compPrimvar.GetSourceComputation(); + if (!sourceComputation) { + continue; + } + HdTokenDataSourceHandle const sourceComputationOutputName = + compPrimvar.GetSourceComputationOutputName(); + if (!sourceComputationOutputName) { + continue; + } + + names.push_back( + TfToken( + _tokens->primvarExtComputationDependency.GetString() + + name.GetString())); + + sources.push_back( + HdDependencySchema::Builder() + // Ext computation prim driving this primvar. + .SetDependedOnPrimPath( + compPrimvar.GetSourceComputation()) + // Value of computation output. + // + // Similar to above, note that the locator does not correspond + // to an actual data source in the scene index. + .SetDependedOnDataSourceLocator( + HdRetainedTypedSampledDataSource::New( + HdExtComputationSchema::GetOutputsLocator() + .Append( + sourceComputationOutputName->GetTypedValue(0.0f)) + .Append(_tokens->value))) + // Primvar value. + .SetAffectedDataSourceLocator( + HdRetainedTypedSampledDataSource::New( + HdPrimvarsSchema::GetDefaultLocator() + .Append(name) + .Append(HdPrimvarSchemaTokens->primvarValue))) + .Build()); + } + + // Dependencies for the dependencies. + names.push_back(_tokens->extComputationPrimvarsDependenciesDependency); + sources.push_back(_ExtComputationPrimvarsDependenciesDependency()); + + return HdRetainedContainerDataSource::New( + names.size(), names.data(), sources.data()); +} + +// Build dependencies schema. +HdContainerDataSourceHandle +_BuildDependencies(const HdSceneIndexPrim &prim) +{ + TRACE_FUNCTION(); + + if (prim.primType == HdPrimTypeTokens->extComputation) { + return _BuildExtComputationDependencies(prim.dataSource); + } else { + return _BuildPrimvarDependencies(prim.dataSource); + } +} + +} // anonymous namespace + +/* static */ +HdsiExtComputationDependencySceneIndexRefPtr +HdsiExtComputationDependencySceneIndex::New( + const HdSceneIndexBaseRefPtr &inputSceneIndex) +{ + return TfCreateRefPtr( + new HdsiExtComputationDependencySceneIndex(inputSceneIndex)); +} + + +HdsiExtComputationDependencySceneIndex:: + HdsiExtComputationDependencySceneIndex( + const HdSceneIndexBaseRefPtr &inputSceneIndex) +: HdSingleInputFilteringSceneIndexBase(inputSceneIndex) +{ +} + +HdSceneIndexPrim +HdsiExtComputationDependencySceneIndex::GetPrim(const SdfPath &primPath) const +{ + TRACE_FUNCTION(); + + HdSceneIndexPrim prim = _GetInputSceneIndex()->GetPrim(primPath); + + if (prim.dataSource) { + prim.dataSource = HdOverlayContainerDataSource::New( + HdRetainedContainerDataSource::New( + HdDependenciesSchema::GetSchemaToken(), + _BuildDependencies(prim)), + prim.dataSource); + } + + return prim; +} + +SdfPathVector +HdsiExtComputationDependencySceneIndex::GetChildPrimPaths( + const SdfPath &primPath) const +{ + return _GetInputSceneIndex()->GetChildPrimPaths(primPath); +} + +void +HdsiExtComputationDependencySceneIndex::_PrimsAdded( + const HdSceneIndexBase &sender, + const HdSceneIndexObserver::AddedPrimEntries &entries) +{ + _SendPrimsAdded(entries); +} + +void +HdsiExtComputationDependencySceneIndex::_PrimsRemoved( + const HdSceneIndexBase &sender, + const HdSceneIndexObserver::RemovedPrimEntries &entries) +{ + _SendPrimsRemoved(entries); +} + +void +HdsiExtComputationDependencySceneIndex::_PrimsDirtied( + const HdSceneIndexBase &sender, + const HdSceneIndexObserver::DirtiedPrimEntries &entries) +{ + _SendPrimsDirtied(entries); +} + +PXR_NAMESPACE_CLOSE_SCOPE diff --git a/pxr/imaging/hdsi/extComputationDependencySceneIndex.h b/pxr/imaging/hdsi/extComputationDependencySceneIndex.h new file mode 100644 index 0000000000..a97ca3096f --- /dev/null +++ b/pxr/imaging/hdsi/extComputationDependencySceneIndex.h @@ -0,0 +1,78 @@ + +// +// Copyright 2024 Pixar +// +// Licensed under the terms set forth in the LICENSE.txt file available at +// https://openusd.org/license. +// +#ifndef PXR_IMAGING_HDSI_EXT_COMPUTATION_DEPENDENCY_SCENE_INDEX_H +#define PXR_IMAGING_HDSI_EXT_COMPUTATION_DEPENDENCY_SCENE_INDEX_H + +#include "pxr/imaging/hdsi/api.h" +#include "pxr/imaging/hd/filteringSceneIndex.h" + +PXR_NAMESPACE_OPEN_SCOPE + +TF_DECLARE_WEAK_AND_REF_PTRS(HdsiExtComputationDependencySceneIndex); + +/// \class HdsiExtComputationDependencySceneIndex +/// +/// Adds dependencies to dependencies schema for ext computations. +/// +/// More precisely, it adds a dependency of the value of an output of a +/// computation on any input value or the value of any output of another +/// computation serving as computation input. +/// E.g., it adds a dependency of the locator +/// extComputation/outputs/FOO/value on extComputation/inputValues +/// (on the same ext computation prim) or extComputation/outputs/BAR/value +/// (on a different ext computation prim). +/// +/// For an ext computation primvar (on a non-ext computation prim), it +/// adds a dependency on the corresponding primvar value on the input of the +/// respective computation output. +/// E.g., it adds a dependency of the locator +/// primvars/FOO/primvarValue on extComputation/outputs/FOO/value (on the +/// ext computation prim identified by the path data source at +/// extComputationPrimvars/FOO/sourceComputation). +/// +/// Also adds dependencies for these dependencies. +/// +class HdsiExtComputationDependencySceneIndex : + public HdSingleInputFilteringSceneIndexBase +{ +public: + HDSI_API + static HdsiExtComputationDependencySceneIndexRefPtr + New(const HdSceneIndexBaseRefPtr &inputSceneIndex); + + HDSI_API + HdSceneIndexPrim GetPrim(const SdfPath &primPath) const override; + + HDSI_API + SdfPathVector GetChildPrimPaths(const SdfPath &primPath) const override; + +protected: + HDSI_API + void _PrimsAdded( + const HdSceneIndexBase &sender, + const HdSceneIndexObserver::AddedPrimEntries &entries) override; + + HDSI_API + void _PrimsRemoved( + const HdSceneIndexBase &sender, + const HdSceneIndexObserver::RemovedPrimEntries &entries) override; + + HDSI_API + void _PrimsDirtied( + const HdSceneIndexBase &sender, + const HdSceneIndexObserver::DirtiedPrimEntries &entries) override; + + HDSI_API + HdsiExtComputationDependencySceneIndex( + const HdSceneIndexBaseRefPtr &inputSceneIndex); + +}; + +PXR_NAMESPACE_CLOSE_SCOPE + +#endif //PXR_IMAGING_HDSI_EXT_COMPUTATION_PRIMVAR_PRUNING_SCENE_INDEX_H