JDK-8095137 : [Canvas] Maximize Windows with Canvas as Drawing surface produce Runtime Errors
  • Type: Bug
  • Component: javafx
  • Sub-Component: graphics
  • Affected Version: 8
  • Priority: P3
  • Status: Resolved
  • Resolution: Won't Fix
  • Submitted: 2014-04-10
  • Updated: 2015-06-12
  • Resolved: 2014-08-12
Related Reports
Relates :  
Relates :  
Description
Whenever i maximize a window where i draw to a canvas, the software gets unresponsive and throws runtime errors

java.lang.NullPointerException
	at com.sun.javafx.sg.prism.NGCanvas$RenderBuf.validate(NGCanvas.java:199)
	at com.sun.javafx.sg.prism.NGCanvas.initCanvas(NGCanvas.java:598)
	at com.sun.javafx.sg.prism.NGCanvas.renderContent(NGCanvas.java:575)
	at com.sun.javafx.sg.prism.NGNode.doRender(NGNode.java:2043)
	at com.sun.javafx.sg.prism.NGNode.render(NGNode.java:1951)
	at com.sun.javafx.sg.prism.NGGroup.renderContent(NGGroup.java:225)
	at com.sun.javafx.sg.prism.NGRegion.renderContent(NGRegion.java:575)
	at com.sun.javafx.sg.prism.NGNode.doRender(NGNode.java:2043)
	at com.sun.javafx.sg.prism.NGNode.render(NGNode.java:1951)
	at com.sun.javafx.sg.prism.NGGroup.renderContent(NGGroup.java:225)
	at com.sun.javafx.sg.prism.NGRegion.renderContent(NGRegion.java:575)
	at com.sun.javafx.sg.prism.NGNode.renderForClip(NGNode.java:2282)
	at com.sun.javafx.sg.prism.NGNode.renderRectClip(NGNode.java:2176)
	at com.sun.javafx.sg.prism.NGNode.renderClip(NGNode.java:2202)
	at com.sun.javafx.sg.prism.NGNode.doRender(NGNode.java:2037)
	at com.sun.javafx.sg.prism.NGNode.render(NGNode.java:1951)
	at com.sun.javafx.sg.prism.NGGroup.renderContent(NGGroup.java:225)
	at com.sun.javafx.sg.prism.NGRegion.renderContent(NGRegion.java:575)
	at com.sun.javafx.sg.prism.NGNode.renderForClip(NGNode.java:2282)
	at com.sun.javafx.sg.prism.NGNode.renderRectClip(NGNode.java:2176)
	at com.sun.javafx.sg.prism.NGNode.renderClip(NGNode.java:2202)
	at com.sun.javafx.sg.prism.NGNode.doRender(NGNode.java:2037)
	at com.sun.javafx.sg.prism.NGNode.render(NGNode.java:1951)
	at com.sun.javafx.sg.prism.NGGroup.renderContent(NGGroup.java:225)
	at com.sun.javafx.sg.prism.NGRegion.renderContent(NGRegion.java:575)
	at com.sun.javafx.sg.prism.NGNode.doRender(NGNode.java:2043)
	at com.sun.javafx.sg.prism.NGNode.render(NGNode.java:1951)
	at com.sun.javafx.sg.prism.NGGroup.renderContent(NGGroup.java:225)
	at com.sun.javafx.sg.prism.NGRegion.renderContent(NGRegion.java:575)
	at com.sun.javafx.sg.prism.NodeEffectInput.getImageDataForBoundedNode(NodeEffectInput.java:237)
	at com.sun.javafx.sg.prism.NodeEffectInput.filter(NodeEffectInput.java:131)
	at com.sun.scenario.effect.FilterEffect.filter(FilterEffect.java:168)
	at com.sun.scenario.effect.Offset.filter(Offset.java:160)
	at com.sun.scenario.effect.Merge.filter(Merge.java:147)
	at com.sun.scenario.effect.DelegateEffect.filter(DelegateEffect.java:70)
	at com.sun.scenario.effect.impl.prism.PrEffectHelper.render(PrEffectHelper.java:164)
	at com.sun.javafx.sg.prism.EffectFilter.render(EffectFilter.java:61)
	at com.sun.javafx.sg.prism.NGNode.renderEffect(NGNode.java:2353)
	at com.sun.javafx.sg.prism.NGNode.doRender(NGNode.java:2040)
	at com.sun.javafx.sg.prism.NGNode.render(NGNode.java:1951)
	at com.sun.javafx.tk.quantum.ViewPainter.doPaint(ViewPainter.java:469)
	at com.sun.javafx.tk.quantum.ViewPainter.paintImpl(ViewPainter.java:324)
	at com.sun.javafx.tk.quantum.PresentingPainter.run(PresentingPainter.java:89)
	at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
	at java.util.concurrent.FutureTask.runAndReset(FutureTask.java:308)
	at com.sun.javafx.tk.RenderJob.run(RenderJob.java:58)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
	at com.sun.javafx.tk.quantum.QuantumRenderer$PipelineRunnable.run(QuantumRenderer.java:129)
	at java.lang.Thread.run(Thread.java:744)
