Optimisation for animated MultipleGradientPaint code

K

Knute Johnson

Andrew said:
Can the frame rate of this example code* be made higher?

* The 650ish lines of the code are posted here..
<http://forum.java.sun.com/thread.jspa?threadID=5297524>

Andrew:

Interesting program. I looked at what your buddy said on the web forum
and without trying those things for myself that is what I would have
guessed (with my vast experience and deductive capabilities). The only
way I can think of to get more performance would be to go to active
rendering. This requires that you draw on a Canvas or a Window as those
are the only components where getting at the BufferStrategy is possible
(as far as I know). I'm not that sure that the performance increase
would be that great. I would guess that the largest cost on your
program is the gradient painting although eliminating the BufferedImage
buffer should help some. I used to do a lot with VolatileImages but the
newer JVMs are much faster than the old ones and if I can't do it by
drawing a BufferedImage I go to active rendering.

Below is a simple active rendering example. It will do about 220 frames
per second maximized on my 1024x768 screen. Your program does about 7
but it is doing considerably more processing. You might see if you can
adapt this framework to your program.

One other thing, I'm running the newer beta version of 1.6 and it will
give me a FlipSubregionBufferStrategy and that is faster than the
BlitSubregionBufferStrategy that you can get with the non-beta 1.6.

So my best guess is if you change to active rendering you can save the
time difference between drawing the BufferedImage to the graphics
context and the time it takes to flip buffers. Also you might get a few
microseconds increase by drawing to the back buffer that is in fast
video memory versus drawing to the BufferedImage that is in regular memory.

import java.awt.*;
import java.awt.event.*;
import java.awt.geom.*;
import java.awt.image.*;

public class test2 extends Canvas implements Runnable {
volatile Thread thread;
volatile BufferStrategy bs;
double angle;
long then = System.currentTimeMillis();
int n;
double rate;

public test2() {
setIgnoreRepaint(true);
setPreferredSize(new Dimension(400,300));

addComponentListener(new ComponentAdapter() {
public void componentResized(ComponentEvent ce) {
if (bs == null) {
createBufferStrategy(2);
bs = getBufferStrategy();
System.out.println(bs);
}
}
});
}

public void start() {
then = System.currentTimeMillis();
thread = new Thread(this);
thread.start();
}

public void stop() {
thread.interrupt();
}

public void run() {
while (!thread.interrupted()) {
render();
}
}

public void render() {
do {
do {
int w = getWidth();
int h = getHeight();

Graphics2D g = (Graphics2D)bs.getDrawGraphics();
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);

g.setColor(Color.WHITE);
g.fillRect(0,0,w,h);

AffineTransform at = g.getTransform();

angle += 0.001;
g.rotate(angle,w/2,h/2);
g.setColor(Color.BLUE);
g.fillRect(w/2 - 100,h/2 - 100,200,200);

if (++n % 100 == 0) {
long now = System.currentTimeMillis();
long time = now - then;
then = now;
rate = 100000.0 / time;
}

g.setTransform(at);
g.setColor(Color.RED);
g.drawString(String.format("%3.1f",rate),10,10);

g.dispose();
} while (bs.contentsRestored()) ;
bs.show();
} while (bs.contentsLost()) ;
}

public static void main(String[] args) {
final test2 t2 = new test2();
final Frame f = new Frame();
f.addWindowListener(new WindowAdapter() {
public void windowOpened(WindowEvent we) {
t2.start();
}
public void windowClosing(WindowEvent we) {
t2.stop();
f.dispose();
}
});

f.add(t2,BorderLayout.CENTER);
f.pack();
f.setVisible(true);
}
}
 
A

Andrew Thompson

