I am trying to control frame rate by measuring the time taken to drawImage, but I’m getting wierd results. In the code below, period = 0 makes the animation free run. For me, each draw/render cycle takes around 13ms and typical output is:
Rendering took 13.254757ms, Drawing finished (T/F) = true, about to sleep for -13ms
If I try to impose a frame rate (e.g. 20ms - period = 20000000 in the code), suddenly the draw/render cycle seems to take a lot less time:
Rendering took 0.139124ms, Drawing finished (T/F) = true, about to sleep for 14ms
It’s pretty obvious the draw/render cycle is not taking this little time because the code runs slower visually. I’ve tried to find out whether the image has finished drawing by interpreting the boolean returned by drawImage and by using ImageObserver. To me, it looks like drawImage has finished by the time it returns (contrary to the JavaDoc which states that it returns immediately?).
Thread.sleep was used for example - I’ve tried all sorts of code in place of it and problem is not there (simple empty loop causes the same effect). Any clues as to what is going on? This is causing a major headache…
Using 1.5.0_02-b09
The image I used was pinched from:
http://users.design.ucla.edu/~badgerow/Photos/SnowSummit/03-5-Landscape.jpg
import java.awt.DisplayMode;
import java.awt.Frame;
import java.awt.Graphics;
import java.awt.GraphicsConfiguration;
import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment;
import java.awt.Image;
import java.awt.Rectangle;
import java.awt.image.BufferStrategy;
import java.awt.image.ImageObserver;
import java.io.File;
import javax.imageio.ImageIO;
public class MultiBufferTest {
private static Image image;
private static DisplayMode[] BEST_DISPLAY_MODES = new DisplayMode[] {
new DisplayMode(640, 480, 32, 0), new DisplayMode(640, 480, 16, 0),
new DisplayMode(640, 480, 8, 0) };
Frame mainFrame;
public MultiBufferTest(int numBuffers, GraphicsDevice device) {
long startTime;
long endTime;
long renderTime;
long period = 0;
//long period = 20000000; // Nanoseconds
long sleepTime = 0;
boolean drawFinished;
MyObserver imageObserver = new MyObserver();
try {
GraphicsConfiguration gc = device.getDefaultConfiguration();
mainFrame = new Frame(gc);
mainFrame.setUndecorated(true);
mainFrame.setIgnoreRepaint(true);
device.setFullScreenWindow(mainFrame);
if (device.isDisplayChangeSupported()) {
chooseBestDisplayMode(device);
}
Rectangle bounds = mainFrame.getBounds();
mainFrame.createBufferStrategy(numBuffers);
BufferStrategy bufferStrategy = mainFrame.getBufferStrategy();
for (int j = 0; j < 100; j++) {
for (int i = 0; i < numBuffers; i++) {
Graphics g = bufferStrategy.getDrawGraphics();
if (!bufferStrategy.contentsLost()) {
startTime = System.nanoTime();
drawFinished = g.drawImage(image, 0, 0, bounds.width,
bounds.height, j, j, bounds.width + j,
bounds.height + j, imageObserver);
bufferStrategy.show();
g.dispose();
endTime = System.nanoTime();
renderTime = endTime - startTime;
sleepTime = period - renderTime;
sleepTime /= 1000000;
System.out.println("Rendering took " + renderTime / 1E6
+ "ms,\tDrawing finished (T/F) = "
+ drawFinished + ",\tabout to sleep for "
+ sleepTime + "ms");
}
if (sleepTime > 0) {
try {
Thread.sleep((int) sleepTime);
} catch (InterruptedException e) {
}
}
}
}
} catch (Exception e) {
e.printStackTrace();
} finally {
device.setFullScreenWindow(null);
}
}
private static DisplayMode getBestDisplayMode(GraphicsDevice device) {
for (int x = 0; x < BEST_DISPLAY_MODES.length; x++) {
DisplayMode[] modes = device.getDisplayModes();
for (int i = 0; i < modes.length; i++) {
if (modes[i].getWidth() == BEST_DISPLAY_MODES[x].getWidth()
&& modes[i].getHeight() == BEST_DISPLAY_MODES[x]
.getHeight()
&& modes[i].getBitDepth() == BEST_DISPLAY_MODES[x]
.getBitDepth()) {
return BEST_DISPLAY_MODES[x];
}
}
}
return null;
}
public static void chooseBestDisplayMode(GraphicsDevice device) {
DisplayMode best = getBestDisplayMode(device);
if (best != null) {
device.setDisplayMode(best);
}
}
public static void main(String[] args) {
try {
int numBuffers = 2;
if (args != null && args.length > 0) {
numBuffers = Integer.parseInt(args[0]);
if (numBuffers < 2 || numBuffers > 5) {
System.err.println("Must specify between 2 and 5 buffers");
System.exit(1);
}
}
GraphicsEnvironment env = GraphicsEnvironment
.getLocalGraphicsEnvironment();
GraphicsDevice device = env.getDefaultScreenDevice();
// Any image bigger than 740x580
image = ImageIO.read(new File("03-5-Landscape.jpg"));
MultiBufferTest test = new MultiBufferTest(numBuffers, device);
} catch (Exception e) {
e.printStackTrace();
}
System.exit(0);
}
class MyObserver implements ImageObserver {
public boolean imageUpdate(Image img, int infoflags, int x, int y, int width, int height) {
System.out.println("AN IMAGE UPDATE OCCURRED");
return false;
}
}
}