ERROR: unexpected fbo is bound! Expected 48, but found 20
java.lang.NullPointerException
	at com.sun.javafx.sg.prism.NGCanvas$RenderBuf.validate(NGCanvas.java:199)
	at com.sun.javafx.sg.prism.NGCanvas.initCanvas(NGCanvas.java:598)
	at com.sun.javafx.sg.prism.NGCanvas.renderContent(NGCanvas.java:575)
	at com.sun.javafx.sg.prism.NGNode.doRender(NGNode.java:2043)
	at com.sun.javafx.sg.prism.NGNode.render(NGNode.java:1951)
	at com.sun.javafx.sg.prism.NGGroup.renderContent(NGGroup.java:225)
	at com.sun.javafx.sg.prism.NGRegion.renderContent(NGRegion.java:575)
	at com.sun.javafx.sg.prism.NGNode.doRender(NGNode.java:2043)
	at com.sun.javafx.sg.prism.NGNode.render(NGNode.java:1951)
	at com.sun.javafx.sg.prism.NGGroup.renderContent(NGGroup.java:225)
	at com.sun.javafx.sg.prism.NGRegion.renderContent(NGRegion.java:575)
	at com.sun.javafx.sg.prism.NGNode.renderForClip(NGNode.java:2282)
	at com.sun.javafx.sg.prism.NGNode.renderRectClip(NGNode.java:2176)
	at com.sun.javafx.sg.prism.NGNode.renderClip(NGNode.java:2202)
	at com.sun.javafx.sg.prism.NGNode.doRender(NGNode.java:2037)
	at com.sun.javafx.sg.prism.NGNode.render(NGNode.java:1951)
	at com.sun.javafx.sg.prism.NGGroup.renderContent(NGGroup.java:225)
	at com.sun.javafx.sg.prism.NGRegion.renderContent(NGRegion.java:575)
	at com.sun.javafx.sg.prism.NGNode.renderForClip(NGNode.java:2282)
	at com.sun.javafx.sg.prism.NGNode.renderRectClip(NGNode.java:2176)
	at com.sun.javafx.sg.prism.NGNode.renderClip(NGNode.java:2202)
	at com.sun.javafx.sg.prism.NGNode.doRender(NGNode.java:2037)
	at com.sun.javafx.sg.prism.NGNode.render(NGNode.java:1951)
	at com.sun.javafx.sg.prism.NGGroup.renderContent(NGGroup.java:225)
	at com.sun.javafx.sg.prism.NGRegion.renderContent(NGRegion.java:575)
	at com.sun.javafx.sg.prism.NGNode.doRender(NGNode.java:2043)
	at com.sun.javafx.sg.prism.NGNode.render(NGNode.java:1951)
	at com.sun.javafx.sg.prism.NGGroup.renderContent(NGGroup.java:225)
	at com.sun.javafx.sg.prism.NGRegion.renderContent(NGRegion.java:575)
	at com.sun.javafx.sg.prism.NodeEffectInput.getImageDataForBoundedNode(NodeEffectInput.java:237)
	at com.sun.javafx.sg.prism.NodeEffectInput.filter(NodeEffectInput.java:131)
	at com.sun.scenario.effect.FilterEffect.filter(FilterEffect.java:168)
	at com.sun.scenario.effect.Offset.filter(Offset.java:160)
	at com.sun.scenario.effect.Merge.filter(Merge.java:147)
	at com.sun.scenario.effect.DelegateEffect.filter(DelegateEffect.java:70)
	at com.sun.scenario.effect.impl.prism.PrEffectHelper.render(PrEffectHelper.java:164)
	at com.sun.javafx.sg.prism.EffectFilter.render(EffectFilter.java:61)
	at com.sun.javafx.sg.prism.NGNode.renderEffect(NGNode.java:2353)
	at com.sun.javafx.sg.prism.NGNode.doRender(NGNode.java:2040)
	at com.sun.javafx.sg.prism.NGNode.render(NGNode.java:1951)
	at com.sun.javafx.tk.quantum.ViewPainter.doPaint(ViewPainter.java:469)
	at com.sun.javafx.tk.quantum.ViewPainter.paintImpl(ViewPainter.java:324)
	at com.sun.javafx.tk.quantum.PresentingPainter.run(PresentingPainter.java:89)
	at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
	at java.util.concurrent.FutureTask.runAndReset(FutureTask.java:308)
	at com.sun.javafx.tk.RenderJob.run(RenderJob.java:58)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
	at com.sun.javafx.tk.quantum.QuantumRenderer$PipelineRunnable.run(QuantumRenderer.java:129)
	at java.lang.Thread.run(Thread.java:744)
