Skip to content

Commit

Permalink
MAYA-126763: implement custom scene index plugin registration in maya…
Browse files Browse the repository at this point in the history
…-hydra (#313)

* MAYA-126763: implement plugin registration on maya-hydra side

* MAYA-126763: remove scene index support

* MAYA-126763: fix comment

* MAYA-126763: address Pierre's concerns

* MAYA-126763: magic string used

* MAYA-126763: add perf bottleneck comment

* MAYA-126763: improve comment

* MAYA-126763: address Alan's concerns

* MAYA-126763: replace path with MObject inside of data source completely

* MAYA-126763: fix mobject handle

* MAYA-126763: small cleanup; reinit, scene indices and callbacks on exit; fix scene index suffix

* MAYA-126763: remove unused header

* MAYA-126763: fix bad comment
  • Loading branch information
perrauo-adsk authored and GitHub Enterprise committed Jan 10, 2023
1 parent a9a2e17 commit 2d37175
Show file tree
Hide file tree
Showing 2 changed files with 173 additions and 4 deletions.
159 changes: 155 additions & 4 deletions lib/mayaUsd/render/mayaToHydra/renderOverride.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,14 @@
#include <mayaHydraLib/renderItemClient/renderDelegate.h>
#include <mayaHydraLib/utils.h>

#include <pxr/base/tf/type.h>
#include <pxr/base/plug/plugin.h>
#include "pxr/base/plug/registry.h"

#include <pxr/imaging/hd/dataSourceTypeDefs.h>
#include <pxr/imaging/hd/retainedDataSource.h>
#include <pxr/imaging/hd/sceneIndexPlugin.h>

#if defined(MAYAUSD_VERSION)
#include <mayaUsd/render/px_vp20/utils.h>
#include <mayaUsd/utils/hash.h>
Expand All @@ -56,6 +64,7 @@
#include <pxr/imaging/glf/contextCaps.h>
#include <pxr/imaging/hd/camera.h>
#include <pxr/imaging/hd/rendererPluginRegistry.h>
#include <pxr/imaging/hd/sceneIndexPluginRegistry.h>
#include <pxr/imaging/hd/rprim.h>
#include <pxr/imaging/hdx/colorizeSelectionTask.h>
#include <pxr/imaging/hdx/pickTask.h>
Expand All @@ -75,6 +84,8 @@
#include <maya/MSelectionList.h>
#include <maya/MTimerMessage.h>
#include <maya/MUiMessage.h>
#include <maya/MDGMessage.h>
#include <maya/MObjectHandle.h>

#include <atomic>
#include <chrono>
Expand Down Expand Up @@ -311,10 +322,6 @@ MtohRenderOverride::~MtohRenderOverride()
for (auto operation : _operations) {
delete operation;
}

for (auto callback : _callbacks) {
MMessage::removeCallback(callback);
}
for (auto& panelAndCallbacks : _renderPanelCallbacks) {
MMessage::removeCallbacks(panelAndCallbacks.second);
}
Expand Down Expand Up @@ -766,6 +773,141 @@ MtohRenderOverride* MtohRenderOverride::_GetByName(TfToken rendererName)
return nullptr;
}

namespace {
constexpr char kDataSourceEntryName[] = { "object" };
constexpr char kSceneIndexPluginSuffix[] = {
"MayaNodeSceneIndexPlugin"
}; // every scene index plugin compatible with the hydra viewport require this suffix
constexpr char kDagNodeMessageName[] = { "dagNode" };
} // namespace

bool MtohRenderOverride::_RemoveCustomSceneIndexForNode(const MObject& dagNode)
{
MObjectHandle dagNodeHandle(dagNode);
auto customSceneIndex = _customSceneIndices.find(dagNodeHandle);
if (customSceneIndex != _customSceneIndices.end()) {
_renderIndex->RemoveSceneIndex(customSceneIndex->second);
_customSceneIndices.erase(dagNodeHandle);
auto preRemovalCallback = _customSceneIndexNodePreRemovalCallbacks.find(dagNodeHandle);
if (TF_VERIFY(preRemovalCallback != _customSceneIndexNodePreRemovalCallbacks.end())) {
MNodeMessage::removeCallback(preRemovalCallback->second);
_customSceneIndexNodePreRemovalCallbacks.erase(dagNodeHandle);
}
return true;
}
return false;
}

