Skip to content

Commit

Permalink
[android] cache Join and Cap enum values (#24248)
Browse files Browse the repository at this point in the history
Context: #23991
Context: https://github.com/chabiss/periodictable

In the above sample, a lot of time is spent in:

    921.46ms (4.3%) mono!Android.Graphics.Paint.Cap.get_Butt()
    872.40ms (4.1%) mono!Android.Graphics.Paint.Join.get_Miter()

This exposes a performance issue with `Java.Lang.Enum` values:

* `java.lang.Enum` in Java are objects (not `int` like C#)

* When accessing an enum value, Java returns an object we have to wrap
  in a C# object.

* .NET for Android has to do bookkeeping around this, lookup in a hash
  table, etc.

To avoid this, we can store the `Join` and `Cap` values in a static
field and avoid calling into Java. This approach is already working
in .NET MAUI for `ImageView.ScaleType`:

https://github.com/dotnet/maui/blob/9361f90a5d9eaf922432b36906ff18f6ccb2f52f/src/Core/src/Platform/Android/AspectExtensions.cs#L7-L10

After this change, the time spent is completely gone:

    2.41ms (0.02%) mono.android!Android.Graphics.Paint.Join.get_Miter()

I can't find the same call for (the unfortunately named) `get_Butt()`
at all.

In the future, we might consider changing the C# binding for
`Java.Lang.Enum` to "auto-cache" values in C# static fields. Not sure
if there is enough time left for it to happen in .NET 9, though.
  • Loading branch information
jonathanpeppers authored Aug 16, 2024
1 parent 0370361 commit a02f1d4
Showing 1 changed file with 20 additions and 26 deletions.
46 changes: 20 additions & 26 deletions src/Core/src/Graphics/MauiDrawable.Android.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,14 @@ namespace Microsoft.Maui.Graphics
{
public class MauiDrawable : PaintDrawable
{
static Join? JoinMiter;
static Join? JoinBevel;
static Join? JoinRound;

static Cap? CapButt;
static Cap? CapSquare;
static Cap? CapRound;

readonly AContext? _context;
readonly float _density;

Expand Down Expand Up @@ -298,20 +306,13 @@ public void SetBorderMiterLimit(float strokeMiterLimit)

public void SetBorderLineJoin(LineJoin lineJoin)
{
Join? aLineJoin = Join.Miter;

switch (lineJoin)
Join? aLineJoin = lineJoin switch
{
case LineJoin.Miter:
aLineJoin = Join.Miter;
break;
case LineJoin.Bevel:
aLineJoin = Join.Bevel;
break;
case LineJoin.Round:
aLineJoin = Join.Round;
break;
}
LineJoin.Miter => JoinMiter ??= Join.Miter,
LineJoin.Bevel => JoinBevel ??= Join.Bevel,
LineJoin.Round => JoinRound ??= Join.Round,
_ => JoinMiter ??= Join.Miter,
};

if (_strokeLineJoin == aLineJoin)
return;
Expand All @@ -323,20 +324,13 @@ public void SetBorderLineJoin(LineJoin lineJoin)

public void SetBorderLineCap(LineCap lineCap)
{
Cap? aLineCap = Cap.Butt;

switch (lineCap)
Cap? aLineCap = lineCap switch
{
case LineCap.Butt:
aLineCap = Cap.Butt;
break;
case LineCap.Square:
aLineCap = Cap.Square;
break;
case LineCap.Round:
aLineCap = Cap.Round;
break;
}
LineCap.Butt => CapButt ??= Cap.Butt,
LineCap.Square => CapSquare ??= Cap.Square,
LineCap.Round => CapRound ??= Cap.Round,
_ => CapButt ??= Cap.Butt,
};

if (_strokeLineCap == aLineCap)
return;
Expand Down

0 comments on commit a02f1d4

Please sign in to comment.