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 <optional>
20#include <unordered_map>
21
22PXR_NAMESPACE_OPEN_SCOPE
23
24using HdExtComputationConstPtr = HdExtComputation const *;
25using HdExtComputationConstPtrVector = std::vector<HdExtComputationConstPtr>;
26
27// This class contains utility methods to allow any Hydra backend to execute
28// CPU computations via the Hydra ExtComputation framework.
29//
30// Note:
31// The computation execution happens during Rprim sync. This precludes the
32// use of computations shared by multiple Rprims, since the chain of
33// computations for a computation primvar is executed for each Rprim.
34class HdExtComputationUtils {
35public:
36 using ValueStore =
37 std::unordered_map<TfToken, VtValue, TfToken::HashFunctor>;
38
39 // Returns a map containing the (token, value) pairs for each "computation
40 // primvar".
41 // The participating computations are ordered based on their dependency
42 // and then, the CPU kernel is executed for each computation.
43 HD_API
44 static ValueStore
45 GetComputedPrimvarValues(
46 HdExtComputationPrimvarDescriptorVector const& compPrimvars,
47 HdSceneDelegate* sceneDelegate);
48
49 template <unsigned int CAPACITY>
50 using SampledValueStore =
51 std::unordered_map<TfToken, HdTimeSampleArray<VtValue, CAPACITY>,
53
58 template <unsigned int CAPACITY>
59 static void
60 SampleComputedPrimvarValues(
61 HdExtComputationPrimvarDescriptorVector const& compPrimvars,
62 HdSceneDelegate* sceneDelegate,
63 size_t maxSampleCount,
64 SampledValueStore<CAPACITY> *computedPrimvarValueStore);
65
67 template <unsigned int CAPACITY>
68 static void
69 SampleComputedPrimvarValues(
70 HdExtComputationPrimvarDescriptorVector const& compPrimvars,
71 HdSceneDelegate* sceneDelegate,
72 float startTime, float endTime,
73 size_t maxSampleCount,
74 SampledValueStore<CAPACITY> *computedPrimvarValueStore);
75
76 // Helper methods (these are public for testing purposes)
77 using ComputationDependencyMap =
78 std::unordered_map<HdExtComputation const *,
79 HdExtComputationConstPtrVector>;
80 // Returns true if an ordering of the computations wherein any dependencies
81 // of a given computation come before it is possible, and fills
82 // sortedComps with the ordering.
83 // Returns false otherwise.
84 // The directed graph of a computation (vertex) and its dependencies (edges)
85 // is represented via the ComputationDependencyMap.
86 HD_API
87 static bool
88 DependencySort(ComputationDependencyMap cdm,
89 HdExtComputationConstPtrVector* sortedComps);
90
91 HD_API
92 static void
93 PrintDependencyMap(ComputationDependencyMap const& cdm);
94
95private:
96 template <unsigned int CAPACITY>
97 static void
98 _SampleComputedPrimvarValues(
99 HdExtComputationPrimvarDescriptorVector const& compPrimvars,
100 HdSceneDelegate* sceneDelegate,
101 std::optional<std::pair<float, float>> startAndEndTime,
102 size_t maxSampleCount,
103 SampledValueStore<CAPACITY> *computedPrimvarValueStore);
104
105 HD_API
106 static ComputationDependencyMap
107 _GenerateDependencyMap(
108 HdExtComputationPrimvarDescriptorVector const& compPrimvars,
109 HdSceneDelegate* sceneDelegate);
110
111 template <unsigned int CAPACITY>
112 static void
113 _ExecuteSampledComputations(
114 HdExtComputationConstPtrVector computations,
115 HdSceneDelegate* sceneDelegate,
116 std::optional<std::pair<float, float>> startAndEndTime,
117 size_t maxSampleCount,
118 SampledValueStore<CAPACITY>* valueStore);
119
120 // Limits the list of the computation input time samples to the specified
121 // maximum number of (unique) samples.
122 HD_API
123 static void
124 _LimitTimeSamples(size_t maxSampleCount, std::vector<double>* times);
125
126 // Internal method to invoke the computation with the specified input
127 // values, storing the output values in the provided buffer. The value
128 // arrays correspond to GetSceneInputNames(), GetComputationInputs(), and
129 // GetComputationOutputs() from the HdExtComputation, respectively, and are
130 // required to have the same lengths.
131 HD_API
132 static bool
133 _InvokeComputation(
134 HdSceneDelegate& sceneDelegate,
135 HdExtComputation const& computation,
136 TfSpan<const VtValue> sceneInputValues,
137 TfSpan<const VtValue> compInputValues,
138 TfSpan<VtValue> compOutputValues);
139};
140
141template <unsigned int CAPACITY>
142/*static*/ void
143HdExtComputationUtils::SampleComputedPrimvarValues(
144 HdExtComputationPrimvarDescriptorVector const& compPrimvars,
145 HdSceneDelegate* sceneDelegate,
146 size_t maxSampleCount,
147 SampledValueStore<CAPACITY> *computedPrimvarValueStore
148)
149{
150 _SampleComputedPrimvarValues<CAPACITY>(
151 compPrimvars,
152 sceneDelegate,
153 /* startAndEndTime = */ std::nullopt,
154 maxSampleCount,
155 computedPrimvarValueStore);
156}
157
158template <unsigned int CAPACITY>
159/*static*/ void
160HdExtComputationUtils::SampleComputedPrimvarValues(
161 HdExtComputationPrimvarDescriptorVector const& compPrimvars,
162 HdSceneDelegate* sceneDelegate,
163 float startTime, float endTime,
164 size_t maxSampleCount,
165 SampledValueStore<CAPACITY> *computedPrimvarValueStore
166)
167{
168 _SampleComputedPrimvarValues<CAPACITY>(
169 compPrimvars,
170 sceneDelegate,
171 { {startTime, endTime }},
172 maxSampleCount,
173 computedPrimvarValueStore);
174}
175
176template <unsigned int CAPACITY>
177/*static*/ void
178HdExtComputationUtils::_SampleComputedPrimvarValues(
179 HdExtComputationPrimvarDescriptorVector const& compPrimvars,
180 HdSceneDelegate* sceneDelegate,
181 std::optional<std::pair<float, float>> startAndEndTime,
182 size_t maxSampleCount,
183 SampledValueStore<CAPACITY> *computedPrimvarValueStore
184)
185{
186 HD_TRACE_FUNCTION();
187
188 // Directed graph representation of the participating computations
189 ComputationDependencyMap cdm =
190 _GenerateDependencyMap(compPrimvars, sceneDelegate);
191
192 // Topological ordering of the computations
193 HdExtComputationConstPtrVector sortedComputations;
194 bool success = DependencySort(cdm, &sortedComputations);
195 if (!success) {
196 return;
197 }
198
199 // Execution
200 SampledValueStore<CAPACITY> valueStore;
201 _ExecuteSampledComputations<CAPACITY>(sortedComputations, sceneDelegate,
202 startAndEndTime,
203 maxSampleCount,
204 &valueStore);
205
206 // Output extraction
207 for (auto const& pv : compPrimvars) {
208 TfToken const& compOutputName = pv.sourceComputationOutputName;
209 (*computedPrimvarValueStore)[pv.name] = valueStore[compOutputName];
210 }
211}
212
213template <unsigned int CAPACITY>
214/*static*/ void
215HdExtComputationUtils::_ExecuteSampledComputations(
216 HdExtComputationConstPtrVector computations,
217 HdSceneDelegate* sceneDelegate,
218 std::optional<std::pair<float, float>> startAndEndTime,
219 size_t maxSampleCount,
220 SampledValueStore<CAPACITY> *valueStore
221)
222{
223 HD_TRACE_FUNCTION();
224
225 for (auto const& comp : computations) {
226 SdfPath const& compId = comp->GetId();
227
228 TfTokenVector const& sceneInputNames = comp->GetSceneInputNames();
229 HdExtComputationInputDescriptorVector const& compInputs =
230 comp->GetComputationInputs();
231 HdExtComputationOutputDescriptorVector const& compOutputs =
232 comp->GetComputationOutputs();
233
234 // Add all the scene inputs to the value store
235 std::vector<double> times;
236 for (TfToken const& input : sceneInputNames) {
237 auto &samples = (*valueStore)[input];
238 if (startAndEndTime) {
239 sceneDelegate->SampleExtComputationInput(
240 compId, input,
241 startAndEndTime->first, startAndEndTime->second,
242 &samples);
243 } else {
244 sceneDelegate->SampleExtComputationInput(
245 compId, input,
246 &samples);
247 }
248
249 for (size_t i = 0; i < samples.count; ++i)
250 times.push_back(samples.times[i]);
251 }
252
253 if (comp->IsInputAggregation()) {
254 // An aggregator computation produces no output, and thus
255 // doesn't need to be executed.
256 continue;
257 }
258
259 // Also find all the time samples from the computed inputs.
260 for (auto const& computedInput : compInputs) {
261 auto const& samples =
262 valueStore->at(computedInput.sourceComputationOutputName);
263 for (size_t i = 0; i < samples.count; ++i) {
264 times.push_back(samples.times[i]);
265 }
266 }
267
268 // Determine the time samples to evaluate the computation at.
269 _LimitTimeSamples(maxSampleCount, &times);
270
271 // Allocate enough space for the evaluated outputs.
272 for (const TfToken &name : comp->GetOutputNames())
273 {
274 auto &output_samples = (*valueStore)[name];
275 output_samples.Resize(times.size());
276 output_samples.count = 0;
277 }
278
279 TfSmallVector<VtValue, CAPACITY> sceneInputValues;
280 sceneInputValues.reserve(sceneInputNames.size());
281
282 TfSmallVector<VtValue, CAPACITY> compInputValues;
283 compInputValues.reserve(compInputs.size());
284
285 TfSmallVector<VtValue, CAPACITY> compOutputValues;
286
287 // Evaluate the computation for each time sample.
288 for (double t : times) {
289
290 // Retrieve all the inputs (scene, computed) from the value store,
291 // resampled to the required time.
292 sceneInputValues.clear();
293 for (auto const& sceneInput : comp->GetSceneInputNames()) {
294 auto const& samples = valueStore->at(sceneInput);
295 sceneInputValues.push_back(samples.Resample(t));
296 }
297
298 compInputValues.clear();
299 for (auto const& computedInput : compInputs) {
300 auto const& samples =
301 valueStore->at(computedInput.sourceComputationOutputName);
302 compInputValues.push_back(samples.Resample(t));
303 }
304
305 compOutputValues.resize(compOutputs.size());
306 if (!_InvokeComputation(*sceneDelegate, *comp,
307 TfMakeSpan(sceneInputValues),
308 TfMakeSpan(compInputValues),
309 TfMakeSpan(compOutputValues))) {
310 // We could bail here, or choose to execute other computations.
311 // Choose the latter.
312 continue;
313 }
314
315 // Add outputs to the value store (subsequent computations may need
316 // them as computation inputs)
317 for (size_t i = 0; i < compOutputValues.size(); ++i) {
318 auto &output_samples = (*valueStore)[compOutputs[i].name];
319
320 output_samples.times[output_samples.count] = t;
321 output_samples.values[output_samples.count] =
322 std::move(compOutputValues[i]);
323 ++output_samples.count;
324 }
325 }
326
327 } // for each computation
328}
329
330PXR_NAMESPACE_CLOSE_SCOPE
331
332#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:157
void push_back(const value_type &v)
Copy an entry to the back of the vector,.
Definition: smallVector.h:478
void reserve(size_type newCapacity)
Reserve storage for newCapacity entries.
Definition: smallVector.h:410
size_type size() const
Returns the current size of the vector.
Definition: smallVector.h:596
void resize(size_type newSize, const value_type &v=value_type())
Resize the vector to newSize and insert copies of \v.
Definition: smallVector.h:421
void clear()
Clear the entries in the vector.
Definition: smallVector.h:441
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