minimizing image bit depth and resolution for better performance?

my game’s running at 25 Frames per second now. i’m using 24 bit images.
a thought occured to me-an image with a smaller bit depth or with a samller resolution can improve performance. should i go to such extent?

Do you create your images using GraphicsConfiguration.createCompatibleImage(…)? Because I’ve heard that this will match the image bit depth to that of the screen, making some things faster. Also it should be good for “managed images”, meaning it might substantially increase the efficiency (so much, in my experience, that maybe you won’t have to bother about further optimizations).

I normally read an image from a file using ImageIO, then draw it onto another image which has been created by graphicsConfiguration.createCompatibleImage(…), but I’ve also heard that in newer versions of java, some of these things should be taken care of automatically.

indeed.

If you are :-
a) using Java1.4 or 1.5
b) running on Windows
c) have fairly uptodate hardware.
c) doing everything correctly & optimally (not doing any silly effects that rely on unaccelerated functionality)

Then reaching the refreshrate of your monitor (60+ fps) should not be a problem.

hmmm…
i do get my BufferedImage the correct you pointed out, so that’s not the problem.

and i do have all the features mentioned in a),b) and c), so i guess i don’t do d) correctly.
what do you mean by “not doing any silly effects that rely on unaccelerated functionality”?
i do use affine transforms alot…
here’s some code, maybe i’m doing something wrong:
class Body//this represents every drawable item
{
private float X;
private float Y;
private BufferedImage theImage;
private float Angle;
//some initialization code and other stuff here…
public void Draw(Graphics2D g)
{
AffineTransform OriginalTrans=g.getTransform();
g.translate(X,Y);
g.rotate(Angle);
g.drawImage(theImage,-theImage.getWidth()/2,-theImage.getHeight()/2,null);
g.setTransform(OriginalTrans);
}
}
class MyApp extends JApplet
{
private BufferedImage BackBuffer;
private Graphics2D BackGraphics;
private Graphics AppGraphics;
private Body[] theArray;
//…
public void paint()
{
for(int i=0;i<theArray.length;i++)
{
theArray[i].Draw(BackGraphics);
}
AppGraphics.drawImage(BackBuffer,0,0,null);
}

}

“i do use affine transforms alot…”

Thats the reason. Consider switching to lwjgl or jogl. Over there it will be even nicely filtered… for free.

i thought that the 2d api uses the opengl pipeline, and hence trasnforming and rotating are supported by opengl. am i wrong?

not everything supported by opengl is supported by the opengl pipeline.

Transformation and Rotation are. Indeed almost everything useful which supported by OpenGL is used to accalerate the OGL-Pipeline as far as possible.

lg Clemens

but the opengl pipeline is not enabled by default.

Add “-Dsun.java2d.opengl=True” on the command-line, or set the property through code (before any awt components are initialized).

ok,

  1. first of all i’ve tried disabling all the affinetransform related operations (not that the code has any meaning without it, but just to check things out), and the time improvement was about 5 miliseconds, so i don’t think that’s the problem…
  2. silly me, forgot to tell you i’m not running in full screen mode and am not using bufferstrategy (for the meantime i prefer the game to be windowed). do you think that can make 25 milisec diffrerence?

