Friday, March 29, 2013

Java Image Acceleration

This is something that took me a long time to figure out. But that might help you if your seeing java performance issues when rendering sprites or other images.


Speeding up image rendering


While working on a game that was using sprite sheets with a background color instead of transparent PNGs. I found that my rendering code was slowing down significantly especially in fullscreen mode. I did some research and found out that Java images have to be hardware accelerated and won't be if the raster is modified directly. Something I had assumed would happen automagically. The problem arises from modifying an Images raster on the CPU and not automatically reallocating it on the GPU.


Check Image Capabilities


There is a check to see if a given image is hardware accelerated. It's in ImageCapabilities which you can get for any java.awt.Image for a given GraphicsConfiguration which is different per GraphicsDevice. There is also setAccelerationPriority method but I don't believe you would want to rely on it for games as much. You should definitely give it a test especially if you don't want to convert all images over to using VolatileImage's which can loose their handle to video memory in certain circumstances akin to DirectX's hardware reset that usually happens in windows when Alt+Tabbing between a fullscreen exclusive application and another windowed application.

Creating Accelerated VoltaileImage's

I've relied on the GraphicsConfiguration function for creating these VolatileImage's. createCompatibleVolatileImage or on the java.awt.Toolkit function with the same name. There are a couple of overloaded methods that you can use to successfully create accelerated images. Combine this and the check in the ImageCapabilities to make sure you've created an image that is going to be accelerated.

Transparency

This is yet another tricky spot, I always make sure to set the following -D or system property flags for explicitly turning on either opengl or directx rendering. The flags I use are

// either

System.setProperty("sun.java2d.opengl", "True");
// or
System.setProperty("sun.java2d.d3d", "True");
System.setProperty("sun.java2d.ddforcevram", "True");
// and

System.setProperty("sun.java2d.transaccel", "True");

The capital T in True actually tells java2d to output to the console whether the accelerated rendering system was enabled this sometimes can be installation and system configuration dependant. I've had issues on some systems with both OpenGL and DirectX where they should be working but for some yet unknown reason they don't. I've also had issues with a WindowsXP hardware acceleration setting on the desktop causing sometimes reverse effects to java applications, when I figure this out I'll let you know. You'll get a message like this "OpenGL pipeline enabled for default config on screen 0" in your console or "Direct3D pipeline enabled on screen 0"

You can also optionally add logging to java2d to debug long rendering operations using:

System.setProperty("sun.java2d.trace", "timestamp,log,count");

*Warning* opengl driver support is kind of iffy on some NVIDIA cards on Windows, not sure what exactly the issue is but I have had reports of slow rendering with SLI cards. You'll have to experiment and offer a way of switching the flags that are turned on in order to get better performance. Additionally on a laptop I've had issues initializing DirectX I need to investigate more on that.


Test Code