Accelerating BufferedImages

I know that my BufferedImages are not accelerated
by using


buffer.setAccelerationPriority(1.0f);
System.out.println(""+buffer.getCapabilities(MainGraphicsFrame.gc).isAccelerated());
System.out.println(""+buffer.getAccelerationPriority());

With the first one I can change the Priority and test it
with the third one.
With the second I know, that my BufferedImage buffer is not accelerated…
But I don´t know how to change this, the priority is worth sh… for this matter
because it doesn´t help me at all to have 400 PS in my car when there´s
no accelerator :wink:

I know you know how to do this,
please help me.
It´s really important to accelerate tile-images for a tile-based game , I guess ::slight_smile:

What I want to say is
how does it help me to change the priority of acceleration if
it isn´t even active.
So how can I tell Java to accerlerate certain Images ?

It depends on how you load the BufferedImages into memory. Here’s the code I use:

public static BufferedImage loadImage(final InputStream inputStream) {
	//load the file
	BufferedImage image = null;
	try {
		image = ImageIO.read(inputStream);
	} catch(Exception exception) {
		if(image == null)
			return null;
	}

	//NOTE: Use "copyImage" instead of "bufferImage" to keep alpha channel transparency
	//that is stored in the file.
	return ImageUtil.copyImage(image);
} //end loadImage

And here’s the copyImage method:

public static BufferedImage copyImage(final BufferedImage image) {
	int width = image.getWidth();
	int height = image.getHeight();
	return createImage(width, height, image.getType() != BufferedImage.OPAQUE,
		image.getRGB(0, 0, width, height, null, 0, width));
} //end copyImage

