javajavafxgraphicsnullpointerexceptiontextures

NullPointers in JavaFX when using a large canvas


I am using Canvas-objects, two identically sized ones in a StackPane to be exact, in my application. When these objects get larger, JavaFX starts crashing when trying to paint/render:

java.lang.NullPointerException: Cannot invoke "com.sun.prism.RTTexture.createGraphics()" because "<local9>" is null
at javafx.graphics/com.sun.javafx.sg.prism.NGCanvas$RenderBuf.validate(NGCanvas.java:214)
at javafx.graphics/com.sun.javafx.sg.prism.NGCanvas.initCanvas(NGCanvas.java:644)
at javafx.graphics/com.sun.javafx.sg.prism.NGCanvas.renderContent(NGCanvas.java:607)
at javafx.graphics/com.sun.javafx.sg.prism.NGNode.doRender(NGNode.java:2072)
(...)

and similar ones (all related to javafx.graphics/com.sun.javafx.sg.prism.NGCanvas). Now, there has been some discussion about stuff like this in the past (e.g. here) and half the internet basically just answers this with turn off hardware accelaration, which is what flags like -Dprism.order=sw do.

I do not think that can be the answer.

My graphics hardware has support for 16384x16384 textures (at least in the OpenGL driver) and 8GB of VRAM. I even wrote a small test-program to verify is is "true" support, and works, as I have been burned in the past by some shitty integrated laptop's graphics device, which claimed to support this to be OpenGL-v3-compliant but was crashing when someone tried to allocate an 8k+ texture. I only have one graphics card in the PC, so no chance of the JavaFX-application using the wrong device.

My application crashes when I resize the canvas-objects from 4156x4156 to 8252x8252. Even if we accept that it will use the next-higher power-of-two size to render these things, I claim that my hardware should be able to handle this setup. Even multiple 16384x16384 textures will fit into memory easily alongside other stuff.

I am on Windows 10, using an OpenJDK and JavaFX in version 15.0.1, though Canvas is old and that should not be an issue.

Does anyone have an idea what exactly is going on here?

EDIT: As suggested in a comment, I did some more exact testing. Further manual testing using hard-coded sizes sizes for the two canvas-objects reveals the following:

Setting both to 4096x4096 works, as does 4097x4097. Remember, the later should internally use textures 8192x8192 because this is how graphic cards work. Internally means on the graphics card, not anywhere else.

Here it gets interesting however:

Setting one of the two canvas-objects to 8192x8192 (and leaving the other on 2x2) works fine as well. Setting BOTH to 8192x8192 does not, leading to the aforementioned NULL-issues.

This suggests it is a memory-problem after all, probably allocation-related. As mentioned however, the graphics device should be able to handle this and seems to be able too, considering that setting both to 4097x4097 worked. I suspect it is on the Java-side of the occasion and potentially related to the Stack Pane. Does anybody know if the StackPane has some sort of internal pixel-arrays or other mechanisms? Likely to detect changes? Obviously, that would be very unfortunate as it runs counter-productive to the use of hardware-accelarated textures.

In addition, I also did more exact tests using -Dprism.order=sw. The transition from 4156x4156 to 8252x8252 does work in that mode. When pushing further (for experimental purpose only), one does eventually run in the exact same issue, again suggesting a memory issue.

I could opt to use one canvas only and repaint more often inside that one to reduce the memory footprint (guess the performance trade-off is okay here) but I would first like to understand what exactly is going so very wrong here...


Solution

  • Since you've verified that you aren't creating a texture exceeding your hardware's maximum size, it sounds like you're likely running out of VRAM. To my knowledge, the default maximum is 512MB. You can request a different maximum by passing the following in your VM args.

    -Dprism.maxvram=xx

    Example: for 2 GB you can use -Dprism.maxvram=2G.