HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
extComputationUtils.h
Go to the documentation of this file.
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"
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 
23 
25 using 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.
35 public:
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
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 
54  /// Returns a map containing the (token, samples) pairs for each
55  /// computation primvar, with up to \a maxSampleCount samples.
56  /// The participating computations are ordered based on their dependency
57  /// and then, the CPU kernel is executed for each computation.
58  template <unsigned int CAPACITY>
59  static void
61  HdExtComputationPrimvarDescriptorVector const& compPrimvars,
62  HdSceneDelegate* sceneDelegate,
63  size_t maxSampleCount,
64  SampledValueStore<CAPACITY> *computedPrimvarValueStore);
65 
66  /// Overload taking startTime and endTime explicitly.
67  template <unsigned int CAPACITY>
68  static void
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)
78  std::unordered_map<HdExtComputation const *,
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
89  HdExtComputationConstPtrVector* sortedComps);
90 
91  HD_API
92  static void
94 
95 private:
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
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 
141 template <unsigned int CAPACITY>
142 /*static*/ void
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 
158 template <unsigned int CAPACITY>
159 /*static*/ void
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 
176 template <unsigned int CAPACITY>
177 /*static*/ void
178 HdExtComputationUtils::_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 {
187 
188  // Directed graph representation of the participating computations
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 
213 template <unsigned int CAPACITY>
214 /*static*/ void
215 HdExtComputationUtils::_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 {
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 
331 
332 #endif // PXR_IMAGING_HD_EXT_COMPUTATION_UTILS_H
std::unordered_map< TfToken, HdTimeSampleArray< VtValue, CAPACITY >, TfToken::HashFunctor > SampledValueStore
void push_back(const value_type &v)
Definition: smallVector.h:478
void resize(size_type newSize, const value_type &v=value_type())
Definition: smallVector.h:421
void reserve(size_type newCapacity)
Definition: smallVector.h:410
std::vector< HdExtComputationInputDescriptor > HdExtComputationInputDescriptorVector
#define HD_API
Definition: api.h:23
size_type size() const
Definition: smallVector.h:596
static HD_API void PrintDependencyMap(ComputationDependencyMap const &cdm)
Functor to use for hash maps from tokens to other things.
Definition: token.h:149
std::vector< HdExtComputationOutputDescriptor > HdExtComputationOutputDescriptorVector
std::unordered_map< HdExtComputation const *, HdExtComputationConstPtrVector > ComputationDependencyMap
static HD_API ValueStore GetComputedPrimvarValues(HdExtComputationPrimvarDescriptorVector const &compPrimvars, HdSceneDelegate *sceneDelegate)
Definition: token.h:70
Definition: span.h:70
#define HD_TRACE_FUNCTION()
Definition: perfLog.h:40
std::vector< TfToken > TfTokenVector
Convenience types.
Definition: token.h:440
GLuint const GLchar * name
Definition: glcorearb.h:786
Definition: path.h:273
static void SampleComputedPrimvarValues(HdExtComputationPrimvarDescriptorVector const &compPrimvars, HdSceneDelegate *sceneDelegate, size_t maxSampleCount, SampledValueStore< CAPACITY > *computedPrimvarValueStore)
GLdouble t
Definition: glad.h:2397
GLsizei samples
Definition: glcorearb.h:1298
virtual HD_API size_t SampleExtComputationInput(SdfPath const &computationId, TfToken const &input, size_t maxSampleCount, float *sampleTimes, VtValue *sampleValues)
PXR_NAMESPACE_CLOSE_SCOPE PXR_NAMESPACE_OPEN_SCOPE
Definition: path.h:1425
std::unordered_map< TfToken, VtValue, TfToken::HashFunctor > ValueStore
TfSpan< typename Container::value_type > TfMakeSpan(Container &cont)
Helper for constructing a non-const TfSpan from a container.
Definition: span.h:224
#define PXR_NAMESPACE_CLOSE_SCOPE
Definition: pxr.h:74
static HD_API bool DependencySort(ComputationDependencyMap cdm, HdExtComputationConstPtrVector *sortedComps)
std::vector< HdExtComputationConstPtr > HdExtComputationConstPtrVector
HdExtComputation const * HdExtComputationConstPtr
std::vector< HdExtComputationPrimvarDescriptor > HdExtComputationPrimvarDescriptorVector