-
Enhancement
-
Resolution: Fixed
-
P3
-
8
I have an app with a simple continuous animation. The animated nodes are expected to be rendered on every frame. I can see that occasionally rendering is skipped between two frame updates correctly performed by the scene graph. The easiest way to observe that is with -Djavafx.pulseLogger=true
The logger reports FX and render thread activity including the number of rendered nodes:
PULSE: 28 [83ms:115ms]
T11 (3 +0ms): CSS Pass
T11 (3 +0ms): Layout Pass
T11 (6 +25ms): Waiting for previous rendering
T11 (31 +5ms): Copy state to render graph
T8 (75 +1ms): Dirty Opts Computed
T8 (76 +35ms): Painted
Counters:
Nodes rendered: 15
Nodes visited during render: 15
PULSE: 29 [67ms:93ms]
T11 (3 +0ms): CSS Pass
T11 (3 +0ms): Layout Pass
T11 (5 +0ms): Waiting for previous rendering
T11 (5 +2ms): Copy state to render graph
T8 (90 +0ms): Dirty Opts Computed
PULSE: 30 [82ms:58ms]
T11 (3 +0ms): CSS Pass
T11 (4 +0ms): Layout Pass
T11 (7 +15ms): Waiting for previous rendering
T11 (22 +2ms): Copy state to render graph
T8 (29 +0ms): Dirty Opts Computed
T8 (30 +21ms): Painted
Counters:
Nodes rendered: 15
Nodes visited during render: 15
Note that in pulse 29 the render thread was invoked but no nodes had been rendered.
To understand what really happens I instrumented various steps in pulse processing:
FX thread:
QuantumToolikt.pulse -- two events are reported: 'pulse start' and 'pulse end'
Scene.synchronizeSceneNodes -- the number of dirty nodes is reported
ViewScene.repaint -- 'addRenderJob' event is reported
Render thread:
PresentingPainter.run -- two events, 'lock' and 'unlock' (i.e. enter and exit) are reported.
BaseNode.accumulateDirtyRegions -- dirty and childDirty flags are reported
The following sequence of events reveals the synchronization problem:
[FX] pulse start
[FX] synchronizeSceneNodes: 15
[FX} addRenderJob
[FX] pulse end
[FX] pulse start
[FX} synchronizeSceneNodes: 15 -- nodes are synchronized before the previous update has been rendered
[Render] PresentingPainter: lock
[Render] BaseNode: dirty: DIRTY chDirty: true -- nodes from two updates will be rendered
[Render] PresentingPainter: unlock
[FX] addRenderJob
[FX} pulse end
[Render] PresentingPainter: lock
[Render] BaseNode: dirty: CLEAN chDirty: false -- nothing to render
[Render] PresentingPainter: unlock
...
While it is true that the FX thread will wait until the render thread is finished with the current RenderJob task, nothing prevents the FX thread from starting a new pulse and synchronizing the nodes again if the previous RenderJob has not yet started.
On embedded, even if there has been no actual rendering during a render task the back buffer is drawn at the end of the task anyway wasting CPU/GPU resources for no actual value.
The logger reports FX and render thread activity including the number of rendered nodes:
PULSE: 28 [83ms:115ms]
T11 (3 +0ms): CSS Pass
T11 (3 +0ms): Layout Pass
T11 (6 +25ms): Waiting for previous rendering
T11 (31 +5ms): Copy state to render graph
T8 (75 +1ms): Dirty Opts Computed
T8 (76 +35ms): Painted
Counters:
Nodes rendered: 15
Nodes visited during render: 15
PULSE: 29 [67ms:93ms]
T11 (3 +0ms): CSS Pass
T11 (3 +0ms): Layout Pass
T11 (5 +0ms): Waiting for previous rendering
T11 (5 +2ms): Copy state to render graph
T8 (90 +0ms): Dirty Opts Computed
PULSE: 30 [82ms:58ms]
T11 (3 +0ms): CSS Pass
T11 (4 +0ms): Layout Pass
T11 (7 +15ms): Waiting for previous rendering
T11 (22 +2ms): Copy state to render graph
T8 (29 +0ms): Dirty Opts Computed
T8 (30 +21ms): Painted
Counters:
Nodes rendered: 15
Nodes visited during render: 15
Note that in pulse 29 the render thread was invoked but no nodes had been rendered.
To understand what really happens I instrumented various steps in pulse processing:
FX thread:
QuantumToolikt.pulse -- two events are reported: 'pulse start' and 'pulse end'
Scene.synchronizeSceneNodes -- the number of dirty nodes is reported
ViewScene.repaint -- 'addRenderJob' event is reported
Render thread:
PresentingPainter.run -- two events, 'lock' and 'unlock' (i.e. enter and exit) are reported.
BaseNode.accumulateDirtyRegions -- dirty and childDirty flags are reported
The following sequence of events reveals the synchronization problem:
[FX] pulse start
[FX] synchronizeSceneNodes: 15
[FX} addRenderJob
[FX] pulse end
[FX] pulse start
[FX} synchronizeSceneNodes: 15 -- nodes are synchronized before the previous update has been rendered
[Render] PresentingPainter: lock
[Render] BaseNode: dirty: DIRTY chDirty: true -- nodes from two updates will be rendered
[Render] PresentingPainter: unlock
[FX] addRenderJob
[FX} pulse end
[Render] PresentingPainter: lock
[Render] BaseNode: dirty: CLEAN chDirty: false -- nothing to render
[Render] PresentingPainter: unlock
...
While it is true that the FX thread will wait until the render thread is finished with the current RenderJob task, nothing prevents the FX thread from starting a new pulse and synchronizing the nodes again if the previous RenderJob has not yet started.
On embedded, even if there has been no actual rendering during a render task the back buffer is drawn at the end of the task anyway wasting CPU/GPU resources for no actual value.
- blocks
-
JDK-8092220 Consider rendering directly to framebuffer instead of RTT
-
- Closed
-