i’ve tried moving to full screen double buffering (using the info in this link: http://javaalmanac.com/egs/java.awt/screen_Flip.html), and it just slowed me down…

Could you re-run your game with the system-property:
-Dsun.java2d.trace=count

and post the output here?

Thank you in advance, lg Clemens

Using BufferStrategy (or manually using a VolatileImage for a backbuffer) is the only way to get your blits hardware accelerated.

It doesn’t matter if you want your game to be windowed, or fullscreen.

thank me? no no, thank you :slight_smile:

here’s the output

36 calls to sun.java2d.loops.MaskBlit::MaskBlit(IntArgb, AnyAlpha, IntArgbBm)
26 calls to sun.java2d.loops.Blit$GeneralMaskBlit::Blit(IntArgb, SrcOverNoEa, IntArgb)
2670 calls to sun.java2d.loops.MaskFill::MaskFill(AnyColor, SrcOver, IntRgb)
692 calls to sun.java2d.loops.Blit::Blit(IntRgb, SrcNoEa, IntArgb)
660704 calls to sun.java2d.loops.Blit::Blit(IntArgbBm, SrcOverNoEa, IntRgb)
26 calls to sun.java2d.loops.MaskBlit::MaskBlit(IntArgb, SrcOver, IntArgb)
50 calls to sun.java2d.loops.DrawGlyphList::DrawGlyphList(OpaqueColor, SrcNoEa, AnyInt)
35 calls to D3DDrawRect
15659 calls to sun.java2d.loops.Blit$GeneralMaskBlit::Blit(IntArgb, SrcOverNoEa, “D3D texture destination”)
20976 calls to sun.java2d.loops.MaskBlit$General::MaskBlit(IntArgbBm, SrcOverNoEa, “D3D texture destination”)
5 calls to GDIFillRect
36 calls to sun.java2d.loops.Blit$GeneralMaskBlit::Blit(IntRgb, SrcNoEa, IntArgbBm)
1344416 calls to sun.java2d.loops.MaskFill::MaskFill(AnyColor, Src, IntRgb)
1268 calls to DDFillRect
36 calls to sun.java2d.loops.MaskBlit$General::MaskBlit(IntRgb, SrcNoEa, IntArgbBm)
14 calls to sun.java2d.loops.Blit::Blit(IntRgb, SrcNoEa, IntRgb)
36635 calls to sun.java2d.loops.MaskBlit::MaskBlit(IntArgb, SrcOver, IntRgb)
20976 calls to sun.java2d.loops.Blit::Blit(IntArgbBm, SrcNoEa, IntArgb)
33 calls to sun.awt.windows.Win32BlitLoops::Blit(“Integer RGB DirectDraw”, SrcNoEa, “Integer RGB DirectDraw”)
406 calls to sun.java2d.loops.MaskBlit::MaskBlit(IntRgb, AnyAlpha, IntArgb)
561 calls to sun.java2d.loops.MaskFill::MaskFill(AnyColor, Src, IntArgb)
2105260 total calls to 21 different primitives

The problem is that your backbuffer appears to be a BufferedImage. Rendering to BI is done via the
software loops. If you want to have acceleration, you’ll need to either have
VolaileImage as your backbuffer, or use BufferStrategy. You don’t have to be in fullscreen
mode to get the acceleration (assuming you’ve enabled it via -Dsun.java2d.opengl=true or
-Dsun.java2d.d3d=true).

Thanks,
Dmitri
Java2D

how did you reach that conclusion?

edit:
anyway, i’ve run ImageCapabilities.isAccelerated() and ImageCapabilities. isTrueVolatile() and they both return true, so i guess you we’re wrong.
anyway,
if i enable -Dsun.java2d.d3d=true, i don’t see any improvment,

and if enable -Dsun.java2d.opengl=true(of course, after disabling d3d), i get the following exception:

Exception in thread “main” java.lang.IllegalArgumentException: Width (0) and height (0) cannot be <= 0
at java.awt.image.DirectColorModel.createCompatibleWritableRaster(Unknown Source)
at sun.awt.image.SunVolatileImage.getBackupImage(Unknown Source)
at sun.awt.image.VolatileSurfaceManager.getBackupSurface(Unknown Source)
at sun.awt.image.VolatileSurfaceManager.initialize(Unknown Source)
at sun.awt.image.SunVolatileImage.(Unknown Source)
at sun.awt.image.SunVolatileImage.(Unknown Source)
at sun.awt.image.SunVolatileImage.(Unknown Source)
at sun.awt.image.SunVolatileImage.(Unknown Source)
at sun.awt.windows.WComponentPeer.createVolatileImage(Unknown Source)
at java.awt.Component.createVolatileImage(Unknown Source)
at java.awt.Component$BltBufferStrategy.createBackBuffers(Unknown Source)
at java.awt.Component$BltBufferStrategy.revalidate(Unknown Source)
at java.awt.Component$BltBufferStrategy.getDrawGraphics(Unknown Source)

Because all your rendering is done in plain software (have a look at the java2d.loops.* innvocations) which explains why its so damn slow.
Which grapiccard do you sue?

lg Clemens

so why do the calls “ImageCapabilities.isAccelerated()” and “ImageCapabilities. isTrueVolatile()” both return true?

anyway my graphics card’s an old one- nvidia geforce 2 mx/mx 400

and why does the initialization fail when i enable opengl?

I think the explanation is that the rendering TO the image is done in software, whereas rendering the image to the screen would be accelerated.If this is the case, every time you draw onto the image, a lot of software stuff occurs. When that is finished, taking horribly long time, the image is transferred via the bus to the graphics card, taking awfully long time, and then, at last, the accelerated image is rendered to the screen as fast as lightning!

As I understand this, the way to overcome this is to let the BufferStrategy take care of the stuff, such that the operations you specify are somehow given to the graphics card which will execute them quickly. So: no drawing onto BufferedImages if you want them accelerated. If you draw once (generate the image or rarely add some damage while the program is running) it probably wouldn’t matter that much, but drawing onto the image every frame is deadly.

That’s my suggestion to what’s going on, I hope it’s correct.

well, that’s a good advice, but i have already implemented it a month ago. currently, i don’t do any drawing to a buffered image. the only drawing that occures is the drawing of the buffered images on to the screen…

besides, that’s not my question :slight_smile: