Open deeprobin opened 3 years ago
This are the hot spots of UIElement.Measure. Would it perhaps be useful to take a closer look at the TextAnalyzer performance-wise?
There is the fastest font renderer in the Rust language. Would make sense to create bindings for it and let fontdue do the work. Or what do you think?
Instead of switching from C++ to Rust and still having calls to native code (with allocations and overhead), wouldn't it be better to check if the code can be replaced with C# instead? Now that we have Span
@Symbai You're right about that. Are there any benchmarks on how much performance the native overhead takes away? And how does it look with the Ahead-of-time compilation, there should be no overhead in my opinion. Would it make sense to distinguish between AOT and JIT compilation (with e.g. preprocessor expressions)? What should also be noted, in my opinion, is that performance has already been radically improved in interoperability (See this article).
WPF does not support AOT. There were benchmarks on .NET repo on each commit where they got rid of native code but I don't have any links. The best would be someone (else, because I have no idea what the code does) re-writes the code in C# and compare both. But then it needs to be reviewed by the new WPF repo owners and they are not very good on that.
@deeprobin can you provide a repro sample?
@miloush I think this should be easily achieveable when you create a large grid view with lots of columns and rows and then scroll thorugh it. When virtualization is enabled, textblocks get lots of updates.
@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 :).
@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);
`
Hey @IAmTheCShark, I just tried your Reflection hack. It makes a minimal difference for me, but it's not an improvement that drastically improves performance.
Has the reimplementation in C# already been started, if so, does a branch already exist for it?
@miloush I think this should be easily achieveable when you create a large grid view with lots of columns and rows and then scroll thorugh it. When virtualization is enabled, textblocks get lots of updates.
I have adapted your solution a bit and added a custom rendering using SkiaSharp and notice that the scrolling is significantly smoother.
Maybe it would be the best solution in the long run to switch from DWrite to SkiaSharp (first for the text rendering). TextblockPerformance.zip - with Skia
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:
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: