Bad rendering loop?

I normally fix that using:


long[] intervals = new long[]{16,17,17}; // 16.666666667
int counter=0;

		if (System.currentTimeMillis() >= next) {

				// LOTS OF LONG STUFF

				next += intervals[(counter++) % intervals.length];
		}

I only get around 24fps. Something as simple as that should run a lot faster, something seriously is killing the speed.

Have you applied Riven’s fix? As I stated before, I was only getting 40 FPS before. Here is the complete code, with his fix:

import java.awt.*;
import java.awt.image.*;

public class FPS extends Canvas implements Runnable {
	private int FPS = 60;
	private int gameW = 1024;
	private int gameH = 768;

	private Graphics screen;
	private BufferedImage buffer;

	private int fps = 0;
	private	int frames = 0;
	private long lastLoopTime = System.currentTimeMillis();

	public FPS() {
		setSize(gameW, gameH);
		setIgnoreRepaint(true);
	}

	public void addNotify() {
		super.addNotify();

		buffer = new BufferedImage(gameW, gameH, Transparency.OPAQUE);
		screen = buffer.getGraphics();

		(new Thread(this)).start();
	}

	public void run() {
		long next = System.currentTimeMillis()+(1000/FPS);

		while(true) {
			if (System.currentTimeMillis() >= next) {
				long last = (System.currentTimeMillis()-lastLoopTime);
				if (last >= 1000) {
					fps = frames;
					frames = 0;
					lastLoopTime = System.currentTimeMillis();
				}
				frames++;

				screen.setColor(Color.black);
				screen.fillRect(0, 0, gameW, gameH);

				gameLoop();

				next += 1000/FPS;
			}

			Graphics g = getGraphics();
			g.drawImage(buffer, 0, 0, this);
			g.dispose();
		}
	}

	public void gameLoop() {
		screen.setColor(Color.green);
		screen.drawString("FPS = "+fps, 100, 100);

		int w = 20;
		int h = 20;
		screen.setColor(Color.gray);
		for (int i=0; i<100; i++) {
			int x = (int)(Math.random() * (gameW-w));
			int y = (int)(Math.random() * (gameH-h));
			screen.drawOval(x, y, w, h);
		}
	}

	public static void main(String args[]) {
		Frame f = new Frame("FPS");

		f.add(new FPS());
		f.setResizable(false);

		f.pack();
		f.show();
	}
}

UPDATE: This also has ignore repaint set to true (the orignal did not) because it was causing repaint problems (screen flicker, bleeding) when the OS would attempt to repaint the screen.

Using BufferedImage for a back-buffer is a bad idea. You should use either VolatileImage or BufferStrategy (preferably the
latter). Basically, with your current code you don’t get any hardware acceleration: your rendering
goes to the an image in heap, and it is then copied to the screen.

Search around for examples on BufferStrategy or take a look at javadocs for jdk6
(much improved docs for how to use the BS):
http://java.sun.com/javase/6/docs/api/java/awt/image/BufferStrategy.html

Thanks,
Dmitri
Java2D Team

Tell me this: How is a BufferStrategy better than a BufferedImage when I can get about 500 frames per second with a BufferedImage (when nothing is rendered, just the back ground color and the FPS) and only about 150 frames per second with a BufferStrategy.

(NOTE: I could get much more than 500 frames per second if I did not use Thread.sleep())

When debuging my game I wrote a small test, BufferStrategy vs. BufferedImage, BS was noticably better. Here is a conclusion:

all this in windowed mode, later in thread Commander Keith told me BS should be even faster in full screen because it can use page flipping (pointer shifting).

So I guess your example is broken somewhere in rendering loop when using BS.

In my game, I’m drawing full-alpha PNG images and I changed my buffer to a BufferStrategy and I only got about 120 FPS. Why stick with 120 FPS when I can get over 500 FPS with a BufferedImage? It just makes absolutely no sense at all - it’s a huge speed decrease.

