Rendering performance on Linux

Moderators: FourthWorld, heatherlaine, Klaus, kevinmiller, LCMark

ricochet1k
Posts: 39
Joined: Tue Apr 23, 2013 1:30 am

Re: Rendering performance on Linux

Post by ricochet1k » Wed May 08, 2013 3:09 pm

runrevmark wrote:@ricochet1k: Good find! I'd actually forgotten the field was 'dumb' enough to do that! As for why it does it, then lack of time to optimise appropriately is perhaps all I can say. Certainly if you can make it so paragraphs recalculate when changed that would make a big difference - then making it so blocks only recalc when adjusted that would most likely obviate the need for a 'textwidth' cache.
Recomputing everything is certainly easier to code, and apparently the other platforms don't need the optimization as much as Linux does, even though it will improve performance.
runrevmark wrote:Btw, it's great to get another set of eyes on stuff like this - I've done a lot of work in the field over the years and it's easy to get entrenched and develop 'code-blindness' with such things :)
No problem. I've always liked this engine since I got introduced to it volunteering at CMSEC a few years ago. It's been fun learning how it works.

Anyway, my ideas for optimization so far:
  1. Paragraphs only need a layout when a property of them changes or text is altered, or when a text-related property of the field changes.
  2. Block textwidth only needs to change when a font property changes or text is altered, or when a text-related property of the field changes.
  3. Blocks should be split on tab boundaries, so that their width (or a separate inner width) won't need to be recalculated whenever the tab width changes, and it can just check for a tab an then get the width of everything else, instead of having to scan for tabs.
  4. The lines in a paragraph shouldn't need to be recreated unless dontWrap is off and the width of one of the lines changes significantly.
Those are listed in rough order of how difficult each seems to me, and probably the order I'll do them in, assuming I don't decide something else would be more fun.

I'm still quite new to this code, any suggestions/ideas would be appreciated.

EDIT: One I forgot to mention: If each object keeps track of its own dirty state somehow, it would be able to do the layout calculations before the next field redraw instead of immediately, which should mean that many sequential changes to the text of the field won't be slowed down by layout computations.

LCMark
Livecode Staff Member
Livecode Staff Member
Posts: 1209
Joined: Thu Apr 11, 2013 11:27 am

Re: Rendering performance on Linux

Post by LCMark » Wed May 08, 2013 3:41 pm

