Skip to content

Commit

Permalink
perf: Scavenge TextPaintPool storage
Browse files Browse the repository at this point in the history
  • Loading branch information
jeromelaban committed Feb 7, 2022
1 parent 14fdb5d commit 0d4c160
Showing 1 changed file with 48 additions and 23 deletions.
71 changes: 48 additions & 23 deletions src/Uno.UI/Controls/PaintPool.Android.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using Android.Graphics;
using Android.Text;
using System;
using System.Diagnostics;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using System.Text;
Expand All @@ -22,30 +23,19 @@ internal class TextPaintPool
private static readonly Action LogCharacterSpacingNotSupported =
Actions.CreateOnce(() => typeof(TextPaintPool).Log().Warn("CharacterSpacing is only supported on Android API Level 21+"));

private class Entry
private record Entry(
FontWeight FontWeight,
FontStyle FontStyle,
FontFamily FontFamily,
double FontSize,
double CharacterSpacing,
Windows.UI.Color Foreground,
BaseLineAlignment BaseLineAlignment,
TextDecorations TextDecorations)
{
public readonly FontWeight FontWeight;
public readonly FontStyle FontStyle;
public readonly FontFamily FontFamily;
public readonly double FontSize;
public readonly double CharacterSpacing;
public readonly Windows.UI.Color Foreground;
public readonly BaseLineAlignment BaseLineAlignment;
public readonly TextDecorations TextDecorations;

public Entry(FontWeight fontWeight, FontStyle fontStyle, FontFamily fontFamily, double fontSize, double characterSpacing, Windows.UI.Color foreground, BaseLineAlignment baselineAlignment, TextDecorations textDecorations)
{
FontWeight = fontWeight;
FontStyle = fontStyle;
FontFamily = fontFamily;
FontSize = fontSize;
CharacterSpacing = characterSpacing;
Foreground = foreground;
BaseLineAlignment = baselineAlignment;
TextDecorations = textDecorations;
}
public long Timestamp { get; set; }
}

private class EntryComparer : IEqualityComparer<Entry>
{
public bool Equals(Entry x, Entry y) =>
Expand All @@ -69,7 +59,11 @@ public int GetHashCode(Entry entry) =>
^ entry.TextDecorations.GetHashCode();
}

private static Dictionary<Entry, TextPaint> _entries = new Dictionary<Entry, TextPaint>(new EntryComparer());
private static Dictionary<Entry, TextPaint> _entries = new(new EntryComparer());
private static List<Entry> _entriesList = new();
private static Stopwatch _entriesTime = Stopwatch.StartNew();
private static long _minEntryTimestamp;
private const int MaxEntries = 500;

/// <summary>
/// Builds a TextPaint configuration.
Expand All @@ -96,11 +90,42 @@ public static TextPaint GetPaint(FontWeight fontWeight, FontStyle fontStyle, Fon
if (!_entries.TryGetValue(key, out var paint))
{
_entries.Add(key, paint = InnerBuildPaint(fontWeight, fontStyle, fontFamily, fontSize, characterSpacing, foreground, shader, baselineAlignment, textDecorations));
_entriesList.Add(key);

TryScavenge();
}

key.Timestamp = _entriesTime.ElapsedTicks;

return paint;
}

private static void TryScavenge()
{
if(_entriesList.Count > MaxEntries)
{
var cutoff = ((_entriesTime.ElapsedTicks - _minEntryTimestamp) / 2) + _minEntryTimestamp;

for (int i = 0; i < _entriesList.Count; i++)
{
var entry = _entriesList[i];

if (entry.Timestamp < cutoff)
{
_entries.Remove(entry);
_entriesList.RemoveAt(i--);
}
}

_minEntryTimestamp = cutoff;

if (typeof(TextPaintPool).Log().IsEnabled(LogLevel.Debug))
{
typeof(TextPaintPool).Log().Debug($"Cleared pool ({_entries.Count} left)");
}
}
}

private static TextPaint InnerBuildPaint(FontWeight fontWeight, FontStyle fontStyle, FontFamily fontFamily, double fontSize, double characterSpacing, Color foreground, Shader shader, BaseLineAlignment baselineAlignment, TextDecorations textDecorations)
{
var paint = new TextPaint(PaintFlags.AntiAlias);
Expand Down

0 comments on commit 0d4c160

Please sign in to comment.