-
Notifications
You must be signed in to change notification settings - Fork 1.6k
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
Optimizing re-layout of 1MB+ pieces of text in a TextEdit
#3086
Comments
As suggested in #2799, ideally there would be a way to only draw the visible text, similar to something like a I think this dependency ceases to exist if a monospace font is selected, which would actually work for my usecase (large-ish code editor), and then a |
epaint memoizes text layout on a rather coarse level of a Each newline ( If we added another level of memoization at the paragraphs level, we could speed up text layout significantly, while still being immediate mode and without having to resort to exotic string types (like ropes). Each frame, we could split a string based on the newlines in it, then lay out each paragraph if needed (memoized), and the assemble the output by just appending the paragraphs after each other vertically. Editing a very long string would therefore be fast, as long as there are many newlines in the text. This is not a perfect solution. If there are no newlines, we would still need to re-layout the full string (because editing the few characters may cause all subsequent rows to change!). Also, splitting the string on the newlines would still be an I suggest we add this to |
TextEdit
I think I can get started on implementing this. |
I'm guessing this will need to respect the |
Is something in work here? |
The problem
egui's TextEdit becomes sluggish when it holds large amounts of text; probably, this is due to it rendering all of the text without doing anything clever to cull text which doesn't make it on to the screen (apologies if this is the wrong terminology, I'm not an expert in graphics programming). Even without doing anything clever, there seem to be some optimisation opportunities inside the code, but I wanted to seek some guidance on whether this is worth doing or not before committing to working on this.
At least, with my test program (see end, adapted from #2799), when there are 15 million characters inside the widget, it is noticably laggy to use (>1s per character insert, compiled with
--release
).I've done some crude
println!
profiling withstd::time::Instant::now()
to find the hot loops, as I will detail below.Related issues: #1196 #2799 #2906
Profiling
Here are the measured slow parts of the result of inserting one 'a' into the middle of the buffer (took around ~2s on release mode):
egui/crates/epaint/src/text/text_layout.rs
Lines 110 to 136 in 9478e50
Took ~0.5s to complete the loop, and reallocated
paragraph.glyphs
23 times. I think with a call toVec::reserve_exact
the allocator pressure can be eliminated entirely, as it should be possible to determine how big each vector is supposed to be.egui/crates/epaint/src/text/text_layout.rs
Line 64 in 9478e50
Took ~0.5s to complete.
egui/crates/epaint/src/text/text_layout.rs
Lines 480 to 485 in 9478e50
Took ~1s to complete.
Test program
The text was updated successfully, but these errors were encountered: