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