Blender  V3.3
render_delegate.cpp
Go to the documentation of this file.
1 /* SPDX-License-Identifier: Apache-2.0
2  * Copyright 2022 NVIDIA Corporation
3  * Copyright 2022 Blender Foundation */
4 
6 #include "hydra/camera.h"
7 #include "hydra/curves.h"
8 #include "hydra/field.h"
9 #include "hydra/instancer.h"
10 #include "hydra/light.h"
11 #include "hydra/material.h"
12 #include "hydra/mesh.h"
13 #include "hydra/node_util.h"
14 #include "hydra/pointcloud.h"
15 #include "hydra/render_buffer.h"
16 #include "hydra/render_pass.h"
17 #include "hydra/session.h"
18 #include "hydra/volume.h"
19 #include "scene/integrator.h"
20 #include "scene/scene.h"
21 #include "session/session.h"
22 
23 #include <pxr/base/tf/getenv.h>
24 #include <pxr/imaging/hd/extComputation.h>
25 #include <pxr/imaging/hgi/tokens.h>
26 
28 
30 
31 // clang-format off
33  (cycles)
34  (openvdbAsset)
35 );
36 // clang-format on
37 
38 namespace {
39 
40 const TfTokenVector kSupportedRPrimTypes = {
41  HdPrimTypeTokens->basisCurves,
42  HdPrimTypeTokens->mesh,
43  HdPrimTypeTokens->points,
44 #ifdef WITH_OPENVDB
45  HdPrimTypeTokens->volume,
46 #endif
47 };
48 
49 const TfTokenVector kSupportedSPrimTypes = {
50  HdPrimTypeTokens->camera,
51  HdPrimTypeTokens->material,
52  HdPrimTypeTokens->diskLight,
53  HdPrimTypeTokens->distantLight,
54  HdPrimTypeTokens->domeLight,
55  HdPrimTypeTokens->rectLight,
56  HdPrimTypeTokens->sphereLight,
57  HdPrimTypeTokens->extComputation,
58 };
59 
60 const TfTokenVector kSupportedBPrimTypes = {
61  HdPrimTypeTokens->renderBuffer,
62 #ifdef WITH_OPENVDB
63  _tokens->openvdbAsset,
64 #endif
65 };
66 
67 SessionParams GetSessionParams(const HdRenderSettingsMap &settings)
68 {
70  params.threads = 0;
71  params.background = false;
72  params.use_resolution_divider = false;
73 
74  HdRenderSettingsMap::const_iterator it;
75 
76  // Pull all setting that contribute to device creation first
77  it = settings.find(HdCyclesRenderSettingsTokens->threads);
78  if (it != settings.end()) {
79  params.threads = VtValue::Cast<int>(it->second).GetWithDefault(params.threads);
80  }
81 
82  // Get the Cycles device from settings or environment, falling back to CPU
83  std::string deviceType = Device::string_from_type(DEVICE_CPU);
84  it = settings.find(HdCyclesRenderSettingsTokens->device);
85  if (it != settings.end()) {
86  deviceType = VtValue::Cast<std::string>(it->second).GetWithDefault(deviceType);
87  }
88  else {
89  const std::string deviceTypeEnv = TfGetenv("CYCLES_DEVICE");
90  if (!deviceTypeEnv.empty()) {
91  deviceType = deviceTypeEnv;
92  }
93  }
94 
95  // Move to all uppercase for Device::type_from_string
96  std::transform(deviceType.begin(), deviceType.end(), deviceType.begin(), ::toupper);
97 
99  DEVICE_MASK(Device::type_from_string(deviceType.c_str())));
100  if (devices.empty()) {
102  if (!devices.empty()) {
103  params.device = devices.front();
104  }
105  }
106  else {
107  params.device = Device::get_multi_device(devices, params.threads, params.background);
108  }
109 
110  return params;
111 }
112 
113 } // namespace
114 
115 HdCyclesDelegate::HdCyclesDelegate(const HdRenderSettingsMap &settingsMap,
116  Session *session_,
117  const bool keep_nodes)
118  : HdRenderDelegate()
119 {
120  _renderParam = session_ ? std::make_unique<HdCyclesSession>(session_, keep_nodes) :
121  std::make_unique<HdCyclesSession>(GetSessionParams(settingsMap));
122 
123  for (const auto &setting : settingsMap) {
124  // Skip over the settings known to be used for initialization only
125  if (setting.first == HdCyclesRenderSettingsTokens->device ||
126  setting.first == HdCyclesRenderSettingsTokens->threads) {
127  continue;
128  }
129 
130  SetRenderSetting(setting.first, setting.second);
131  }
132 }
133 
135 {
136 }
137 
138 void HdCyclesDelegate::SetDrivers(const HdDriverVector &drivers)
139 {
140  for (HdDriver *hdDriver : drivers) {
141  if (hdDriver->name == HgiTokens->renderDriver && hdDriver->driver.IsHolding<Hgi *>()) {
142  _hgi = hdDriver->driver.UncheckedGet<Hgi *>();
143  break;
144  }
145  }
146 }
147 
149 {
150 #if defined(_WIN32) && defined(WITH_HYDRA_DISPLAY_DRIVER)
151  return _hgi && _hgi->GetAPIName() == HgiTokens->OpenGL;
152 #else
153  return false;
154 #endif
155 }
156 
157 const TfTokenVector &HdCyclesDelegate::GetSupportedRprimTypes() const
158 {
159  return kSupportedRPrimTypes;
160 }
161 
162 const TfTokenVector &HdCyclesDelegate::GetSupportedSprimTypes() const
163 {
164  return kSupportedSPrimTypes;
165 }
166 
167 const TfTokenVector &HdCyclesDelegate::GetSupportedBprimTypes() const
168 {
169  return kSupportedBPrimTypes;
170 }
171 
172 HdRenderParam *HdCyclesDelegate::GetRenderParam() const
173 {
174  return _renderParam.get();
175 }
176 
177 HdResourceRegistrySharedPtr HdCyclesDelegate::GetResourceRegistry() const
178 {
179  return HdResourceRegistrySharedPtr();
180 }
181 
183 {
184  return true;
185 }
186 
188 {
189  _renderParam->session->set_pause(true);
190  return true;
191 }
192 
194 {
195  _renderParam->session->set_pause(false);
196  return true;
197 }
198 
199 HdRenderPassSharedPtr HdCyclesDelegate::CreateRenderPass(HdRenderIndex *index,
200  const HdRprimCollection &collection)
201 {
202  return HdRenderPassSharedPtr(new HdCyclesRenderPass(index, collection, _renderParam.get()));
203 }
204 
205 HdInstancer *HdCyclesDelegate::CreateInstancer(HdSceneDelegate *delegate,
206  const SdfPath &instancerId
207 #if PXR_VERSION < 2102
208  ,
209  const SdfPath &parentId
210 #endif
211 )
212 {
213  return new HdCyclesInstancer(delegate,
214  instancerId
215 #if PXR_VERSION < 2102
216  ,
217  parentId
218 #endif
219  );
220 }
221 
222 void HdCyclesDelegate::DestroyInstancer(HdInstancer *instancer)
223 {
224  delete instancer;
225 }
226 
227 HdRprim *HdCyclesDelegate::CreateRprim(const TfToken &typeId,
228  const SdfPath &rprimId
229 #if PXR_VERSION < 2102
230  ,
231  const SdfPath &instancerId
232 #endif
233 )
234 {
235  if (typeId == HdPrimTypeTokens->mesh) {
236  return new HdCyclesMesh(rprimId
237 #if PXR_VERSION < 2102
238  ,
239  instancerId
240 #endif
241  );
242  }
243  if (typeId == HdPrimTypeTokens->basisCurves) {
244  return new HdCyclesCurves(rprimId
245 #if PXR_VERSION < 2102
246  ,
247  instancerId
248 #endif
249  );
250  }
251  if (typeId == HdPrimTypeTokens->points) {
252  return new HdCyclesPoints(rprimId
253 #if PXR_VERSION < 2102
254  ,
255  instancerId
256 #endif
257  );
258  }
259 #ifdef WITH_OPENVDB
260  if (typeId == HdPrimTypeTokens->volume) {
261  return new HdCyclesVolume(rprimId
262 # if PXR_VERSION < 2102
263  ,
264  instancerId
265 # endif
266  );
267  }
268 #endif
269 
270  TF_CODING_ERROR("Unknown Rprim type %s", typeId.GetText());
271  return nullptr;
272 }
273 
274 void HdCyclesDelegate::DestroyRprim(HdRprim *rPrim)
275 {
276  delete rPrim;
277 }
278 
279 HdSprim *HdCyclesDelegate::CreateSprim(const TfToken &typeId, const SdfPath &sprimId)
280 {
281  if (typeId == HdPrimTypeTokens->camera) {
282  return new HdCyclesCamera(sprimId);
283  }
284  if (typeId == HdPrimTypeTokens->material) {
285  return new HdCyclesMaterial(sprimId);
286  }
287  if (typeId == HdPrimTypeTokens->diskLight || typeId == HdPrimTypeTokens->distantLight ||
288  typeId == HdPrimTypeTokens->domeLight || typeId == HdPrimTypeTokens->rectLight ||
289  typeId == HdPrimTypeTokens->sphereLight) {
290  return new HdCyclesLight(sprimId, typeId);
291  }
292  if (typeId == HdPrimTypeTokens->extComputation) {
293  return new HdExtComputation(sprimId);
294  }
295 
296  TF_CODING_ERROR("Unknown Sprim type %s", typeId.GetText());
297  return nullptr;
298 }
299 
300 HdSprim *HdCyclesDelegate::CreateFallbackSprim(const TfToken &typeId)
301 {
302  return CreateSprim(typeId, SdfPath::EmptyPath());
303 }
304 
305 void HdCyclesDelegate::DestroySprim(HdSprim *sPrim)
306 {
307  delete sPrim;
308 }
309 
310 HdBprim *HdCyclesDelegate::CreateBprim(const TfToken &typeId, const SdfPath &bprimId)
311 {
312  if (typeId == HdPrimTypeTokens->renderBuffer) {
313  return new HdCyclesRenderBuffer(bprimId);
314  }
315 #ifdef WITH_OPENVDB
316  if (typeId == _tokens->openvdbAsset) {
317  return new HdCyclesField(bprimId, typeId);
318  }
319 #endif
320 
321  TF_CODING_ERROR("Unknown Bprim type %s", typeId.GetText());
322  return nullptr;
323 }
324 
325 HdBprim *HdCyclesDelegate::CreateFallbackBprim(const TfToken &typeId)
326 {
327  return CreateBprim(typeId, SdfPath::EmptyPath());
328 }
329 
330 void HdCyclesDelegate::DestroyBprim(HdBprim *bPrim)
331 {
332  delete bPrim;
333 }
334 
335 void HdCyclesDelegate::CommitResources(HdChangeTracker *tracker)
336 {
337  TF_UNUSED(tracker);
338 
339  const SceneLock lock(_renderParam.get());
340 
341  _renderParam->UpdateScene();
342 }
343 
345 {
346  return HdTokens->full;
347 }
348 
349 #if HD_API_VERSION < 41
351 {
352  return _tokens->cycles;
353 }
354 #else
355 TfTokenVector HdCyclesDelegate::GetMaterialRenderContexts() const
356 {
357  return {_tokens->cycles};
358 }
359 #endif
360 
362 {
363  const Stats &stats = _renderParam->session->stats;
364  const Progress &progress = _renderParam->session->progress;
365 
366  double totalTime, renderTime;
367  progress.get_time(totalTime, renderTime);
368  double fractionDone = progress.get_progress();
369 
370  std::string status, substatus;
371  progress.get_status(status, substatus);
372  if (!substatus.empty()) {
373  status += " | " + substatus;
374  }
375 
376  return {{"rendererName", VtValue("Cycles")},
377  {"rendererVersion", VtValue(GfVec3i(0, 0, 0))},
378  {"percentDone", VtValue(floor_to_int(fractionDone * 100))},
379  {"fractionDone", VtValue(fractionDone)},
380  {"loadClockTime", VtValue(totalTime - renderTime)},
381  {"peakMemory", VtValue(stats.mem_peak)},
382  {"totalClockTime", VtValue(totalTime)},
383  {"totalMemory", VtValue(stats.mem_used)},
384  {"renderProgressAnnotation", VtValue(status)}};
385 }
386 
387 HdAovDescriptor HdCyclesDelegate::GetDefaultAovDescriptor(const TfToken &name) const
388 {
389  if (name == HdAovTokens->color) {
390  HdFormat colorFormat = HdFormatFloat32Vec4;
391  if (IsDisplaySupported()) {
392  // Can use Cycles 'DisplayDriver' in OpenGL, but it only supports 'half4' format
393  colorFormat = HdFormatFloat16Vec4;
394  }
395 
396  return HdAovDescriptor(colorFormat, false, VtValue(GfVec4f(0.0f)));
397  }
398  if (name == HdAovTokens->depth) {
399  return HdAovDescriptor(HdFormatFloat32, false, VtValue(1.0f));
400  }
401  if (name == HdAovTokens->normal) {
402  return HdAovDescriptor(HdFormatFloat32Vec3, false, VtValue(GfVec3f(0.0f)));
403  }
404  if (name == HdAovTokens->primId || name == HdAovTokens->instanceId ||
405  name == HdAovTokens->elementId) {
406  return HdAovDescriptor(HdFormatInt32, false, VtValue(-1));
407  }
408 
409  return HdAovDescriptor();
410 }
411 
412 HdRenderSettingDescriptorList HdCyclesDelegate::GetRenderSettingDescriptors() const
413 {
414  Scene *const scene = _renderParam->session->scene;
415 
416  HdRenderSettingDescriptorList descriptors;
417 
418  descriptors.push_back({
419  "Time Limit",
420  HdCyclesRenderSettingsTokens->timeLimit,
421  VtValue(0.0),
422  });
423  descriptors.push_back({
424  "Sample Count",
425  HdCyclesRenderSettingsTokens->samples,
426  VtValue(1024),
427  });
428  descriptors.push_back({
429  "Sample Offset",
430  HdCyclesRenderSettingsTokens->sampleOffset,
431  VtValue(0),
432  });
433 
434  for (const SocketType &socket : scene->integrator->type->inputs) {
435  descriptors.push_back({socket.ui_name.string(),
436  TfToken("cycles:integrator:" + socket.name.string()),
437  GetNodeValue(scene->integrator, socket)});
438  }
439 
440  return descriptors;
441 }
442 
443 void HdCyclesDelegate::SetRenderSetting(const PXR_NS::TfToken &key, const PXR_NS::VtValue &value)
444 {
445  Scene *const scene = _renderParam->session->scene;
446  Session *const session = _renderParam->session;
447 
448  if (key == HdCyclesRenderSettingsTokens->stageMetersPerUnit) {
449  _renderParam->SetStageMetersPerUnit(
450  VtValue::Cast<double>(value).GetWithDefault(_renderParam->GetStageMetersPerUnit()));
451  }
452  else if (key == HdCyclesRenderSettingsTokens->timeLimit) {
453  session->set_time_limit(
454  VtValue::Cast<double>(value).GetWithDefault(session->params.time_limit));
455  }
456  else if (key == HdCyclesRenderSettingsTokens->samples) {
457  static const int max_samples = Integrator::MAX_SAMPLES;
458  int samples = VtValue::Cast<int>(value).GetWithDefault(session->params.samples);
459  samples = std::min(std::max(1, samples), max_samples);
460  session->set_samples(samples);
461  }
462  else if (key == HdCyclesRenderSettingsTokens->sampleOffset) {
463  session->params.sample_offset = VtValue::Cast<int>(value).GetWithDefault(
464  session->params.sample_offset);
465  ++_settingsVersion;
466  }
467  else {
468  const std::string &keyString = key.GetString();
469  if (keyString.rfind("cycles:integrator:", 0) == 0) {
470  ustring socketName(keyString, sizeof("cycles:integrator:") - 1);
471  if (const SocketType *socket = scene->integrator->type->find_input(socketName)) {
472  SetNodeValue(scene->integrator, *socket, value);
473  ++_settingsVersion;
474  }
475  }
476  }
477 }
478 
479 VtValue HdCyclesDelegate::GetRenderSetting(const TfToken &key) const
480 {
481  Scene *const scene = _renderParam->session->scene;
482  Session *const session = _renderParam->session;
483 
484  if (key == HdCyclesRenderSettingsTokens->stageMetersPerUnit) {
485  return VtValue(_renderParam->GetStageMetersPerUnit());
486  }
487  else if (key == HdCyclesRenderSettingsTokens->device) {
488  return VtValue(TfToken(Device::string_from_type(session->params.device.type)));
489  }
490  else if (key == HdCyclesRenderSettingsTokens->threads) {
491  return VtValue(session->params.threads);
492  }
493  else if (key == HdCyclesRenderSettingsTokens->timeLimit) {
494  return VtValue(session->params.time_limit);
495  }
496  else if (key == HdCyclesRenderSettingsTokens->samples) {
497  return VtValue(session->params.samples);
498  }
499  else if (key == HdCyclesRenderSettingsTokens->sampleOffset) {
500  return VtValue(session->params.sample_offset);
501  }
502  else {
503  const std::string &keyString = key.GetString();
504  if (keyString.rfind("cycles:integrator:", 0) == 0) {
505  ustring socketName(keyString, sizeof("cycles:integrator:") - 1);
506  if (const SocketType *socket = scene->integrator->type->find_input(socketName)) {
507  return GetNodeValue(scene->integrator, *socket);
508  }
509  }
510  }
511 
512  return VtValue();
513 }
514 
volatile int lock
SIMD_FORCE_INLINE btVector3 transform(const btVector3 &point) const
DeviceType type
Definition: device/device.h:62
static vector< DeviceInfo > available_devices(uint device_type_mask=DEVICE_MASK_ALL)
static DeviceType type_from_string(const char *name)
static string string_from_type(DeviceType type)
static DeviceInfo get_multi_device(const vector< DeviceInfo > &subdevices, int threads, bool background)
bool IsPauseSupported() const override
PXR_NS::HdBprim * CreateFallbackBprim(const PXR_NS::TfToken &typeId) override
bool Resume() override
~HdCyclesDelegate() override
void SetRenderSetting(const PXR_NS::TfToken &key, const PXR_NS::VtValue &value) override
void DestroyRprim(PXR_NS::HdRprim *rPrim) override
const PXR_NS::TfTokenVector & GetSupportedSprimTypes() const override
PXR_NS::HdRenderParam * GetRenderParam() const override
PXR_NS::HdRenderPassSharedPtr CreateRenderPass(PXR_NS::HdRenderIndex *index, const PXR_NS::HdRprimCollection &collection) override
PXR_NS::HdSprim * CreateFallbackSprim(const PXR_NS::TfToken &typeId) override
PXR_NS::TfToken GetMaterialNetworkSelector() const override
PXR_NS::HdResourceRegistrySharedPtr GetResourceRegistry() const override
PXR_NS::HdInstancer * CreateInstancer(PXR_NS::HdSceneDelegate *delegate, const PXR_NS::SdfPath &id, const PXR_NS::SdfPath &instancerId) override
void DestroySprim(PXR_NS::HdSprim *sPrim) override
bool Pause() override
void CommitResources(PXR_NS::HdChangeTracker *tracker) override
const PXR_NS::TfTokenVector & GetSupportedBprimTypes() const override
const PXR_NS::TfTokenVector & GetSupportedRprimTypes() const override
HdCyclesDelegate(const PXR_NS::HdRenderSettingsMap &settingsMap, CCL_NS::Session *session_=nullptr, const bool keep_nodes=false)
PXR_NS::HdRprim * CreateRprim(const PXR_NS::TfToken &typeId, const PXR_NS::SdfPath &rprimId, const PXR_NS::SdfPath &instancerId) override
PXR_NS::HdAovDescriptor GetDefaultAovDescriptor(const PXR_NS::TfToken &name) const override
PXR_NS::HdSprim * CreateSprim(const PXR_NS::TfToken &typeId, const PXR_NS::SdfPath &sprimId) override
PXR_NS::VtValue GetRenderSetting(const PXR_NS::TfToken &key) const override
void SetDrivers(const PXR_NS::HdDriverVector &drivers) override
bool IsDisplaySupported() const
PXR_NS::HdRenderSettingDescriptorList GetRenderSettingDescriptors() const override
PXR_NS::TfToken GetMaterialBindingPurpose() const override
void DestroyBprim(PXR_NS::HdBprim *bPrim) override
PXR_NS::VtDictionary GetRenderStats() const override
void DestroyInstancer(PXR_NS::HdInstancer *instancer) override
PXR_NS::HdBprim * CreateBprim(const PXR_NS::TfToken &typeId, const PXR_NS::SdfPath &bprimId) override
static const int MAX_SAMPLES
Definition: integrator.h:65
void get_status(string &status_, string &substatus_) const
Definition: progress.h:290
void get_time(double &total_time_, double &render_time_) const
Definition: progress.h:158
double get_progress() const
Definition: progress.h:190
DeviceInfo device
void set_time_limit(double time_limit)
SessionParams params
void set_samples(int samples)
size_t mem_used
Definition: util/stats.h:35
size_t mem_peak
Definition: util/stats.h:36
Scene scene
#define DEVICE_MASK(type)
Definition: device/device.h:58
@ DEVICE_MASK_CPU
Definition: device/device.h:49
@ DEVICE_CPU
Definition: device/device.h:38
#define HDCYCLES_NAMESPACE_CLOSE_SCOPE
Definition: hydra/config.h:17
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
Vector< CPUDevice > devices
list of all CPUDevices. for every hardware thread an instance of CPUDevice is created
void SetNodeValue(Node *node, const SocketType &socket, const VtValue &value)
Definition: node_util.cpp:405
VtValue GetNodeValue(const Node *node, const SocketType &socket)
Definition: node_util.cpp:503
HDCYCLES_NAMESPACE_OPEN_SCOPE TF_DEFINE_PUBLIC_TOKENS(HdCyclesRenderSettingsTokens, HD_CYCLES_RENDER_SETTINGS_TOKENS)
TF_DEFINE_PRIVATE_TOKENS(_tokens,(cycles)(openvdbAsset))
#define HD_CYCLES_RENDER_SETTINGS_TOKENS
#define min(a, b)
Definition: sort.c:35
vector< SocketType, std::allocator< SocketType > > inputs
Definition: node_type.h:118
const SocketType * find_input(ustring name) const
const NodeType * type
Definition: graph/node.h:175
Integrator * integrator
Definition: scene.h:210
ustring name
Definition: node_type.h:72
ustring ui_name
Definition: node_type.h:79
float max
ccl_device_inline int floor_to_int(float f)
Definition: util/math.h:415