-
Notifications
You must be signed in to change notification settings - Fork 1.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Poor performance for <Resource>
fonts
#6236
Comments
The following fix (to diff --git a/src/Microsoft.DotNet.Wpf/src/DirectWriteForwarder/CPP/DWriteWrapper/FontFileStream.cpp b/src/Microsoft.DotNet.Wpf/src/DirectWriteForwarder/CPP/DWriteWrapper/FontFileStream.cpp
index 7e9b51ad..e07bcf9f 100644
--- a/src/Microsoft.DotNet.Wpf/src/DirectWriteForwarder/CPP/DWriteWrapper/FontFileStream.cpp
+++ b/src/Microsoft.DotNet.Wpf/src/DirectWriteForwarder/CPP/DWriteWrapper/FontFileStream.cpp
@@ -61,6 +61,15 @@ namespace MS { namespace Internal { namespace Text { namespace TextInterface
return E_INVALIDARG;
}
+ System::IO::UnmanagedMemoryStream ^ unmanagedStream = dynamic_cast<System::IO::UnmanagedMemoryStream ^>(_fontSourceStream);
+ if (unmanagedStream != nullptr)
+ {
+ // If the stream is a UnmanagedMemoryStream, we can use the pointer directly.
+ *fragmentStart = unmanagedStream->PositionPointer + fileOffset;
+ *fragmentContext = nullptr;
+ return S_OK;
+ }
+
int fragmentSizeInt = (int)fragmentSize;
array<byte>^ buffer = gcnew array<byte>(fragmentSizeInt); (It's not written as well as it could be; just a very simple POC fix.) If this seems like the appropriate direction to take to fix this bug, I'd be happy to open a PR. |
@bgrainger See #5305 , and @ThomasGoulet73 is working on this. |
I saw PR #6171 but it didn't (yet?) touch this file, so I didn't know if it would obsolete my proposed fix. If all the C++/CLI is getting replaced with C#, then yes, fixing the C++/CLI may be pointless, unless:
|
@bgrainger The bad news is I think we hard to replace it with C# version until 8.0 |
If a simple C++/CLI fix can make it into 7.0, I'd like to make that happen; will wait for WPF team triage. |
My PR #6171 is the start of the migration of DirectWriteForwarder to C#. The migration is a direct port with minimal changes to the C++ code when porting. That means that the changes suggested in @bgrainger's patch could be either applied before or after the migration to C#. That being said, the changes looks like a good idea but there is a risk with those changes, due to the fact that it would not copy in a new array. |
As long as the array isn't deallocated before As per the blog post in the OP, a "hack" that implements this solution has been shipping (with no problems) in Logos for years, so I feel confident in this solution. |
@bgrainger send PR to C++ part. I think that way we can hedge if DWrite rewrite in C# get stalled indefinitely. Also if you can measure improvements somehow that helps advocate for the fix |
(cherry picked from commit 066773f)
Problem description:
When using a font that is embedded as a
<Resource>
(see fonts as resource items), the performance of rendering text can be extremely poor.This was first noted in a production .NET 4.8 WPF Application; a detailed writeup of the problem and a solution that was found is at https://faithlife.codes/blog/2019/06/improving-wpf-text-display-performance/.
Actual behavior:
dotTrace shows that very large amounts of time are spent in
MS.Internal.Text.TextInterface.FontFileStream.ReadFileFragment
. Additionally, large amounts of memory are allocated and the program spends a lot of time in GC.Expected behavior:
Rendering a
<Resource>
font is extremely efficient because the resource is already mmap'ed into memory and returning its data could be as simple as a pointer addition.Minimal repro:
An example repro is at https://github.com/bgrainger/EmbeddedFontPerformance. Clone the repo, build the code, and scroll the text box. You'll notice that it can take several seconds to draw the next screen of text (depending on how large the window is).
The following text complements that repo and describes how it reproduces the problem:
This reproduces most easily with the Noto Sans CJK font (perhaps because of the large number of glyphs that have to be read?).
Embed the font:
Then create a text box that references the font and contains a large amount of Chinese text:
Run the app and scroll the ScrollViewer.
The text was updated successfully, but these errors were encountered: