Skip to content

Speed-up Border rendering by avoiding useless pass during size allocation#24844

Merged
PureWeen merged 2 commits intodotnet:mainfrom
albyrock87:reduce-border-mappping-calls
Oct 17, 2024
Merged

Speed-up Border rendering by avoiding useless pass during size allocation#24844
PureWeen merged 2 commits intodotnet:mainfrom
albyrock87:reduce-border-mappping-calls

Conversation

@albyrock87
Copy link
Copy Markdown
Contributor

@albyrock87 albyrock87 commented Sep 20, 2024

Description of Change

While updating the frame from Handler we set Width and Height.
Each of them triggers border mapping:

image image

The first one is useless as the other dimension will change right after.
We can avoid this by batching the change on SizeAllocated:

void UpdateBoundsComponents(Rect bounds)
{
_frame = bounds;
BatchBegin();
X = bounds.X;
Y = bounds.Y;
Width = bounds.Width;
Height = bounds.Height;
SizeAllocated(Width, Height);
SizeChanged?.Invoke(this, EventArgs.Empty);
BatchCommit();
}

This brings us to a better result:
image
image

Issues Fixed

Fixes #24843
Contributes to #24123

@albyrock87 albyrock87 requested a review from a team as a code owner September 20, 2024 12:17
@dotnet-policy-service dotnet-policy-service bot added the community ✨ Community Contribution label Sep 20, 2024
@rmarinho rmarinho requested review from PureWeen and jonathanpeppers and removed request for jsuarezruiz and tj-devel709 September 20, 2024 14:39
@PureWeen
Copy link
Copy Markdown
Member

/azp run

@azure-pipelines
Copy link
Copy Markdown

Azure Pipelines successfully started running 3 pipeline(s).

PropertyChangedEventHandler? _strokeShapeChanged;
WeakNotifyPropertyChangedProxy? _strokeProxy = null;
PropertyChangedEventHandler? _strokeChanged;
bool _sizeChanged;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Should this set to false on disconnect ?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Humm no, I was reading this wrong , but I m afraid that on reuse this "cache" could fail

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

@rmarinho what do you mean with reuse?

There is a very small window where this is true.

void UpdateBoundsComponents(Rect bounds)
{
_frame = bounds;
BatchBegin();
X = bounds.X;
Y = bounds.Y;
Width = bounds.Width;
Height = bounds.Height;
SizeAllocated(Width, Height);
SizeChanged?.Invoke(this, EventArgs.Empty);
BatchCommit();
}

Width = bounds.Width; // this eventually sets it to `true`
Height = bounds.Height; // this eventually sets it to `true`
// right after
SizeAllocated(Width, Height); // this sets it back to false

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Reuse where on a NavigationStack on a page, if you for example push a modal, the border handler could get called a Disconnect and then Connect when the modal is popped and you get to the root page.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I must be missing something here.

I don't understand why that would make any difference.

Before this changes, everything depended on Width and/or Height property changed and that behavior has not changed with my PR.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Yea, I don't think it matters

If the handler disconnects and reconnects

Handler?.UpdateValue(nameof(IBorderStroke.Shape));

is going to run as part of the reconnect anyway.

if (_sizeChanged)
{
_sizeChanged = false;
Handler?.UpdateValue(nameof(IBorderStroke.Shape));
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

is there a way this could move down into the handler?

OnSizeAllocated is basically called during the arrange pass when Handler?.PlatformArrange(Frame); is called.

Copy link
Copy Markdown
Contributor Author

@albyrock87 albyrock87 Sep 25, 2024

Choose a reason for hiding this comment

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

Regarding moving this into the handler:

  • MapFrame aka MappingFrame is basically static platform-specific code, so it's not a good idea to wire it up there: it's not always going through a specific handler method
    static partial void MappingFrame(IViewHandler handler, IView view);
    /// <summary>
    /// Maps the abstract <see cref="IView.Frame"/> property to the platform-specific implementations.
    /// </summary>
    /// <param name="handler">The associated handler.</param>
    /// <param name="view">The associated <see cref="IView"/> instance.</param>
    /// <param name="args">The arguments passed associated to this event.</param>
    public static void MapFrame(IViewHandler handler, IView view, object? args)
    {
    MappingFrame(handler, view);
    }
  • PlatformArrange on the border handler is used to arrange border's content, so it happens after its container has arranged the Border, so also in this case it's not good put that code here (it doesn't work - look how the border radius is messed up here)
    image

I see nothing wrong in invoking the handler on property changed, because it's exactly what happens on everything else.

/// <summary>Method that is called when a bound property is changed.</summary>
/// <param name="propertyName">The name of the bound property that changed.</param>
protected override void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
base.OnPropertyChanged(propertyName);
UpdateHandlerValue(propertyName);
if (_effects?.Count > 0)
{
var args = new PropertyChangedEventArgs(propertyName);
foreach (Effect effect in _effects)
{
effect?.SendOnElementPropertyChanged(args);
}
}
}

@albyrock87 albyrock87 force-pushed the reduce-border-mappping-calls branch from 22c094a to cc1101e Compare September 25, 2024 12:38
@albyrock87
Copy link
Copy Markdown
Contributor Author

I've just rebased onto main to solve conflicts on PublicAPI.

@rmarinho
Copy link
Copy Markdown
Member

/azp run

@azure-pipelines
Copy link
Copy Markdown

Azure Pipelines successfully started running 3 pipeline(s).

@bcaceiro
Copy link
Copy Markdown

This looks quite promising. MAjority of CollectionViews have as a base element a border, will this be available in net8 or net9?

Copy link
Copy Markdown
Member

@PureWeen PureWeen left a comment

Choose a reason for hiding this comment

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

@albyrock87
Copy link
Copy Markdown
Contributor Author

@PureWeen it works, even if I don't know why it didn't when I tried weeks ago.
I've updated the PR accordingly. Thanks.

@MartyIX MartyIX added platform/macos macOS / Mac Catalyst platform/windows platform/android platform/ios perf/general The issue affects performance (runtime speed, memory usage, startup time, etc.) (sub: perf) labels Oct 11, 2024
@PureWeen
Copy link
Copy Markdown
Member

/azp run

@azure-pipelines
Copy link
Copy Markdown

Azure Pipelines successfully started running 3 pipeline(s).

@PureWeen PureWeen merged commit c177617 into dotnet:main Oct 17, 2024
@albyrock87 albyrock87 deleted the reduce-border-mappping-calls branch October 18, 2024 16:48
albyrock87 added a commit to nalu-development/maui-custom that referenced this pull request Nov 9, 2024
…tion (dotnet#24844)

* Speed-up Border rendering by avoiding useless pass during size allocation

* User `BorderHandler.PlatformArrange` instead of `SizeAllocated`

(cherry picked from commit c177617)
@github-actions github-actions bot locked and limited conversation to collaborators Nov 18, 2024
@samhouts samhouts added fixed-in-9.0.10 fixed-in-net8.0-nightly This may be available in a nightly release! labels Dec 16, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

community ✨ Community Contribution fixed-in-9.0.10 fixed-in-net8.0-nightly This may be available in a nightly release! perf/general The issue affects performance (runtime speed, memory usage, startup time, etc.) (sub: perf) platform/android platform/ios platform/macos macOS / Mac Catalyst platform/windows

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Border mapping should perform better

6 participants