Accelerated Image with Transparency.BITMASK on Linux

Hi all,

Im trying to use accelerated graphics for my game. I just discovered my VolatileImage were not accelerated. From [1], in the 1.5 API, only OPAQUE images were accelerated. I can’t find any info regarding this with the 1.6 API. Somwhere on your forum, i see that only BufferedImage can be accelerated with transparency, but my code below shows that my BufferImage are never accelerated. My question is simple : how do i get an accelerated transparent image with Transparency.BITMASK on Linux (and, hopefully, all platforms)?

The code below is a small test i wrote while trying to figure out how to do this.


/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package abricots.test;

import java.awt.AWTException;
import java.awt.GraphicsConfiguration;
import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment;
import java.awt.ImageCapabilities;
import java.awt.Transparency;
import java.awt.image.VolatileImage;

/**
 *
 * @author cghislai
 */
public class testAccel {

    public testAccel() {
        GraphicsEnvironment graphicsEnvironment = GraphicsEnvironment.
                getLocalGraphicsEnvironment();
        for (GraphicsDevice graphicsDevice : graphicsEnvironment.
                getScreenDevices()) {
            System.out.println("DEVICES : " + graphicsDevice.getIDstring());
            System.out.println("   - MEM :" + graphicsDevice.
                    getAvailableAcceleratedMemory());
            System.out.println("   - DISPLAYCHANGE : " + graphicsDevice.
                    isDisplayChangeSupported());
            System.out.println("   - FULLSCREEN : " + graphicsDevice.
                    isFullScreenSupported());
        }
        GraphicsDevice graphicsDevice = graphicsEnvironment.
                getDefaultScreenDevice();
        GraphicsConfiguration graphicsConfiguration = null;
        for (GraphicsConfiguration gc : graphicsDevice.getConfigurations()) {
            System.out.println("CONFIGURATION : " + gc.toString());
            System.out.println("   - BOUNDS :" + gc.getBounds().
                    getWidth() + " x " + gc.getBounds().
                    getHeight());
            System.out.println("   - BUFFER : FullScreenRequired:" + gc.
                    getBufferCapabilities().isFullScreenRequired());
            System.out.println("   - BUFFER : Multi:" + gc.getBufferCapabilities().
                    isMultiBufferAvailable());
            System.out.println("   - BUFFER : PageFlipping:" + gc.
                    getBufferCapabilities().isPageFlipping());
            System.out.println("   - BUFFER : BackBuffer Accelerated:" + gc.
                    getBufferCapabilities().getBackBufferCapabilities().
                    isAccelerated());
            System.out.println("   - BUFFER : FrontBuffer Accelerated:" + gc.
                    getBufferCapabilities().getFrontBufferCapabilities().
                    isAccelerated());

            System.out.println("   - IMAGE :  Accelerated:" + gc.
                    getImageCapabilities().isAccelerated());
            System.out.println("   - COLOR MODEL : " + gc.getColorModel().
                    toString());


            if (gc.getBufferCapabilities().isPageFlipping() &&
                    gc.getBufferCapabilities().
                    getBackBufferCapabilities().isAccelerated() &&
                    gc.getBufferCapabilities().
                    getFrontBufferCapabilities().isAccelerated() &&
                    gc.getImageCapabilities().isAccelerated() &&
                    gc.getColorModel(Transparency.BITMASK) != null) {
                graphicsConfiguration = gc;
                break;
            }
        }

        VolatileImage im = graphicsConfiguration.createCompatibleVolatileImage(
                20, 20);
        System.out.println("VImage accelerated :" + im.getCapabilities().
                isAccelerated());
        im = graphicsConfiguration.createCompatibleVolatileImage(
                20, 20, Transparency.BITMASK);
        System.out.println("tr VImage accelerated :" + im.getCapabilities().
                isAccelerated());
        ImageCapabilities caps = new ImageCapabilities(true);
        try {
            im = graphicsConfiguration.createCompatibleVolatileImage(20, 20,
                                                                     caps,
                                                                     Transparency.BITMASK);
        } catch (AWTException ex) {
            System.out.println("Cant create accel VImage");
        }

        BufferedImage bim = graphicsConfiguration.createCompatibleImage(
                20, 20);
        System.out.println("BImage accelerated :" + bim.getCapabilities(graphicsConfiguration).
                isAccelerated());
        bim = graphicsConfiguration.createCompatibleImage(
                20, 20, Transparency.BITMASK);
        System.out.println("tr BImage accelerated :" + bim.getCapabilities(graphicsConfiguration).
                isAccelerated());

    }
}


Thanks,

Charly

[1] http://java.sun.com/j2se/1.5.0/docs/guide/2d/new_features.html

BITMASK Volatile images aren’t accelerated in 1.5 or 1.6.

Why would you need to use one? VI is typically used as a back-buffer (better yet, of course, to use BufferStrategy for that).

In 6u10 TRANSLUCENT VIs are accelerated on Windows. On Linux, only with OpenGL pipeline enabled (since 1.5).

Dmitri

To clarify: use TRANSLUCENT VI instead of BITMASK if you really need non-opaque VIs.

Thanks for reply. I was using VolatileImage because i found on the blog of one java graphic developper that they are good for managing acceleration. In addition, i tested accelerated TRANSLUCENT BufferedImage and VolatileImage ; only the last one gets accelerated.

I use 1 big volatile image as a backBuffer in addition of a buffer strategy. The buffer strategy holds the screen buffer, while my own buffer holds the whole game area. different cameras can point to different parts of the game area and render them on screen at the same time, so i draw needed sprites on my back buffer and draw part of it to the strategy. I use this to avoid drawing the same sprite more than one time when more than one camera sees it.

Anyway, thanks for reply, accelerated TRANSLUCENT VolatileImage works fine using the opengl pipeline. Can you provide a reliable source for this information? I guess ive skipped this during my searches…

Regards,

Charly

trembovetski is probably the most reliable source of info you can get for anything Java2D :wink:

Well, BufferedImages and VolatileImages serve different purposes, so they “manage acceleration” in differet ways.

Typically you’d use VolatileImage as a backbuffer, because rendering to such image can be accelerated (as well as from). And you’d use BufferedImage for sprites and other things that don’t get changed often, since rendering from such image can be accelerated (once it gets cached in video memory).

You can get all fancy and use non-opaque VolatileImages for sprites (typically to save heap space) but it’s more hassle, and as you found out sometimes they can’t be accelerated.

I would think that you’d want an Opaque VolatileImage for this case, not translucent or bitmask. Opaque VIs have the most chances of being accelerated across platforms and jdk versions.

Unfortunately there isn’t really a single source where you can get this kind of information.
There are some articles here and there, but they’re mostly obsolete since they were written for 1.5 or pre-6u10.
One of these days I’ll find time to write up something.

Dmitri

Youre right, using transparency on my buffer is useless. But regarding my sprites that need to be rotated, i think i need both of them: a BufferedImage holding the sprite image, the one loaded from file; and a VolatileImage holding the real image that is copied to my buffer. When the sprite’s angle has changed, i clear the volatile and copy the Buffered applying the rotation.
Or is it better to just keep the Buffered one and apply the rotation when copying it to the buffer? I thought rotation was an heavy operation and i could skip if if uneeded by holding a copy of the rotated sprite.

So, to summary all this up ; correct me if Im wrong :

  • Drawing TO and FROM VolatileImage is accelerated.
  • Drawing FROM BufferedImage is accelerated once it has been cached in VideoMemory (thats automatically done when image is copied several times)
  • BITMASK Volatile images aren’t accelerated in 1.5 or 1.6.
  • TRANSLUCENT Volatile images are accelerated on Windows or, using OpenGL pipeline, all platforms.
  • OPAQUE Volatile images have the most chances of being accelerated across platforms and jdk versions.

Thanks,

Charly

I hate to say it, but you’ll be much more productive if you use Slick.

It ‘just works’. Something that cannot be said for the Java2D pipeline.

Yeah, Slick seems really good… But I’d really like to know the java capabilities (lwjgl uses opengl directly, im I wrong?), so Ill continue using only sun’s java libs for now. Anyway, as i designed things, it really shouldn’t be hard to switch to Slick, just a matter of implementing a couple of interfaces.

And regarding productivity, im somewhat satisfied. Things are going forward. Im just making sure everything works fine before adding more contents and logic.

If the image transform operation is hw accelerated (which it is with the opengl or d3d pipelines), image rotation is basically free as it’s a simple texture mapping operation. If there’s now hw acceleration then indeed it may be better to cache the rotated version. But the latter only makes sense if you make more than one copy from this cached image.

If your rotation angles are predetermined you can pre-render all rotated versions into a single sprite sheet - an image containing all possible rotations of your sprite (either at run time or at build time) and just copy the corresponding rotated version from that sprite sheet
using drawImage(src rect, dst rect) variant.

Yes.

Correct. There are cases when BI can’t be cached (like if you got a hold of the data buffer, or if the image is too large, or if this type of image can’t be cached - like translucent images on Linux w/o the opengl pipeline).

Correct.

Correct. See the D3D pipeline section in 6u10 release notes for details: http://java.sun.com/javase/6/webnotes/6u10.html .

Yes. However, even if the image is “accelerated” it may not mean that all kinds of rendering operations are
accelerated. For example, in pre-6u10 jdk on windows only simple blits were hw accelerated (unless you
enabled the d3d pipeline with -Dsun.java2d.d3d=true), but not the transforms.

It’s unfortunate that our hw-acceleration story is so complicated. =(

Thanks,
Dmitri

To be fair, Java2D does always work because it has a software pipeline to fall back on. But performance is highly variable.

On the other hand, frameworks relying on OpenGL often do not work at all due to driver problems. But if it does work, it’s lightning fast.

Thanks, rendering is effectively as fast as light doing the rotation each frame, and the code is really clearer.
I use opengl pipeline so it should work on all platform.

In fact it makes sense once you think about it. One should just know how rendering is done in all case. Your answers and this article (http://today.java.net/pub/a/today/2004/11/12/graphics2d.html) might help.

Regards,

Charly

It’s a failure of the abstraction if you need to know what is going on ‘under the hood’.