Tell me this: How is a BufferStrategy better than a BufferedImage when I can get about 500 frames per second
with a BufferedImage (when nothing is rendered, just the back ground color and the FPS) and only about 150
frames per second with a BufferStrategy.

Your follow up post answers that question. You are using some rendering pipeline, which does alpha stuff in software. So keeping the buffer over in software land is surely faster than going back and forth a zillion times a frame.

do you just draw into the bufferedimage or do you also once per round draw it to screen?

Obviously, yes, I draw it to the screen. Why wouldn’t I? If I didn’t than nothing would be visible… Look at the code.

Jamison: 1.) I wonder why your tone is so agressive. Theres absolutly no need to do so!

2.) You are rendering stuff which can’t be done in hw with the java2d-backend you are using. This triggers readbacks from vram->ram which is slow. Run you application with -Dsun.java2d.trace=count to see where software rendering happens and then try to alter your code, and/or experiment with other rendering pipelines (OpenGL for example).

lg Clemens

I think what they’re saying is that the BufferStrategy is using “hardware acceleration” by using DirectDraw/Direct3D whereas the BufferImage is not, its all in software (ie no graphics card & VRAM, just the CPU & normal RAM).

In this case it seems like the hardware ‘acceleration’ is actually slower than software mode, thus your slow-down.

To make sure this is the problem, compare your two approaches when both use the noddraw option so neither have hardware acceleration. This VM option is: -Dsun.java2d.noddraw=true

from: http://java.sun.com/j2se/1.5.0/docs/guide/2d/flags.html

Keith

(PS: this is a hairy topic full of wierd performance things so good luck! Not even the J2D team can work out which pipeline is the best for different computers but they’re working on it…)

I’m sorry about the tone. It’s just this is getting me so agrivated as to why I only got so low framerate while almost every other game I’ve ran gets over 1200+ or something.

Also, those -Dsun.java2d.* commands don’t seem to do anything. But am I using them correctly? I put them in a BAT file to run my game:

@ECHO OFF

java FPS -Dsun.java2d.trace=count
pause

Let me also point out that my screen size (not my actual monitor, but the game’s screen, the buffer) is only 320x240. If I change that to 1024x768, I get less than 60 frames per second.

Well, noddraw just disables the use of direct draw, as far as I know this does not mean everything is unaccalerated (however I could be wrong).

@jamison: I don’t know wether its ok to specify the -D arguments after the main class, better try java -Dsun.java2d.trace=count FPS

You’ll see how often stuff was calles, whereas names with java2d.loopsn in it are in general “bad” -> loops mean stuff is done in Software, however this is only a problem if the count is very high. (-> frequently using software rendering)

lg Clemens

But am I using them correctly?

No you hand that parameter over to your program and not over to java.

java [switches for java] YourProgram [switches for your program]

Okay, I got the -Dsun.java2d.* stuff to work. And trace=count just outputs some weird stuff. Here’s the output, I can’t understand it.

3 calls to GDIFillRect
31769 calls to sun.java2d.loops.Blit::Blit(IntRgb, SrcNoEa, IntRgb)
2787 calls to sun.java2d.loops.DrawGlyphList::DrawGlyphList(AnyColor, SrcNoEa, A
nyInt)
26210 calls to sun.java2d.loops.Blit$GeneralMaskBlit::Blit(IntArgb, SrcOverNoEa,
 IntRgb)
1 call to sun.java2d.loops.TransformHelper::TransformHelper(IntArgb, SrcNoEa, In
tArgbPre)
1858 calls to sun.java2d.loops.FillRect::FillRect(AnyColor, SrcNoEa, AnyInt)
3 calls to GDIDrawRect
931 calls to sun.java2d.windows.GDIBlitLoops::Blit(IntRgb, SrcNoEa, "GDI")
26210 calls to sun.java2d.loops.MaskBlit::MaskBlit(IntArgb, SrcOver, IntRgb)
6790 calls to sun.java2d.windows.DDBlitLoops::Blit("Integer RGB DirectDraw", Src
NoEa, "Integer RGB DirectDraw")
96562 total calls to 10 different primitives