Recomputing everything is certainly easier to code, and apparently the other platforms don't need the optimization as much as Linux does, even though it will improve performance.
I think this is why it was implemented like that (it was easier and there didn't seem to be a need at the time for more speed) - the old X11 font functions, GDI text on Windows and QuickDraw/CG text on Mac have very fast textwidth() functions when dealing with simple scripts. Both Windows and Mac have remained fast such scripts (i.e. Roman script), but pango seems to treat all text uniformly (which, to be fair is 'correct' if you want to use fancy font features that are present in so many modern fonts) which is why I think there's a huge speed difference. [ Of course, it could be that Mac / Windows are caching strings of text internally... ]
Anyway, my ideas for optimization so far:...
You're ordering sounds right from a difficulty point of view - I suspect the speed increase from just reflowing paragraphs when needed will be significant (i.e. number 1).
I'm still quite new to this code, any suggestions/ideas would be appreciated.
In terms of (1) I'd probably be inclined to try and make the changes as internal to MCParagraph as possible - setting a dirty flag whenever a method is performed on it that mutates it in some way. Then, just modify 'layout()' to reflow when the dirty flag is true. Without delving into the code, I'm pretty sure MCParagraph is quite nicely encapsulated for the most part - MCBlock / MCLine less so, MCParagraph tends to be the master of those so the abstraction lines start to blur slightly.
EDIT: One I forgot to mention: If each object keeps track of its own dirty state somehow, it would be able to do the layout calculations before the next field redraw instead of immediately, which should mean that many sequential changes to the text of the field won't be slowed down by layout computations.
This would also be a good thing to try and solve - 'recompute()' really only needs to be done on the next redraw or field metrics / text metrics (e.g. the formatted* props) are queried.

ricochet1k
Posts: 39
Joined: Tue Apr 23, 2013 1:30 am

Re: Rendering performance on Linux

Post by ricochet1k » Wed May 08, 2013 4:01 pm

PS_LINES_NOT_SYNCHED seems to almost be the dirty flag I want, but it doesn't seem to be used everywhere it seems like it should.

Do you know why lines are deleted and recreated in noflow()? That seems to be the one place where doing that should be unnecessary. Maybe only if state & PS_LINES_NOT_SYNCHED?

ricochet1k
Posts: 39
Joined: Tue Apr 23, 2013 1:30 am

Re: Rendering performance on Linux

Post by ricochet1k » Wed May 08, 2013 5:08 pm

Well, that was surprisingly easy. Holding down backspace is still pretty slow, but performance is a lot better than before. Changes here: https://github.com/ricochet1k/livecode/ ... 38b9d06a04

FourthWorld
VIP Livecode Opensource Backer
VIP Livecode Opensource Backer
Posts: 9834
Joined: Sat Apr 08, 2006 7:05 am
Location: Los Angeles
Contact:

Re: Rendering performance on Linux

Post by FourthWorld » Wed May 08, 2013 9:04 pm

Thank you, ricochet1k. This is a very exciting development. Finally, I can look forward to my Linux apps being as fast as they run on Mac and Win. So nice....
Richard Gaskin
LiveCode development, training, and consulting services: Fourth World Systems
LiveCode Group on Facebook
LiveCode Group on LinkedIn

mwieder
VIP Livecode Opensource Backer
VIP Livecode Opensource Backer
Posts: 3581
Joined: Mon Jan 22, 2007 7:36 am
Location: Berkeley, CA, US
Contact:

Re: Rendering performance on Linux

Post by mwieder » Wed May 08, 2013 9:24 pm

While we're at it, I'm a bit uncomfortable with using non-booleans as boolean values, so I'd like to see

Code: Select all

	if (pref.textsize)
changed to

Code: Select all

 
	if (0 != pref.textsize)
in the MCParagraph copy constructor.

mwieder
VIP Livecode Opensource Backer
VIP Livecode Opensource Backer
Posts: 3581
Joined: Mon Jan 22, 2007 7:36 am
Location: Berkeley, CA, US
Contact:

Re: Rendering performance on Linux

Post by mwieder » Wed May 08, 2013 9:27 pm

as fast as
...think big, Richard... why settle for "as fast as"? Linux should allow us to get much closer to the metal.

FourthWorld
VIP Livecode Opensource Backer
VIP Livecode Opensource Backer
Posts: 9834
Joined: Sat Apr 08, 2006 7:05 am
Location: Los Angeles
Contact:

Re: Rendering performance on Linux

Post by FourthWorld » Wed May 08, 2013 9:29 pm

mwieder wrote:
as fast as
...think big, Richard... why settle for "as fast as"? Linux should allow us to get much closer to the metal.
I'd certainly like that, but with Pango and GTK in the middle I don't have enough experience with either to feel comfortable with such expectations. But of course, if we can make Linux the most satisfying LiveCode experience on any platform I certainly wouldn't mind. :)
Richard Gaskin
LiveCode development, training, and consulting services: Fourth World Systems
LiveCode Group on Facebook
LiveCode Group on LinkedIn

ricochet1k
Posts: 39
Joined: Tue Apr 23, 2013 1:30 am

Re: Rendering performance on Linux

Post by ricochet1k » Wed May 08, 2013 11:41 pm

Having Linux performance be fast is especially important when it comes to computers like the Raspberry Pi (I have one, so I may end up playing with this at some point too) because they are less powerful machines, and need all the speed the engine can give. Which brings up an interesting point: does the Android version of LiveCode use Pango?

But the most interesting thing about these optimizations I'm trying to do is that they will affect all platforms. Apparently the font rendering engines for Win/Mac are much faster than Pango, but they will still see similar kinds of slowness with a few million lines of text.

ricochet1k
Posts: 39
Joined: Tue Apr 23, 2013 1:30 am

Re: Rendering performance on Linux

Post by ricochet1k » Thu May 09, 2013 6:02 am

Turns out all the code to cache block widths was already there, but for some reason noflow was resetting them all, and I can't determine a reason why. https://github.com/ricochet1k/livecode/ ... c86a7efd8b

LCMark
Livecode Staff Member
Livecode Staff Member
Posts: 1209
Joined: Thu Apr 11, 2013 11:27 am

Re: Rendering performance on Linux

Post by LCMark » Thu May 09, 2013 10:05 am

While we're at it, I'm a bit uncomfortable with using non-booleans as boolean values, so I'd like to see
Yup - with you on this one - the older code in the engine does this a fair bit... (Although our preference is '(pref.textsize != 0)' ;))
...think big, Richard... why settle for "as fast as"? Linux should allow us to get much closer to the metal.
You can only get so close unfortunately - although with the graphics changes (switching to use Skia on all platforms) we've been working on we'll be taking another chunk of X11ness out... Graphics-wise, the engine will only need the OS to provide the ability to blit a buffer to the screen. Unfortunately things like typesetting (converting strings to sequences of glyphs and rendering) is quite a complicated business and so there'll always be a need to use something like pango. However, for cross-platform consistency I've been keeping my eye on 'harfbuzz' which looks to be smaller and potentially more efficient - it is what Chrome uses to do its text layout.

LCMark
Livecode Staff Member
Livecode Staff Member
Posts: 1209
Joined: Thu Apr 11, 2013 11:27 am

Re: Rendering performance on Linux

Post by LCMark » Thu May 09, 2013 10:16 am