...
public class test2 extends Canvas implements Runnable {

Huhh. Not 'quite' as pretty, but 70+ frames per second here.

Thanks, I will have to look more closely at the code
to see if there is anything I can practically glean for
the RadialGradientPaint example. I fear the major
CPU hit is in the creation of the gradient each loop
though, as I vaguely recall has been intimated by
others.

Thanks for your input.
 
K

Knute Johnson

Andrew said:
Huhh. Not 'quite' as pretty, but 70+ frames per second here.

Thanks, I will have to look more closely at the code
to see if there is anything I can practically glean for
the RadialGradientPaint example. I fear the major
CPU hit is in the creation of the gradient each loop
though, as I vaguely recall has been intimated by
others.

I don't know anything about gradients but is it possible to reuse them?
I'm pretty sure you can gain some performance increase over drawing on
the BufferedImage.
 
K

Knute Johnson

Andrew said:
On May 21, 2:23 pm, Knute Johnson <[email protected]>
wrote:
...

I don't think so, they seem immutable. No
way to 'set' the constraints after construction.

Andrew:

I hacked up your code (sorry) to use active rendering and got a huge
increase in speed. It has a few problems but it works more or less.
The code below is probably too trashed to copy so I'll post the source
file at;

http://rabbitbrush.frazmtn.com/GradientPainter2.java

//package org.physci.paint.gradient;

import java.awt.MultipleGradientPaint;
import java.awt.LinearGradientPaint;
import java.awt.RadialGradientPaint;

import java.awt.BorderLayout;
import java.awt.GridLayout;
import java.awt.Canvas;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Toolkit;

import java.awt.image.BufferedImage;
import java.awt.image.BufferStrategy;

import java.awt.geom.AffineTransform;

import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import java.awt.event.ComponentListener;
import java.awt.event.ComponentEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;

import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.ButtonGroup;
import javax.swing.JPanel;
import javax.swing.JCheckBox;
import javax.swing.JRadioButton;
import javax.swing.SwingUtilities;
import javax.swing.JColorChooser;
import javax.swing.JFrame;
import javax.swing.JWindow;

import java.text.DecimalFormat;

import javax.swing.border.TitledBorder;

import java.util.Random;

/**
A simple animated demo of LinearGradiantPaint and RadialGradiantPaint
(both extending MultipleGradientPaint). While MultipleGradientPaint
derivatives support arrays of many colors, this demo uses just three.
These classes have been included in the J2SE since Java 1.6.
@author Andrew Thompson
@version 2008-05-19
*/
class GradientPainter2 extends Canvas implements ComponentListener,
Runnable {
volatile BufferStrategy bs;
volatile Thread mainThread;

/** Constant to represent a radial gradientType */
static final int RADIAL = 0;
/** Constant to represent a linear gradientType */
static final int LINEAR = 1;

/** Type of gradient to draw. */
int gradientType;

/** The 'fractions' between the gradient painted colors.
See The J2SE JavaDocs for details. */
float[] fractions = new float[3];
/** The colors used for each of the base
colors of the fractions above. */
Color[] colors = new Color[3];

/** Initial (configurable) CycleMethod. */
MultipleGradientPaint.CycleMethod cycleMethod =
MultipleGradientPaint.CycleMethod.REFLECT;

/** Initial (configurable) ColorSpaceType. */
MultipleGradientPaint.ColorSpaceType colorSpace =
MultipleGradientPaint.ColorSpaceType.SRGB;

/** In the LGP example, this is used as point 1, for RGP eg, it is the
'center'. See The J2SE JavaDocs for details. */
Point center;

/** The amount of pixels to move the center point each move. */
int centerStepX;
/** The amount of pixels to move the center point each move. */
int centerStepY;

/** In the LGP example, this is used as point 2, for RGP eg, it is the
'focus'. See The J2SE JavaDocs for details. */
Point focus;

/** The amount of pixels to move the focus point each move. */
int focusStepX;
/** The amount of pixels to move the focus point each move. */
int focusStepY;

/** The radius of any RadialGradientPaint. When the
focus point is outside the radius from the center point,
the area of the screen around the focus point collapses
into moire patterns (assuming a cycle method of either
repeat or reflect). */
int radius = 200;

/** Move the radius continuously from
lowRadius through highRadius and back. */
boolean alterRadius = true;
/** The amount by which to move the radius
(+1 for expanding, -1 for contracting) */
int radiusStep = 1;
/** The maximum radius to use, before contracting. */
int highRadius = 250;
/** The minimum radius to use, before expanding. */
int lowRadius = 150;

/** Whether to also draw the points and radius
(radius is for RadialGradientPaint only). */
boolean showPoints = false;

/** Whether to display the frame rate. */
boolean showFps = true;

/** Used in frame rate calculation. */
long timeSinceLastFrame = -1;

/** The dormat used for displaying the frame rate. */
DecimalFormat dfFps = new DecimalFormat("0.0");
/** We only update the frame rate every ten frames. */
int iterations = 0;
/** The last frame rate caluclated. */
double rate = 0;

/** We draw our graphics to the store, before quickly
drawImage()'*** to screen in the paintComponent method. */
private BufferedImage store;

/** The single random number generater used for any
random values required. */
private Random rnd;

/** The MultipleGradientPaint's accept an AffineTransform
for further processing. This example does not need that,
so we suply an 'identity' (no change) transform. */
private AffineTransform affineTransform;

/** Construct a GradientPainter with default values. */
GradientPainter2() {
super();
setPreferredSize( new Dimension(400,300) );
// setOpaque(true);
rnd = new Random();
fractions = new float[3];
fractions[0] = 0.02f;
fractions[1] = 0.5f;
fractions[2] = 0.98f;

colors = new Color[3];
colors[0] = new Color(200,220,100);
colors[1] = new Color(50,40,30);
//colors[0].darker().darker();
colors[2] = colors[0].brighter();

initialiseImage();

center = new Point(
rnd.nextInt( getPreferredSize().width ),
rnd.nextInt( getPreferredSize().height ) ); // center

focus = new Point(
rnd.nextInt( getPreferredSize().width ),
rnd.nextInt( getPreferredSize().height ) ); // focus

centerStepX = rnd.nextInt(10)+1;
centerStepY = rnd.nextInt(10)+1;

focusStepX = rnd.nextInt(10)+1;
focusStepY = rnd.nextInt(10)+1;

affineTransform = new AffineTransform();

this.addComponentListener(this);
}

public void run() {
while (!mainThread.interrupted()) {
do {
do {
Graphics2D g = (Graphics2D)bs.getDrawGraphics();
render(g);
g.dispose();
} while (bs.contentsRestored()) ;
bs.show();
} while (bs.contentsLost()) ;
}
}

public void start() {
mainThread = new Thread(this);
mainThread.start();
}

public void stop() {
mainThread.interrupt();
}

/** Get the color used for this colors array index */
public Color getColor(int index) {
return colors[index];
}

/** Set the color used for this colors array index */
public void setColor(Color color, int index) {
colors[index] = color;
}

/** Set the gradientType. */
public void setGradientType(int type) {

gradientType = type;
}

/** Set the cycleMethod. */
public void setCycleMethod(
MultipleGradientPaint.CycleMethod method) {

cycleMethod = method;
}

/** Set the colorSpace. */
public void setColorSpace(
MultipleGradientPaint.ColorSpaceType color) {

colorSpace = color;
}

/** Set the showPoints. */
public void setShowPoints(boolean show) {
showPoints = show;
}

public void setShowFps(boolean show) {
showFps = show;
}

/** Move the two points according to their current step values
and reverse the direction of any that hit component boundaries.*/
public void movePoints() {
int newCenterX = (int)center.getX() + centerStepX;
if ( newCenterX>getWidth() ) {
centerStepX = -(rnd.nextInt(2)+3);
} else if ( newCenterX<0 ) {
centerStepX = (rnd.nextInt(2)+3);
}

int newCenterY = (int)center.getY() + centerStepY;
if ( newCenterY>getHeight() ) {
centerStepY = -(rnd.nextInt(2)+3);
} else if ( newCenterY<0 ) {
centerStepY = (rnd.nextInt(2)+3);
}

center = new Point( newCenterX, newCenterY );

int newFocusX = (int)focus.getX() + focusStepX;
if ( newFocusX>getWidth() ) {
focusStepX = -(rnd.nextInt(2)+3);
} else if ( newFocusX<0 ) {
focusStepX = (rnd.nextInt(2)+3);
}

int newFocusY = (int)focus.getY() + focusStepY;
if ( newFocusY>getHeight() ) {
focusStepY = -(rnd.nextInt(2)+3);
} else if ( newFocusY<0 ) {
focusStepY = (rnd.nextInt(2)+3);
}

if (alterRadius) {
radius += radiusStep;
if ( radius>highRadius ) {
radiusStep = -1;
} else if (radius<lowRadius) {
radiusStep = 1;
}
}

focus = new Point(
newFocusX,
newFocusY );
}

public void componentHidden(ComponentEvent ce) {}
public void componentShown(ComponentEvent ce) {}
public void componentMoved(ComponentEvent ce) {}

/** On component resize, do a single repaint (which will force
the last frame of the earlier sized BufferedImage to be scaled
to current screen size when drawn), then invoke a resizing of
the BufferedImage on a priority thread, kicked off by
SwingUtilites.invokeLater(). */
public void componentResized(ComponentEvent ce) {
if (bs == null) {
createBufferStrategy(2);
bs = getBufferStrategy();
System.out.println(bs);
}
start();
}

/** Create a BufferedImage suitable as a backing store
for the current Component size. */
public void initialiseImage() {
initialiseImage(
getPreferredSize().width,
getPreferredSize().height );
}

/** Create a BufferedImage of size - width x height. */
public void initialiseImage(int width, int height) {
store = new BufferedImage(
width,
height,
BufferedImage.TYPE_INT_RGB );
}

/** Render the new GradientPaint to the store, then blast it to
screen. */
public void render(Graphics2D g1) {
movePoints();

MultipleGradientPaint paint = null;

switch(gradientType) {
case RADIAL:
paint = new RadialGradientPaint(
center, // center
radius, // radius
focus, // focus
fractions,
colors,
cycleMethod,
colorSpace,
affineTransform
);
break;
case LINEAR:
paint = new LinearGradientPaint(
center, // 'point 1'
focus, // 'point 2'
fractions,
colors,
cycleMethod
);
}

// Graphics2D g1 = (Graphics2D)store.getGraphics();
g1.setPaint(paint);
g1.fillRect( 0,0,getWidth(),getHeight() );

if (showPoints) {
int small = 2;
int big = 3;
g1.setColor( new Color(0,0,0,128) );
g1.fillOval( (int)center.getX()-big, (int)center.getY()-big,
2*big, 2*big );
g1.fillOval( (int)focus.getX()-big, (int)focus.getY()-big, 2*big,
2*big );

g1.setColor( Color.RED );

g1.fillOval(
(int)center.getX()-small,
(int)center.getY()-small, 2*small, 2*small );
g1.fillOval(
(int)focus.getX()-small,
(int)focus.getY()-small, 2*small, 2*small );
if ( gradientType==RADIAL ) {
g1.drawOval(
(int)center.getX()-radius,
(int)center.getY()-radius,
radius*2,
radius*2 );
g1.drawString( "C", (int)center.getX()+5, (int)center.getY()+5 );
g1.drawString( "F", (int)focus.getX()+5, (int)focus.getY()+5 );
} else {
g1.drawString( "P1", (int)center.getX()+5, (int)center.getY()+5 );
g1.drawString( "P2", (int)focus.getX()+5, (int)focus.getY()+5 );
}
}

if (showFps) {
long time = System.currentTimeMillis();
if ( timeSinceLastFrame>0 ) {
if (iterations%10==0) {
long millisSinceLastFrame = time - timeSinceLastFrame;
rate = 1000d/millisSinceLastFrame;
}
g1.setColor(Color.RED);
g1.drawString( dfFps.format( rate ), 10, 20 );
}

timeSinceLastFrame = time;
iterations++;
}

// g.drawImage( store,0,0,getWidth(),getHeight(),this );
}

public static void main(String[] args) {
Thread t = new Thread() {
public void run() {
final JWindow w = new JWindow();
w.setSize( Toolkit.getDefaultToolkit().getScreenSize() );
w.setLocation(0,0);

final JFrame f = new JFrame("Gradient Painter");
f.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );

final GradientPainter2 gp = new GradientPainter2();

final JPanel mainUI = new JPanel(new BorderLayout(5,3));
mainUI.add( gp, BorderLayout.CENTER );

gp.addMouseListener( new MouseAdapter(){
public void mouseClicked(MouseEvent me) {
if (me.getClickCount()==2) {
Container c = gp.getFocusCycleRootAncestor();
if ( c instanceof JFrame ) {
gp.stop();
mainUI.remove( gp );
w.add( gp );
w.setVisible(true);
w.validate();
} else {
gp.stop();
w.remove( gp );
mainUI.add( gp, BorderLayout.CENTER );
w.setVisible(false);
f.validate();
}
}
}
} );

GradiantPainterControls gpc = new GradiantPainterControls(gp);
mainUI.add( gpc, BorderLayout.EAST );

f.add( mainUI );

f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
}
};
SwingUtilities.invokeLater(t);
}
}

