CPU usage in a pure Java2D game

Hi all.
I would talk about the CPU usage in a pure Java2D game (developed using only BufferStrategy or VolatileImage/BufferedImage).
In these months I’m developing a sort of wrapper library to simplify the implementation of 2D-games, but I got some problems concerning the CPU usage. For the creation of a Animation I instancied an ArrayList with the sequence of BufferedImages, every N milliseconds I change the index of the ArrayList to simulate the animation. Therefore in the Game Loop there is an update of Animation and a getCurrentImage method to show the animation on the screen (to do this I used a BufferStrategy).

With 50 Animations (composed by Images of 60 pixels by 60 pixels, more or less) and a 640 by 480 resolution with 32 bit of colors (full-screen mode) the CPU ratio (I watched it with TaskManager) is about 5%-10%; with 100 animations I got 50%-60%; with 150 animations I got 75%-85% and with more than 150 I always have 100%. The Animation is updated every 80 milliseconds.

The “engine” goes well and it’s faster enough, but I would like to know if there is a way to decrease the CPU usage. I mean for example there is the way to show the Sprites and the rest splitting the Images in tiles, but this helps? Other methods?

could you run your game with -Dsun.java2d.trace=count and post the results.
Could it be that you fallback to software-rendering?

lg Clemens

Whoa! :o I don’t understand anything, but if for you it’s a help to understand…

388750 calls to sun.java2d.loops.Blit$GeneralMaskBlit::Blit(IntArgb, SrcOverNoEa, "D3D texture destination") 2 calls to sun.java2d.loops.Blit$GeneralMaskBlit::Blit(IntArgb, SrcOverNoEa, IntArgb) 765 calls to DXFillRect 1 call to GDIFillRect 760 calls to sun.awt.windows.Win32BlitLoops::Blit("Integer RGB DirectDraw", SrcNoEa, "Integer RGB DirectDraw") 389293 calls to sun.java2d.loops.MaskBlit::MaskBlit(IntArgb, SrcOver, IntRgb) 2 calls to sun.java2d.loops.MaskBlit::MaskBlit(IntArgb, SrcOver, IntArgb) 780116 total calls to 7 different primitives

So what is that? ???

Well left you see how often the number how often your a rendering-pipeline-functionality was called and right you see the type of the operation.

Your log shows that about 98% of the rendering your application does is in software which means very low performance…
So basically you now need to figure out why Java2D falls back to software rendering. Do your images contain translucent areas? Do you draw them translated?

lg Clemens

Btw, can u explain which calls are software rendering ones?Is there a web page explaining this trace?

I don’t know wether its documented at all, but stuff with “loops” in it most likely means software.
Since its renedered in a software-loop :wink:

lg Clemens

Great… :-\ I thought to have solved this problem in my code, so it seems there is still something wrong. Mmh… maybe when I load the Images? In your opinion is it better to load images with ImageIO? I said that because I load my images with ImageIcon and then I convert them in BufferedImage in this way:


public static BufferedImage loadBufferedImage(String path) {
...
    ImageIcon i = new ImageIcon(path);
    BufferedImage bi = new BufferedImage(i.getIconWidth(), i.getIconHeight());
    bi.getImage().getGraphics().drawImage(i.getImage(), 0, 0, null); // image, width, height, image observer
    return bi;
}

but maybe it’s not the right method…

I don’t see why this should be wrong (which java-version are you testing on?) but why don’t you simply use the toolkit-image ImageIcon gives you with getImage()? However the way you load your images indicates that there is no problem with translucency., which I thought would be the problem.

And you really draw to a BufferStrategy?

lg Clemens

The image you’re actually using is the image you’re creating with the BufferedImage constructor. I don’t believe you get image acceleration when you use the BufferedImage constructors. I don’t know why you wouldn’t - I’m just pretty sure you don’t. Use ImageIo instead.

You also aren’t disposing the Graphics object you use, but I don’t think that’s the problem.

BufferedImages are managed (automatically accalerated) since Java-5.

Well thats not needed.

lg Clemens

yeah but you still need to create compatible image and then draw your image onto it to make it accelerated.

No (as far as I know, however it can be I tell garbage again), an accalerated “copy” of BufferedImages are automatically created as soon as some accaleration heuristics are triggered. (e.g. blitted more than x times with no modification, …)

lg Clemens

Well before the game loop I do this:


frame.setVisible(true);
frame.createBufferStrategy(2);
graphics = (Graphics2D) frame.getBufferStrategy().getDrawGraphics();

