API Review RT:17407 Canvas Node

Jim Graham james.graham at oracle.com
Thu Apr 26 16:54:10 PDT 2012

Hi Michael,

You are pulling together a lot of issues but in the nexus of all of 
these issues is a single problem that we don't yet have a solution for. 
  This doesn't invalidate all of the individual mechanisms because none 
of them solve your particular problem, it just means that none of these 
have yet addressed that one problem.  I understand that problem can be 
frustrating, but I have tried to share the issues with you in some of 
those bug reports you have filed.  Thank you for filing the issues so 
they are on the table and we can remember they exist and track our plans 
to eventually solve them.

In most of your examples you are trying to draw, pan, and zoom a large 
collection of lines.  You either are able to use a large collection of 
individual unconnected lines, or you are willing to use a large polygon 
and not care how the segments of the polygon are connected to each other.

Organizing them as a collection of Line nodes would probably get the 
rendering to be very fast, but it adds a lot of overhead to create the 
number of nodes you want to create.  Using a Path or a Polygon node lets 
you more efficiently declare the list of line segments, but we have 
strict rendering policies about how the entire path and Polygon are 
rendered which don't allow us to render it the same way as a bunch of 
separate Line nodes.

In Java2D/Swing you can render the lines either as individual calls to 
drawLine, or as a Polygon or Path and if you set it up just right (which 
is fairly easy because all of the defaults lead to just the right 
conditions usually) then we can draw any of those really fast. 
Unfortunately, FX has different defaults and we don't have (working, 
yet) attributes you can modify to enable the conditions that allow the 
use of simpler rendering algorithms to get your nest of lines drawn 
equally as fast.  Note that Java2D/Swing will fall down as well if you 
turn on Antialiasing (on by default in FX with no supported way to turn 
it off in our current implementations) or if you scale greater than 1.0 
or use a line width greater than 1.0 where the join conditions do not 
default well and have to be manually calculated.

The Canvas node has the same rendering back end as the graphics nodes so 
it isn't going to be magically faster, unfortunately, but that doesn't 
mean that the "immediate mode" rendering API (which in this case doesn't 
really mean rendered synchronously with the method call so perhaps 
another term would be more appropriate) is not a boon for other 

Also, when you originally mentioned your doubts about being able to do 
interactive graphics earlier in this thread, I didn't have the context 
that you were referring to some rendering operations that we don't yet 
efficiently handle.  Yes, those long running rendering operations will 
still delay the rendering thread whether you use the Canvas "immediate 
mode" API or a node, unfortunately.  But, for faster operations the 
transfer of rendering calls to the rendering thread is not an overhead 
that gets in the way.

What Canvas would allow you to do, though, is write some code that draws 
the collection of lines you want as individual calls to drawLine() and 
they should go very fast.  The overhead of putting the lines in a buffer 
is a few orders of magnitude smaller than creating an equal number of 
Line nodes, though, so I wouldn't transfer the frustration with the 
overhead of using a Group of Line nodes onto using a Canvas with lots of 
calls to GC.drawLine().  GC.drawLine will have overhead of 17 bytes per 
line.  It's been a while since I've seen figures on a Line node, and it 
depends on how much binding and listening goes on, but let's just say 
that you might find yourself using less than 1% of the memory that the 
huge number of nodes was using - and getting the faster hw-accelerated 
rendering of the separated line primitives...


On 4/26/12 8:42 AM, Dr. Michael Paus wrote:
>  From what I have read about the new Canvas node now, I have to
> conclude that it will only be of very little use for me. I think
> it would be very important to clarify the design goals first
> before any decisions are made on the technical concept.
> My original expectation was that the Canvas is a Node which
> manages an image buffer (actually two of them for double
> buffering) and provides me with an immediate mode graphics context
> which would allow me to draw directly into this image buffer. My
> expectation was also that I could do this drawing at any time
> on a background thread so that I could keep long lasting renderings
> away from the normal rendering thread. In addition to that I
> expected that this graphics context would implement a general
> purpose 2D drawing interface (or extend an abstract class) which
> could later be used to implement graphics contexts for other output
> types like SVG, PDF, etc.
> I spent some of my spare time in the last couple of weeks to
> examine whether JavaFX could be used for GIS, CAD or similar
> applications which make heavy use of graphic primitives.
> My conclusion so far is that this would currently
> be very difficult if not impossible and I was hoping that the
> new Canvas would help me here to improve the situation but apparently
> it does not.
> Let me explain how I got to this conclusion.
> The first problem is drawing performance. When you have a complex
> drawing, a critical operation is to pan your drawing or to zoom
> in and out. The user expects this to be a smooth operation and
> so I started to examine how many graphic primitives you could
> have in your scene graph and still have an acceptable pan and zoom.
> (This was partly inspired by the first JIRA entry below.)
> The result is a bit frustrating because it turns out that JavaFX
> is actually quite slow for practical scenarios. At first I tried
> simple line shapes and on my laptop the limit seems to be at
> around 50,000 lines. This looks quite good but then I tried to
> put these lines into a Path object because in practice you do not
> deal so often with simple unconnected lines. With the lines within
> a Path the limit for an acceptable pan and zoom drops to around 500
> lines, which is not very much. This number can already be exceed
> by just implementing a fine background grid that way. One also
> has to know that even simple polylines and polygons do suffer from
> the same performance degradation because internally they are based
> on a path object too. Only simple lines, circles and rectangles
> are rendered in hardware. All other shapes are rendered in software
> and are too slow for the affore mentioned type of application.
> You also have to expect additional surprises. For example Rectangles
> are normally rendered in hardware and are thus quite fast unless
> you accidentally set the line join to Bevel. The performance then
> drops tremendously.
> The details and some explanations for all this can be found here:
> http://javafx-jira.kenai.com/browse/RT-20405
> http://javafx-jira.kenai.com/browse/RT-20857
> The conclusion here is that it is currently not possible to get
> an acceptable drawing performance for the non-trivial shape types
> even if you know that you will never use any of the features that
> hinder a hardware acceleration. There are no rendering hints or
> something like that so that the programmer could make a choice.
> To summarize this: Complex renderings just take too long and
> prevent a smooth pan and zoom operation. The new Canvas also won't
> be of any help here because, as I have learned, it also has to do
> its rendering on the rendering thread and thus delays all other
> rendering in the same way as the scene graph does. The only thing
> you get is the buffering effect but that could in principle be
> achieved already right now without the Canvas.
> In order to achieve such a buffering, and thus allowing a smooth pan,
> I put all my shapes in a group node and then activated the caching
> of this group node. All the rendering of my shapes is now captured
> in a bitmap and I get my smooth pan. In principle this works
> nicely but I have not been able to solve the zooming problem in
> the same way. It also does of course not solve the problem that
> the initial rendering is done on the rendering thread. I hoped
> that the Canvas would help here but apparently it doesn't.
> Handling a zoom in the same way did not work because there seems
> to be something wrong with the logic of the caching when you switch
> between QUALITY and SPEED. The details can be found here:
> http://javafx-jira.kenai.com/browse/RT-20970
> There are a lot more conceptual issues which make the use
> of JavaFX problematic for me at the moment. For example it is
> difficult to handle the selection of many overlapping shapes.
> Details can be found here:
> http://javafx-jira.kenai.com/browse/RT-20452
> http://javafx-jira.kenai.com/browse/RT-20455
> Working with Transforms is also problematic because you
> cannot perform any mathematical operations on them.
> (Not yet reported.)
> So coming back to the Canvas issue. I am still trying to understand
> which problem the current Canvas proposal is actually supposed to solve.
> - It does not provide a real immediate mode rendering into a bitmap.
> - It does not prevent the creation of a potentially huge amount of
> objects because it first creates a render list internally.
> - The render list is executed on the rendering thread and thus blocks it.
> - The render list cannot be created on a separate thread.
> Please forgive me if this posting was a bit long but I just had to
> write off my frustration from my soul (as we say here).
> You can now stone me if you like :-)
> Michael

More information about the openjfx-dev mailing list