/** A GUI based configuration class for the GradientPainter. */
class GradiantPainterControls extends JPanel {

/** Used for selecting alternate colors for the
three in the default array. */
JColorChooser colorChooser;

GradiantPainterControls(final GradientPainter2 painter) {
colorChooser = new JColorChooser();

BoxLayout layout = new BoxLayout(this, BoxLayout.Y_AXIS);
setLayout(layout);

ButtonGroup type = new ButtonGroup();

JPanel typeContainer = new JPanel();
BoxLayout typeLayout = new BoxLayout(typeContainer, BoxLayout.Y_AXIS);
typeContainer.setLayout(typeLayout);

typeContainer.setBorder( new TitledBorder("Paint Type") );

JRadioButton radial = new JRadioButton("Radial", true);
radial.addActionListener( new ActionListener(){
public void actionPerformed(ActionEvent ae) {
painter.setGradientType( GradientPainter2.RADIAL );
}
} );
typeContainer.add(radial);
type.add(radial);

JRadioButton linear = new JRadioButton("Linear", false);
linear.addActionListener( new ActionListener(){
public void actionPerformed(ActionEvent ae) {
painter.setGradientType( GradientPainter2.LINEAR );
}
} );
typeContainer.add(linear);
type.add(linear);

JPanel typeWidthStretch = new JPanel(new BorderLayout());

typeWidthStretch.add( typeContainer, BorderLayout.CENTER );
add( typeWidthStretch );

ButtonGroup spaceGroup = new ButtonGroup();

JPanel spaceContainer = new JPanel();
BoxLayout spaceLayout = new BoxLayout(spaceContainer,
BoxLayout.Y_AXIS);
spaceContainer.setLayout(spaceLayout);

spaceContainer.setBorder( new TitledBorder("Color Space") );

JRadioButton srgb = new JRadioButton("S-RGB", true);
srgb.addActionListener( new ActionListener(){
public void actionPerformed(ActionEvent ae) {
painter.setColorSpace(
MultipleGradientPaint.ColorSpaceType.SRGB);
}
} );
spaceContainer.add(srgb);
spaceGroup.add(srgb);

JRadioButton lrgb = new JRadioButton("Linear RGB", false);
lrgb.addActionListener( new ActionListener(){
public void actionPerformed(ActionEvent ae) {
painter.setColorSpace(
MultipleGradientPaint.ColorSpaceType.LINEAR_RGB);
}
} );
spaceContainer.add(lrgb);
spaceGroup.add(lrgb);

JPanel spaceWidthStretch = new JPanel(new BorderLayout());

spaceWidthStretch.add( spaceContainer, BorderLayout.CENTER );
add( spaceWidthStretch );

ButtonGroup cycleGroup = new ButtonGroup();

JPanel cycleContainer = new JPanel();
BoxLayout cycleLayout = new BoxLayout(cycleContainer,
BoxLayout.Y_AXIS);
cycleContainer.setLayout(cycleLayout);

cycleContainer.setBorder( new TitledBorder("Cycle Method") );

JRadioButton reflect = new JRadioButton("Reflect", true);
reflect.addActionListener( new ActionListener(){
public void actionPerformed(ActionEvent ae) {
painter.setCycleMethod(
MultipleGradientPaint.CycleMethod.REFLECT );
}
} );
cycleContainer.add(reflect);
cycleGroup.add(reflect);

JRadioButton repeat = new JRadioButton("Repeat", false);
repeat.addActionListener( new ActionListener(){
public void actionPerformed(ActionEvent ae) {
painter.setCycleMethod(
MultipleGradientPaint.CycleMethod.REPEAT );
}
} );
cycleContainer.add(repeat);
cycleGroup.add(repeat);

JRadioButton noCycle = new JRadioButton("No Cycle", false);
noCycle.addActionListener( new ActionListener(){
public void actionPerformed(ActionEvent ae) {
painter.setCycleMethod(
MultipleGradientPaint.CycleMethod.NO_CYCLE );
}
} );
cycleContainer.add(noCycle);
cycleGroup.add(noCycle);


JPanel cycleWidthStretch = new JPanel(new BorderLayout());

cycleWidthStretch.add( cycleContainer, BorderLayout.CENTER );
add( cycleWidthStretch );

final JCheckBox displayFps = new JCheckBox("Show FPS", true);
displayFps.addActionListener( new ActionListener(){
public void actionPerformed(ActionEvent ae){
painter.setShowFps( displayFps.isSelected() );
}
} );

JPanel displayWidthStretch = new JPanel(new GridLayout(0,1));
displayWidthStretch.add( displayFps );

final JCheckBox displayPoints = new JCheckBox("Show Points", false);
displayPoints.addActionListener( new ActionListener(){
public void actionPerformed(ActionEvent ae){
painter.setShowPoints( displayPoints.isSelected() );
}
} );

displayWidthStretch.add( displayPoints );

add( displayWidthStretch );

JPanel colorContainer = new JPanel();
BoxLayout colorLayout = new BoxLayout(colorContainer,
BoxLayout.Y_AXIS);
colorContainer.setLayout(colorLayout);
colorContainer.setBorder( new TitledBorder("Colors") );

JPanel colorWidthStretch = new JPanel(new BorderLayout());

colorWidthStretch.add( colorContainer, BorderLayout.CENTER );
add( colorWidthStretch );

final JButton c1 = new JButton("Color 1");
c1.setOpaque(true);
c1.addActionListener( new ActionListener(){
public void actionPerformed(ActionEvent ae) {
Color temp = colorChooser.showDialog(
painter,
"Color 1",
painter.getColor(0));
if (temp!=null) {
painter.setColor(temp, 0);
c1.setBackground( temp );
}
}
} );
colorContainer.add(c1);

final JButton c2 = new JButton("Color 2");
c2.setOpaque(true);
c2.addActionListener( new ActionListener(){
public void actionPerformed(ActionEvent ae) {
Color temp = colorChooser.showDialog(
painter,
"Color 2",
painter.getColor(1));
if (temp!=null) {
painter.setColor(temp, 1);
c2.setBackground( temp );
}
}
} );
colorContainer.add(c2);

final JButton c3 = new JButton("Color 3");
c3.setOpaque(true);
c3.addActionListener( new ActionListener(){
public void actionPerformed(ActionEvent ae) {
Color temp = colorChooser.showDialog(
painter,
"Color 3",
painter.getColor(2));
if (temp!=null) {
painter.setColor(temp, 2);
c3.setBackground( temp );
}
}
} );
colorContainer.add(c3);
}
}
 
