Skip to content

Commit

Permalink
Merge pull request #3015 from Autodesk/gamaj/smarter_signaling_for_re…
Browse files Browse the repository at this point in the history
…nderers

Smart signaling must emit MNodeMessages
  • Loading branch information
seando-adsk authored Apr 27, 2023
2 parents 8ffa4a4 + 74bb161 commit d4b357c
Show file tree
Hide file tree
Showing 18 changed files with 749 additions and 299 deletions.
90 changes: 90 additions & 0 deletions lib/mayaUsd/listeners/stageNoticeListener.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,12 @@

#include <pxr/base/tf/notice.h>
#include <pxr/base/tf/weakBase.h>
#include <pxr/base/vt/value.h>
#include <pxr/usd/sdf/listOp.h>
#include <pxr/usd/usd/notice.h>
#include <pxr/usd/usd/stage.h>
#include <pxr/usd/usd/tokens.h>
#include <pxr/usd/usdUI/tokens.h>

PXR_NAMESPACE_OPEN_SCOPE

Expand Down Expand Up @@ -168,4 +172,90 @@ void UsdMayaStageNoticeListener::_OnStageEditTargetChanged(
}
}

namespace {
bool _IsUiSchemaPrepend(const VtValue& v)
{
static std::set<size_t> UiSchemaPrependHashes;
std::once_flag hasHashes;
std::call_once(hasHashes, [&]() {
SdfTokenListOp op;
op.SetPrependedItems(TfTokenVector { TfToken("NodeGraphNodeAPI") });
UiSchemaPrependHashes.insert(hash_value(op));
});

if (v.IsHolding<SdfTokenListOp>()) {
const size_t hash = hash_value(v.UncheckedGet<SdfTokenListOp>());
if (UiSchemaPrependHashes.count(hash)) {
return true;
}
}
return false;
}
} // namespace

UsdMayaStageNoticeListener::ChangeType
UsdMayaStageNoticeListener::ClassifyObjectsChanged(UsdNotice::ObjectsChanged const& notice)
{
using PathRange = UsdNotice::ObjectsChanged::PathRange;

auto range = notice.GetResyncedPaths();
if (!range.empty()) {
size_t ignoredCount = 0;
size_t resyncCount = 0;
for (auto it = range.begin(); it != range.end(); ++it) {
if (it->IsPropertyPath()) {
// We have a bunch of UI properties to ignore. Especially anything that comes from
// UI schemas.
if (it->GetName().rfind("ui:", 0) == 0) {
++ignoredCount;
continue;
}
}
for (const SdfChangeList::Entry* entry : it.base()->second) {
for (auto&& infoChanged : entry->infoChanged) {
if (infoChanged.first == UsdTokens->apiSchemas
&& _IsUiSchemaPrepend(infoChanged.second.second)) {
++ignoredCount;
} else {
++resyncCount;
}
}
}
}

if (ignoredCount) {
return resyncCount ? ChangeType::kResync : ChangeType::kIgnored;
} else {
return ChangeType::kResync;
}
}

auto retVal = ChangeType::kIgnored;

const PathRange pathsToUpdate = notice.GetChangedInfoOnlyPaths();
for (PathRange::const_iterator it = pathsToUpdate.begin(); it != pathsToUpdate.end(); ++it) {
if (it->IsAbsoluteRootOrPrimPath()) {
const TfTokenVector changedFields = it.GetChangedFields();
if (!changedFields.empty()) {
retVal = ChangeType::kUpdate;
}
} else if (it->IsPropertyPath()) {
// We have a bunch of UI properties to ignore. Especially anything that comes from UI
// schemas.
if (it->GetName().rfind("ui:", 0) == 0) {
continue;
}
retVal = ChangeType::kUpdate;
for (const auto& entry : it.base()->second) {
if (entry->flags.didChangeAttributeConnection) {
retVal = ChangeType::kResync;
break;
}
}
}
}

return retVal;
}

PXR_NAMESPACE_CLOSE_SCOPE
27 changes: 27 additions & 0 deletions lib/mayaUsd/listeners/stageNoticeListener.h
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,33 @@ class UsdMayaStageNoticeListener : public TfWeakBase
MAYAUSD_CORE_PUBLIC
void SetStageEditTargetChangedCallback(const StageEditTargetChangedCallback& callback);

