Saturday, April 2, 2011

Response: Debugging High CPU Usage

Answer to: a comment posted on Double Buffering and Timed Rendering and on Game State Machine about 100% CPU usage with those samples.

Disclaimer: If you modified the examples, I can't help you, lol just kidding, it's a silly thing to have to say but try just redownloading and running the examples without any modifications.

The answer is a bit complicated, high CPU usage might be due to a few things.

Note: One thing I did not do that might make a difference is to use the createCompatibleImage method, this might make all the difference but I've never seen it have any effect. Or you could try using a VolatileImage it has it's own issues though, and I've never seen it have any effect either. If that doesn't work turn on java2D logging using the system properties see link below and look to see how long drawing operations are taking.

Another Note: If not on windows, try turning on opengl rendering and make sure it's actually on, you can verify it by using the "True" string for turning it on, with the capital "T" it will output whether opengl or directx rendering are being used.

Java Version Issues
Using your own buffer and repaint should work decently in Java versions on windows greater than 1.4.1 update 2, when directx support was added and turned on by default. Opengl support was added as of 1.5 but is not turned on by default on any platform, so you'd want to try fiddling with some of these properties. See System Properties docs

Problem with Repaint
In earlier versions of Java using repaint would result in tearing issues, because old swing versions would be not be double buffered. Thus the example with their own double buffering.

Hardware Acceleration Issues
No hardware acceleration will be available if you don't have some type of graphics card or if java has issues with the drivers, so it will only go as fast as the underlining computers CPU can handle in that case. Another issue using BufferedImages is the hardware acceleration can be lost if the bufferedimage raster is modified. Another choice is to use the Canvas approach with BufferStrategy which I have seen much much better performance than either creating a buffer myself .

I haven't seen 100% constant CPU usage with this example myself. If repaint works I do suggest going with what you know works well until you find something better. In the end if looks good and feels good for your game then it doesn't matter which method you use.

Things I tried
Trying to duplicate the 100% CPU usage with the Double Buffering and the Game State Machine examples was unsuccessful. I tried turning off hardware acceleration -Dsun.java2d.noddraw=True still performed as expected. I didn't change any of the code so it was left as is, still no 100% CPU usage, on an old 2.66 GHZ pentium 4 with a NVIDIA GeForce 8400 GS graphics card and tested with Java versions 1.5, 1.6, and 1.7ea without issue.

The only thing I could think of that would cause 100% CPU usage with these examples in their unmodified state is if the TimerTask run method takes more than 16 milliseconds. That would bog down the timer with continuous tasks needing to be fired since the java.awt.Timer is a single threaded queue based task scheduler. I was able to bog down the Timer and see high cpu usage. Haven't tried forcibly making the bufferedimage non-hardware accelerated yet. You could implement your own timer and see if that makes a difference.

I am meaning to work up a new snippet with better rendering methods, and updated code. The BufferStrategy approach link above is a good alternative and much better frame rates. Give that a try if your having trouble, I would also like to know if that works better for most systems. It's been a long time since I did those snippets back in 2007 I have learned a lot since then, still there is much much more to learn.

One Last Thing
I do remember that there was some issues I had on windows with a graphics card installed that slowed my rendering significantly, those were the options in the Display Properties -> Settings (tab) -> Advanced -> Troubleshoot (tab) the Hardware Acceleration, I have seen it have interesting effects at different levels with some of my Java games projects.

For further help just ask and you shall receive, of course more details next time would help tremendously.

Good Luck!


Thi Võ said...

Thank you for your kind assistance, I've just resolve that problem,just need change a bit
it's in the line create back buffer image
bufferImage=new BufferedImage(WIDTH_WINDOW, HEIGHT_WINDOW, BufferedImage.TYPE_INT_ABGR);
I change the third parameter to "...TYPE_INT_RGB" (just delete "A":D)or other types, very easy but it's costs me too much time ^^
thank you anyway

MorbidMorvick said...

Your welcome, sorry I didn't respond sooner.

The "A" is for the alpha channel, so it would seem your Java environment was having problems hardware accelerating images with alpha. You should try
-Dsun.java2d.translaccel=true on the command line it's only necessary with Java versions older than 1.5 beta 1 according to the docs. This might be your issue. You might want to try the createCompatible image as different display environments may be setup to use a different color models. I should change the examples to use that instead of add the translaccel flag for compatibility reasons like this.

The problem with image formats is that you will have to manage them if you don't use all 32 bit images. Converting when necessary compositing those that don't require alpha without converting them. I tend to stay away from issues with image formats as much as possible.

If you don't have the alpha channel I believe you will have further issues drawing images with transparent sections or they will also make things run slowly. Alpha channels are a big part of techniques used in games, Java 2D does not provide some basic blending operations which most games utilize. Such as a blending function

Post a Comment