Skip to main content

DropShadow performance

2 replies [Last post]
billg
Offline
Joined: 2008-02-03
Points: 0

Hello,

As to be expected, I have found that the rendering (and re-rendering) of a DropShadow effect on a Node is very process intensive. The challenge I am working on (and looking for feedback on) is how to minimize the negative impact this has on animation, or in case of my example, dragging of a node with shadow on it (which results in a significant lag in rendering for me).

In the past, when dealing with rendering shadows with animation, I have ended up caching the shadow as a BufferedImage that is redrawn in place of re-rendering the shadow. I took a quick look at the DropShadow code did not see any apparent caching of the shadow happening (it is entirely possibly I'm just not seeing where in the code this is happening). I realize that caching of a shadow would also have negative impacts (additional memory overhead, etc), so with that in mind, I have the following questions:

1) Are there any planned changes that would improve the shadow re-rendering (e.g. caching)?
2) If not, does anyone have any suggestions on the best way to implement some custom caching of an effect? I would like avoid modifying any Scene Graph code directly, so I was thinking of using the Effect.render to draw to a buffered image that I then add that BufferedImage to an FXImage node which I would position correctly in the scene.

Below is an example building off the drag demo initially provided by jantaubert (thanks jantaubert for providing that). Please try dragging the circles around to see the lag.

-----------------------------------------------------------------

import java.awt.Color;
import java.awt.Font;
import java.awt.Point;
import java.awt.RenderingHints;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseWheelEvent;
import java.awt.geom.Ellipse2D;

import javax.swing.JFrame;

import com.sun.scenario.effect.DropShadow;
import com.sun.scenario.effect.Effect;
import com.sun.scenario.scenegraph.JSGPanel;
import com.sun.scenario.scenegraph.SGGroup;
import com.sun.scenario.scenegraph.SGNode;
import com.sun.scenario.scenegraph.SGText;
import com.sun.scenario.scenegraph.SGTransform;
import com.sun.scenario.scenegraph.event.SGMouseListener;
import com.sun.scenario.scenegraph.fx.FXShape;

public class DragDemo implements SGMouseListener, MouseListener {

public static void main(String[] args) {
new DragDemo();
}

private Point point;

private SGGroup scene;

public DragDemo() {
JFrame f = new JFrame("Drag Circle Demo");
f.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);

scene = new SGGroup();

JSGPanel panel = new JSGPanel();
panel.addMouseListener(this);
panel.setBackground(Color.ORANGE);
panel.setScene(scene);

SGText textNode = new SGText();
textNode.setText("Drag circle; Middle click - delete circle; Right click - create new circle");
textNode.setLocation(new Point(2, 10));
textNode.setDrawPaint(Color.BLACK);
textNode.setFillPaint(Color.BLUE);
textNode.setFont(new Font("Sanserif", Font.BOLD, 12));
scene.add(textNode);

addCircle(50, 50);
addCircle(200, 100);
addCircle(300, 250);

f.add(panel);
f.pack();
f.setSize(600, 600);
f.setVisible(true);
}

private void addCircle(double x, double y) {
FXShape circ = new FXShape();
circ.setShape(new Ellipse2D.Double(x - 25, y - 25, 300, 250));
circ.setFillPaint(Color.BLUE);
circ.setAntialiasingHint(RenderingHints.VALUE_ANTIALIAS_ON);

Effect dropShadow = new DropShadow( );
circ.setEffect( dropShadow );

SGTransform.Translate trans = SGTransform.createTranslation(0, 0, circ);
trans.addMouseListener(this);
scene.add(trans);
}

public void mouseClicked(MouseEvent e, SGNode node) {
if (e.getButton() == MouseEvent.BUTTON2) {
node.getParent().remove(node);
}
}

public void mousePressed(MouseEvent e, SGNode node) {
point = e.getPoint();
}

public void mouseReleased(MouseEvent e, SGNode node) {

}