@richochet1k:
Well, that was surprisingly easy. Holding down backspace is still pretty slow, but performance is a lot better than before.
This is great... Simple too - which is encouraging (occam's razor and all) :)
Having Linux performance be fast is especially important when it comes to computers like the Raspberry Pi (I have one, so I may end up playing with this at some point too) because they are less powerful machines, and need all the speed the engine can give. Which brings up an interesting point: does the Android version of LiveCode use Pango?
The Android engine doesn't do complex text layout yet as there isn't native support (it would have to indirect through Java at the moment, which is something we've not yet done). That being said, the new graphics work is probably the time we'll look to integrate a text layout library (e.g. harfbuzz) to bring support for such things there. It might even allow a cross-platform solution depending on whether it supports platform-specific eccentricities (Windows in particular has two variants of OpenType layout tables for Indic scripts!).
But the most interesting thing about these optimizations I'm trying to do is that they will affect all platforms. Apparently the font rendering engines for Win/Mac are much faster than Pango, but they will still see similar kinds of slowness with a few million lines of text.
Very true :) I wonder how many lines will actually be usable after some of the optimizations you've been working on... At that point we might find the doubly-linked list of paragraphs needs a rethink into a binary tree...
Turns out all the code to cache block widths was already there, but for some reason noflow was resetting them all, and I can't determine a reason why.
Hmmm - this might be because blocks don't recalculate themselves when changed and wait for a 'noflow()' / 'flow()' to do so. Theres a 'block -> reset()' call in MCLine::fitblocks() which is what 'flow()' uses to do line wrapping. However, if this hypothesis is correct then a similar dirty flag in block could be used in 'getwidth()' to work out whether to recompute and thus make those reset() calls unnecessary. That being said, there may be dragons here - MCParagraph is a friend of MCBlock and I'm not sure whether MCParagraph always uses accessor methods to mutate blocks which would make things a little trickier.

mwieder
VIP Livecode Opensource Backer
VIP Livecode Opensource Backer
Posts: 3581
Joined: Mon Jan 22, 2007 7:36 am
Location: Berkeley, CA, US
Contact:

Re: Rendering performance on Linux

Post by mwieder » Thu May 09, 2013 6:01 pm

(Although our preference is '(pref.textsize != 0)' ;))
I switched over to the "0 != prefs.textsize" syntax many years ago. It doesn't impact the "!=" format much, but it avoids problems where you accidentally use "=" instead of "==". The compiler will immediately tell you that you can't assign a value to a constant. Saves you from some troublesome runtime debugging.

ricochet1k
Posts: 39
Joined: Tue Apr 23, 2013 1:30 am

Re: Rendering performance on Linux

Post by ricochet1k » Thu May 09, 2013 6:11 pm

Pango actually uses HarfBuzz on Linux for "complex text rendering" (http://www.pango.org), but since HarfBuzz is being used by GNOME, Firefox, Chrome OS, and Chrome, it's probably a safe bet :P I wish I had known about it back when I was writing my own toy game engine.
runrevmark wrote:Hmmm - this might be because blocks don't recalculate themselves when changed and wait for a 'noflow()' / 'flow()' to do so. Theres a 'block -> reset()' call in MCLine::fitblocks() which is what 'flow()' uses to do line wrapping. However, if this hypothesis is correct then a similar dirty flag in block could be used in 'getwidth()' to work out whether to recompute and thus make those reset() calls unnecessary. That being said, there may be dragons here - MCParagraph is a friend of MCBlock and I'm not sure whether MCParagraph always uses accessor methods to mutate blocks which would make things a little trickier.
I guess I wasn't clear. Block->reset() only sets width = 0, which is already being done all over the MCBlock code, and it looks to me like it's everywhere the block changes. In other words, width == 0 is the dirty flag. I didn't check specifically for MCParagraph accessing MCBlock directly, but I don't remember seeing any of it. Maybe it would be worthwhile to remove the friend status for better encapsulation? I'm going to try removing the reset code from MCLine::fitblocks() as well, because I'm not convinced it's necessary.

I have hit a bug with layout() not being called when it should have been causing an infinite loop, but I suspect it's because clearzeros isn't setting the dirty flag. Debugging this could be very difficult. It would be very nice to have some kind of code proving engine with constraints saying something like "whenever this changes, this needs to be called before this is called" and have it tell me the sequence of events when something breaks...

mwieder
VIP Livecode Opensource Backer
VIP Livecode Opensource Backer
Posts: 3581
Joined: Mon Jan 22, 2007 7:36 am
Location: Berkeley, CA, US
Contact:

Re: Rendering performance on Linux

Post by mwieder » Thu May 09, 2013 6:15 pm

Maybe it would be worthwhile to remove the friend status for better encapsulation?
I'm in favor of removing friend status wherever it appears. Never seen it cause anything but problems.

Locked

Return to “Engine Contributors”