How can I create a hardware-accelerated image with Java2D?
I'm trying to create a fast image generator that does lots of 2d transformations and shape rendering, so I'm trying to use a BufferedImage and then acquire the Graphics2D object to perform all my drawing. My main concern now is to make is really fast so I'm creating a BufferedImage like this:
GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
GraphicsConfiguration gc = ge.getDefaultScreenDevice().getDefaultConfiguration();
BufferedImage bImage = gc.createCompatibleImage(width, height, Transparency.TRANSLUCENT);
Graphics2D graphics = bImage.createGraphics();
However if I do:
System.out.println(bImage.getCapabilities(gc).isAccelerated());
The output is always false, even if I start the JVM with -Dsun.java2d.opengl=True which prints the line:
OpenGL pipeline enabled for default config on screen 0
I'm doing a BufferedImage because in the end I want to save it to a PNG file with ImageIO.write(bImage, "PNG", file);
I can create a VolatileImage which will say that it is accelerated but ImageIO doesn't like it when trying to save, saying that that image cannot be casted to RenderedImage. Any 开发者_开发知识库ideas on how to get an accelerated image that can be stored to disk? Also I don't want to create a VolatileImage and the copy to a BufferedImage to save since my images are really big and I'll run into out of memory issues...
From my investigation and reading the Sun/Oracle 2D tutorial this is what I've found:
To create an accelerated image one can either use the volatile image, which is created as a pbuffer. There are advantages and disadvantages, VolatileImages are fast until you try to get the raster pixel data. At that moment they become a normal bufferedImage. Also they are volatile and there is no guarantee that it will be available in the end of your rendering. To do this you execute:
GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
GraphicsConfiguration gc = ge.getDefaultScreenDevice().getDefaultConfiguration();
VolatileImage vImage = gc.createCompatibleVolatileImage(width, height, Transparency.TRANSLUCENT);
This will get you a accelerated image, however it is not possible to use the ImageIO to write it directly to say a PNG file.
In order to use a normal BufferedImage you need to do something like:
GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
GraphicsConfiguration gc = ge.getDefaultScreenDevice().getDefaultConfiguration();
BufferedImage img = gc.createCompatibleImage(width, height, Transparency.TRANSLUCENT);
img.setAccelerationPriority(1);
This creates a BufferedImage which is not accelerated but you give the hint to the JVM that is should by passing 1 in setAccelerationPriority. This you can read on the 2D trail of the Java Tutorial.
Try adding this to your command line:
-Dsun.java2d.accthreshold=0
EDIT
I did some reading on this after you said the above didn't work. Try changing the True on the OpenGL parameter to be all lowercase.
-Dsun.java2d.opengl=true
Here is how it works:
The way you create the image is correct. But Java does not accelerate the image right away. There is a threshold of render calls that need to be directed at your image after which the image will be accelerated. But if you set the following,
-Dsun.java2d.accthreshold=0
your image should be accelerated the moment you create it.
You might still have to use the image somehow for it to become accelerated. For example, i have the following code piece that is used to copy a loaded image (loading through ImageIO will give you an image that can not be accelerated) into my new BufferedImage.
Graphics2D g2d = bufferedImage.createGraphics();
g2d.drawImage(image,0,0,null);
g2d.dispose();
Before this code segment, the BufferedImage is not accelerated, afterwards it is.
But beware, if you manipulate the image data directly (i.e. not through Java-2d) your image will no longer be cached in VRAM and you have to copy it over to a new Managed Image in order to regain your acceleration.
精彩评论