Blender V4.3
render_delegate.cpp
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2022 NVIDIA Corporation
2 * SPDX-FileCopyrightText: 2022 Blender Foundation
3 *
4 * SPDX-License-Identifier: Apache-2.0 */
5
7#include "hydra/camera.h"
8#include "hydra/curves.h"
9#include "hydra/field.h"
10#include "hydra/instancer.h"
11#include "hydra/light.h"
12#include "hydra/material.h"
13#include "hydra/mesh.h"
14#include "hydra/node_util.h"
15#include "hydra/pointcloud.h"
16#include "hydra/render_buffer.h"
17#include "hydra/render_pass.h"
18#include "hydra/session.h"
19#include "hydra/volume.h"
20#include "scene/integrator.h"
21#include "scene/scene.h"
22#include "session/session.h"
23
24#include <pxr/base/tf/getenv.h>
25#include <pxr/imaging/hd/extComputation.h>
26#include <pxr/imaging/hgi/tokens.h>
27
29
31
32// clang-format off
34 (cycles)
35 (openvdbAsset)
36);
37// clang-format on
38
39namespace {
40
41const TfTokenVector kSupportedRPrimTypes = {
42 HdPrimTypeTokens->basisCurves,
43 HdPrimTypeTokens->mesh,
44 HdPrimTypeTokens->points,
45#ifdef WITH_OPENVDB
46 HdPrimTypeTokens->volume,
47#endif
48};
49
50const TfTokenVector kSupportedSPrimTypes = {
51 HdPrimTypeTokens->camera,
52 HdPrimTypeTokens->material,
53 HdPrimTypeTokens->diskLight,
54 HdPrimTypeTokens->distantLight,
55 HdPrimTypeTokens->domeLight,
56 HdPrimTypeTokens->rectLight,
57 HdPrimTypeTokens->sphereLight,
58 HdPrimTypeTokens->extComputation,
59};
60
61const TfTokenVector kSupportedBPrimTypes = {
62 HdPrimTypeTokens->renderBuffer,
63#ifdef WITH_OPENVDB
64 _tokens->openvdbAsset,
65#endif
66};
67
68SessionParams GetSessionParams(const HdRenderSettingsMap &settings)
69{
71 params.threads = 0;
72 params.background = false;
73 params.use_resolution_divider = false;
74
75 HdRenderSettingsMap::const_iterator it;
76
77 // Pull all setting that contribute to device creation first
78 it = settings.find(HdCyclesRenderSettingsTokens->threads);
79 if (it != settings.end()) {
80 params.threads = VtValue::Cast<int>(it->second).GetWithDefault(params.threads);
81 }
82
83 // Get the Cycles device from settings or environment, falling back to CPU
84 std::string deviceType = Device::string_from_type(DEVICE_CPU);
85 it = settings.find(HdCyclesRenderSettingsTokens->device);
86 if (it != settings.end()) {
87 deviceType = VtValue::Cast<std::string>(it->second).GetWithDefault(deviceType);
88 }
89 else {
90 const std::string deviceTypeEnv = TfGetenv("CYCLES_DEVICE");
91 if (!deviceTypeEnv.empty()) {
92 deviceType = deviceTypeEnv;
93 }
94 }
95
96 // Move to all uppercase for Device::type_from_string
97 std::transform(deviceType.begin(), deviceType.end(), deviceType.begin(), ::toupper);
98
100 DEVICE_MASK(Device::type_from_string(deviceType.c_str())));
101 if (devices.empty()) {
103 if (!devices.empty()) {
104 params.device = devices.front();
105 }
106 }
107 else {
108 params.device = Device::get_multi_device(devices, params.threads, params.background);
109 }
110
111 return params;
112}
113
114} // namespace
115
116HdCyclesDelegate::HdCyclesDelegate(const HdRenderSettingsMap &settingsMap,
117 Session *session_,
118 const bool keep_nodes)
119 : HdRenderDelegate()
120{
121 _renderParam = session_ ? std::make_unique<HdCyclesSession>(session_, keep_nodes) :
122 std::make_unique<HdCyclesSession>(GetSessionParams(settingsMap));
123
124 for (const auto &setting : settingsMap) {
125 // Skip over the settings known to be used for initialization only
126 if (setting.first == HdCyclesRenderSettingsTokens->device ||
127 setting.first == HdCyclesRenderSettingsTokens->threads)
128 {
129 continue;
130 }
131
132 SetRenderSetting(setting.first, setting.second);
133 }
134}
135
137
138void 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
158{
159 return kSupportedRPrimTypes;
160}
161
163{
164 return kSupportedSPrimTypes;
165}
166
168{
169 return kSupportedBPrimTypes;
170}
171
173{
174 return _renderParam.get();
175}
176
177HdResourceRegistrySharedPtr 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
199HdRenderPassSharedPtr HdCyclesDelegate::CreateRenderPass(HdRenderIndex *index,
200 const HdRprimCollection &collection)
201{
202 return HdRenderPassSharedPtr(new HdCyclesRenderPass(index, collection, _renderParam.get()));
203}
204
205HdInstancer *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
222void HdCyclesDelegate::DestroyInstancer(HdInstancer *instancer)
223{
224 delete instancer;
225}
226
227HdRprim *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
275{
276 delete rPrim;
277}
278
279HdSprim *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 {
291 return new HdCyclesLight(sprimId, typeId);
292 }
293 if (typeId == HdPrimTypeTokens->extComputation) {
294 return new HdExtComputation(sprimId);
295 }
296
297 TF_CODING_ERROR("Unknown Sprim type %s", typeId.GetText());
298 return nullptr;
299}
300
301HdSprim *HdCyclesDelegate::CreateFallbackSprim(const TfToken &typeId)
302{
303 return CreateSprim(typeId, SdfPath::EmptyPath());
304}
305
307{
308 delete sPrim;
309}
310
311HdBprim *HdCyclesDelegate::CreateBprim(const TfToken &typeId, const SdfPath &bprimId)
312{
313 if (typeId == HdPrimTypeTokens->renderBuffer) {
314 return new HdCyclesRenderBuffer(bprimId);
315 }
316#ifdef WITH_OPENVDB
317 if (typeId == _tokens->openvdbAsset) {
318 return new HdCyclesField(bprimId, typeId);
319 }
320#endif
321
322 TF_CODING_ERROR("Unknown Bprim type %s", typeId.GetText());
323 return nullptr;
324}
325
326HdBprim *HdCyclesDelegate::CreateFallbackBprim(const TfToken &typeId)
327{
328 return CreateBprim(typeId, SdfPath::EmptyPath());
329}
330
332{
333 delete bPrim;
334}
335
336void HdCyclesDelegate::CommitResources(HdChangeTracker *tracker)
337{
338 TF_UNUSED(tracker);
339
340 const SceneLock lock(_renderParam.get());
341
342 _renderParam->UpdateScene();
343}
344
346{
347 return HdTokens->full;
348}
349
350#if HD_API_VERSION < 41
352{
353 return _tokens->cycles;
354}
355#else
356TfTokenVector HdCyclesDelegate::GetMaterialRenderContexts() const
357{
358 return {_tokens->cycles};
359}
360#endif
361
363{
364 const Stats &stats = _renderParam->session->stats;
365 const Progress &progress = _renderParam->session->progress;
366
367 double totalTime, renderTime;
368 progress.get_time(totalTime, renderTime);
369 double fractionDone = progress.get_progress();
370
371 std::string status, substatus;
372 progress.get_status(status, substatus);
373 if (!substatus.empty()) {
374 status += " | " + substatus;
375 }
376
377 return {{"rendererName", VtValue("Cycles")},
378 {"rendererVersion", VtValue(GfVec3i(0, 0, 0))},
379 {"percentDone", VtValue(floor_to_int(fractionDone * 100))},
380 {"fractionDone", VtValue(fractionDone)},
381 {"loadClockTime", VtValue(totalTime - renderTime)},
382 {"peakMemory", VtValue(stats.mem_peak)},
383 {"totalClockTime", VtValue(totalTime)},
384 {"totalMemory", VtValue(stats.mem_used)},
385 {"renderProgressAnnotation", VtValue(status)}};
386}
387
388HdAovDescriptor HdCyclesDelegate::GetDefaultAovDescriptor(const TfToken &name) const
389{
390 if (name == HdAovTokens->color) {
391 HdFormat colorFormat = HdFormatFloat32Vec4;
392 if (IsDisplaySupported()) {
393 // Can use Cycles 'DisplayDriver' in OpenGL, but it only supports 'half4' format
394 colorFormat = HdFormatFloat16Vec4;
395 }
396
397 return HdAovDescriptor(colorFormat, false, VtValue(GfVec4f(0.0f)));
398 }
399 if (name == HdAovTokens->depth) {
400 return HdAovDescriptor(HdFormatFloat32, false, VtValue(1.0f));
401 }
402 if (name == HdAovTokens->normal) {
403 return HdAovDescriptor(HdFormatFloat32Vec3, false, VtValue(GfVec3f(0.0f)));
404 }
405 if (name == HdAovTokens->primId || name == HdAovTokens->instanceId ||
406 name == HdAovTokens->elementId)
407 {
408 return HdAovDescriptor(HdFormatInt32, false, VtValue(-1));
409 }
410
411 return HdAovDescriptor();
412}
413
414HdRenderSettingDescriptorList HdCyclesDelegate::GetRenderSettingDescriptors() const
415{
416 Scene *const scene = _renderParam->session->scene;
417
418 HdRenderSettingDescriptorList descriptors;
419
420 descriptors.push_back({
421 "Time Limit",
422 HdCyclesRenderSettingsTokens->timeLimit,
423 VtValue(0.0),
424 });
425 descriptors.push_back({
426 "Sample Count",
427 HdCyclesRenderSettingsTokens->samples,
428 VtValue(1024),
429 });
430 descriptors.push_back({
431 "Sample Offset",
432 HdCyclesRenderSettingsTokens->sampleOffset,
433 VtValue(0),
434 });
435
436 for (const SocketType &socket : scene->integrator->type->inputs) {
437 descriptors.push_back({socket.ui_name.string(),
438 TfToken("cycles:integrator:" + socket.name.string()),
439 GetNodeValue(scene->integrator, socket)});
440 }
441
442 return descriptors;
443}
444
445void HdCyclesDelegate::SetRenderSetting(const PXR_NS::TfToken &key, const PXR_NS::VtValue &value)
446{
447 Scene *const scene = _renderParam->session->scene;
448 Session *const session = _renderParam->session;
449
450 if (key == HdCyclesRenderSettingsTokens->stageMetersPerUnit) {
451 _renderParam->SetStageMetersPerUnit(
452 VtValue::Cast<double>(value).GetWithDefault(_renderParam->GetStageMetersPerUnit()));
453 }
454 else if (key == HdCyclesRenderSettingsTokens->timeLimit) {
455 session->set_time_limit(
456 VtValue::Cast<double>(value).GetWithDefault(session->params.time_limit));
457 }
458 else if (key == HdCyclesRenderSettingsTokens->samples) {
459 static const int max_samples = Integrator::MAX_SAMPLES;
460 int samples = VtValue::Cast<int>(value).GetWithDefault(session->params.samples);
461 samples = std::min(std::max(1, samples), max_samples);
462 session->set_samples(samples);
463 }
464 else if (key == HdCyclesRenderSettingsTokens->sampleOffset) {
465 session->params.sample_offset = VtValue::Cast<int>(value).GetWithDefault(
466 session->params.sample_offset);
467 ++_settingsVersion;
468 }
469 else {
470 const std::string &keyString = key.GetString();
471 if (keyString.rfind("cycles:integrator:", 0) == 0) {
472 ustring socketName(keyString, sizeof("cycles:integrator:") - 1);
473 if (const SocketType *socket = scene->integrator->type->find_input(socketName)) {
474 SetNodeValue(scene->integrator, *socket, value);
475 ++_settingsVersion;
476 }
477 }
478 }
479}
480
481VtValue HdCyclesDelegate::GetRenderSetting(const TfToken &key) const
482{
483 Scene *const scene = _renderParam->session->scene;
484 Session *const session = _renderParam->session;
485
486 if (key == HdCyclesRenderSettingsTokens->stageMetersPerUnit) {
487 return VtValue(_renderParam->GetStageMetersPerUnit());
488 }
489 else if (key == HdCyclesRenderSettingsTokens->device) {
490 return VtValue(TfToken(Device::string_from_type(session->params.device.type)));
491 }
492 else if (key == HdCyclesRenderSettingsTokens->threads) {
493 return VtValue(session->params.threads);
494 }
495 else if (key == HdCyclesRenderSettingsTokens->timeLimit) {
496 return VtValue(session->params.time_limit);
497 }
498 else if (key == HdCyclesRenderSettingsTokens->samples) {
499 return VtValue(session->params.samples);
500 }
501 else if (key == HdCyclesRenderSettingsTokens->sampleOffset) {
502 return VtValue(session->params.sample_offset);
503 }
504 else {
505 const std::string &keyString = key.GetString();
506 if (keyString.rfind("cycles:integrator:", 0) == 0) {
507 ustring socketName(keyString, sizeof("cycles:integrator:") - 1);
508 if (const SocketType *socket = scene->integrator->type->find_input(socketName)) {
509 return GetNodeValue(scene->integrator, *socket);
510 }
511 }
512 }
513
514 return VtValue();
515}
516
volatile int lock
DeviceType type
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:80
void get_status(string &status_, string &substatus_) const
Definition progress.h:305
void get_time(double &total_time_, double &render_time_) const
Definition progress.h:168
double get_progress() const
Definition progress.h:200
DeviceInfo device
void set_time_limit(double time_limit)
SessionParams params
void set_samples(int samples)
size_t mem_used
Definition util/stats.h:32
size_t mem_peak
Definition util/stats.h:33
#define DEVICE_MASK(type)
@ DEVICE_MASK_CPU
@ DEVICE_CPU
#define HDCYCLES_NAMESPACE_CLOSE_SCOPE
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)
VtValue GetNodeValue(const Node *node, const SocketType &socket)
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
Type type
Definition node_type.h:80
ccl_device_inline int floor_to_int(float f)
Definition util/math.h:429