Skip to content

Commit

Permalink
Adding support for Delegate Render Products and turning off progressi…
Browse files Browse the repository at this point in the history
…ve mode when used in husk. (#758)

Fixes #650
Fixes #755
  • Loading branch information
sirpalee authored Apr 20, 2021
1 parent 65416a9 commit 416775b
Show file tree
Hide file tree
Showing 6 changed files with 469 additions and 98 deletions.
5 changes: 5 additions & 0 deletions common/constant_strings.h
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,7 @@ ASTR(disk_light);
ASTR(disp_map);
ASTR(displacement);
ASTR(distant_light);
ASTR(driver_deepexr);
ASTR(emission);
ASTR(emission_color);
ASTR(emissiveColor);
Expand Down Expand Up @@ -196,6 +197,7 @@ ASTR(frame);
ASTR(gaussian_filter);
ASTR(ginstance);
ASTR(grids);
ASTR(husk);
ASTR(hydra);
ASTR(id);
ASTR(id_pointer);
Expand Down Expand Up @@ -232,6 +234,9 @@ ASTR(interactive_target_fps);
ASTR(interactive_target_fps_min);
ASTR(ior);
ASTR(latlong);
ASTR(layer_enable_filtering);
ASTR(layer_half_precision);
ASTR(layer_tolerance);
ASTR(light_group);
ASTR(light_path_expressions);
ASTR(linear);
Expand Down
159 changes: 144 additions & 15 deletions render_delegate/render_delegate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,20 @@ TF_DEFINE_PRIVATE_TOKENS(_tokens,
(openvdbAsset)
((arnoldGlobal, "arnold:global:"))
(percentDone)
(delegateRenderProducts)
(orderedVars)
((aovSettings, "aovDescriptor.aovSettings"))
(productType)
(productName)
(sourceType)
(sourceName)
(dataType)
((format, "aovDescriptor.format"))
((clearValue, "aovDescriptor.clearValue"))
((multiSampled, "aovDescriptor.multiSampled"))
((aovName, "driver:parameters:aov:name"))
(deep)
(raw)
(instantaneousShutter)
);
// clang-format on
Expand Down Expand Up @@ -319,13 +333,15 @@ std::mutex HdArnoldRenderDelegate::_mutexResourceRegistry;
std::atomic_int HdArnoldRenderDelegate::_counterResourceRegistry;
HdResourceRegistrySharedPtr HdArnoldRenderDelegate::_resourceRegistry;

HdArnoldRenderDelegate::HdArnoldRenderDelegate()
HdArnoldRenderDelegate::HdArnoldRenderDelegate(HdArnoldRenderContext context) : _context(context)
{
_lightLinkingChanged.store(false, std::memory_order_release);
_id = SdfPath(TfToken(TfStringPrintf("/HdArnoldRenderDelegate_%p", this)));
if (AiUniverseIsActive()) {
TF_CODING_ERROR("There is already an active Arnold universe!");
}
// TODO(pal): We need to investigate if it's safe to set session to AI_SESSION_BATCH when rendering in husk for
// example. ie. is husk creating a separate render delegate for each frame, or syncs the changes?
AiBegin(AI_SESSION_INTERACTIVE);
_supportedRprimTypes = {
HdPrimTypeTokens->mesh, HdPrimTypeTokens->volume, HdPrimTypeTokens->points, HdPrimTypeTokens->basisCurves};
Expand Down Expand Up @@ -354,7 +370,7 @@ HdArnoldRenderDelegate::HdArnoldRenderDelegate()
_nativeRprimParams.emplace(AiNodeEntryGetNameAtString(nodeEntry), std::move(paramList));
AiParamIteratorDestroy(paramIter);
}
AiRenderSetHintStr(str::render_context, str::hydra);
AiRenderSetHintStr(str::render_context, _context == HdArnoldRenderContext::Hydra ? str::hydra : str::husk);
std::lock_guard<std::mutex> guard(_mutexResourceRegistry);
if (_counterResourceRegistry.fetch_add(1) == 0) {
_resourceRegistry.reset(new HdResourceRegistry());
Expand Down Expand Up @@ -394,9 +410,13 @@ HdArnoldRenderDelegate::HdArnoldRenderDelegate()

_renderParam.reset(new HdArnoldRenderParam());

// AiRenderSetHintBool(str::progressive, true);
// We need access to both beauty and P at the same time.
AiRenderSetHintBool(str::progressive_show_all_outputs, true);
if (_context == HdArnoldRenderContext::Husk) {
AiRenderSetHintBool(str::progressive, false);
AiNodeSetBool(_options, str::enable_progressive_render, false);
} else {
AiRenderSetHintBool(str::progressive_show_all_outputs, true);
}
}

HdArnoldRenderDelegate::~HdArnoldRenderDelegate()
Expand All @@ -423,6 +443,11 @@ const TfTokenVector& HdArnoldRenderDelegate::GetSupportedBprimTypes() const { re

void HdArnoldRenderDelegate::_SetRenderSetting(const TfToken& _key, const VtValue& _value)
{
// Special setting that describes custom output, like deep AOVs.
if (_key == _tokens->delegateRenderProducts) {
_ParseDelegateRenderProducts(_value);
return;
}
TfToken key;
_RemoveArnoldGlobalPrefix(_key, key);

Expand All @@ -448,23 +473,33 @@ void HdArnoldRenderDelegate::_SetRenderSetting(const TfToken& _key, const VtValu
AiMsgSetLogFileName(_logFile.c_str());
}
} else if (key == str::t_enable_progressive_render) {
_CheckForBoolValue(value, [&](const bool b) {
AiRenderSetHintBool(str::progressive, b);
AiNodeSetBool(_options, str::enable_progressive_render, b);
});
if (_context != HdArnoldRenderContext::Husk) {
_CheckForBoolValue(value, [&](const bool b) {
AiRenderSetHintBool(str::progressive, b);
AiNodeSetBool(_options, str::enable_progressive_render, b);
});
}
} else if (key == str::t_progressive_min_AA_samples) {
_CheckForIntValue(value, [&](const int i) { AiRenderSetHintInt(str::progressive_min_AA_samples, i); });
if (_context != HdArnoldRenderContext::Husk) {
_CheckForIntValue(value, [&](const int i) { AiRenderSetHintInt(str::progressive_min_AA_samples, i); });
}
} else if (key == str::t_interactive_target_fps) {
if (value.IsHolding<float>()) {
AiRenderSetHintFlt(str::interactive_target_fps, value.UncheckedGet<float>());
if (_context != HdArnoldRenderContext::Husk) {
if (value.IsHolding<float>()) {
AiRenderSetHintFlt(str::interactive_target_fps, value.UncheckedGet<float>());
}
}
} else if (key == str::t_interactive_target_fps_min) {
if (value.IsHolding<float>()) {
AiRenderSetHintFlt(str::interactive_target_fps_min, value.UncheckedGet<float>());
if (_context != HdArnoldRenderContext::Husk) {
if (value.IsHolding<float>()) {
AiRenderSetHintFlt(str::interactive_target_fps_min, value.UncheckedGet<float>());
}
}
} else if (key == str::t_interactive_fps_min) {
if (value.IsHolding<float>()) {
AiRenderSetHintFlt(str::interactive_fps_min, value.UncheckedGet<float>());
if (_context != HdArnoldRenderContext::Husk) {
if (value.IsHolding<float>()) {
AiRenderSetHintFlt(str::interactive_fps_min, value.UncheckedGet<float>());
}
}
} else if (key == str::t_profile_file) {
if (value.IsHolding<std::string>()) {
Expand All @@ -483,6 +518,100 @@ void HdArnoldRenderDelegate::_SetRenderSetting(const TfToken& _key, const VtValu
}
}

void HdArnoldRenderDelegate::_ParseDelegateRenderProducts(const VtValue& value)
{
// Details about the data layout can be found here:
// https://www.sidefx.com/docs/hdk/_h_d_k__u_s_d_hydra.html#HDK_USDHydraHuskDRP
// Delegate Render Products are used by husk, so we only have to parse them once.
// We don't support cases where delegate render products are passed AFTER the first execution
// of the render pass.
if (!_delegateRenderProducts.empty()) {
return;
}
using DataType = VtArray<HdAovSettingsMap>;
if (!value.IsHolding<DataType>()) {
return;
}
auto products = value.UncheckedGet<DataType>();
for (auto& productIter : products) {
HdArnoldDelegateRenderProduct product;
const auto* productType = TfMapLookupPtr(productIter, _tokens->productType);
// We only care about deep products for now.
if (productType == nullptr || !productType->IsHolding<TfToken>() ||
productType->UncheckedGet<TfToken>() != _tokens->deep) {
continue;
}
// Ignoring cases where productName is not set.
const auto* productName = TfMapLookupPtr(productIter, _tokens->productName);
if (productName == nullptr || !productName->IsHolding<TfToken>()) {
continue;
}
product.productName = productName->UncheckedGet<TfToken>();
productIter.erase(_tokens->productType);
productIter.erase(_tokens->productName);
// Elements of the HdAovSettingsMap in the product are either a list of RenderVars or generic attributes
// of the render product.
for (const auto& productElem : productIter) {
// If the key is "aovDescriptor.aovSettings" then we got the list of RenderVars.
if (productElem.first == _tokens->orderedVars) {
if (!productElem.second.IsHolding<DataType>()) {
continue;
}
const auto& renderVars = productElem.second.UncheckedGet<DataType>();
for (const auto& renderVarIter : renderVars) {
HdArnoldRenderVar renderVar;
renderVar.sourceType = _tokens->raw;
// Each element either contains a setting, or "aovDescriptor.aovSettings" which will hold
// extra settings for the RenderVar including metadata.
for (const auto& renderVarElem : renderVarIter) {
if (renderVarElem.first == _tokens->aovSettings) {
if (!renderVarElem.second.IsHolding<HdAovSettingsMap>()) {
continue;
}
renderVar.settings = renderVarElem.second.UncheckedGet<HdAovSettingsMap>();
// name is not coming through as a top parameter.
const auto* aovName = TfMapLookupPtr(renderVar.settings, _tokens->aovName);
if (aovName != nullptr) {
if (aovName->IsHolding<std::string>()) {
renderVar.name = aovName->UncheckedGet<std::string>();
} else if (aovName->IsHolding<TfToken>()) {
renderVar.name = aovName->UncheckedGet<TfToken>().GetString();
}
}
} else if (
renderVarElem.first == _tokens->sourceName &&
renderVarElem.second.IsHolding<std::string>()) {
renderVar.sourceName = renderVarElem.second.UncheckedGet<std::string>();
} else if (
renderVarElem.first == _tokens->sourceType && renderVarElem.second.IsHolding<TfToken>()) {
renderVar.sourceType = renderVarElem.second.UncheckedGet<TfToken>();
} else if (
renderVarElem.first == _tokens->dataType && renderVarElem.second.IsHolding<TfToken>()) {
renderVar.dataType = renderVarElem.second.UncheckedGet<TfToken>();
} else if (
renderVarElem.first == _tokens->format && renderVarElem.second.IsHolding<HdFormat>()) {
renderVar.format = renderVarElem.second.UncheckedGet<HdFormat>();
} else if (renderVarElem.first == _tokens->clearValue) {
renderVar.clearValue = renderVarElem.second;
} else if (
renderVarElem.first == _tokens->multiSampled && renderVarElem.second.IsHolding<bool>()) {
renderVar.multiSampled = renderVarElem.second.UncheckedGet<bool>();
}
}
// Any other cases should have good/reasonable defaults.
if (!renderVar.sourceName.empty() && !renderVar.name.empty()) {
product.renderVars.emplace_back(std::move(renderVar));
}
}
} else {
// It's a setting describing the RenderProduct.
product.settings.insert({productElem.first, productElem.second});
}
}
_delegateRenderProducts.emplace_back(std::move(product));
}
}

void HdArnoldRenderDelegate::SetRenderSetting(const TfToken& key, const VtValue& value)
{
_renderParam->Interrupt();
Expand Down
59 changes: 51 additions & 8 deletions render_delegate/render_delegate.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,11 +49,46 @@

PXR_NAMESPACE_OPEN_SCOPE

struct HdArnoldRenderVar {
/// Settings for the RenderVar.
HdAovSettingsMap settings;
/// Name of the render var.
std::string name;
/// Source name of the Render Var.
std::string sourceName;
/// Source type of the Render Var.
TfToken sourceType;
/// Data Type of the Render Var.
TfToken dataType;
/// Format of the AOV descriptor.
HdFormat format = HdFormatFloat32Vec4;
/// Clear Value, currently ignored.
VtValue clearValue;
/// Whether or not the render var is multisampled, currently ignored.
bool multiSampled = true;
};

struct HdArnoldDelegateRenderProduct {
/// List of RenderVars used by the RenderProduct.
std::vector<HdArnoldRenderVar> renderVars;
/// Map of settings for the RenderProduct.
HdAovSettingsMap settings;
/// Name of the product, this is equal to the output location.
TfToken productName;
};

/// Render context for the render delegate.
enum class HdArnoldRenderContext {
Hydra, ///< Generic Hydra renderer.
Husk, ///< Husk from Houdini.
};

/// Main class point for the Arnold Render Delegate.
class HdArnoldRenderDelegate final : public HdRenderDelegate {
public:
HDARNOLD_API
HdArnoldRenderDelegate(); ///< Constructor for the Render Delegate.
HdArnoldRenderDelegate(
HdArnoldRenderContext context = HdArnoldRenderContext::Hydra); ///< Constructor for the Render Delegate.
HDARNOLD_API
~HdArnoldRenderDelegate() override; ///< Destuctor for the Render Delegate.
/// Returns an instance of HdArnoldRenderParam.
Expand Down Expand Up @@ -298,6 +333,11 @@ class HdArnoldRenderDelegate final : public HdRenderDelegate {
HDARNOLD_API
bool ShouldSkipIteration(HdRenderIndex* renderIndex, float shutterOpen, float shutterClose);

using DelegateRenderProducts = std::vector<HdArnoldDelegateRenderProduct>;
/// Returns the list of available Delegate Render Products.
///
/// @return Const Reference to the list of Delegate Render Products.
const DelegateRenderProducts& GetDelegateRenderProducts() const { return _delegateRenderProducts; }
/// Advertise whether this delegate supports pausing and resuming of
/// background render threads. Default implementation returns false.
///
Expand Down Expand Up @@ -399,13 +439,14 @@ class HdArnoldRenderDelegate final : public HdRenderDelegate {
ShapeMaterialChangesQueue _shapeMaterialUntrackQueue; ///< Queue to untrack shape material assignment changes.
MaterialToShapeMap _materialToShapeMap; ///< Map to track dependencies between materials and shapes.

std::mutex _lightLinkingMutex; ///< Mutex to lock all light linking operations.
LightLinkingMap _lightLinks; ///< Light Link categories.
LightLinkingMap _shadowLinks; ///< Shadow Link categories.
std::atomic<bool> _lightLinkingChanged; ///< Whether or not Light Linking have changed.
TfTokenVector _supportedRprimTypes; ///< List of supported rprim types.
NativeRprimTypeMap _nativeRprimTypes; ///< Remapping between the native rprim type names and arnold types.
NativeRprimParams _nativeRprimParams; ///< List of parameters for native rprims.
std::mutex _lightLinkingMutex; ///< Mutex to lock all light linking operations.
LightLinkingMap _lightLinks; ///< Light Link categories.
LightLinkingMap _shadowLinks; ///< Shadow Link categories.
std::atomic<bool> _lightLinkingChanged; ///< Whether or not Light Linking have changed.
DelegateRenderProducts _delegateRenderProducts; ///< Delegate Render Products for batch renders via husk.
TfTokenVector _supportedRprimTypes; ///< List of supported rprim types.
NativeRprimTypeMap _nativeRprimTypes; ///< Remapping between the native rprim type names and arnold types.
NativeRprimParams _nativeRprimParams; ///< List of parameters for native rprims.
/// Pointer to an instance of HdArnoldRenderParam.
///
/// This is shared with all the primitives, so they can control the flow of
Expand All @@ -417,6 +458,8 @@ class HdArnoldRenderDelegate final : public HdRenderDelegate {
AtNode* _fallbackShader; ///< Pointer to the fallback Arnold Shader.
AtNode* _fallbackVolumeShader; ///< Pointer to the fallback Arnold Volume Shader.
std::string _logFile;
/// Top level render context using Hydra. Ie. Hydra, Solaris, Husk.
HdArnoldRenderContext _context = HdArnoldRenderContext::Hydra;
int _verbosityLogFlags = AI_LOG_WARNINGS | AI_LOG_ERRORS;
float _shutterOpen = 0.0f; ///< Saved Shutter Open value of the active camera.
float _shutterClose = 0.0f; ///< Saved Shutter Close value of the active camera.
Expand Down
Loading

0 comments on commit 416775b

Please sign in to comment.