ERROR: unexpected fbo is bound! Expected 48, but found 20
java.lang.IllegalArgumentException: Texture must be non-null
	at com.sun.scenario.effect.impl.prism.PrTexture.<init>(PrTexture.java:38)
	at com.sun.scenario.effect.impl.prism.PrDrawable.<init>(PrDrawab.......

The code who triggers the problem are to big and complexe to post here. If its needed i can try to compile a stripped down version
Comments
Uwe has worked around the problem by not using Canvas. The non-persistent idea is being tracked by RT-36475. Closing.
12-08-2014

We are unlikely to be able to address this for 8u20. Moving it to 9 for now.
02-05-2014

They aren't necessarily a replacement for nodes, they are for using sparingly to do things that are best expressed as immediate mode graphics calls and which cannot easily be expressed as a set of nodes. If you could replace them with nodes (assuming you achieved the same effect with just a bit of effort) then they were likely not a very good candidate for your current use case. There are likely some cases that are better expressed as immediate mode graphics calls, and which can be re-rendered at will, and those cases will be better served by the "non-persistent" form that is being tracked under RT-36475. But until we add that mechanism the calls are a one-way feed from your code to ours and they currently require saving all of the pixels forever and that cost needs to be factored in to design decisions to use them and how to use them.
16-04-2014

I have now removed all Canvas objects from my application and replaced it with javafx.scene.Node(s). So far no more runtime errors. Sounds for me like Canvas is kind of evil when using with large screen resolutions.
16-04-2014

Each canvas uses wxhx4 bytes of vram permanently until you drop the reference to the Canvas and let GC claim it. We eventually want to enable a non-persistent form of canvas, but we will need a callback for when we've let the pixels go to tell you to repaint. Until then, all canvases are essentially "write once, keep forever" and that means keeping the pixels forever. (See RT-36475) If you can find a way to recycle your Canvas objects, or manually drop them on the floor when a tab goes away (and reconstruct them when it comes back), then you should see a radical drop in resource usage. You can also request more vram using -Dprism.maxvram=###m, but it sounds like you would be better served by recycling your Canvas objects when not needed for display.
15-04-2014

I think i found the problem. As soon as my test application has a certain amount of canvas added to the scene it runs out of vram. For the test application it needs a number of 50 canvas to run into the problem. I am using that high number of canvas because i have a TabPane with several tabs and each tab has up to 6 different canvas overlaying each other. Here is a sample code: <BorderPane id="AnchorPane" prefHeight="200" prefWidth="320" xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/8" fx:controller="vramtest.FXMLDocumentController"> <center><TabPane fx:id="TabPane" layoutX="-5.0" prefHeight="200.0" prefWidth="320.0" tabClosingPolicy="UNAVAILABLE"> <tabs> <Tab text="Untitled Tab 1"> <content> <AnchorPane minHeight="0.0" minWidth="0.0" prefHeight="180.0" prefWidth="200.0" /> </content> </Tab> <Tab text="Untitled Tab 2"> <content> <AnchorPane minHeight="0.0" minWidth="0.0" prefHeight="180.0" prefWidth="200.0" /> </content> </Tab> </tabs> </TabPane> </center> </BorderPane> public class FXMLDocumentController implements Initializable { @FXML TabPane TabPane; @Override public void initialize(URL url, ResourceBundle rb) { for (int i = 0; i < 60; i++) { makeTab(i); } } private void makeTab(int i) { final Tab tab = new Tab(); TabPane.getTabs().add(i, tab); Canvas canvas = new Canvas(); tab.setContent(canvas); canvas.widthProperty().bind(tab.getTabPane().widthProperty()); canvas.heightProperty().bind(tab.getTabPane().heightProperty()); tab.setClosable(false); //SetSizeAndResizeRepaintListener(layout, tab); } Every time you change a tab the amount of used VRam increases. When you put the window size to something big, like 1900x1400 and change the tabs a couple of times, you run into the VRam limit.
14-04-2014

This is what i get when the runtime error occurs: ES2 Vram Pool: 267.379.712 used (99,6%), 267.379.712 managed (99,6%), 268.435.456 total 24 total resources being managed average resource age is 0.0 frames 0 resources at maximum supported age (0,000000) 23 resources marked permanent (95,800000) 0 resources have had mismatched locks (0,000000) 0 resources locked (0,000000) 22 resources contain interesting data (91,700000) 0 resources disappeared (0,000000)
14-04-2014

You can also try -Dprism.poolstats=true to see if you are running into vram limits when it happens.
11-04-2014

Screen Size is 2560x1440 Problem occurs with window height around >1200. With smaller windows it never happend so far. The runtime error only occurs when painting several times within some milliseconds. For me it seems like the problem is related to RT-36627. These 2 problems happens topgether. So far i was not able to reproduce the problem with a simple test application. Will try to add complexity until the problem occurs.
11-04-2014

We do need a stripped down test case. Also how big is the screen and is it retina or normal?
11-04-2014

This seems like a possible out of resources issue. Assign to Jim (for 8u20 since he is already looking at other Canvas rendering issues).
10-04-2014

The problem is actually not limited to maximized windows. Whenever the window is larger than a certain size, this problem occurs. The GUI either gets unresponsive and java Profiler says java is spending constantly 10% of the time in GC. This happens without any actual drawing to the canvas. The runtime error mentioned above happens when actually drawing on the canvas.
10-04-2014