public void mouseEntered(MouseEvent e, SGNode node) {

}

public void mouseExited(MouseEvent e, SGNode node) {

}

public void mouseDragged(MouseEvent e, SGNode node) {
if (node instanceof SGTransform.Translate) {
Point newpoint = e.getPoint();
SGTransform.Translate trans = (SGTransform.Translate) node;
trans.translateBy(newpoint.getX() - point.getX(), newpoint.getY()
- point.getY());
point = newpoint;
}
}

public void mouseMoved(MouseEvent e, SGNode node) {

}

public void mouseWheelMoved(MouseWheelEvent e, SGNode node) {

}

public void mouseClicked(MouseEvent e) {
if (e.getButton() == MouseEvent.BUTTON3) {
addCircle(e.getX(), e.getY());
}
}

public void mousePressed(MouseEvent e) {

}

public void mouseReleased(MouseEvent e) {

}

public void mouseEntered(MouseEvent e) {

}

public void mouseExited(MouseEvent e) {

}
}
-----------------------------------------------------------------------------------------

Thanks for any feedback,
Bill

Message was edited by: billg

Reply viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.
Chris Campbell

Hi Bill,

Are you familiar with SGRenderCache (or the more convenient API,
FXNode.setCachedAsBitmap())? This automatically handles caching a scene
graph node in an image, and then rendering from that image for as long
as the node remains unchanged. You can transform the FXNode all you
want, and it will continue to use that cached image. This is probably
the easiest solution anytime you are not satisfied with the performance
of certain nodes, or of the effects applied to nodes.

(In the internal FXNode chain, the SGRenderCache node sits above the
SGEffect node, so the rendered effect will be cached as you would expect.)

BTW, like all other Effects, DropShadow is accelerated by D3D and OGL
when those pipelines are in use. You need the various Decora-*.jars on
your classpath, and the appropriate Decora-*.dlls on your native library
path. The JavaFX launcher scripts take care of all this for you, as do
the JavaFX and Scenario JNLP extensions, but so far we haven't put more
effort into simplifying this for raw Scenario apps (that's less of a
priority than making JavaFX support first class).

Hope this helps,
Chris

scenario@javadesktop.org wrote:
> Hello,
>
> As to be expected, I have found that the rendering (and re-rendering) of a DropShadow effect on a Node is very process intensive. The challenge I am working on (and looking for feedback on) is how to minimize the negative impact this has on animation, or in case of my example, dragging of a node with shadow on it (which results in a significant lag in rendering for me).
>
> In the past, when dealing with rendering shadows with animation, I have ended up caching the shadow as a BufferedImage that is redrawn in place of re-rendering the shadow. I took a quick look at the DropShadow code did not see any apparent caching of the shadow happening (it is entirely possibly I'm just not seeing where in the code this is happening). I realize that caching of a shadow would also have negative impacts (additional memory overhead, etc), so with that in mind, I have the following questions:
>
> 1) Are there any planned changes that would improve the shadow re-rendering (e.g. caching)?
> 2) If not, does anyone have any suggestions on the best way to implement some custom caching of an effect? I would like avoid modifying any Scene Graph code directly, so I was thinking of using the Effect.render to draw to a buffered image that I then add that BufferedImage to an FXImage node which I would position correctly in the scene.
>

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@scenegraph.dev.java.net
For additional commands, e-mail: dev-help@scenegraph.dev.java.net

billg
Offline
Joined: 2008-02-03
Points: 0

Hi Chris,

Thank you very much for the feedback, setCachedAsBitmap does exactly what I was hoping for.

I had actually just found that method myself, and was coming back to post the results in hopes of redeeming myself (for making an idiot post) by providing the answer, but you beat me to it :).

That info on accelerated effects is extremely useful. I will be playing around with that shortly (after I get all my effects caching).

Thanks again for all your help!
Bill

Message was edited by: billg