/// We have incoming changes that USD will consider either requiring an
/// update (meaning the render delegate needs to refresh and redraw) or
/// a resync (meaning the scene delegate needs to fetch new datum). We
/// want external clients to be aware of these classes of updates in case
/// they do not use the Hydra system for refreshing and drawing the scene.
enum class ChangeType
{
kIgnored, // Change does not require redraw: UI change, metadata change.
kUpdate, // Change requires redraw after refreshing parameter values
kResync // Change requires refreshing cached buffers
};

/// This is a stripped down copy of UsdImagingDelegate::_OnUsdObjectsChanged which is the main
/// USD notification handler where paths to refresh and paths to update are compiled for the
/// next Hydra refresh. We do not gather paths as there is no simple way to know when to flush
/// these maps.
///
/// This needs to stay as quick as possible since it is stuck in the middle of the notification
/// code path.
///
/// This is a work in progress. Some improvements might be necessary in the future. The
/// following potential issues are already visible:
///
/// - Changing a parameter value for the first time creates the attribute, which is a kResync
MAYAUSD_CORE_PUBLIC
static ChangeType ClassifyObjectsChanged(UsdNotice::ObjectsChanged const& notice);

private:
UsdMayaStageNoticeListener(const UsdMayaStageNoticeListener&) = delete;
UsdMayaStageNoticeListener& operator=(const UsdMayaStageNoticeListener&) = delete;
Expand Down
4 changes: 2 additions & 2 deletions lib/mayaUsd/nodes/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ target_sources(${PROJECT_NAME}
proxyShapeBase.cpp
proxyShapePlugin.cpp
proxyShapeStageExtraData.cpp
proxyShapeUpdateManager.cpp
proxyShapeListenerBase.cpp
stageData.cpp
stageNode.cpp
usdPrimProvider.cpp
Expand All @@ -23,7 +23,7 @@ set(HEADERS
proxyShapePlugin.h
proxyStageProvider.h
proxyShapeStageExtraData.h
proxyShapeUpdateManager.h
proxyShapeListenerBase.h
stageData.h
stageNode.h
usdPrimProvider.h
Expand Down
49 changes: 5 additions & 44 deletions lib/mayaUsd/nodes/proxyShapeBase.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -157,9 +157,6 @@ MObject MayaUsdProxyShapeBase::drawGuidePurposeAttr;
MObject MayaUsdProxyShapeBase::sessionLayerNameAttr;
MObject MayaUsdProxyShapeBase::rootLayerNameAttr;
MObject MayaUsdProxyShapeBase::mutedLayersAttr;
// Change counter attributes
MObject MayaUsdProxyShapeBase::updateCounterAttr;
MObject MayaUsdProxyShapeBase::resyncCounterAttr;
// Output attributes
MObject MayaUsdProxyShapeBase::outTimeAttr;
MObject MayaUsdProxyShapeBase::outStageDataAttr;
Expand Down Expand Up @@ -403,26 +400,6 @@ MStatus MayaUsdProxyShapeBase::initialize()
retValue = addAttribute(outStageDataAttr);
CHECK_MSTATUS_AND_RETURN_IT(retValue);

updateCounterAttr
= numericAttrFn.create("updateId", "upid", MFnNumericData::kInt64, -1, &retValue);
CHECK_MSTATUS_AND_RETURN_IT(retValue);
numericAttrFn.setStorable(false);
numericAttrFn.setWritable(false);
numericAttrFn.setHidden(true);
numericAttrFn.setInternal(true);
retValue = addAttribute(updateCounterAttr);
CHECK_MSTATUS_AND_RETURN_IT(retValue);

resyncCounterAttr
= numericAttrFn.create("resyncId", "rsid", MFnNumericData::kInt64, -1, &retValue);
CHECK_MSTATUS_AND_RETURN_IT(retValue);
numericAttrFn.setStorable(false);
numericAttrFn.setWritable(false);
numericAttrFn.setHidden(true);
numericAttrFn.setInternal(true);
retValue = addAttribute(resyncCounterAttr);
CHECK_MSTATUS_AND_RETURN_IT(retValue);

outStageCacheIdAttr
= numericAttrFn.create("outStageCacheId", "ostcid", MFnNumericData::kInt, -1, &retValue);
CHECK_MSTATUS_AND_RETURN_IT(retValue);
Expand Down Expand Up @@ -589,22 +566,6 @@ void MayaUsdProxyShapeBase::postConstructor()
}
}

/* virtual */
bool MayaUsdProxyShapeBase::getInternalValue(const MPlug& plug, MDataHandle& handle)
{
bool retVal = true;

if (plug == updateCounterAttr) {
handle.set(_shapeUpdateManager.GetUpdateCount());
} else if (plug == resyncCounterAttr) {
handle.set(_shapeUpdateManager.GetResyncCount());
} else {
retVal = MPxSurfaceShape::getInternalValue(plug, handle);
}

return retVal;
}

/* virtual */
MStatus MayaUsdProxyShapeBase::compute(const MPlug& plug, MDataBlock& dataBlock)
{
Expand Down Expand Up @@ -2025,6 +1986,11 @@ void MayaUsdProxyShapeBase::_OnStageObjectsChanged(const UsdNotice::ObjectsChang
MProfilingScope profilingScope(
_shapeBaseProfilerCategory, MProfiler::kColorB_L1, "Process USD objects changed");

if (UsdMayaStageNoticeListener::ClassifyObjectsChanged(notice)
== UsdMayaStageNoticeListener::ChangeType::kIgnored) {
return;
}

// This will definitely force a BBox recomputation on "Frame All" or when framing a selected
// stage. Computing bounds in USD is expensive, so if it pops up in other frequently used
// scenarios we will have to investigate ways to make this cache clearing less expensive.
Expand All @@ -2033,11 +1999,6 @@ void MayaUsdProxyShapeBase::_OnStageObjectsChanged(const UsdNotice::ObjectsChang
ProxyAccessor::stageChanged(_usdAccessor, thisMObject(), notice);
MayaUsdProxyStageObjectsChangedNotice(*this, notice).Send();

// Also keeps track of the notification counters:
if (_shapeUpdateManager.CanIgnoreObjectsChanged(notice)) {
return;
}

// Recompute the extents of any UsdGeomBoundable that has authored extents
const auto& stage = notice.GetStage();
if (stage != getUsdStage()) {
Expand Down
12 changes: 0 additions & 12 deletions lib/mayaUsd/nodes/proxyShapeBase.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,6 @@ constexpr char USD_UFE_SEPARATOR = '/';
#include <mayaUsd/base/api.h>
#include <mayaUsd/listeners/stageNoticeListener.h>
#include <mayaUsd/nodes/proxyAccessor.h>
#include <mayaUsd/nodes/proxyShapeUpdateManager.h>
#include <mayaUsd/nodes/proxyStageProvider.h>
#include <mayaUsd/nodes/usdPrimProvider.h>

Expand Down Expand Up @@ -127,12 +126,6 @@ class MayaUsdProxyShapeBase
MAYAUSD_CORE_PUBLIC
static MObject mutedLayersAttr;

// Change counter attributes
MAYAUSD_CORE_PUBLIC
static MObject updateCounterAttr;
MAYAUSD_CORE_PUBLIC
static MObject resyncCounterAttr;

// Output attributes
MAYAUSD_CORE_PUBLIC
static MObject outTimeAttr;
Expand Down Expand Up @@ -179,8 +172,6 @@ class MayaUsdProxyShapeBase
MAYAUSD_CORE_PUBLIC
void postConstructor() override;
MAYAUSD_CORE_PUBLIC
bool getInternalValue(const MPlug&, MDataHandle&) override;
MAYAUSD_CORE_PUBLIC
MStatus compute(const MPlug& plug, MDataBlock& dataBlock) override;
MAYAUSD_CORE_PUBLIC
bool isBounded() const override;
Expand Down Expand Up @@ -415,9 +406,6 @@ class MayaUsdProxyShapeBase
size_t _excludePrimPathsVersion { 1 };
size_t _UsdStageVersion { 1 };

// This helper class keeps track of the notification counters:
MayaUsdProxyShapeUpdateManager _shapeUpdateManager;

MayaUsd::ProxyAccessor::Owner _usdAccessor;

static ClosestPointDelegate _sharedClosestPointDelegate;
Expand Down
Loading

0 comments on commit d4b357c

Please sign in to comment.