question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Very low Text Rendering Performance due native C++ interop

See original GitHub issue
  • .NET Core Version: 5.0.6
  • Windows version: 21H1 (Build 19043.928)
  • Does the bug reproduce also in WPF for .NET Framework 4.8?: Yes
  • Is this bug related specifically to tooling in Visual Studio (e.g. XAML Designer, Code editing, etc…)?: No

Problem description: UIElement.Measure this very slow

Actual behavior: image

Expected behavior: Fast measuring for WPF rendering. If there is nothing more that can be optimized in the measure method, it might make sense to cache the measures according to certain parameters, since this is very slow with large visual trees. Compared to Windows Forms, Windows Forms is superior in terms of performance here.

Would it not make sense to write the measure method in native C++ somehow to optimize the performance accordingly or is the overhead here too large?

Minimal repro:

<Grid>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="*"/>
        <!-- ... Many column definitions -->
    </Grid.ColumnDefinitions>
    <Grid.RowDefinitions>
        <RowDefinition Heigth="*"/>
        <!-- ... Many row definitions -->
    </Grid.RowDefinitions>
    <Button Grid.Row="0" Grid.Column="0">Test</Button>
    <Button Grid.Row="1" Grid.Column="0">Test</Button>
    <Button Grid.Row="0" Grid.Column="2">Test</Button>
    <Button Grid.Row="2" Grid.Column="3">Test</Button>
    <Button Grid.Row="12" Grid.Column="0">Test</Button>
    <Button Grid.Row="7" Grid.Column="8">Test</Button>
    <!-- ... big visual tree -->
</Grid>

Issue Analytics

  • State:open
  • Created 2 years ago
  • Reactions:6
  • Comments:10 (8 by maintainers)

github_iconTop GitHub Comments

2reactions
deeprobincommented, Aug 19, 2021

@IAmTheCShark This is exactly what I meant in DataGrid and this makes scrolling very unperformant. And it shouldn’t be like that. Thank you for providing the example 😃.

1reaction
IAmTheCSharkcommented, Aug 4, 2021

@deeprobin I wrote a small hack that uses reflection to turn on some optimizations. Just out of curiosity, can you give it a try and see if there are any improvements?

Obviously, this is nothing for productoin enivronment and only for testing purposes. This might have weird consequences so use with cuaiton.

The hack will make Typeface.CheckFastPathNominalGlyphs (https://referencesource.microsoft.com/#PresentationCore/Core/CSharp/System/Windows/Media/Typeface.cs,550) return true alot more often

Paste the following code into your MainWindow constructor before InitializeComponent or before you create all the TextBlocks. The first line creates a Typeface. If you have different FontFamilies, Styles and so on, you might need to call this multiple times. `

        Typeface typeFace = new Typeface(FontFamily, FontStyle, FontWeight, FontStretch);

        var tryGetGlyphTypeFaceMethod =
            typeof(Typeface).GetMethod("TryGetGlyphTypeface", BindingFlags.Instance | BindingFlags.NonPublic);

        GlyphTypeface glyphTypeFace = tryGetGlyphTypeFaceMethod.Invoke(typeFace, null) as GlyphTypeface;

        var fontFaceLayoutInfoProperty =
            typeof(GlyphTypeface).GetProperty("FontFaceLayoutInfo", BindingFlags.Instance | BindingFlags.NonPublic);

        var fontFaceLayoutInfo = fontFaceLayoutInfoProperty.GetValue(glyphTypeFace);
        var fontFaceLayoutInfoType = fontFaceLayoutInfo.GetType();
        var typographyAvailabilitiesField = fontFaceLayoutInfoType
            .GetField("_typographyAvailabilities", BindingFlags.NonPublic | BindingFlags.Instance);

        var typographyAvailabilitiesProperty
            = fontFaceLayoutInfoType
                .GetProperty("TypographyAvailabilities", BindingFlags.Instance | BindingFlags.NonPublic);

        // forces initialization of a few things
        typographyAvailabilitiesProperty.GetValue(fontFaceLayoutInfo);
        
        // the actual hack, fake some enum value that is suitable
        typographyAvailabilitiesField.SetValue(fontFaceLayoutInfo, 16);

`

Read more comments on GitHub >

github_iconTop Results From Across the Web

Fastest API for rendering text in Windows Forms?
5000+ text rendering is slow even with GDI, especially if you need scrolling. Create a separate rendering thread and notify the UI thread...
Read more >
[Performance] Rewrite DirectWriteForwarder in C# to ...
I'm skeptical that this will improve performance. We still have to call into dwrite.dll so the native interop is just done in a...
Read more >
Rendering text and images performance help? : r/opengl
The problem is in the performance. With just 5 small images and 5 labels, the app is sitting at a comfortable 5-10% cpu...
Read more >
ASP.NET Core Blazor performance best practices
Tips for increasing performance in ASP.NET Core Blazor apps and avoiding common performance problems.
Read more >
Low-level native plug-in interface
An example of a low-level rendering plug-in is on github: github.com/Unity-Technologies/NativeRenderingPlugin. It demonstrates two things:.
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found