|
||||||||||
| PREV CLASS NEXT CLASS | FRAMES NO FRAMES | |||||||||
| SUMMARY: NESTED | FIELD | CONSTR | METHOD | DETAIL: FIELD | CONSTR | METHOD | |||||||||
java.lang.Objectorg.jdesktop.swing.animation.rendering.JActiveRenderer
public final class JActiveRenderer
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.
JRendererTarget.renderSetup(Object) is called once when
on is made visible. It allows the client to perform any necessary
setup.JRendererTarget.renderUpdate() is called at the start of each
rendering cycle to allow the client to update its state prior to rendering.JRendererTarget.render(Object, int, int) is called after
renderUpdate() during each rendering cycle to allow the client to
control what is displayed on-screen.JRendererTarget.renderShutdown() is called once after
shutdown() to allow the implementation to perform any
necessary cleanup.
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:
JRendererTarget.renderUpdate() to allow the
client to update its state.CountDownLatch.await() is called on the latch that is
waiting for the EDT thread to finish painting (skipped during the first
iteration).JRendererTarget.render(Object, int, int) to
allow the client to render onto an off-screen image.SwingUtilities.invokeLater(Runnable) asks the EDT
thread to paint the off-screen image on the screen.The EDT thread, in addition to its normal Swing processing, performs the following:
CountDownLatch.countDown() to "pass" the off-screen image
back to the animator thread.
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.
getFPS() provides "frames per second" or how many times per
second the screen is painted. This is the best measure of overall performance
and is often displayed on-screen.getAverageCycleTimeNanos() provides how many nanoseconds, on
average, it tools to execute one complete rendering cycle.getAveragePaintTimeNanos() provides how many nanoseconds, on
average, it took the EDT to paint the off-screen image to the screen.getAverageRenderTimeNanos() provides how many nanoseconds, on
average, it took the rendering thread to render to the off-screen image (by
calling JRendererTarget.render(Object, int, int)).getAveragePaintWaitTimeNanos() provides how many nanoseconds, on
average, the rendering thread "blocked" waiting for the EDT to finish
painting to the screen. Because the rendering thread invokes
JRendererTarget.renderUpdate() before it has to "block" and wait for
the EDT to finish painting, this time can be significantly smaller than
getAveragePaintTimeNanos(). If this time is not smaller than
getAveragePaintTimeNanos() then this two-thread active rendering
approach should probably not be used, i.e., a simple loop in a single thread
will be more efficient (i.e., provide more FPS).
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().
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 |
|---|
public JActiveRenderer(JRendererPanel on,
org.jdesktop.core.animation.rendering.JRendererTarget<GraphicsConfiguration,Graphics2D> target,
boolean hasChildren)
Should only be invoked from the Swing EDT.
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.
IllegalArgumentException - if either on or target are null.
IllegalStateException - if invoked outside of the Swing EDT.| Method Detail |
|---|
public void shutdown()
shutdown in interface org.jdesktop.core.animation.rendering.JRendererpublic long getFPS()
getFPS in interface org.jdesktop.core.animation.rendering.JRendererpublic long getAverageCycleTimeNanos()
getAverageCycleTimeNanos in interface org.jdesktop.core.animation.rendering.JRendererpublic long getAverageRenderTimeNanos()
JRendererTarget.render(Object, int, int).
Safe to be called at any time within any thread.
public long getAveragePaintWaitTimeNanos()
Safe to be called at any time within any thread.
public long getAveragePaintTimeNanos()
Safe to be called at any time within any thread.
public org.jdesktop.core.animation.timing.TimingSource getTimingSource()
getTimingSource in interface org.jdesktop.core.animation.rendering.JRendererpublic void invokeLater(Runnable task)
invokeLater in interface org.jdesktop.core.animation.rendering.JRenderer
|
||||||||||
| PREV CLASS NEXT CLASS | FRAMES NO FRAMES | |||||||||
| SUMMARY: NESTED | FIELD | CONSTR | METHOD | DETAIL: FIELD | CONSTR | METHOD | |||||||||