Ok, its not that complicated to read at all.
1.) the number tells you how often this pipeline-functionality has been used.
2.) The name of the pipelinefunctionality used, almost everything with “loops” in it and a high count in 1.) is evil.

In fact your profile here shows that everything happens in the software rendering loops. If you did trace your BufferedImage implementation, then this is no surpise - everything is done in SW except blitting some images. If no you’re doing some fancy stuff which cannot be accalerated by the default java2d-pipeline.

Try wether -Dsun.java2d.opengl=True helps (java displays wether this works or not). Use Java-6 if you plant to try it.

The following operations could cause problems on the windows default pipeline:

  • Antialiasing
  • Translucent stuff (transparent images work)
  • Image transformations

The X11 pipeline seems to be even a little bit trickier, e.g. Substance LNF is very slow on Linux but works OK on Windows. However accalerated stuff is on X11 as fast / almost as fast / faster than on Windows.

Best wishes, lg Clemens

OK, I understand that. But even if they are high, what can I do about it?

Also, I did some messing around with both BufferStrategy and BufferedImage. It seems that if I’m drawing only transparent PNG images (and a String to show the FPS display), I can draw over 25,000 images and still get almost 80 frames per second (no differance whether using BufferStrategy or a BufferedImage). My screen size is 1024x768 (my screen resolution, however, is 1280x1024; not in FSEM). My images are 16x16, 204 colors. However, on the down side, my CPU was shot upto like 90%. I’m using code that is supposed to load the images as accelarated (using the video RAM and not CPU), however, if it was in the video memory, shouldn’t my CPU usage be a lot lower? Or is it because I’m running through almost 80 for…loops in one second in which each loops 25,000 times?

Here’s the code I got from Kev’s site, cokeandcode.com - from his Space Invaders 101 tutorial:

		try {
			URL url = getClass().getClassLoader().getResource("Image.png");
			Image source = ImageIO.read(url);

			GraphicsConfiguration gc = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getDefaultConfiguration();
			image = gc.createCompatibleImage(source.getWidth(null), source.getHeight(null), Transparency.BITMASK);
			image.getGraphics().drawImage(source, 0, 0, null);
		} catch(Exception e) {
			e.printStackTrace();
			System.exit(-1);
		}

UPDATE: A BufferStrategy actually gets about 10 frames per second more (almost 90 frames per second) than using a BufferedImage (about 80 frames per second) when doing what’s explained above.

UPDATE: I get pretty close to 100 frames per second with FSEM (about 96 FPS average, using BufferStrategy, 1024x768x32 at 75mhz).

25k images :o
I’m surprised it works that well beyond 1k :slight_smile: Your high CPU usage is from all that drawing I guess. Do you even use sleep() ? If not it’s logical that CPU usage is near 100% becouse it’s doing your program all the time.

Yes, I’m sleeping for one millisecond every frame. So I’m assuming this is pretty damn good? So my code should be OK then, right?

OK, I just looked at my code and realized my screen size is actually 640x480x32 at 75mhz. I thought I had it at 1024x768… However, I still get 90 frames per second even at 1280x1024x32 at 75mhz.

UPDATE: I’m so stupid. :frowning: More than like 9/10 of the images weren’t even on the screen. I changed my code to actually draw ALL 5,120 images to screen, and I get only about 30 frames per second (at 1280x1024x32, 75mhz).

Here’s a summery of how many images I can draw at 5 major used resolutions and the average framerated displayed.
320x240, 300 images, 250 frames per second
640x480, 1200 images, 110 frames per second
800x600, 1850 images, 77 frames per second
1024x768, 3072 images, 49 frames per second
1280x1024, 5120 images, 30 frames per second