Skip to main content

Strange drawImage() performance problem

5 replies [Last post]
mungo
Offline
Joined: 2010-05-04
Points: 0

Here's some drawImage() performance problem I don't understand...

For a game I've got an image containing some sprites. For each sprite I create a new BufferedImage using the clip()-method you can see below.
Let's say I've got a sprite A that I can draw a hundred times or so with ~130 FPS and about 10% CPU usage using drawImage() (only sprite A is drawn).
Now, when I create a copy B of A using the copy()-method the FPS suddenly drop to ~60 with 20+% CPU usage (still only A is drawn). If I draw B instead the FPS/CPU are as good as before.

Can somebody explain why drawImage() gets so much slower after creating a copy of the drawn image? What am I doing wrong / how would I do it right?

------

public BufferedImage clip(BufferedImage src, int x, int y, int w, int h) {
BufferedImage newImage = getNewBufferedImage(w, h);
int[] pixels = new int[w * h];
src.getRGB(x, y, w, h, pixels, 0, w);
newImage.setRGB(0, 0, w, h, pixels, 0, w);

return newImage;
}

public BufferedImage copy(BufferedImage image) {
BufferedImage copy = getNewBufferedImage(image.getWidth(), image.getHeight());
int[] pixels = new int[image.getWidth() * image.getHeight()];
image.getRGB(0, 0, image.getWidth(), image.getHeight(), pixels, 0, image.getWidth());
copy.setRGB(0, 0, image.getWidth(), image.getHeight(), pixels, 0, image.getWidth());

return copy;
}

public BufferedImage getNewBufferedImage(int width, int height) {
GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
GraphicsDevice screen = ge.getDefaultScreenDevice();
GraphicsConfiguration gc = screen.getDefaultConfiguration();
BufferedImage newImage = gc.createCompatibleImage(width, height, Transparency.BITMASK);
return newImage;
}

Reply viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.
mungo
Offline
Joined: 2010-05-04
Points: 0

Allright, thanks - I create a copy now like this, which seems to fix the problem:

public static BufferedImage copy(BufferedImage image) {
BufferedImage copy = getNewBufferedImage(image.getWidth(), image.getHeight());
copy.getGraphics().drawImage(image, 0, 0, null);
return copy;
}

So, hardware acceleration gets disabled by just _accessing_ the RGB data using getRGB(), although the data doesn't actually get changed? If so, how do I acess pixels of an image without disabling hardware acceleration? Creating a copy of the image which doesn't get drawn and accessing its pixels would probably work, but seems kinda strange...

linuxhippy
Offline
Joined: 2004-01-07
Points: 0

> So, hardware acceleration gets disabled by just
> _accessing_ the RGB data using getRGB(), although the
> data doesn't actually get changed?

Yes right, because the data has to be copied from video-ram back to system-memory which is horrible slow. The penality is so high that it usually destroys any advantage of having hardware accelerated rendering.
Another problem is, if you access pixel-by-pixel how much of the image should get copied to system-ram.

> Yeah, more great engineering by the SUN Java team.
Please, demonduck, stop your personal attacks and use Flash instead or sit down and write the code.
Just because *you* think its important, doesn't mean its the case for everybody.

Whats the problem with using a temporary BufferedImage? This way you gain full control of the migration process - and its the most efficient way you can do.

- Clemens

mungo
Offline
Joined: 2010-05-04
Points: 0

> Whats the problem with using a temporary
> BufferedImage? This way you gain full control of the
> migration process - and its the most efficient way
> you can do.

Not really a problem, just counterintuitive. And since the documentation of BufferedImage doesn't say anything about hardware acceleration I wasn't sure whether this is the correct way or just another performance trap ;)

Thank you both for your help!

johnpm
Offline
Joined: 2005-06-15
Points: 0

Accesing the image RGB data directly disables hardware acceleration. You could make a copy by drawing the source image into the destination image.

demonduck
Offline
Joined: 2008-03-14
Points: 0

Yeah, more great engineering by the SUN Java team. I tried
and tried to tell them about the importance of direct pixel
access and keeping hardware acceleration in all instances but
was repeatedly told "...use BufferedImage..." as if that
was a cure all.

I hope they are all happy in their new jobs....