void MtohRenderOverride::_AddCustomSceneIndexForNode(MObject& dagNode)
{
MFnDependencyNode dependNodeFn(dagNode);
// Name must match Plugin TfType registration thus must begin with upper case
std::string pluginName(dependNodeFn.typeName().asChar());
pluginName[0] = toupper(pluginName[0]);
pluginName += kSceneIndexPluginSuffix;
TfToken pluginId(pluginName);

static HdSceneIndexPluginRegistry& sceneIndexPluginRegistry
= HdSceneIndexPluginRegistry::GetInstance();
if (sceneIndexPluginRegistry.IsRegisteredPlugin(pluginId)) {
using HdMObjectDataSource = HdRetainedTypedSampledDataSource<MObject>;
TfToken names[1] { TfToken(kDataSourceEntryName) };
HdDataSourceBaseHandle values[1] { HdMObjectDataSource::New(dagNode) };
HdSceneIndexBaseRefPtr sceneIndex = sceneIndexPluginRegistry.AppendSceneIndex(
pluginId, nullptr, HdRetainedContainerDataSource::New(1, names, values));
if (TF_VERIFY(
sceneIndex,
"HdSceneIndexBase::AppendSceneIndex failed to create %s scene index from given "
"node type.",
pluginName.c_str())) {
MStatus status;
MCallbackId preRemovalCallback = MNodeMessage::addNodePreRemovalCallback(
dagNode, _CustomSceneIndexNodeRemovedCallback, this, &status);
if (TF_VERIFY(
status != MS::kFailure, "MNodeMessage::addNodePreRemovalCallback failed")) {
_renderIndex->InsertSceneIndex(sceneIndex, SdfPath::AbsoluteRootPath());
// MAYA-126790 TODO: properly resolve missing PrimsAdded notification issue
// https://github.com/PixarAnimationStudios/USD/blob/dev/pxr/imaging/hd/sceneIndex.cpp#L38
// Pixar has discussed adding a missing overridable virtual function when an
// observer is registered For now GetPrim called with magic string populates the
// scene index
static SdfPath maya126790Workaround("maya126790Workaround");
sceneIndex->GetPrim(maya126790Workaround);
MObjectHandle dagNodeHandle(dagNode);
_customSceneIndices.insert({ dagNodeHandle, sceneIndex });
_customSceneIndexNodePreRemovalCallbacks.insert(
{ dagNodeHandle, preRemovalCallback });
}
}
}
}

void MtohRenderOverride::_CustomSceneIndexNodeAddedCallback(MObject& dagNode, void* clientData)
{
if (dagNode.isNull() || dagNode.apiType() != MFn::kPluginShape)
return;
auto renderOverride = static_cast<MtohRenderOverride*>(clientData);
renderOverride->_AddCustomSceneIndexForNode(dagNode);
}

void MtohRenderOverride::_CustomSceneIndexNodeRemovedCallback(MObject& dagNode, void* clientData)
{
if (dagNode.isNull() || dagNode.apiType() != MFn::kPluginShape)
return;
auto renderOverride = static_cast<MtohRenderOverride*>(clientData);
renderOverride->_RemoveCustomSceneIndexForNode(dagNode);
}

void MtohRenderOverride::_InitCustomSceneIndices()
{
// Begin registering of custom scene indices for given node types
if (!_customSceneIndicesInitialized) {
HdSceneIndexPluginRegistry& sceneIndexPluginRegistry
= HdSceneIndexPluginRegistry::GetInstance();
// Ensure scene index plugin registration
std::vector<HfPluginDesc> customSceneIndexDescs;
sceneIndexPluginRegistry.GetPluginDescs(&customSceneIndexDescs);
if (customSceneIndexDescs.size() != 0) {
MCallbackId id;
MStatus status;
id = MDGMessage::addNodeAddedCallback(
_CustomSceneIndexNodeAddedCallback, kDagNodeMessageName, this, &status);
if (status == MS::kSuccess)
_customSceneIndexAddedCallbacks.append(id);

// Iterate over scene to find out existing node which will miss eventual dagNode added
// callbacks
// TODO: This is traversing the whole Dag hierarchy looking for appropriate nodes. This
// won't scale to large scenes; perhaps something like what the MEL command "ls -type"
// is doing would be more appropriate. We can save this for later.
MItDag nodesDagIt(MItDag::kDepthFirst, MFn::kInvalid);
for (; !nodesDagIt.isDone(); nodesDagIt.next()) {
MStatus status;
MObject dagNode(nodesDagIt.item(&status));
if (TF_VERIFY(status == MS::kSuccess)) {
_AddCustomSceneIndexForNode(dagNode);
}
}
_customSceneIndicesInitialized = true;
}
}
}