and I use the object ‘graphics’ to draw everything and then when I finished I call frame.getBufferStrategy().show(). I think it’s right or not?
I tried to hide all the unnecessary code for the drawing operation, but the CPU usage is still high.

Uh! Last thing I use Java 1.5.0 u11, I began with this version and I want to wait some time to pass to 1.6.0.

Thanx a lot to everybody! ^____^

Yeah, that’s what I thought also, but if you just load an image into BufferedImage using ImageIO it (probably) won’t be accelerated, same thing if you create a compatible BufferedImage and then load your raster, it never got accelerated in my game. I asked about this here and got an answer to draw image onto compatible one, it worked.

I also tried your method Kova, but at this point it seems there is some problems with accelerated images on my machine (a notebook with a Mobility Radeon 9600 and 64Mb VRam)… ??? Perhaps do I have to put some command flags? Such as opengl-pipeline or something like that?

UPDATE: Great Gaia! Every time I run my application with this flag -Dsun.java2d.opengl=true I got this error:
`

An unexpected error has been detected by HotSpot Virtual Machine:

EXCEPTION_ACCESS_VIOLATION (0xc0000005) at pc=0x694085d0, pid=1952, tid=516

Java VM: Java HotSpot™ Client VM (1.5.0_11-b03 mixed mode, sharing)

Problematic frame:

C [atioglxx.dll+0x4085d0]

An error report file with more information is saved as hs_err_pid1952.log

If you would like to submit a bug report, please visit:

http://java.sun.com/webapps/bugreport/crash.jsp

`

:’(

Maybe your video card doesn’t have opengl drivers for some reason?

Try using this code for creating the image that is supposed to be accellerated:

//get the GraphicsConfiguration
GraphicsConfiguration graphicsConfiguration = GraphicsEnvironment.
	getLocalGraphicsEnvironment().getDefaultScreenDevice().getDefaultConfiguration();

//this enables/disables transparency and makes the Image more likely to be managed
BufferedImage compatibleImage = graphicsConfiguration.createCompatibleImage(width, height,
	shouldTransparencyBeAllowed ? Transparency.BITMASK : Transparency.OPAQUE);

I have code like this in a “createImage” method because my games essentially slow to a standstill when I don’t use this code. I believe that this “compatible” image business was a feature added to Java relatively late to allow image acceleration. It would be better if all BufferedImages were compatible unless you called a special constructor that has a “mustBeCompatible” boolean parameter, but that’s not the way it is. Hence, there’s alot of confusion.

I already tried this method but nothing doing. I also tried to search something about this problem and I found a bug report concerning this error, in Java 1.6.0 it is fixed but for my graphic card the problem still remains.

It’s very probably that the created graphics drivers for my notebook (an ASUS As2500D) have some problems with OpenGL. It’s only an assuption, because I do not find anything about that.

You don’t need OpenGL at all for accalerated image-blitting, it should happen even with the GDI/DDraw default pipeline.
Could it be that you have too many images created so that you run out of VRAM? How much video-ram do you have?

lg Clemens

I just want to add that not so much ago (like 2-3 weeks) someone also stated that acceleration doesn’t work with his laptop, it was something about VRAM, BufferStrategy wasn’t accelerated or something. As I remember campbell or trembovetski answered and told bufferstrategy is broken with vram.

edit: oh, here it is, hope you’ll find it usefull

I understood (but if not please tell me) that: is it a bug in the BufferCapabilities class? But if I use a library such as Java3D or LWOGL or another, do I solve my problem?
Another question:


bufferStrategy.getCapabilities().getFrontBufferCapabilities().isAccelerated() returns true
bufferStrategy.getCapabilities().getBackBufferCapabilities().isAccelerated() returns true
bufferStrategy.getCapabilities().getFrontBufferCapabilities().isTrueVolatile() returns false
bufferStrategy.getCapabilities().getBackBufferCapabilities().isTrueVolatile() returns false

And:
GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getAvailableAcceleratedMemory() returns (more or less) 119000000

Is it right? Or not? I mean I understood that the first 4 methods if Java uses Accelerated Memory they must return true, is it right? But in my case the third one and the forth one return false. Last strange thing is the result of the fifth method because it returns 119000000 so it seems that my graphic card has almost 128Mb RAM but in reality my ATi Mobility Radeon 9600 has only 64Mb RAM on my notebook…

Did I misunderstand something? ???