diff options
Diffstat (limited to 'intern/cycles/hydra/render_delegate.cpp')
-rw-r--r-- | intern/cycles/hydra/render_delegate.cpp | 514 |
1 files changed, 514 insertions, 0 deletions
diff --git a/intern/cycles/hydra/render_delegate.cpp b/intern/cycles/hydra/render_delegate.cpp new file mode 100644 index 00000000000..748b6a66e1e --- /dev/null +++ b/intern/cycles/hydra/render_delegate.cpp @@ -0,0 +1,514 @@ +/* SPDX-License-Identifier: Apache-2.0 + * Copyright 2022 NVIDIA Corporation + * Copyright 2022 Blender Foundation */ + +#include "hydra/render_delegate.h" +#include "hydra/camera.h" +#include "hydra/curves.h" +#include "hydra/field.h" +#include "hydra/instancer.h" +#include "hydra/light.h" +#include "hydra/material.h" +#include "hydra/mesh.h" +#include "hydra/node_util.h" +#include "hydra/pointcloud.h" +#include "hydra/render_buffer.h" +#include "hydra/render_pass.h" +#include "hydra/session.h" +#include "hydra/volume.h" +#include "scene/integrator.h" +#include "scene/scene.h" +#include "session/session.h" + +#include <pxr/base/tf/getenv.h> +#include <pxr/imaging/hd/extComputation.h> +#include <pxr/imaging/hgi/tokens.h> + +HDCYCLES_NAMESPACE_OPEN_SCOPE + +// clang-format off +TF_DEFINE_PRIVATE_TOKENS(_tokens, + (cycles) + (openvdbAsset) +); + +TF_DEFINE_PRIVATE_TOKENS(HdCyclesRenderSettingsTokens, + ((device, "cycles:device")) + ((threads, "cycles:threads")) + ((time_limit, "cycles:time_limit")) + ((samples, "cycles:samples")) + ((sample_offset, "cycles:sample_offset")) +); +// clang-format on + +namespace { + +const TfTokenVector kSupportedRPrimTypes = { + HdPrimTypeTokens->basisCurves, + HdPrimTypeTokens->mesh, + HdPrimTypeTokens->points, +#ifdef WITH_OPENVDB + HdPrimTypeTokens->volume, +#endif +}; + +const TfTokenVector kSupportedSPrimTypes = { + HdPrimTypeTokens->camera, + HdPrimTypeTokens->material, + HdPrimTypeTokens->diskLight, + HdPrimTypeTokens->distantLight, + HdPrimTypeTokens->domeLight, + HdPrimTypeTokens->rectLight, + HdPrimTypeTokens->sphereLight, + HdPrimTypeTokens->extComputation, +}; + +const TfTokenVector kSupportedBPrimTypes = { + HdPrimTypeTokens->renderBuffer, +#ifdef WITH_OPENVDB + _tokens->openvdbAsset, +#endif +}; + +SessionParams GetSessionParams(const HdRenderSettingsMap &settings) +{ + SessionParams params; + params.threads = 0; + params.background = false; + params.use_resolution_divider = false; + + HdRenderSettingsMap::const_iterator it; + + // Pull all setting that contribute to device creation first + it = settings.find(HdCyclesRenderSettingsTokens->threads); + if (it != settings.end()) { + params.threads = VtValue::Cast<int>(it->second).GetWithDefault(params.threads); + } + + // Get the Cycles device from settings or environment, falling back to CPU + std::string deviceType = Device::string_from_type(DEVICE_CPU); + it = settings.find(HdCyclesRenderSettingsTokens->device); + if (it != settings.end()) { + deviceType = VtValue::Cast<std::string>(it->second).GetWithDefault(deviceType); + } + else { + const std::string deviceTypeEnv = TfGetenv("CYCLES_DEVICE"); + if (!deviceTypeEnv.empty()) { + deviceType = deviceTypeEnv; + } + } + + // Move to all uppercase for Device::type_from_string + std::transform(deviceType.begin(), deviceType.end(), deviceType.begin(), ::toupper); + + vector<DeviceInfo> devices = Device::available_devices( + DEVICE_MASK(Device::type_from_string(deviceType.c_str()))); + if (devices.empty()) { + devices = Device::available_devices(DEVICE_MASK_CPU); + if (!devices.empty()) { + params.device = devices.front(); + } + } + else { + params.device = Device::get_multi_device(devices, params.threads, params.background); + } + + return params; +} + +} // namespace + +HdCyclesDelegate::HdCyclesDelegate(const HdRenderSettingsMap &settingsMap, Session *session_) + : HdRenderDelegate() +{ + _renderParam = session_ ? std::make_unique<HdCyclesSession>(session_) : + std::make_unique<HdCyclesSession>(GetSessionParams(settingsMap)); + + // If the delegate owns the session, pull any remaining settings + if (!session_) { + for (const auto &setting : settingsMap) { + // Skip over the settings known to be used for initialization only + if (setting.first == HdCyclesRenderSettingsTokens->device || + setting.first == HdCyclesRenderSettingsTokens->threads) { + continue; + } + + SetRenderSetting(setting.first, setting.second); + } + } +} + +HdCyclesDelegate::~HdCyclesDelegate() +{ +} + +void HdCyclesDelegate::SetDrivers(const HdDriverVector &drivers) +{ + for (HdDriver *hdDriver : drivers) { + if (hdDriver->name == HgiTokens->renderDriver && hdDriver->driver.IsHolding<Hgi *>()) { + _hgi = hdDriver->driver.UncheckedGet<Hgi *>(); + break; + } + } +} + +bool HdCyclesDelegate::IsDisplaySupported() const +{ +#ifdef _WIN32 + return _hgi && _hgi->GetAPIName() == HgiTokens->OpenGL; +#else + return false; +#endif +} + +const TfTokenVector &HdCyclesDelegate::GetSupportedRprimTypes() const +{ + return kSupportedRPrimTypes; +} + +const TfTokenVector &HdCyclesDelegate::GetSupportedSprimTypes() const +{ + return kSupportedSPrimTypes; +} + +const TfTokenVector &HdCyclesDelegate::GetSupportedBprimTypes() const +{ + return kSupportedBPrimTypes; +} + +HdRenderParam *HdCyclesDelegate::GetRenderParam() const +{ + return _renderParam.get(); +} + +HdResourceRegistrySharedPtr HdCyclesDelegate::GetResourceRegistry() const +{ + return HdResourceRegistrySharedPtr(); +} + +bool HdCyclesDelegate::IsPauseSupported() const +{ + return true; +} + +bool HdCyclesDelegate::Pause() +{ + _renderParam->session->set_pause(true); + return true; +} + +bool HdCyclesDelegate::Resume() +{ + _renderParam->session->set_pause(false); + return true; +} + +HdRenderPassSharedPtr HdCyclesDelegate::CreateRenderPass(HdRenderIndex *index, + const HdRprimCollection &collection) +{ + return HdRenderPassSharedPtr(new HdCyclesRenderPass(index, collection, _renderParam.get())); +} + +HdInstancer *HdCyclesDelegate::CreateInstancer(HdSceneDelegate *delegate, + const SdfPath &instancerId +#if PXR_VERSION < 2102 + , + const SdfPath &parentId +#endif +) +{ + return new HdCyclesInstancer(delegate, + instancerId +#if PXR_VERSION < 2102 + , + parentId +#endif + ); +} + +void HdCyclesDelegate::DestroyInstancer(HdInstancer *instancer) +{ + delete instancer; +} + +HdRprim *HdCyclesDelegate::CreateRprim(const TfToken &typeId, + const SdfPath &rprimId +#if PXR_VERSION < 2102 + , + const SdfPath &instancerId +#endif +) +{ + if (typeId == HdPrimTypeTokens->mesh) { + return new HdCyclesMesh(rprimId +#if PXR_VERSION < 2102 + , + instancerId +#endif + ); + } + if (typeId == HdPrimTypeTokens->basisCurves) { + return new HdCyclesCurves(rprimId +#if PXR_VERSION < 2102 + , + instancerId +#endif + ); + } + if (typeId == HdPrimTypeTokens->points) { + return new HdCyclesPoints(rprimId +#if PXR_VERSION < 2102 + , + instancerId +#endif + ); + } +#ifdef WITH_OPENVDB + if (typeId == HdPrimTypeTokens->volume) { + return new HdCyclesVolume(rprimId +# if PXR_VERSION < 2102 + , + instancerId +# endif + ); + } +#endif + + TF_CODING_ERROR("Unknown Rprim type %s", typeId.GetText()); + return nullptr; +} + +void HdCyclesDelegate::DestroyRprim(HdRprim *rPrim) +{ + delete rPrim; +} + +HdSprim *HdCyclesDelegate::CreateSprim(const TfToken &typeId, const SdfPath &sprimId) +{ + if (typeId == HdPrimTypeTokens->camera) { + return new HdCyclesCamera(sprimId); + } + if (typeId == HdPrimTypeTokens->material) { + return new HdCyclesMaterial(sprimId); + } + if (typeId == HdPrimTypeTokens->diskLight || typeId == HdPrimTypeTokens->distantLight || + typeId == HdPrimTypeTokens->domeLight || typeId == HdPrimTypeTokens->rectLight || + typeId == HdPrimTypeTokens->sphereLight) { + return new HdCyclesLight(sprimId, typeId); + } + if (typeId == HdPrimTypeTokens->extComputation) { + return new HdExtComputation(sprimId); + } + + TF_CODING_ERROR("Unknown Sprim type %s", typeId.GetText()); + return nullptr; +} + +HdSprim *HdCyclesDelegate::CreateFallbackSprim(const TfToken &typeId) +{ + return CreateSprim(typeId, SdfPath::EmptyPath()); +} + +void HdCyclesDelegate::DestroySprim(HdSprim *sPrim) +{ + delete sPrim; +} + +HdBprim *HdCyclesDelegate::CreateBprim(const TfToken &typeId, const SdfPath &bprimId) +{ + if (typeId == HdPrimTypeTokens->renderBuffer) { + return new HdCyclesRenderBuffer(bprimId); + } +#ifdef WITH_OPENVDB + if (typeId == _tokens->openvdbAsset) { + return new HdCyclesField(bprimId, typeId); + } +#endif + + TF_RUNTIME_ERROR("Unknown Bprim type %s", typeId.GetText()); + return nullptr; +} + +HdBprim *HdCyclesDelegate::CreateFallbackBprim(const TfToken &typeId) +{ + return CreateBprim(typeId, SdfPath::EmptyPath()); +} + +void HdCyclesDelegate::DestroyBprim(HdBprim *bPrim) +{ + delete bPrim; +} + +void HdCyclesDelegate::CommitResources(HdChangeTracker *tracker) +{ + TF_UNUSED(tracker); + + const SceneLock lock(_renderParam.get()); + + _renderParam->UpdateScene(); +} + +TfToken HdCyclesDelegate::GetMaterialBindingPurpose() const +{ + return HdTokens->full; +} + +#if HD_API_VERSION < 41 +TfToken HdCyclesDelegate::GetMaterialNetworkSelector() const +{ + return _tokens->cycles; +} +#else +TfTokenVector HdCyclesDelegate::GetMaterialRenderContexts() const +{ + return {_tokens->cycles}; +} +#endif + +VtDictionary HdCyclesDelegate::GetRenderStats() const +{ + const Stats &stats = _renderParam->session->stats; + const Progress &progress = _renderParam->session->progress; + + double totalTime, renderTime; + progress.get_time(totalTime, renderTime); + double fractionDone = progress.get_progress(); + + std::string status, substatus; + progress.get_status(status, substatus); + if (!substatus.empty()) { + status += " | " + substatus; + } + + return {{"rendererName", VtValue("Cycles")}, + {"rendererVersion", VtValue(GfVec3i(0, 0, 0))}, + {"percentDone", VtValue(floor_to_int(fractionDone * 100))}, + {"fractionDone", VtValue(fractionDone)}, + {"loadClockTime", VtValue(totalTime - renderTime)}, + {"peakMemory", VtValue(stats.mem_peak)}, + {"totalClockTime", VtValue(totalTime)}, + {"totalMemory", VtValue(stats.mem_used)}, + {"renderProgressAnnotation", VtValue(status)}}; +} + +HdAovDescriptor HdCyclesDelegate::GetDefaultAovDescriptor(const TfToken &name) const +{ + if (name == HdAovTokens->color) { + HdFormat colorFormat = HdFormatFloat32Vec4; + if (IsDisplaySupported()) { + // Can use Cycles 'DisplayDriver' in OpenGL, but it only supports 'half4' format + colorFormat = HdFormatFloat16Vec4; + } + + return HdAovDescriptor(colorFormat, false, VtValue(GfVec4f(0.0f))); + } + if (name == HdAovTokens->depth) { + return HdAovDescriptor(HdFormatFloat32, false, VtValue(1.0f)); + } + if (name == HdAovTokens->normal) { + return HdAovDescriptor(HdFormatFloat32Vec3, false, VtValue(GfVec3f(0.0f))); + } + if (name == HdAovTokens->primId || name == HdAovTokens->instanceId || + name == HdAovTokens->elementId) { + return HdAovDescriptor(HdFormatInt32, false, VtValue(-1)); + } + + return HdAovDescriptor(); +} + +HdRenderSettingDescriptorList HdCyclesDelegate::GetRenderSettingDescriptors() const +{ + Scene *const scene = _renderParam->session->scene; + + HdRenderSettingDescriptorList descriptors; + + descriptors.push_back({ + "Time Limit", + HdCyclesRenderSettingsTokens->time_limit, + VtValue(0.0), + }); + descriptors.push_back({ + "Sample Count", + HdCyclesRenderSettingsTokens->samples, + VtValue(1024), + }); + descriptors.push_back({ + "Sample Offset", + HdCyclesRenderSettingsTokens->sample_offset, + VtValue(0), + }); + + for (const SocketType &socket : scene->integrator->type->inputs) { + descriptors.push_back({socket.ui_name.string(), + TfToken("cycles:integrator:" + socket.name.string()), + GetNodeValue(scene->integrator, socket)}); + } + + return descriptors; +} + +void HdCyclesDelegate::SetRenderSetting(const PXR_NS::TfToken &key, const PXR_NS::VtValue &value) +{ + Scene *const scene = _renderParam->session->scene; + Session *const session = _renderParam->session; + + if (key == HdCyclesRenderSettingsTokens->time_limit) { + session->set_time_limit( + VtValue::Cast<double>(value).GetWithDefault(session->params.time_limit)); + } + else if (key == HdCyclesRenderSettingsTokens->samples) { + int samples = VtValue::Cast<int>(value).GetWithDefault(session->params.samples); + samples = std::min(std::max(1, samples), Integrator::MAX_SAMPLES); + session->set_samples(samples); + } + else if (key == HdCyclesRenderSettingsTokens->sample_offset) { + session->params.sample_offset = VtValue::Cast<int>(value).GetWithDefault( + session->params.sample_offset); + ++_settingsVersion; + } + else { + const std::string &keyString = key.GetString(); + if (keyString.rfind("cycles:integrator:", 0) == 0) { + ustring socketName(keyString, sizeof("cycles:integrator:") - 1); + if (const SocketType *socket = scene->integrator->type->find_input(socketName)) { + SetNodeValue(scene->integrator, *socket, value); + ++_settingsVersion; + } + } + } +} + +VtValue HdCyclesDelegate::GetRenderSetting(const TfToken &key) const +{ + Scene *const scene = _renderParam->session->scene; + Session *const session = _renderParam->session; + + if (key == HdCyclesRenderSettingsTokens->device) { + return VtValue(TfToken(Device::string_from_type(session->params.device.type))); + } + else if (key == HdCyclesRenderSettingsTokens->threads) { + return VtValue(session->params.threads); + } + else if (key == HdCyclesRenderSettingsTokens->time_limit) { + return VtValue(session->params.time_limit); + } + else if (key == HdCyclesRenderSettingsTokens->samples) { + return VtValue(session->params.samples); + } + else if (key == HdCyclesRenderSettingsTokens->sample_offset) { + return VtValue(session->params.sample_offset); + } + else { + const std::string &keyString = key.GetString(); + if (keyString.rfind("cycles:integrator:", 0) == 0) { + ustring socketName(keyString, sizeof("cycles:integrator:") - 1); + if (const SocketType *socket = scene->integrator->type->find_input(socketName)) { + return GetNodeValue(scene->integrator, *socket); + } + } + } + + return VtValue(); +} + +HDCYCLES_NAMESPACE_CLOSE_SCOPE |