D

Daniele Futtorovic

Andrew:

I hacked up your code (sorry) to use active rendering and got a huge
increase in speed. It has a few problems but it works more or less.
The code below is probably too trashed to copy so I'll post the
source file at;

Knute/Andrew:

On my machine that code runs about as fast as the solution with
VolatileImage I tried, and that is *twice as slow* as Andrew's original
solution.

Intel Celeron 2GHz
WinXP SP2
java version "1.6.0_06"
 
D

Daniele Futtorovic

If you are really bored,

Let's just say I was /interested/... ;)

try downloading and running the beta 1.6.0_10.
It is a lot faster.

Indeed! Amazing. Readings went off scale (using Andrews measurement
technique).

FWIW: the simple VolatileImage solution -- without using the
BufferStrategy, using a VolatileImage as an offscreen buffer and
rendering actively -- seemed about as fast. NOT as far as the
full-screen mode was concerned, however. I made use of the "full-screen
exclusive mode", as accessed via
GraphicsDevice#setFullScreenWindow(Window). No improvement there
compared to 1.6.0_06.
 
K

Knute Johnson

Daniele said:
Let's just say I was /interested/... ;)



Indeed! Amazing. Readings went off scale (using Andrews measurement
technique).

FWIW: the simple VolatileImage solution -- without using the
BufferStrategy, using a VolatileImage as an offscreen buffer and
rendering actively -- seemed about as fast. NOT as far as the
full-screen mode was concerned, however. I made use of the "full-screen
exclusive mode", as accessed via
GraphicsDevice#setFullScreenWindow(Window). No improvement there
compared to 1.6.0_06.

The FlipSubRegionBufferStrategy, Windows XP and 1.6.0_10 is really fast.
 
A

Andrew Thompson

On 2008-05-22 02:27 +0100, Knute Johnson allegedly wrote:

(re. running the new code..)
Indeed! Amazing. Readings went off scale (using Andrews measurement
technique).

Huhh.. In contrast, here, the numbers were so similar
(to the original results I was getting) I went to
extra measures to check it was running using the
1.6.0_10 JRE! I never saw the frame rate rise
above 21.7.

I can only assume that if the _10 update is a significant
improvement, that the improvement is aimed at later
hardware* than I have. :-(

* My machine is about 6 years ancient.

..a few minutes later - thought to recheck the
*original* code in 1.6.0_10 and it (very) occasionally
cracks 32 FPS. Mostly though it seems 'around' as fast
as it did in the 1.6.0-b105 variant.
 
D

Daniele Futtorovic

(re. running the new code..)

Huhh.. In contrast, here, the numbers were so similar (to the
original results I was getting) I went to extra measures to check it
was running using the 1.6.0_10 JRE! I never saw the frame rate rise
above 21.7.

I can only assume that if the _10 update is a significant
improvement, that the improvement is aimed at later hardware* than I
have. :-(

* My machine is about 6 years ancient.

Mine too. The release info for the beta10 says:
Sun's JRE has been steadily getting faster over the years, and 6u10
is no exception. Key performance improvements are the introduction of
Java Quick Starter, which will substantially improve Java cold start
time on most systems, and a new graphics pipeline on Windows.

The new graphics pipeline will use Direct3D to accelerate most common
operations, so the powerful 3D graphics card you probably have in
your computer will have a use other than playing games. Translucency,
gradients, affine transforms, antialiasing, rectangular fills and
copies, and various other graphics operations will all be accelerated
by 3D graphics cards. And, unlike previous 3D pipelines which were
not robust enough to be enabled by default, the new pipeline is
rock-solid and used by default in 6u10.

Read more about these features in Chet Haase's blog
<http://weblogs.java.net/blog/chet/archive/2007/05/consumer_jre_le.html>.

..a few minutes later - thought to recheck the *original* code in
1.6.0_10 and it (very) occasionally cracks 32 FPS. Mostly though it
seems 'around' as fast as it did in the 1.6.0-b105 variant.

Yup, on my machine too, your original (BufferedImage) code was about as
fast with the 1.6.0_10 than with 1.6.0_6.

I've modified the FPS measurement to be more accurate. Here are the
results I get on my machine:

Method 1 (Andrew): JPanel + BufferedImage as off-screen buffer; passive
rendering; full-screen emulated via JWindow the size of the screen
Method 2 (Daniele): Canvas + VolatileImage as off-screen buffer; active
rendering; full-screen via GraphicsDevice#setFullScreenWindow
Method 3 (Knute): Canvas + FlipSubRegionBufferStrategy; active
rendering; full-screen emulated via JWindow the size of the screen


With 1.6.0_6:
Method # windowed full-screen
1 ~22-23 fps ~3.5 fps
2 ~12 fps ~1.5 fps
3 ~12 fps ~1.5 fps

With 1.6.0_b10
Method # windowed full-screen
1 ~22 fps ~3.5 fps
2 ~320 fps ~3 fps
3 ~330-340 fps ~45 fps
 
K

Knute Johnson

Andrew said:
(re. running the new code..)

Huhh.. In contrast, here, the numbers were so similar
(to the original results I was getting) I went to
extra measures to check it was running using the
1.6.0_10 JRE! I never saw the frame rate rise
above 21.7.

I can only assume that if the _10 update is a significant
improvement, that the improvement is aimed at later
hardware* than I have. :-(

* My machine is about 6 years ancient.

..a few minutes later - thought to recheck the
*original* code in 1.6.0_10 and it (very) occasionally
cracks 32 FPS. Mostly though it seems 'around' as fast
as it did in the 1.6.0-b105 variant.

Andrew:

I'm sure that this is only true on Windows and you need the latest
DirectX. I think the latest version is 9.
 
A

Andrew Thompson

On May 23, 12:48 am, Daniele Futtorovic <[email protected]>
wrote:
...
With 1.6.0_b10
Method #        windowed        full-screen
1               ~22 fps         ~3.5 fps
2               ~320 fps        ~3 fps
3               ~330-340 fps    ~45 fps

Sheesh! Just out of curiosity, was any of the
'blue smoke' escaping out of the machine in the
320+ fps modes?

As an aside. I have decided upon a 'crude kludge'
to bring up the frame rates using the original
technique. I found that the quality of a 'half
screen size' rendering when scaled to full screen
size was acceptable, so I offer the user a setting
for 'scaling' from 1-4.

This brings the full screen FPS from 3.0-3.6 up
to about 8.0-9.2 (for scaling of '2').

Of course, to work well with the faster techniques,
the code would need to be changed (ironically) to
*limit* the upper speed. I am guessing it looks
quite 'busy' at the high frame rates - possibly to
the point of triggering photo-sensitive epileptic
fits!

And at a ten time improvement of rendering rate,
my original question is sure answered!
 
D

Daniele Futtorovic

On May 23, 12:48 am, Daniele Futtorovic


Sheesh! Just out of curiosity, was any of the 'blue smoke' escaping
out of the machine in the 320+ fps modes?

Well, no, but I did start to feel a bit dizzy... :)

As an aside. I have decided upon a 'crude kludge' to bring up the
frame rates using the original technique. I found that the quality
of a 'half screen size' rendering when scaled to full screen size was
acceptable, so I offer the user a setting for 'scaling' from 1-4.

This brings the full screen FPS from 3.0-3.6 up to about 8.0-9.2 (for
scaling of '2').

Note: the measurements I reported were for the JFrame in its original
size (400x300 + ControlPanel). When I maximized the frame, they went
down from 300+ to about 45 fps (consistent with the measurement for
solution 3 in full-screen mode).

I still find it a bit puzzling why the performance of both solutions 2
and 3 were *worse* than the BufferedImage with 1.6.0_6.
What's more, I don't understand why the full-screen mode I used worked
so poorly.

Of course, to work well with the faster techniques, the code would
need to be changed (ironically) to *limit* the upper speed.

Why, yes. I'd suppose one would use a time-constrained model in
combination with a more or less unconstrained rendering. The current
test code had an unconstrained model, as it was changed (via
movePoints()) in each rendering pass.

And at a ten time improvement of rendering rate, my original question
is sure answered!

Yet the difference is primarily due to the improvement of the runtime,
not of the code...

For what it's worth, I'll post the test code I used on the sun forum.
 
A

Andrew Thompson

On May 23, 2:53 am, Daniele Futtorovic <[email protected]>
wrote:
...
Why, yes. I'd suppose one would use a time-constrained model in
combination with a more or less unconstrained rendering. The current
test code had an unconstrained model, as it was changed (via
movePoints()) in each rendering pass.

Even as I was typing that, I was thinking - I
can't wait to see how Daniele rephrases that in
'tech. terms'.

A 'time-constrained model'.. (vaguely) ..yes,
yes, that's what I meant. ;-)

And to Knute. After a recent crash/rebuild, my
machine almost certainly does not have the updated
DirectX drivers. I should check that out - I want
to get dizzy, too!
 
D

Daniele Futtorovic

Even as I was typing that, I was thinking - I can't wait to see how
Daniele rephrases that in 'tech. terms'.

A 'time-constrained model'.. (vaguely) ..yes, yes, that's what I
meant. ;-)

:)

