org.jdesktop.swing.animation.rendering
Class JActiveRenderer

java.lang.Object
  extended by org.jdesktop.swing.animation.rendering.JActiveRenderer
All Implemented Interfaces:
org.jdesktop.core.animation.rendering.JRenderer

public final class JActiveRenderer
extends Object
implements org.jdesktop.core.animation.rendering.JRenderer

Manages two-thread active rendering on a Swing JRendererPanel.

To use this renderer a client constructs a JRendererPanel and passes it to the constructor with a flag indicating if the passed component will have children that need to be rendered and a JRendererTarget implementation. A typical sequence would be

 JFrame frame = new JFrame("Renderer Demonstration");
 final JRendererPanel on = new JRendererPanel();
 frame.setContentPane(on);
 final JRendererTarget<GraphicsConfiguration, Graphics2D> target = this;
 JRenderer renderer = new JActiveRenderer(on, target, true);
 
In the above snippet on will be rendered to. Swing children will be added to on by the client code (indicated by passing true as the second argument) and should be shown. The enclosing instance, this, implements JRendererTarget and will be called to customize what is displayed on-screen.

The JRendererTarget implementation is called according to the following protocol.

The rendering cycle occurs as fast as the hardware can support. So renderUpdate() and render() will be called many times per second.

There are two threads involved in active rendering: (1) a rendering thread and (2) the Swing Event Dispatch Thread (EDT). When the passed JComponent is made visible this is detected in the EDT and two tasks are submitted to be executed in the rendering thread: (1) The JRendererTarget.renderSetup(Object) method is called to let the client perform its setup. (2) The rendering loop is started.

The rendering thread runs the following sequence as fast as it can:

The EDT thread, in addition to its normal Swing processing, performs the following:

This two-thread active rendering approach has several advantages. First, it never blocks the EDT. Second, it allows the JRendererTarget.renderUpdate() to execute concurrently with painting to the screen. Third, while the render thread can block, this only occurs if painting to the screen takes longer than invoking JRendererTarget.renderUpdate().

The implementation depends upon the safe sharing of the BufferedImage used as the off-screen image between the rendering thread and the EDT. The use of SwingUtilities.invokeLater(Runnable) safely "passes" the image from the rendering thread to the EDT and the use of the CountDownLatch safely "passes" from the EDT back to the rendering thread.

Clients can execute code in the rendering thread by calling invokeLater(Runnable) (in a manner similar to SwingUtilities.invokeLater(Runnable)). This call is essential to safely notify the rendering thread about events that occur in the EDT or other program threads.

Several statistics are tracked which can be queried to understand active rendering performance.

Adding Swing components as children of on is supported. Ensure that true is passed as the third argument to JActiveRenderer(JRendererPanel, JRendererTarget, boolean). The children are drawn in the EDT and never accessed in the rendering thread.

Use of the Timing Framework is supported via a ManualTimingSource that can be obtained via getTimingSource(). This timing source is "ticked" once per rendering cycle. Client code should consider setting the timing source as the default for animations, similar to the snippet below.

 AnimatorBuilder.setDefaultTimingSource(renderer.getTimingSource());
 
Then the timing source's tick() method is invoked within the rendering thread just prior to the call to renderUpdate().

Author:
Tim Halloran
See Also:
JRendererTarget, ManualTimingSource

Constructor Summary
JActiveRenderer(JRendererPanel on, org.jdesktop.core.animation.rendering.JRendererTarget<GraphicsConfiguration,Graphics2D> target, boolean hasChildren)
          Constructs a new active renderer.
 
Method Summary
 long getAverageCycleTimeNanos()
           
 long getAveragePaintTimeNanos()
          The time spent within the EDT thread painting to the screen.
 long getAveragePaintWaitTimeNanos()
          Gets the average amount of time spent waiting in the animator thread for the EDT thread to complete painting to the screen.
 long getAverageRenderTimeNanos()
          Calculates the average time spent rendering in the rendering thread.
 long getFPS()
           
 org.jdesktop.core.animation.timing.TimingSource getTimingSource()
           
 void invokeLater(Runnable task)
           
 void shutdown()
           
 
Methods inherited from class java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
 

Constructor Detail

JActiveRenderer

public JActiveRenderer(JRendererPanel on,
                       org.jdesktop.core.animation.rendering.JRendererTarget<GraphicsConfiguration,Graphics2D> target,
                       boolean hasChildren)
Constructs a new active renderer.

Should only be invoked from the Swing EDT.

Parameters:
on - the Swing component to render on.
target - to be called to control what is rendered.
hasChildren - true if on has child components that need to be painted. If on has no child components passing false can improve rendering performance.
Throws:
IllegalArgumentException - if either on or target are null.
IllegalStateException - if invoked outside of the Swing EDT.
Method Detail

shutdown

public void shutdown()
Specified by:
shutdown in interface org.jdesktop.core.animation.rendering.JRenderer

getFPS

public long getFPS()
Specified by:
getFPS in interface org.jdesktop.core.animation.rendering.JRenderer

getAverageCycleTimeNanos

public long getAverageCycleTimeNanos()
Specified by:
getAverageCycleTimeNanos in interface org.jdesktop.core.animation.rendering.JRenderer

getAverageRenderTimeNanos

public long getAverageRenderTimeNanos()
Calculates the average time spent rendering in the rendering thread. This is the time spent in the call to JRendererTarget.render(Object, int, int).

Safe to be called at any time within any thread.

Returns:
average time in nanoseconds.

getAveragePaintWaitTimeNanos

public long getAveragePaintWaitTimeNanos()
Gets the average amount of time spent waiting in the animator thread for the EDT thread to complete painting to the screen.

Safe to be called at any time within any thread.

Returns:
average time in nanoseconds.

getAveragePaintTimeNanos

public long getAveragePaintTimeNanos()
The time spent within the EDT thread painting to the screen.

Safe to be called at any time within any thread.

Returns:
average time in nanoseconds.

getTimingSource

public org.jdesktop.core.animation.timing.TimingSource getTimingSource()
Specified by:
getTimingSource in interface org.jdesktop.core.animation.rendering.JRenderer

invokeLater

public void invokeLater(Runnable task)
Specified by:
invokeLater in interface org.jdesktop.core.animation.rendering.JRenderer


Copyright © 2012. All Rights Reserved.