High performance text component
André Thieme
a.thieme at freenet.de
Thu Aug 16 11:48:19 PDT 2012
Am 03.08.2012 05:14, schrieb Richard Bair:
>
> With a Canvas approach. the way I would have approached it would have
> been to have a canvas the size of the viewport, and then simply use
> it as a place to draw all my text. The ScrollBar associated with it
> would be just sitting there, and I'd use its value as an indication
> of where to start drawing the text.
I started playing with a variation of this:
A Pane for absolute positioning of Text instances. The Pane will be the
content of a ScrollPane, and have always the size that fits exactly into
the it, so that no scrollbars will be needed. But then I set the option
to always show the scrollbars.
A binding on the ScrollPane’s hvalue and vvalue will allow me to
specify a function that is always called as soon the user moves the
thumb of one of the scrollbars.
There is a pool of 20k Text instances, as this many different Texts
could potentially be visible on the screen at the same time.
The “paint” function always looks into the model and finds out which
Texts would be visible, if they were actually on the Pane. I then add
the correct number of Texts from the caches to the Pane and set their
position and text content. This should indeed produce the illusion of
scrolling.
I am trying to come up with a prototype for this, but I already have a
question here: is there a way to set the thumb size?
When I set the scrollbars to always appear, then the thumb will have the
minimum size, as if my Pane were massively huge. I want the scrollbars
to have a realistic look, so that the thumbs are bigger, relative to the
content in my virtual Pane.
So far I did not try this out, to see how fast it goes. But one thing
feels suboptimal to this: the JFX team already implemented all of this!
I did some test, and I noticed some things. This is what I did:
1) Created a Pane and added 15k Text instances to it, all visible at the
same time. The Pane had a resolution of 1200x900. Resizing the window
was very slow. The lesson I learned: JFX does not perform well when
there are very many Text instances visible at the same time.
2) Created a ScrollPane, containing a Pane with just a single Text
instance. Into this Text I put a 23 MB String. The scrolling was
extremly slow (less than 1 FPS). I found out that JFX performs bad when
a single Text (same is true for TextArea) contains a huge String.
3) I created a ScrollPane, containing a Pane which contains 100k Text
instances, of which 1200 were visible at the same time.
This one scrolled very nicely.
Now my comments about those three tests:
1) JFX really needs to speed up the performance of extremly many Text
instances that are visible at the same time. In a code editor that wants
to compete with the one found in Eclipse, NetBeans or Visual Studio,
we must assume the worst case scenario. People could be using two
monitors, both in full screen mode, and displaying tons of Text instances.
With a small font I could imagine that 50k could be visible at the same
time. In my opinion, whatever I do (resizing the window, scrolling,
animating the texts, or all at the same time), I should get 50-100 FPS
on good video cards. The top video cards today allow playing the game
“Battlefield 3” in very high resolution with “Ultra Quality” at over
50 FPS.
This is a nearly photorealistic world, with complex light and shadow
effects and lots of 3d models. So, from this perspective it should be
possible in my opinion, to do anything with Text at very high FPS.
How many Texts I paint on top of each other, in what strange ways I
let them change colors and rotate, and scroll through 3000 screens of
it: it should all be fluid. JFX currently can do this fine when we do
this with some hundred Texts that are visible at the same time.
Do you see a chance to speed this up even more?
I don’t want to do all this crazy animation stuff, I just want to make
sure that if I put 20k (or 50k, the more the better) Texts on the screen
at the same time, and have 10 screens of this (so 200k to 500k Text
instances added to a Pane inside a ScrollPane), then scrolling should be
completly fluid.
2) Making this more performant should be pretty straightforward.
There is already RT-16853 for this.
A single 3 GB String (be it a Text or TextArea) should scroll fluidly.
3) This looks promising. In principle this is enough for realistic cases
of code editors. Typically it should be enough to display ca. 500 Texts
at the same time. I tried this with over 1200, and it scrolled very
nicely. Even when I added 100k Texts to the pane it was very nice.
Also with 200k Texts it was still usable enough. It was nowhere near
Visual Studio, but still good.
Unfortunately a Text seems to consume very much RAM. It would be no
problem to create several million Strings, but Texts require very much
more RAM than comparable Strings. I was already thinking about creating
a CachedText, which just stores a String and a font (a single font can
be reused for millions of instances, so on a 64 bit system the font
attribute would just be an 8 byte pointer to an existing immutable font
instance) and some style info (flags for bold, italic, underlined,
striked through, overlined) and the color (can again be a pointer to
an existing shared Color instance).
The CachedTexts could be placed on a Pane as if they were Texts.
As soon they become visible they would pull out a real Text instance
from a pool of maybe 50k Texts, and use this as their visual
representation. Unfortunately I did not find a way to do this.
How can a component know that it is now visible on the screen, and when
it is no longer visible?
Another thing that I noticed: the scrolling was only fast when using
Gray font smoothing. As soon LCD was used the number of Texts that can
be visible at the same time is drastically reduced. I created RT-24329
for this.
So, in principle what JFX already does is usable for realistic coding
situations. This is why I feel a bit unwell when thinking about the
approach of implementing a pane, and manage scrollbars manually.
The Scenegraph should already know which components are visible.
I also saw that you implemented
com.sun.javafx.scene.control.skin.VirtualContainerBase
com.sun.javafx.scene.control.skin.VirtualFlow
com.sun.javafx.scene.control.skin.VirtualScrollBar
In principle I would have to reimplement what already exists.
Provided that you can improve LCD performance and the number of Text
instances that are visible at the same time on the screen, then it
would be very close already to be ready for implementing a code editor
with this. The only hurdle is to have millions of Texts added to a
Pane.
I did some tests with Firefox. In Visual Studio I took a big F# code
file, pasted it 100x into the same file, and opened it.
Opening took about 3 seconds. Scrolling then became pretty slow. But
when I reached the bottom of the file, which were over 600k LOC, then
from this moment on the scrolling was perfectly fluid. That was for
colorized source code, a 23 MB file and all in a crystal clear LCD font.
I want to do the same thing in JFX.
With the current tools this is still a bit difficult.
How does a Text or Label actually draw its text on the screen?
Is it using some Prism calls? In principle I need something that is very
low level, but the fastest possible way to draw text.
Also it would be great if I wouldn’t have to implement scrolling again,
as the existing scrollbar is doing this nicely. And instead of a 700
bytes Text instance I need something that is much more low level, so
that millions of instances can be placed on the scenegraph. A caching
mechanism could help, but should not the scenegraph do this already?
If not, would you add a VirtualPane and/or VirtualCanvas to the public
API? I imagine that Lists, Tables, TextAreas and all scrollable things
may be able to use the same API.
I would like to be able to add millions of instances to a Container,
and have very fluid scrolling.
This posting was unstructured, sorry for that. I just wrote down the
ideas as soon they arrived :-)
Sunny greetings,
André
More information about the openjfx-dev
mailing list