Browse Source

Merge remote-tracking branch 'origin/ShapedBufferPooling' into ShapedBufferPooling

pull/9954/head
Sergey Mikolaitis 4 years ago
parent
commit
a73b18a8ee
  1. 8
      src/Avalonia.Base/Media/TextFormatting/ShapedBuffer.cs
  2. 7
      src/Avalonia.Base/Media/TextFormatting/TextLineImpl.cs
  3. 3
      src/Avalonia.Controls/Presenters/TextPresenter.cs
  4. 11
      src/Avalonia.Controls/TextBlock.cs
  5. 21
      tests/Avalonia.Benchmarks/Text/HugeTextLayout.cs

8
src/Avalonia.Base/Media/TextFormatting/ShapedBuffer.cs

@ -8,7 +8,7 @@ namespace Avalonia.Media.TextFormatting
public sealed class ShapedBuffer : IList<GlyphInfo>, IDisposable public sealed class ShapedBuffer : IList<GlyphInfo>, IDisposable
{ {
private static readonly IComparer<GlyphInfo> s_clusterComparer = new CompareClusters(); private static readonly IComparer<GlyphInfo> s_clusterComparer = new CompareClusters();
private bool _rented; private bool _bufferRented;
public ShapedBuffer(CharacterBufferRange characterBufferRange, int bufferLength, IGlyphTypeface glyphTypeface, double fontRenderingEmSize, sbyte bidiLevel) : public ShapedBuffer(CharacterBufferRange characterBufferRange, int bufferLength, IGlyphTypeface glyphTypeface, double fontRenderingEmSize, sbyte bidiLevel) :
this(characterBufferRange, this(characterBufferRange,
@ -17,7 +17,7 @@ namespace Avalonia.Media.TextFormatting
fontRenderingEmSize, fontRenderingEmSize,
bidiLevel) bidiLevel)
{ {
_rented = true; _bufferRented = true;
Length = bufferLength; Length = bufferLength;
} }
@ -272,7 +272,7 @@ namespace Avalonia.Media.TextFormatting
public void Dispose() public void Dispose()
{ {
GC.SuppressFinalize(this); GC.SuppressFinalize(this);
if (_rented) if (_bufferRented)
{ {
GlyphInfos.ReturnRent(); GlyphInfos.ReturnRent();
} }
@ -280,7 +280,7 @@ namespace Avalonia.Media.TextFormatting
~ShapedBuffer() ~ShapedBuffer()
{ {
if (_rented) if (_bufferRented)
{ {
GlyphInfos.ReturnRent(); GlyphInfos.ReturnRent();
} }

7
src/Avalonia.Base/Media/TextFormatting/TextLineImpl.cs

@ -981,9 +981,12 @@ namespace Avalonia.Media.TextFormatting
public override void Dispose() public override void Dispose()
{ {
foreach (var run in _textRuns.OfType<ShapedTextRun>()) for (int i = 0; i < _textRuns.Count; i++)
{ {
run.Dispose(); if (_textRuns[i] is ShapedTextRun shapedTextRun)
{
shapedTextRun.Dispose();
}
} }
} }

3
src/Avalonia.Controls/Presenters/TextPresenter.cs

@ -588,6 +588,7 @@ namespace Avalonia.Controls.Presenters
protected virtual void InvalidateTextLayout() protected virtual void InvalidateTextLayout()
{ {
_textLayout?.Dispose();
_textLayout = null; _textLayout = null;
InvalidateMeasure(); InvalidateMeasure();
@ -597,6 +598,7 @@ namespace Avalonia.Controls.Presenters
{ {
_constraint = availableSize; _constraint = availableSize;
_textLayout?.Dispose();
_textLayout = null; _textLayout = null;
InvalidateArrange(); InvalidateArrange();
@ -622,6 +624,7 @@ namespace Avalonia.Controls.Presenters
_constraint = new Size(Math.Ceiling(finalSize.Width), double.PositiveInfinity); _constraint = new Size(Math.Ceiling(finalSize.Width), double.PositiveInfinity);
_textLayout?.Dispose();
_textLayout = null; _textLayout = null;
return finalSize; return finalSize;

11
src/Avalonia.Controls/TextBlock.cs

@ -173,13 +173,7 @@ namespace Avalonia.Controls
/// <summary> /// <summary>
/// Gets the <see cref="TextLayout"/> used to render the text. /// Gets the <see cref="TextLayout"/> used to render the text.
/// </summary> /// </summary>
public TextLayout TextLayout public TextLayout TextLayout => _textLayout ??= CreateTextLayout(_text);
{
get
{
return _textLayout ??= CreateTextLayout(_text);
}
}
/// <summary> /// <summary>
/// Gets or sets the padding to place around the <see cref="Text"/>. /// Gets or sets the padding to place around the <see cref="Text"/>.
@ -648,6 +642,7 @@ namespace Avalonia.Controls
/// </summary> /// </summary>
protected void InvalidateTextLayout() protected void InvalidateTextLayout()
{ {
_textLayout?.Dispose();
_textLayout = null; _textLayout = null;
InvalidateVisual(); InvalidateVisual();
@ -663,6 +658,7 @@ namespace Avalonia.Controls
_constraint = availableSize.Deflate(padding); _constraint = availableSize.Deflate(padding);
_textLayout?.Dispose();
_textLayout = null; _textLayout = null;
var inlines = Inlines; var inlines = Inlines;
@ -726,6 +722,7 @@ namespace Avalonia.Controls
_constraint = new Size(Math.Ceiling(finalSize.Deflate(padding).Width), double.PositiveInfinity); _constraint = new Size(Math.Ceiling(finalSize.Deflate(padding).Width), double.PositiveInfinity);
_textLayout?.Dispose();
_textLayout = null; _textLayout = null;
if (HasComplexContent) if (HasComplexContent)

21
tests/Avalonia.Benchmarks/Text/HugeTextLayout.cs

@ -1,5 +1,6 @@
using System; using System;
using System.Linq; using System.Linq;
using Avalonia.Controls;
using Avalonia.Media; using Avalonia.Media;
using Avalonia.Media.TextFormatting; using Avalonia.Media.TextFormatting;
using Avalonia.UnitTests; using Avalonia.UnitTests;
@ -70,6 +71,26 @@ In respect that the structure of the sufficient amount poses problems and challe
[Benchmark] [Benchmark]
public TextLayout[] BuildManySmallTexts() => _manySmallStrings.Select(MakeLayout).ToArray(); public TextLayout[] BuildManySmallTexts() => _manySmallStrings.Select(MakeLayout).ToArray();
[Benchmark]
public void VirtualizeTextBlocks()
{
var blocks = new TextBlock[10];
for (var i = 0; i < blocks.Length; i++)
{
blocks[i] = new TextBlock
{
Width = 120,
Height = 32,
};
}
for (int i = 0, j = 0; i < _manySmallStrings.Length; i++, j = j < blocks.Length - 1 ? j + 1 : 0)
{
blocks[j].Text = _manySmallStrings[i];
blocks[j].Measure(new Size(200, 200));
}
}
private static TextLayout MakeLayout(string str) private static TextLayout MakeLayout(string str)
{ {
var layout = new TextLayout(str, Typeface.Default, 12d, Brushes.Black, maxWidth: 120); var layout = new TextLayout(str, Typeface.Default, 12d, Brushes.Black, maxWidth: 120);

Loading…
Cancel
Save