Loading...
Searching...
No Matches
extComputationUtils.h
1//
2// Copyright 2019 Pixar
3//
4// Licensed under the terms set forth in the LICENSE.txt file available at
5// https://openusd.org/license.
6//
7#ifndef PXR_IMAGING_HD_EXT_COMPUTATION_UTILS_H
8#define PXR_IMAGING_HD_EXT_COMPUTATION_UTILS_H
9
10#include "pxr/pxr.h"
11#include "pxr/imaging/hd/api.h"
12#include "pxr/imaging/hd/extComputation.h"
13#include "pxr/imaging/hd/sceneDelegate.h"
14
15#include "pxr/base/tf/span.h"
16#include "pxr/base/tf/token.h"
17#include "pxr/base/vt/value.h"
18
19#include <unordered_map>
20
21PXR_NAMESPACE_OPEN_SCOPE
22
23using HdExtComputationConstPtr = HdExtComputation const *;
24using HdExtComputationConstPtrVector = std::vector<HdExtComputationConstPtr>;
25
26// This class contains utility methods to allow any Hydra backend to execute
27// CPU computations via the Hydra ExtComputation framework.
28//
29// Note:
30// The computation execution happens during Rprim sync. This precludes the
31// use of computations shared by multiple Rprims, since the chain of
32// computations for a computation primvar is executed for each Rprim.
33class HdExtComputationUtils {
34public:
35 using ValueStore =
36 std::unordered_map<TfToken, VtValue, TfToken::HashFunctor>;
37
38 // Returns a map containing the (token, value) pairs for each "computation
39 // primvar".
40 // The participating computations are ordered based on their dependency
41 // and then, the CPU kernel is executed for each computation.
42 HD_API
43 static ValueStore
44 GetComputedPrimvarValues(
45 HdExtComputationPrimvarDescriptorVector const& compPrimvars,
46 HdSceneDelegate* sceneDelegate);
47
48 template <unsigned int CAPACITY>
49 using SampledValueStore =
50 std::unordered_map<TfToken, HdTimeSampleArray<VtValue, CAPACITY>,
52
57 template <unsigned int CAPACITY>
58 static void
59 SampleComputedPrimvarValues(
60 HdExtComputationPrimvarDescriptorVector const& compPrimvars,
61 HdSceneDelegate* sceneDelegate,
62 size_t maxSampleCount,
63 SampledValueStore<CAPACITY> *computedPrimvarValueStore);
64
65 // Helper methods (these are public for testing purposes)
66 using ComputationDependencyMap =
67 std::unordered_map<HdExtComputation const *,
68 HdExtComputationConstPtrVector>;
69 // Returns true if an ordering of the computations wherein any dependencies
70 // of a given computation come before it is possible, and fills
71 // sortedComps with the ordering.
72 // Returns false otherwise.
73 // The directed graph of a computation (vertex) and its dependencies (edges)
74 // is represented via the ComputationDependencyMap.
75 HD_API
76 static bool
77 DependencySort(ComputationDependencyMap cdm,
78 HdExtComputationConstPtrVector* sortedComps);
79
80 HD_API
81 static void
82 PrintDependencyMap(ComputationDependencyMap const& cdm);
83
84private:
85 HD_API
86 static ComputationDependencyMap
87 _GenerateDependencyMap(
88 HdExtComputationPrimvarDescriptorVector const& compPrimvars,
89 HdSceneDelegate* sceneDelegate);
90
91 template <unsigned int CAPACITY>
92 static void
93 _ExecuteSampledComputations(
94 HdExtComputationConstPtrVector computations,
95 HdSceneDelegate* sceneDelegate,
96 size_t maxSampleCount,
97 SampledValueStore<CAPACITY>* valueStore);
98
99 // Limits the list of the computation input time samples to the specified
100 // maximum number of (unique) samples.
101 HD_API
102 static void
103 _LimitTimeSamples(size_t maxSampleCount, std::vector<double>* times);
104
105 // Internal method to invoke the computation with the specified input
106 // values, storing the output values in the provided buffer. The value
107 // arrays correspond to GetSceneInputNames(), GetComputationInputs(), and
108 // GetComputationOutputs() from the HdExtComputation, respectively, and are
109 // required to have the same lengths.
110 HD_API
111 static bool
112 _InvokeComputation(
113 HdSceneDelegate& sceneDelegate,
114 HdExtComputation const& computation,
115 TfSpan<const VtValue> sceneInputValues,
116 TfSpan<const VtValue> compInputValues,
117 TfSpan<VtValue> compOutputValues);
118};
119
120template <unsigned int CAPACITY>
121/*static*/ void
122HdExtComputationUtils::SampleComputedPrimvarValues(
123 HdExtComputationPrimvarDescriptorVector const& compPrimvars,
124 HdSceneDelegate* sceneDelegate,
125 size_t maxSampleCount,
126 SampledValueStore<CAPACITY> *computedPrimvarValueStore
127)
128{
129 HD_TRACE_FUNCTION();
130
131 // Directed graph representation of the participating computations
132 ComputationDependencyMap cdm =
133 _GenerateDependencyMap(compPrimvars, sceneDelegate);
134
135 // Topological ordering of the computations
136 HdExtComputationConstPtrVector sortedComputations;
137 bool success = DependencySort(cdm, &sortedComputations);
138 if (!success) {
139 return;
140 }
141
142 // Execution
143 SampledValueStore<CAPACITY> valueStore;
144 _ExecuteSampledComputations<CAPACITY>(sortedComputations, sceneDelegate,
145 maxSampleCount, &valueStore);
146
147 // Output extraction
148 for (auto const& pv : compPrimvars) {
149 TfToken const& compOutputName = pv.sourceComputationOutputName;
150 (*computedPrimvarValueStore)[pv.name] = valueStore[compOutputName];
151 }
152}
153
154template <unsigned int CAPACITY>
155/*static*/ void
156HdExtComputationUtils::_ExecuteSampledComputations(
157 HdExtComputationConstPtrVector computations,
158 HdSceneDelegate* sceneDelegate,
159 size_t maxSampleCount,
160 SampledValueStore<CAPACITY> *valueStore
161)
162{
163 HD_TRACE_FUNCTION();
164
165 for (auto const& comp : computations) {
166 SdfPath const& compId = comp->GetId();
167
168 TfTokenVector const& sceneInputNames = comp->GetSceneInputNames();
169 HdExtComputationInputDescriptorVector const& compInputs =
170 comp->GetComputationInputs();
171 HdExtComputationOutputDescriptorVector const& compOutputs =
172 comp->GetComputationOutputs();
173
174 // Add all the scene inputs to the value store
175 std::vector<double> times;
176 for (TfToken const& input : sceneInputNames) {
177 auto &samples = (*valueStore)[input];
178 sceneDelegate->SampleExtComputationInput(compId, input, &samples);
179
180 for (size_t i = 0; i < samples.count; ++i)
181 times.push_back(samples.times[i]);
182 }
183
184 if (comp->IsInputAggregation()) {
185 // An aggregator computation produces no output, and thus
186 // doesn't need to be executed.
187 continue;
188 }
189
190 // Also find all the time samples from the computed inputs.
191 for (auto const& computedInput : compInputs) {
192 auto const& samples =
193 valueStore->at(computedInput.sourceComputationOutputName);
194 for (size_t i = 0; i < samples.count; ++i) {
195 times.push_back(samples.times[i]);
196 }
197 }
198
199 // Determine the time samples to evaluate the computation at.
200 _LimitTimeSamples(maxSampleCount, &times);
201
202 // Allocate enough space for the evaluated outputs.
203 for (const TfToken &name : comp->GetOutputNames())
204 {
205 auto &output_samples = (*valueStore)[name];
206 output_samples.Resize(times.size());
207 output_samples.count = 0;
208 }
209
210 TfSmallVector<VtValue, CAPACITY> sceneInputValues;
211 sceneInputValues.reserve(sceneInputNames.size());
212
213 TfSmallVector<VtValue, CAPACITY> compInputValues;
214 compInputValues.reserve(compInputs.size());
215
216 TfSmallVector<VtValue, CAPACITY> compOutputValues;
217
218 // Evaluate the computation for each time sample.
219 for (double t : times) {
220
221 // Retrieve all the inputs (scene, computed) from the value store,
222 // resampled to the required time.
223 sceneInputValues.clear();
224 for (auto const& sceneInput : comp->GetSceneInputNames()) {
225 auto const& samples = valueStore->at(sceneInput);
226 sceneInputValues.push_back(samples.Resample(t));
227 }
228
229 compInputValues.clear();
230 for (auto const& computedInput : compInputs) {
231 auto const& samples =
232 valueStore->at(computedInput.sourceComputationOutputName);
233 compInputValues.push_back(samples.Resample(t));
234 }
235
236 compOutputValues.resize(compOutputs.size());
237 if (!_InvokeComputation(*sceneDelegate, *comp,
238 TfMakeSpan(sceneInputValues),
239 TfMakeSpan(compInputValues),
240 TfMakeSpan(compOutputValues))) {
241 // We could bail here, or choose to execute other computations.
242 // Choose the latter.
243 continue;
244 }
245
246 // Add outputs to the value store (subsequent computations may need
247 // them as computation inputs)
248 for (size_t i = 0; i < compOutputValues.size(); ++i) {
249 auto &output_samples = (*valueStore)[compOutputs[i].name];
250
251 output_samples.times[output_samples.count] = t;
252 output_samples.values[output_samples.count] =
253 std::move(compOutputValues[i]);
254 ++output_samples.count;
255 }
256 }
257
258 } // for each computation
259}
260
261PXR_NAMESPACE_CLOSE_SCOPE
262
263#endif // PXR_IMAGING_HD_EXT_COMPUTATION_UTILS_H
Hydra Representation of a Client defined computation.
Adapter class providing data exchange with the client scene graph.
virtual HD_API size_t SampleExtComputationInput(SdfPath const &computationId, TfToken const &input, size_t maxSampleCount, float *sampleTimes, VtValue *sampleValues)
Return up to maxSampleCount samples for a given computation id and input token.
A path value used to locate objects in layers or scenegraphs.
Definition: path.h:274
This is a small-vector class with local storage optimization, the local storage can be specified via ...
Definition: smallVector.h:155
void push_back(const value_type &v)
Copy an entry to the back of the vector,.
Definition: smallVector.h:476
void reserve(size_type newCapacity)
Reserve storage for newCapacity entries.
Definition: smallVector.h:408
size_type size() const
Returns the current size of the vector.
Definition: smallVector.h:594
void resize(size_type newSize, const value_type &v=value_type())
Resize the vector to newSize and insert copies of \v.
Definition: smallVector.h:419
void clear()
Clear the entries in the vector.
Definition: smallVector.h:439
Represents a range of contiguous elements.
Definition: span.h:71
Token for efficient comparison, assignment, and hashing of known strings.
Definition: token.h:71
TfSpan< typename Container::value_type > TfMakeSpan(Container &cont)
Helper for constructing a non-const TfSpan from a container.
Definition: span.h:224
Functor to use for hash maps from tokens to other things.
Definition: token.h:149
TfToken class for efficient string referencing and hashing, plus conversions to and from stl string c...
std::vector< TfToken > TfTokenVector
Convenience types.
Definition: token.h:440