void MtohRenderOverride::_ClearCustomSceneIndices()
{
if (_customSceneIndicesInitialized) {
MDGMessage::removeCallbacks(_customSceneIndexAddedCallbacks);
for (auto it : _customSceneIndexNodePreRemovalCallbacks) {
MNodeMessage::removeCallback(it.second);
}
_customSceneIndexAddedCallbacks.clear();
_customSceneIndexNodePreRemovalCallbacks.clear();
// Since render index is deleted above, scene indices must be recreated.
_customSceneIndices.clear();
_customSceneIndicesInitialized = false;
}
}

// TODO: Pass MViewportScene inside here
void MtohRenderOverride::_InitHydraResources()
{
Expand All @@ -783,6 +925,10 @@ void MtohRenderOverride::_InitHydraResources()
if (!_rendererPlugin)
return;

// TODO: Must create render delegate via HdRenderPluginRegistry, otherwise display name isn't
// assigned
//_renderDelegate =
//HdRendererPluginRegistry::GetInstance().CreateRenderDelegate(_rendererDesc.rendererName);
auto* renderDelegate = _rendererPlugin->CreateRenderDelegate();
if (!renderDelegate)
return;
Expand Down Expand Up @@ -868,6 +1014,9 @@ void MtohRenderOverride::_InitHydraResources()
break;
}
}

_InitCustomSceneIndices();

_initializationSucceeded = true;
}

Expand Down Expand Up @@ -912,6 +1061,8 @@ void MtohRenderOverride::ClearHydraResources()
_rendererPlugin = nullptr;
}

_ClearCustomSceneIndices();

_viewport = GfVec4d(0, 0, 0, 0);
_initializationSucceeded = false;
_initializationAttempted = false;
Expand Down
18 changes: 18 additions & 0 deletions lib/mayaUsd/render/mayaToHydra/renderOverride.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
#include <maya/MMessage.h>
#include <maya/MString.h>
#include <maya/MViewport2Renderer.h>
#include <maya/MObjectHandle.h>

#include <atomic>
#include <chrono>
Expand Down Expand Up @@ -115,6 +116,12 @@ class MtohRenderOverride : public MHWRender::MRenderOverride

static MtohRenderOverride* _GetByName(TfToken rendererName);

void _InitCustomSceneIndices();
void _ClearCustomSceneIndices();
void _AddCustomSceneIndexForNode(MObject& dagNode); // dagNode non-const because of callback registration
bool _RemoveCustomSceneIndexForNode(const MObject& dagNode);
static void _CustomSceneIndexNodeAddedCallback(MObject& obj, void* clientData);
static void _CustomSceneIndexNodeRemovedCallback(MObject& obj, void* clientData);
void _InitHydraResources();
void _RemovePanel(MString panelName);
void _SelectionChanged();
Expand Down Expand Up @@ -207,6 +214,17 @@ class MtohRenderOverride : public MHWRender::MRenderOverride

int _currentOperation = -1;

std::atomic_bool _customSceneIndicesInitialized;
MCallbackIdArray _customSceneIndexAddedCallbacks;
struct _HashObjectHandle
{
unsigned long operator()(const MObjectHandle& handle) const { return handle.hashCode(); }
};
// MObjectHandle only used as opposed to MObject here because of their hashCode function.
std::unordered_map<MObjectHandle, MCallbackId, _HashObjectHandle>
_customSceneIndexNodePreRemovalCallbacks;
std::unordered_map<MObjectHandle, HdSceneIndexBasePtr, _HashObjectHandle> _customSceneIndices;

const bool _isUsingHdSt = false;
bool _initializationAttempted = false;
bool _initializationSucceeded = false;
Expand Down

0 comments on commit 2d37175

Please sign in to comment.