public static BufferedImage createImage(final int width, final int height,
	final boolean shouldTransparencyBeAllowed)
{
	//get the GraphicsConfiguration
	GraphicsConfiguration graphicsConfiguration = GraphicsEnvironment.
		getLocalGraphicsEnvironment().getDefaultScreenDevice().getDefaultConfiguration();

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

I believe the main idea is that you have to use GraphicsConfiguration.createCompatibleImage to make the image actually get accelerated. I guess the image’s data has to match the screen resolution, color depth, etc.

It’s sort of silly that it matters which methods you use to load the BufferedImages, but that’s the way it is. It should create “compatible” images unless told otherwise, but it only creates them when you use a method like GraphicsConfiguration.createCompatibleImage.

Hi
Thanks for your help which I really appreciate :slight_smile:
I’ve been thinking a lot about this matter and this
is not the first game where I thought:
Let’s do it better this time :wink:
But I wonder why it still isn´t accelerated…
I used the


createCompatibleImage()

method and it´s still the same, not even one accelerated BufferedImage.
It´s the same with BufferedImages created by the program.
I use 3*3 BufferedImages for the ground in my RPG´s world,
so I can easily scroll through the world.
I already don´t draw the ground every frame because of the FPS dropping.
I hoped accelerating would change this a bit.
In general I wouldn’t mind not redrawing the tiles at all because once they are on
the BufferedImage I just need to put that on the screen.
But what to do if there´s animation in the groundtiles, f.e. with water ?
Is it maybe something with my Java (jre1.6.0_07), or Windows XP that
doesn´t allow this ?
Or should I use some other Image like VolatileImage?
Although I must admit that I didn’t really get the advantages of it :-
If you need more data, please say so.
I also checked my memory and Java says there’s ~255 MB of accelerated memory available…

Maybe you have too many images? It only accelerates the images that are used the most.

How big is the frame? You have to take into account that the entire screen has to be stored on the graphics card. If your frame is some huge high-resolution thing, it might take up alot of MB on its own.

Are you using BufferStrategy for rendering? If you’re doing something weird for drawing to the screen, it might screw everything up.

Honestly, I don’t know what the problem is, but I’m surprised you haven’t gotten a ton of responses. This is a common problem.

Have the results of the following code changed?

System.out.println(""+buffer.getCapabilities(MainGraphicsFrame.gc).isAccelerated());
System.out.println(""+buffer.getAccelerationPriority());

It has nothing to do with Windows XP, and image acceleration has worked since java 5 (or maybe even java 4). Still, upgrading to the newest JRE can’t hurt.

Using VolatileImage shouldn’t solve your problem. BufferedImages usually get accelerated just fine. If you use VolatileImage, you’ll basically be rewriting the code that manages BufferedImages.

I just have 9 images to be accelerated
with the same size as the screensize which is 1280*1024.
But I think there has to be enough memory available.
I start the game with a .bat-file containing the entry:


-mx1024M

And 1,5 GB RAM and a 8600 GTS should do the job.
I already used the Fullscreen-mode with BufferStrategy as you mentioned
which in fact gives me more FPS.
But this has nothing to do with my BufferedImages because they are, as said above,
offscreen-buffer.
I use them to draw tiles onto and put the buffer on the screen using BufferStrategy
as suggested in the Sun tutorial.

The results of the code didn´t change.


System.out.println(""+buffer.getCapabilities(MainGraphicsFrame.gc).isAccelerated());
System.out.println(""+buffer.getAccelerationPriority());

It still has no acceleration.
If you´d say these images are to much for my memory I must say
that I print the capabilities for everey single image and it´s always the same:
false and 0.5
At least the first one should have enough memory to use.

If this is a common problem then why can´t Sun solve this ? :-
Maybe when Java 1.7 is released…

I am not sure, but isn’t it true that Java 2D learns what to accelerate and what not? So if you check at the very beginning of the runtime of your app, it could well be that everything is still unaccelerated, but while your game is running and the images are being drawn, in the background they are being optimized by keeping them in videomemory?

Hi :o
you are permitted to be sure :wink:
I just tried again in my render-loop and
it turns out now all buffer are accelerated after some time.
But still after initializing them they aren´t accelerated at all.
When having done some rendering it happens,
what a surprise.
I guess another Java mystery has been solved ;D
Thanks for that
and welcome to JGO (as it was your first post here).

There is a flag to make them accelerated on first use, but can’t remember it atm…

I thought this was the case too, but just recently I found that it’s not the case in java 6 update n, see this thread:

http://forums.java.net/jive/thread.jspa?threadID=39749&tstart=0

From the java2D man himself, Dmitri T:

I’m not sure why BufferedImages can’t just be wrappers for VolatileImages and do all the checking automagically, I though that was how it worked in older java versions, oh well…

Thanks. I’ve been reading the forum for a while now, but I usually hang around in the forums at java.sun.com :wink: More hostile environment than it needs to be, but it makes me laugh.

Just to note, I find this wiki page to be very helpful in my own research into these matters:

http://gpwiki.org/index.php/Java:Tutorials:VolatileImage

It seems, especially with the excellent forum post that CommanderKeith linked to, that game developers should always use VolatileImage just in case hardware acceleration is available. But I must say it is a murky subject to understand properly.

Thanks again,
that are both really helpful links.
I’ve been into this topic of Volatile Images for some time
but it has always bothered me that they so easily
lose there content.
Then again that goes for the BufferStrategy, too,
which I’m using already, so
maybe after reading that new tutorial in full
I will also use them for my issues.

Wow, I just switched from BufferedImages to VolatileImages and got a speed up from 30 fps to 70!

Yee-hah!

PS: for Pyrodragoon, try this VM option to get output on what java2D is doing:

-Dsun.java2d.trace=,count

The more of these: calls to sun.java2d.loops., the worse, the more of these: calls to sun.java2d.d3d. the better.

I changed my backbuffer also to VolatileImage
but the effect was really bad:
The FPS dropped a bit and for the worst part
when scrolling through the map and redrawing one of the buffers
it needs two seconds to do it.

With


-Dsun.java2d.trace=,count

I got the following:


27317 calls to D3DDrawLine
20 calls to sun.java2d.loops.Blit::Blit(ThreeByteBgr, SrcNoEa, IntArgb)
46 calls to sun.java2d.loops.Blit::Blit(IntRgb, SrcNoEa, IntRgb)
36 calls to sun.java2d.d3d.DelegateSwToTextureLoop::Blit(Any, SrcNoEa, "Direct3D
 Texture")
4896 calls to sun.java2d.loops.DrawGlyphList::DrawGlyphList(AnyColor, SrcNoEa, A
nyInt)
276 calls to D3DDrawGlyphs
48 calls to sun.java2d.d3d.D3DMaskFill::MaskFill(AnyColor, SrcOver, "D3D render
target")
47 calls to sun.java2d.loops.MaskBlit$General::MaskBlit(Any, SrcOverNoEa, IntArg
bBm)
20 calls to sun.java2d.loops.Blit$GeneralMaskBlit::Blit(ThreeByteBgr, SrcNoEa, I
ntArgbBm)
67 calls to sun.java2d.loops.MaskBlit::MaskBlit(IntArgb, AnyAlpha, IntArgbBm)
4916 calls to sun.java2d.loops.Blit::Blit(IntArgbBm, SrcOverNoEa, IntRgb)
15 calls to sun.java2d.loops.Blit$GeneralMaskBlit::Blit(IntArgbBm, SrcNoEa, IntA
rgbPre)
47 calls to sun.java2d.loops.OpaqueCopyAnyToArgb::Blit(Any, SrcNoEa, IntArgb)
561 calls to D3DFillRect
4896 calls to sun.java2d.loops.DrawPolygons::DrawPolygons(AnyColor, SrcNoEa, Any
Int)
15 calls to sun.java2d.loops.MaskBlit$General::MaskBlit(IntArgbBm, SrcNoEa, IntA
rgbPre)
15 calls to sun.java2d.loops.Blit::Blit(IntArgbBm, SrcNoEa, IntArgb)
2537 calls to sun.java2d.d3d.D3DTextureToSurfaceBlit::Blit("Direct3D Texture", A
nyAlpha, "D3D render target")
15 calls to sun.java2d.loops.MaskBlit::MaskBlit(IntArgb, AnyAlpha, IntArgbPre)
20 calls to sun.java2d.loops.MaskBlit$General::MaskBlit(ThreeByteBgr, SrcNoEa, I
ntArgbBm)
47 calls to sun.java2d.loops.Blit$GeneralMaskBlit::Blit(Any, SrcOverNoEa, IntArg
bBm)
45857 total calls to 21 different primitives

27317 calls to D3DDrawLine seems good
but what about
4916 calls to sun.java2d.loops.Blit:
and
4896 calls to sun.java2d.loops.DrawPolygons:
? Is there a way around ?

an increase of 40fps??? That seems a bit excessive :s Are you sure your BufferedImage objects were accelerated? Did you turn transparent images into BITMASK transparency in stead of TRANSLUCENT?

I get 60FPS no problem without VolatileImages (but with BufferedStrategy) and I do a lot of drawing per frame.

No they were TRANSLUCENT… so is that why they weren’t accelerated?!

They really need to be translucent though - otherwise anti-aliased lines on a transparent-background sprite don’t come out anti-aliased when the sprite is painted on another image.

I’m no expert, but blitting is when an image is painted to the screen, and by the looks of it that’s done in software on your VM, rather than d3d. Are you running java 6 update N?

For N=7, yes.
As written above I have jre1.6.0_07 working on my Pc.
I think the images painted to the screen are
my tiles and that´s a lot:
33 buffers with size 12801024 and a tilesize of 128*64
makes 1440 images at first.
When scrolling to a side there is also drawing of 480 images to do.
Tell me if I’m wrong here, but that has to be normal for every tilebased RPG.
Or not ?
Is there any way to do this with 3D, too ?
Of course I would prefer that if it is faster.

Seems like TRANSLUCENT BufferedImages are drawn through the software pipeline only, which is godawfully slow. When you switched to the VolatileImage however, they are now drawn through the D3D pipeline, which is a whole lot faster. That certainly explains the dramatic increase.

If you want more reliable acceleration you should be using jre1.6.0_10.