Skip to content

Conversation

@zeusongit
Copy link
Contributor

Purpose

The PR is based on changes here

changes from the original PR:

  • Using a feature flag to define max zoom scale at which cache will be cleared.
  • Using shared bitmap cache to save on memory

As described in the original PR,

It introduces a mechanism by which, when the number of nodes on canvas is higher than a certain threshold(150) and zoom scale is at a certain level , we replace all node views with rendered bitmaps, using WPF's existing mechanism called BitmapCache.
Based on the current zoom, we can vary the resolution of the images and create a pseudo Load On Demand system that switches between a low, medium, high and native scale.

So at the zoomed out state we load node views at 0.2 scale (low res), then as zoom increases we switch to 0.5, and then to native scale.

Improved graph movement:

Before:
DynamoSandbox_eI4ZR9s9vZ

After:
DynamoSandbox_Gz0qdrIgEe

Profile results: When scrolling to change zoom level, the cache update and clear takes an additional ~350ms (0.3s) at certain zoom level when the bitmap kicks in, but has no significant change from previous state.
Screenshot 2025-04-28 at 3 38 52 PM

Tested with Autodesk-MaRS-office-example-v3.dyn and Entry 05_Christmas Tree with ornaments over and around.dyn graphs with identical results.

Declarations

Check these if you believe they are true

  • The codebase is in a better state after this PR
  • Is documented according to the standards
  • The level of testing this PR includes is appropriate
  • User facing strings, if any, are extracted into *.resx files
  • All tests pass using the self-service CI.
  • Snapshot of UI changes, if any.
  • Changes to the API follow Semantic Versioning and are documented in the API Changes document.
  • This PR modifies some build requirements and the readme is updated
  • This PR contains no files larger than 50 MB

Release Notes

  • Implement Bitmap Cache for nodes when zoomed out

@zeusongit zeusongit requested review from a team, BogdanZavu, mjkkirschner and pinzart April 28, 2025 21:54
Copy link

@github-actions github-actions bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See the ticket for this pull request: https://jira.autodesk.com/browse/DYN-8305

//disable bitmap caching if max zoom scale set to 0, or feature flag was unable to fetch;
if (ViewModel.MaxZoomScaleForBitmapCache == 0) return;

if (!ViewModel.StopNodeViewOpacityAnimations)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this bitmap cache being tied to this other animation property?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Graphs with lower number of nodes, does not really require this optimization, so it makes sense to trigger this beyond a certain number of nodes. In this case the animation property also uses another feature flag that is set to 150, which we are re-using in this case.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what do you think about renaming this property?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about NodeCountOptimizationEnabled ? (As suggested by copilot)

return;
}

var newRenderScale = newZoomScale <= .2 ? .2 : newZoomScale <= .5 ? .5 : 1;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought this was a bit hard to read - copilot suggests:

var newRenderScale = newZoomScale switch
{
    <= 0.2 => 0.2,
    <= 0.5 => 0.5,
    _ => 1
};

which I think looks a bit simpler?


private void ClearNodeViewCache()
{
var nodes = this.ChildrenOfType<NodeView>();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hmm - have you tested this change on a custom node workspace?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes

DynamoSandbox_nEllgn1Ed9

BitmapCache sharedCache = null;
foreach (var node in nodes)
{
if (node.CacheMode is BitmapCache cache)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this just a null check?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it might be more clear if you just check it's null.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need to cast anyway if the condition is true, I think it is better since it checks for null and also gives us the appropriate object

internal T CheckFeatureFlag<T>(string featureFlagKey, T defaultval)
{
if(!(defaultval is bool || defaultval is string || defaultval is long)){
if(!(defaultval is bool || defaultval is string || defaultval is long || defaultval is double)){
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

comment is now out of date on this method.

@zeusongit zeusongit merged commit 393fa2a into DynamoDS:master May 1, 2025
23 of 24 checks passed
@zeusongit
Copy link
Contributor Author

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants