canvas vs scene graph for animation

I built an animation using a JavaFX Canvas and it is having some performance problems. Before I go to the extensive trouble of rebuilding it relying on scene graph manipulations, I thought I’d check in here for opinions.

The animation has the following elements:

  • a trail that has been traced by the mouse (via recording mouse positions at 60fps for several seconds)
  • an animation of a cursor-like graphic traversing the trail
  • a static background
  • a graphic (several octaves of piano keys) that is used as a reference, overlaying a portion of the screen and subject to translation.

Both the trail and the piano key graphic will be subjected to X and Y scaling, independently.

My first instinct was to animate these with an AnimationTimer redrawing a Canvas, kind of like I might have done in the past with drawing on a Swing JPanel. But printing the “mouse trail” using GraphicsContext.strokePolyline method is killing the animation rate. (Actually, the rate is fine on my laptop Windows10, but there is a huge drop on Ubuntu 18.04 desktop.)

So I was thinking, maybe I should try using an actual Polyline node on a scene graph instead? (Assumption, the Polyline is somehow already “assembled” as opposed to the strokePolyline which relies on arrays of all the location data points.)

Am also thinking of other things where I don’t know if they are reasonable or not.

Maybe the Canvas performance would improve drastically if I put the drawing of the trail on a separate pane and didn’t update it except when the scaling events occur. (But having the speed go wonky when scaling happens would not be desirable.)

Maybe the trail should be “drawn” one time into a WritableImage instead of redrawing it every iteration? (I’d want to find some code to do this with some smoothing/anti-aliasing.) Then, handle the scaling as a ImageView node.

For the “cursor” object that traverses the trail, is it better to draw it on the GraphicsContext as a simple, small shape (8x8 pixels?) or to make it into a WritableImage and animate it as an ImageView? (I’m kind of thinking it could be neat if the cursor could “pulse” which might be easier to do with ImageView.)

I spend so much more time with sound than I do with graphics, and am really feeling the lack of experience. Any guidance or advice?

I posted something on WritableImages backed by NIO ByteBuffers (news a while back on improvements to JavaFX graphics) but I never had a call to actually try it out, and don’t know how to implement it.

Bizzaro bug!

The AnimationTimer on the OpenJDK 8 that I installed on Ubuntu 18.04 turns out to be running much faster than 60 fps (more like 600 fps). This is causing all sorts of weirdness in the code which was written assuming a reliable 60fps rate.

Among other things, it consumes mega cpu and seems to be the source of performance issues (e.g., dropouts in the sound processing).

Am going to put in a basic Thread.sleep throttle. But what the heck!

I was using this Java version as a was to simplify being able to send some other folks a working JAR file. I guess that isn’t happening now. Will have to install and use a newer JDK & JFX. I hope this weirdness isn’t a problem there, too.

Has anyone else come across this and any solutions? The only thing I could find as a reference was this bug report:
https://bugs.java.com/bugdatabase/view_bug.do?bug_id=JDK-8211059, but it is for Oracle’s JDK1.8, not OpenJDK, and the problem was on Fedora 27.