Actually there might be more to it than that (I have precisely zero
experience in designing games, so I'm just mumbling to myself here), for
if one were designing a real-time game, for instance, one couldn't allow
the model to proceed at faster speed than what the gamer can see. So the
model would have to be constrained upwards in two ways: first absolutely
in terms of what the real-time in that virtual world is, and secondly by
how much throughput the rendering yields, in those cases were the latter
number is lower than the former.

And to Knute. After a recent crash/rebuild, my machine almost
certainly does not have the updated DirectX drivers. I should check
that out - I want to get dizzy, too!

Hush, you fool! That's illegal!
 
A

Andrew Thompson

On May 23, 1:42 am, Knute Johnson <[email protected]>
wrote:
...
(rendering speed increases)
I'm sure that this is only true on Windows and you need the latest
DirectX.  I think the latest version is 9.

Apparently there is a DirectX 10 that only works with
Vista. Since I'm running XP, I guess v. 9 would be the
latest for this box.

But after downloading 'a directX update' patch and
running it, and seeing no difference, leads me to ask..
Just how can I determine what version of DirectX is
running here? I cannot even locate any references to
DirectX on this box!
 
D

Daniele Futtorovic

On May 23, 1:42 am, Knute Johnson <[email protected]>
wrote:
...
(rendering speed increases)

Apparently there is a DirectX 10 that only works with
Vista. Since I'm running XP, I guess v. 9 would be the
latest for this box.

But after downloading 'a directX update' patch and
running it, and seeing no difference, leads me to ask..
Just how can I determine what version of DirectX is
running here? I cannot even locate any references to
DirectX on this box!

Andrew,

There may be more than one way to find out which DirectX you're running,
but one useful one would be to run the Windoze utility called "dxdiag.exe".

Note that I am running the same system as you, and I'm using DirectX 9.0c.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,054
Latest member
TrimKetoBoost

Latest Threads

Top