Skip to content

Commit

Permalink
Improve and generalize Hydra dependency graph #1158 (#1159)
Browse files Browse the repository at this point in the history
* Improve and generalize Hydra dependency graph #1158

* Missing returned value in GetNodeGraph #1158

* Removing debugging line #1158

* Fixes build issues for hydra dependency graph #1158
  • Loading branch information
sebastienblor authored May 16, 2022
1 parent 16fe02a commit 0b0d118
Show file tree
Hide file tree
Showing 17 changed files with 219 additions and 429 deletions.
1 change: 1 addition & 0 deletions common/constant_strings.h
Original file line number Diff line number Diff line change
Expand Up @@ -290,6 +290,7 @@ ASTR(latlong);
ASTR(layer_enable_filtering);
ASTR(layer_half_precision);
ASTR(layer_tolerance);
ASTR(light_filter);
ASTR(light_group);
ASTR(light_path_expressions);
ASTR(linear);
Expand Down
2 changes: 0 additions & 2 deletions render_delegate/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ set(SRC
mesh.cpp
native_rprim.cpp
node_graph.cpp
node_graph_tracker.cpp
openvdb_asset.cpp
points.cpp
render_buffer.cpp
Expand All @@ -38,7 +37,6 @@ set(HDR
mesh.h
native_rprim.h
node_graph.h
node_graph_tracker.h
openvdb_asset.h
points.h
render_buffer.h
Expand Down
1 change: 0 additions & 1 deletion render_delegate/SConscript
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ source_files = [
'mesh.cpp',
'native_rprim.cpp',
'node_graph.cpp',
'node_graph_tracker.cpp',
'openvdb_asset.cpp',
'points.cpp',
'render_buffer.cpp',
Expand Down
5 changes: 4 additions & 1 deletion render_delegate/basis_curves.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,10 @@ void HdArnoldBasisCurves::Sync(
if (*dirtyBits & HdChangeTracker::DirtyMaterialId) {
param.Interrupt();
const auto materialId = sceneDelegate->GetMaterialId(id);
_nodeGraphTracker.TrackSingleNodeGraph(GetRenderDelegate(), id, materialId);
// Ensure the reference from this shape to its material is properly tracked
// by the render delegate
GetRenderDelegate()->TrackDependencies(id, HdArnoldRenderDelegate::PathSet {materialId});

const auto* material = reinterpret_cast<const HdArnoldNodeGraph*>(
sceneDelegate->GetRenderIndex().GetSprim(HdPrimTypeTokens->material, materialId));
if (material != nullptr) {
Expand Down
87 changes: 44 additions & 43 deletions render_delegate/light.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -445,13 +445,13 @@ class HdArnoldGenericLight : public HdLight {
private:
SyncParams _syncParams; ///< Function object to sync light parameters.
HdArnoldRenderDelegate* _delegate; ///< Pointer to the Render Delegate.
HdArnoldNodeGraphTracker _nodeGraphTracker; ///< Utility to track material assignments of shapes.
AtNode* _light; ///< Pointer to the Arnold Light.
AtNode* _texture = nullptr; ///< Pointer to the Arnold Texture Shader.
AtNode* _filter = nullptr; ///< Pointer to the Arnold Light filter for barndoor effects.
TfToken _lightLink; ///< Light Link collection the light belongs to.
TfToken _shadowLink; ///< Shadow Link collection the light belongs to.
bool _supportsTexture = false; ///< Value indicating texture support.
bool _hasNodeGraphs = false;
};

HdArnoldGenericLight::HdArnoldGenericLight(
Expand Down Expand Up @@ -487,7 +487,7 @@ HdArnoldGenericLight::~HdArnoldGenericLight()
if (_filter != nullptr) {
AiNodeDestroy(_filter);
}
_nodeGraphTracker.UntrackNodeGraphs(_delegate, GetId());
_delegate->ClearDependencies(GetId());
}

void HdArnoldGenericLight::Sync(HdSceneDelegate* sceneDelegate, HdRenderParam* renderParam, HdDirtyBits* dirtyBits)
Expand Down Expand Up @@ -620,6 +620,48 @@ void HdArnoldGenericLight::Sync(HdSceneDelegate* sceneDelegate, HdRenderParam* r
}
}
AiNodeSetDisabled(_light, !sceneDelegate->GetVisible(id));

// get the sdf path for the light shader arnold node graph container
SdfPath lightShaderPath;
ArnoldUsdCheckForSdfPathValue(sceneDelegate->GetLightParamValue(id, TfToken("primvars:arnold:shaders")),
[&](const SdfPath& p) { lightShaderPath = p; });

AtNode *color = nullptr;
std::vector<AtNode *> lightFilters;
AiNodeResetParameter(_light, str::color);
AiNodeResetParameter(_light, str::shader);
AiNodeResetParameter(_light, str::filters);
HdArnoldRenderDelegate::PathSet pathSet;

if (!lightShaderPath.IsEmpty()) {
pathSet.insert(lightShaderPath);
const HdArnoldNodeGraph *nodeGraph = HdArnoldNodeGraph::GetNodeGraph(&sceneDelegate->GetRenderIndex(), lightShaderPath);
if (nodeGraph) {
color = nodeGraph->GetTerminal(str::t_color);
if (color) {
// Only certain types of light can be linked
if (AiNodeIs(_light, str::skydome_light) ||
AiNodeIs(_light, str::quad_light) ||
AiNodeIs(_light, str::mesh_light)) {
AiNodeLink(color, str::color, _light);
} else {
AiMsgWarning("%s : Cannot connect shader to light's color for \"%s\"", AiNodeGetName(_light), AiNodeEntryGetName(AiNodeGetNodeEntry(_light)));
}
}

lightFilters = nodeGraph->GetTerminals(str::t_light_filter);
if (!lightFilters.empty()) {
AiNodeSetArray(_light, str::filters, AiArrayConvert(static_cast<uint32_t>(lightFilters.size()), 1,
AI_TYPE_NODE, lightFilters.data()));
}
}
}
// If we previously had node graph connected, we need to call TrackDependencies
// even if our list is empty. This is needed to clear the previous dependencies
if (_hasNodeGraphs || !pathSet.empty()) {
_delegate->TrackDependencies(id, pathSet);
}
_hasNodeGraphs = !pathSet.empty();
}

if (*dirtyBits & HdLight::DirtyTransform) {
Expand Down Expand Up @@ -651,47 +693,6 @@ void HdArnoldGenericLight::Sync(HdSceneDelegate* sceneDelegate, HdRenderParam* r
updateLightLinking(_shadowLink, HdTokens->shadowLink, true);
#endif

// get the sdf path for the light shader arnold node graph container
SdfPath lightShaderPath;
ArnoldUsdCheckForSdfPathValue(sceneDelegate->GetLightParamValue(id, TfToken("primvars:arnold:shaders")),
[&](const SdfPath& p) { lightShaderPath = p; });

AtNode *color = nullptr;
AtNode *shader = nullptr;
std::vector<AtNode *> lightFilters;
if (!lightShaderPath.IsEmpty()) {
color = HdArnoldNodeGraph::GetNodeGraphTerminal(&sceneDelegate->GetRenderIndex(), lightShaderPath,
TfToken("color"));
if (color) {
AiNodeLink(color, str::color, _light);
}

// make sure this is a skydome light otherwise we have no shader parameter
if (AiNodeIs(_light, str::skydome_light)) {
shader = HdArnoldNodeGraph::GetNodeGraphTerminal(&sceneDelegate->GetRenderIndex(), lightShaderPath,
TfToken("shader"));
if (shader) {
AiNodeSetPtr(_light, str::shader, shader);
}
}

lightFilters = HdArnoldNodeGraph::GetNodeGraphTerminals(&sceneDelegate->GetRenderIndex(), lightShaderPath,
TfToken("light_filter"));
if (!lightFilters.empty()) {
AiNodeSetArray(_light, str::filters, AiArrayConvert(static_cast<uint32_t>(lightFilters.size()), 1,
AI_TYPE_NODE, lightFilters.data()));
}

if (color == nullptr)
AiNodeResetParameter(_light, str::color);
if (shader == nullptr)
AiNodeResetParameter(_light, str::shader);
if (lightFilters.empty())
AiNodeResetParameter(_light, str::filters);

_nodeGraphTracker.TrackLightNodeGraph(_delegate, id, lightShaderPath);
}

*dirtyBits = HdLight::Clean;
}

Expand Down
10 changes: 4 additions & 6 deletions render_delegate/mesh.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -307,11 +307,9 @@ void HdArnoldMesh::Sync(
auto* dispMapArray = AiArrayAllocate(numShaders, 1, AI_TYPE_POINTER);
auto* shader = static_cast<AtNode**>(AiArrayMap(shaderArray));
auto* dispMap = static_cast<AtNode**>(AiArrayMap(dispMapArray));
// We are using VtAray here, so it's going to be COW.
auto oldMaterials = _nodeGraphTracker.GetCurrentNodeGraphs(numShaders);

HdArnoldRenderDelegate::PathSet nodeGraphs;
auto setMaterial = [&](const SdfPath& materialId, size_t arrayId) {
_nodeGraphTracker.SetNodeGraph(materialId, arrayId);
nodeGraphs.insert(materialId);
const auto* material = reinterpret_cast<const HdArnoldNodeGraph*>(
sceneDelegate->GetRenderIndex().GetSprim(HdPrimTypeTokens->material, materialId));
if (material == nullptr) {
Expand All @@ -327,8 +325,8 @@ void HdArnoldMesh::Sync(
setMaterial(_subsets[subset], subset);
}
setMaterial(sceneDelegate->GetMaterialId(id), numSubsets);
// If there has been a change in data, we already detached materials and the two arrays are different.
_nodeGraphTracker.TrackNodeGraphChanges(GetRenderDelegate(), id, oldMaterials);
// Keep track of the materials assigned to this mesh
GetRenderDelegate()->TrackDependencies(id, nodeGraphs);

if (std::any_of(dispMap, dispMap + numShaders, [](AtNode* disp) { return disp != nullptr; })) {
AiArrayUnmap(dispMapArray);
Expand Down
5 changes: 4 additions & 1 deletion render_delegate/native_rprim.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,10 @@ void HdArnoldNativeRprim::Sync(
if (*dirtyBits & HdChangeTracker::DirtyMaterialId) {
param.Interrupt();
const auto materialId = sceneDelegate->GetMaterialId(id);
_nodeGraphTracker.TrackSingleNodeGraph(GetRenderDelegate(), id, materialId);
// Ensure the reference from this shape to its material is properly tracked
// by the render delegate
GetRenderDelegate()->TrackDependencies(id, HdArnoldRenderDelegate::PathSet {materialId});

const auto* material = reinterpret_cast<const HdArnoldNodeGraph*>(
sceneDelegate->GetRenderIndex().GetSprim(HdPrimTypeTokens->material, materialId));
if (material != nullptr) {
Expand Down
34 changes: 8 additions & 26 deletions render_delegate/node_graph.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -505,19 +505,13 @@ HdArnoldNodeGraph::HdArnoldNodeGraph(HdArnoldRenderDelegate* renderDelegate, con
{
}

HdArnoldNodeGraph::~HdArnoldNodeGraph() {
_renderDelegate->RemoveNodeGraph(GetId());
_renderDelegate->RemoveLightNodeGraph(GetId());
}

void HdArnoldNodeGraph::Sync(HdSceneDelegate* sceneDelegate, HdRenderParam* renderParam, HdDirtyBits* dirtyBits)
{
const auto id = GetId();
if ((*dirtyBits & HdMaterial::DirtyResource) && !id.IsEmpty()) {
HdArnoldRenderParamInterrupt param(renderParam);
auto value = sceneDelegate->GetMaterialResource(GetId());
auto nodeGraphChanged = false;
bool lightShaders = false;
if (value.IsHolding<HdMaterialNetworkMap>()) {
param.Interrupt();
// Mark all nodes as unused before any translation happens.
Expand Down Expand Up @@ -551,22 +545,19 @@ void HdArnoldNodeGraph::Sync(HdSceneDelegate* sceneDelegate, HdRenderParam* rend
readNetwork(&terminal.second, terminal.first == HdMaterialTerminalTokens->displacement))) {
nodeGraphChanged = true;
}
if (terminal.first == str::color || terminal.first == str::shader || terminal.first.GetString().rfind(
if (terminal.first == str::color || terminal.first.GetString().rfind(
"light_filter", 0) == 0) {
lightShaders = true;
_renderDelegate->DirtyLightNodeGraph(id);
AtNode* terminalNode = _nodeGraph.GetTerminal(terminal.first);
if (terminalNode)
AiUniverseCacheFlush(AiNodeGetUniverse(terminalNode), AI_CACHE_BACKGROUND);
nodeGraphChanged = true;
AiUniverseCacheFlush(_renderDelegate->GetUniverse(), AI_CACHE_BACKGROUND);
}
}
#endif
ClearUnusedNodes();
}
// We only mark the material dirty if one of the terminals have changed, but ignore the initial sync, because we
// expect Hydra to do the initial assignment correctly.
if (_wasSyncedOnce && nodeGraphChanged && !lightShaders) {
_renderDelegate->DirtyNodeGraph(id);
if (_wasSyncedOnce && nodeGraphChanged) {
_renderDelegate->DirtyDependency(id);
}
}
*dirtyBits = HdMaterial::Clean;
Expand Down Expand Up @@ -646,7 +637,7 @@ bool HdArnoldNodeGraph::ReadMaterialNetwork(const HdMaterialNetwork2& network)
if (fileValue == nullptr) {
continue;
}
const auto nodeGraph = mtlxDoc->getNodeGraph(texturePath.GetParentPath().GetName());
const auto nodeGraph = mtlxDoc->GetNodeGraphTerminal(texturePath.GetParentPath().GetName());
const auto texture = nodeGraph->getNode(texturePath.GetName());
if (fileValue->IsHolding<SdfAssetPath>()) {
const auto resolvedPath = fileValue->UncheckedGet<SdfAssetPath>().GetResolvedPath();
Expand Down Expand Up @@ -1017,23 +1008,14 @@ void HdArnoldNodeGraph::SetNodesUnused()
}
}

AtNode* HdArnoldNodeGraph::GetNodeGraphTerminal(HdRenderIndex* renderIndex, const SdfPath& id, const TfToken& terminal)
const HdArnoldNodeGraph* HdArnoldNodeGraph::GetNodeGraph(HdRenderIndex* renderIndex, const SdfPath& id)
{
if (id.IsEmpty()) {
return nullptr;
}
auto* nodeGraph = reinterpret_cast<const HdArnoldNodeGraph*>(renderIndex->GetSprim(HdPrimTypeTokens->material, id));
return nodeGraph == nullptr ? nullptr : nodeGraph->GetTerminal(terminal);
return reinterpret_cast<const HdArnoldNodeGraph*>(renderIndex->GetSprim(HdPrimTypeTokens->material, id));
}

std::vector<AtNode*> HdArnoldNodeGraph::GetNodeGraphTerminals(HdRenderIndex* renderIndex, const SdfPath& id, const TfToken& terminalBase)
{
if (id.IsEmpty()) {
return std::vector<AtNode*>();
}
auto* nodeGraph = reinterpret_cast<const HdArnoldNodeGraph*>(renderIndex->GetSprim(HdPrimTypeTokens->material, id));
return nodeGraph == nullptr ? std::vector<AtNode*>() : nodeGraph->GetTerminals(terminalBase);
}


PXR_NAMESPACE_CLOSE_SCOPE
22 changes: 6 additions & 16 deletions render_delegate/node_graph.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ class HdArnoldNodeGraph : public HdMaterial {
/// Destructor for HdArnoldNodeGraph.
///
/// Destory all Arnold Shader Nodes created.
~HdArnoldNodeGraph() override;
~HdArnoldNodeGraph() override = default;

/// Syncing the Hydra Material to the Arnold Shader Network.
///
Expand Down Expand Up @@ -114,23 +114,13 @@ class HdArnoldNodeGraph : public HdMaterial {
HDARNOLD_API
std::vector<AtNode*> GetTerminals(const TfToken& terminalBase) const;

/// Utility function to return a shader graph for a given terminal.
/// Helper static function that returns the node graph for a given path
///
/// @param renderIndex
/// @param id Path to ArnoldNodeGraph
/// @param terminal Terminal token
/// @return Vector of pointers to the terminal, nullptr if not found.
HDARNOLD_API
static AtNode* GetNodeGraphTerminal(HdRenderIndex* renderIndex, const SdfPath& id, const TfToken& terminal);

/// Utility function to return multiple shader graphs for a given terminal base token.
///
/// @param renderIndex
/// @param id Path to ArnoldNodeGraph
/// @param terminalBase Terminal base token
/// @return Vector of pointers to the terminal, nullptr if not found.
/// @param renderIndex Pointer to the Hydra render index
/// @param id Path of the node graph primitive
/// @return Pointer to the requested HdArnoldNodeGraph
HDARNOLD_API
static std::vector<AtNode*> GetNodeGraphTerminals(HdRenderIndex* renderIndex, const SdfPath& id, const TfToken& terminalBase);
static const HdArnoldNodeGraph* GetNodeGraph(HdRenderIndex* renderIndex, const SdfPath& id);

protected:
/// Utility struct to store translated nodes.
Expand Down
Loading

0 comments on commit 0b0d118

Please sign in to comment.