Info:HW support for translucent images in 1.4.1_02

Here’s that long-time-ago promised information on some of “hidden” features in 1.4.1_02.

In 1.4.1_02, we’ve implemented a number of features
mostly dealing with acceleration of translucent
images in hardware using Direct3D. Unfortunately we
didn’t have enough time to test them appropriately,

so we had to disable them by default for now.

Please note that flags mentioned here are ‘for educational purposes
only’, and can (and most likely will) be changed in the future
releases.

Note: Always make sure you have the latest video drivers installed.
Also, we recommend at least DirectX 7 to be installed.

  1. Acceleration of translucent images
    Images created with
    • GraphicsConfiguration.createCompatibleImage(w,h, Transparency.TRANSLUCENT),
    • Toolkit images (those loaded with Toolkit.getImage()) with
      translucent color model
      will be attempted to be accelerated in vram.

Disabled by default, enabled via flag:
-Dsun.java2d.translaccel=true
You will also need to set the following flag:
-Dsun.java2d.ddforcevram=true

With this flag set Java2D will attempt to put images created as
mentioned above into vram, and use D3D for rendering (compositing)
them to the screen or to a VolatileImage.
Currently only translation transforms are supported (no rotation,
scaling, etc).

The following code fragment illustrates the use of accelerated
images. The fragment assumes that backBuffer is a VolatileImage.
BufferStrategy can be used as well.


    Image translucentImage = gc.createCompatibleImage(w, h, Transparency.TRANSLUCENT);
    //...
    Graphics2D g2 = (Grahics2D)backBuffer.getGraphics();
    g2.drawImage(translucentImage, x, y, null);
  

Compositing with extra alpha with SRC_OVER rule (which is
the default Graphics2D compositing rule) is accelerated, so the
following code will allow the use of hardware for compositing:


    Image translucentImage = gc.createCompatibleImage(w, h, Transparency.TRANSLUCENT);
    // ...
    float ea = 0.5;
    Graphics2D g2 = (Grahics2D)backBuffer.getGraphics();
    g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, ea));
    g2.drawImage(translucentImage, x, y, null);
  
  1. 16-bit 4444 image format support.
    2.1. Software loops support:
    4444 image format is 16-bit per pixel image format, ARGB.
    It’s useful if you’re trying to save some memory, as it takes half
    as much memory as TYPE_INT_ARGB.
    One can create an Argb 4444 BufferedImage like this:

     private static final int DCM_4444_RED_MASK = 0x0f00;
     private static final int DCM_4444_GRN_MASK = 0x00f0;
     private static final int DCM_4444_BLU_MASK = 0x000f;
     private static final int DCM_4444_ALP_MASK = 0xf000;
     static ColorModel translucentCM = null;
     public static ColorModel getTranslucentColorModel() {
          if (translucentCM == null) {
              translucentCM = new DirectColorModel(16,
                                         DCM_4444_RED_MASK,
                                         DCM_4444_GRN_MASK,
                                         DCM_4444_BLU_MASK,
                                         DCM_4444_ALP_MASK);
          }
          return translucentCM;
     }
    
and then:

      // ...
      ColorModel cmSw = getTranslucentColorModel();
      wr = cmSw.createCompatibleWritableRaster(mWidth, mHeight);
      BufferedImage image = new BufferedImage(cmSw, wr, cmSw.isAlphaPremultiplied(), null);
    
Then the buffered image can be used like any other
BufferedImage. Note that it won't be accelerated, but
we've added some optimized software loops for this image format.

2.2 Acceleration of 4444 images:
When enabled, forces the accelerated surfaces for
managed images, created with
GraphicsConfiguratio.createCompatibleImage(w,h, TRANSLUCENT)
or translucent images loaded with Toolkit.getImage
to be in 4444 format, saving vram and system memory. The system
memory surface for these images will be in 4444 format as well.

Disabled by default, enabled via flag:
-Dsun.java2d.d3dtexbpp=16

This option is useful when you have lots of images to be stored in
vram. The downside is poorer quality.

Note that some videoboards  (for example, 3dfx Voodoo3) do not
support 32-bit textures, which are attempted to be used by defaul,
so this flag must be set in order to get 
acceleration of translucent images.
  1. Changing acceleration threshold
    Acceleration threshold controls how many copies from managed images
    will occur before we create a vram version of the image.
    If the number is ‘0’, the accelerated surface is created during
    image initialization.

The default threshold is 1.
A new threshold can be set via flag:
-Dsun.java2d.accthreshold=N (where N>=0)

If the threshold is set to 0, all the vram surfaces
for all managed images will be created at the image
creation time, and updated during the first copy from image.

This flag can be used to eliminate the initial delay in rendering
when the images are being copied to the vram after the first few
copies. Instead, the delay is effectively shifted to the image
creation time.

This could be useful behavior when you know that your application
will be able to take advantage of image management; just get the
overhead of the copy over with at the start instead of incurring some
number of slower copies to begin with and then having the copy overhead
at some later time.

  1. How to check if the acceleration works in your configuration.
    Compile and run the following test:

  import java.awt.*;
  import java.awt.event.*;
  import java.awt.image.*;
  import javax.swing.*;
  
  public class Test extends JFrame implements ActionListener {
      Image img = null;
      public Test() {
          setLocation(200, 200);
          setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
          pack();
          setSize(170, 200);
          

          GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
          GraphicsConfiguration gc = ge.getDefaultScreenDevice().getDefaultConfiguration();
          img = gc.createCompatibleImage(100, 100, Transparency.TRANSLUCENT);
          Graphics g = img.getGraphics();
          g.setColor(new Color(255, 0, 0, 128));
          g.fillRect(0, 0, 99, 99);
  
          getContentPane().add("Center", new JComponent() {
              public void paintComponent(Graphics g) {
                float ea = (float)extraAlpha/255f;
                ((Graphics2D)g).setComposite(
                     AlphaComposite.getInstance(AlphaComposite.SRC_OVER, ea));
                g.drawImage(img, 30, 30, null);
              }
          });
          new javax.swing.Timer(50, this).start();
      }
  
      int extraAlpha = 1;
      int alphaStep = 10;
      public void actionPerformed(ActionEvent e) {
          extraAlpha += alphaStep;
          if (extraAlpha < 0 || extraAlpha > 255) {
              alphaStep = -alphaStep;
              extraAlpha += alphaStep;
          }
          repaint();
      }
  

      public static void main(String argv[]) {
          try {
              System.setProperty("sun.java2d.translaccel", "true");
              System.setProperty("sun.java2d.ddforcevram", "true");
              System.setProperty("sun.java2d.trace", "count");
              System.setProperty("sun.java2d.accthreshold", "0");
              if (argv != null && argv.length > 0 && argv[0].equals("-16")) {
                System.setProperty("sun.java2d.d3dtexbpp", "16");
              }
          } catch (Exception e) {
              System.err.println("Can't set properties: " + e);
          }
          new Test().setVisible(true);
      }
  }
  

After you quit it, it’ll print out the trace information about the
loops which have been used. If you see a line there similar to:
xxxx calls to sun.awt.windows.D3DBlitLoops::Blit(“Integer ARGB D3D with translucency”, SrcOver, “Short 565 RGB DirectDraw”)
or, if the test run with ‘-16’ parameter to force 16-bit textures,
xxxx calls to sun.awt.windows.D3DBlitLoops::Blit(“UShort 4444 ARGB D3D with translucency”, SrcOver, “Short 565 RGB DirectDraw”)
it means that the acceleration works on your configuration.

  1. Known issues
  • Rendering accelerated translucent images to the screen
    is not clipped. While blasting your rendering through
    all windows covering your window certainly looks cool, you should
    be using double buffering anyway
    (either through BufferStrategy, Swing back-buffer or an
    app-managed VolatileImage back-buffer).
  • Sometimes the contents of the translucent managed images
    are not restored properly after the display change
  • still no translucent VolatileImages, as it requires new API,
    which we cannot introduce in a dot (maintenance) release.
    We hope to have it in 1.5.
  • managed translucent images may take up more vram than
    their size, because the textures are allocated
    with sizes of power of two. So, for example,
    a 33x33 image will actually take as much vram as 64x64 one.
  • there’s no way to automatically choose between 16- and 32-
    bit textures on the fly depending on the desktop bit depth,
    for example. You can sort of workaround it as shown in
    the test app above.
  • on some hardware (like ATI Radeon) the performance depends on the
    display mode depth your app is running at. For some reason it
    works much faster if the display mode depth is 16 bit,
    no matter what depth the textures (manaded images) are.
  1. Some other useful flags:
    -Dsun.java2d.ddscale=true - turns on hardware scaling support

  2. Feedback
    We post this solely to get your feedback on the features we’ve
    already implemented and are yet to implement in future releases.
    Please send us your comments, either on this forum,
    or directly on java2d-comments@sun.com - this alias goes directly to the
    development team.

What happens with Linux and translucent images?

Sorry, nothing new for Linux in _02. It’ll get full OpenGL pipeline in 1.5, though.

fullscreen too?

woohoo, finally downloaded _02 :smiley:

Seems to work well (though not as fast as opaque/bitmask images)

1 thing i did notice (which in fairness is covered in the txt above)
for AlphaCompositing to be accelerated, the source image must already have an alpha channel (i.e. Transparency.TRANSLUCENT)

apart from that,
with regard to switching between fullscreen/windowed
and different displaymodes,
_02 seems to contain all the bugs that _01 had
plus some new ones :frowning:

The fullscreen->windowed->fullscreen bug
can be replicated in 9lines of code ->


// start with a fresh frame
setUndecorated(true);
gd.setFullScreenWindow(this);
gd.setDisplayMode(dm);
createBufferStrategy(2);
dispose(); //you have to dispose before making the frame decorated
setUndecorated(false);
setSize(dm.getWidth(),dm.getHeight);
show();
createBufferStrategy(2);
//any graphics context obtained from the bufferstrategy will now be totally useless
//and a further change (back to fullscreen/undecorated)
// will result in a 'java.lang.NullPointerException: peer'

lol, Abuse… you should become Suns Bug Tester. You find em all. :wink:

Abuse, thanks for the detailed bugreport. The usual info about hw/sw setup would’ve made it even more complete.

I haven’t looked at this bug in details, but it’s likely to be caused by asynchronous actions taking place.

setDisplayMode is executed asyncronously, so there’s no guarantee that createBufferStrategy will be using the right data because the display mode may not have changed yet.

Same about show() and createBufferStrategy.

Of course, you won’t find any documentation on this (you didn’t expect for life to be easy, did you?)… Sorry about this. I’m planning on creating a ‘bulletproof fullscreen app’, which hopefully will show how to avoid these kinds of problems.

mill, if you’re talking about changing display modes and such, then no, unfortunately, we don’t have bandwidth to work on this for 1.5.

You would be able to use the ‘second best thing’, that is, our fullscreen emulation - a borderless undecorated frame of the size of the screen. It will be created with a double-buffered visual, so you’ll get hw-accelerated double-buffering.

yup, that works in some cases. not in 2D games where everything is pre-rendered though, as in a 640x480 static background doesn’t get scaled up. sure, one can always resize all the images at run-time, but i’ll wait for 1.5+ since i’m sooo lazy.

i’m gonna stick to “if linux then window mode” ;D

[quote]Abuse, thanks for the detailed bugreport. The usual info about hw/sw setup would’ve made it even more complete.

I haven’t looked at this bug in details, but it’s likely to be caused by asynchronous actions taking place.

setDisplayMode is executed asyncronously, so there’s no guarantee that createBufferStrategy will be using the right data because the display mode may not have changed yet.

Same about show() and createBufferStrategy.

Of course, you won’t find any documentation on this (you didn’t expect for life to be easy, did you?)… Sorry about this. I’m planning on creating a ‘bulletproof fullscreen app’, which hopefully will show how to avoid these kinds of problems.
[/quote]
Wasn’t realy meant as a bug report :smiley:

I kinda guessed those methods would have an asynchronous element to them, but I didn’t realise show() executed asynchronously!

I have already added several sleeps after each of the likely culprits (setDisplayMode and setFullScreenWindow)

and I managed to almost get a fully working fullscreen<->window mode switchable frame. However, it still crashes occasionally when switching mode with this error…


An unexpected exception has been detected in native code outside the VM.
Unexpected Signal : EXCEPTION_ACCESS_VIOLATION occurred at PC=0x834DCA2F
Function=[Unknown.]
Library=(N/A)

NOTE: We are unable to locate the function name symbol for the error
      just occurred. Please refer to release documentation for possible
      reason and solutions.


Current Java thread:
      at sun.java2d.DefaultDisposerRecord.invokeNativeDispose(Native Method)
      at sun.java2d.DefaultDisposerRecord.dispose(DefaultDisposerRecord.java:24)
      at sun.java2d.Disposer.run(Disposer.java:99)
      at java.lang.Thread.run(Thread.java:536)

I’m guessing this error is related to the disposing of the Vram used as a backbuffer for BufferStrategy?

Anyhow, i’m just guessing (and until i got this error, didn’t even know there was a ‘Disposer’ class :D)

I’m gonna go away and add some sleeps around show() and createBufferStrategy(), I’ll report back l8er…

p.s.
Just incase the actual aim of this got lost along the way,
i’m trying to switch from an undecorated full screen frame, to a decorated windowed frame.

(perhaps I should post it in the code requests forum
see if its just me, or whether this requirement is beyond the current capabilities of the API :D)

ok, here we go,

http://www.pkl.net/~rsc/downloads/Balls.jar
(src included in the jar, the most important class is GameFrame.java )

I’ve tried to work around as many bugs as I can.

  1. I’ve put sleeps (500ms) after every operation that may be abit asynchronous. (that fixed 1 bug)

  2. When switching from fullscreen to windowed mode,
    I first return to the resolution/bitdepth of the desktop - setDisplayMode(initialDisplayMode).
    Then explicitly get rid of fullscreen mode - setFullScreenWindow(null).
    before making the frame invisible. (that fixed 2 bugs)

  3. I have 2 frames, 1 decorated, 1 undecorated.
    When in fullscreen mode, I use the undecorated.
    When in window mode, I use the decorated.
    (that fixed 1 bug)

but 1 bug still remains.

After several fullscreen<-> window mode switches [using different fullscreen resolutions/bitdepths] I get the disposer crash bug…

It appears to be happening when the garbage collector tries to collect one of the old BufferStrategy Objects.


An unexpected exception has been detected in native code outside the VM.
Unexpected Signal : EXCEPTION_ACCESS_VIOLATION occurred at PC=0x6D069916
Function=[Unknown.]
Library=(N/A)

NOTE: We are unable to locate the function name symbol for the error
      just occurred. Please refer to release documentation for possible
      reason and solutions.


Current Java thread:
      at sun.java2d.DefaultDisposerRecord.invokeNativeDispose(Native Method)
      at sun.java2d.DefaultDisposerRecord.dispose(DefaultDisposerRecord.java:24)
      at sun.java2d.Disposer.run(Disposer.java:99)
      at java.lang.Thread.run(Thread.java:536)

Dynamic libraries:
0x7D750000 - 0x7D76D000       C:\WINDOWS\SYSTEM\IMAGEHLP.DLL

Local Time = Tue Apr 08 01:43:26 2003
Elapsed Time = 80
#
# The exception above was detected in native code outside the VM
#
# Java VM: Java HotSpot(TM) Client VM (1.4.1_02-b06 mixed mode)
#

have fun trembovetski :smiley:
p.s.
If you want versions that show each of the crash bugs that I have worked around, I can prolly manage to roll the code back abit :smiley:

** edit **

and just incase the controls arn’t clear…

there are 2 sets of controls,
The 1st are instant effect, these are…

‘enter’ - changes the image type used for the bouncing ball
‘a’ - toggles alphacompositing on/off
‘f1’ - toggles the help txt on/off
‘pgup/pgdn’ - changes the target fps
‘space’ - applies the batched display mode settings
‘escape’ - quits the program

The 2nd, are the controls that modify what the next display mode will be (which is triggered with ‘space’)

‘left/right’ - cycle through the number of back buffers to use.
‘up/down’ - cycle through the resolution/bit depth to use.
‘f’ - toggle Fullscreen or windowed

To instigate the remaining crash bug, simply change between the different resolutions, and between fullscreen/windowed mode a few times.
(it helps if you change to a fullscreen mode that uses 8bpp)

Also, i’ve noted, as long as you use the desktop resolution & bitdepth when in fullscreen mode, it wont crash.
(prolly cos it never has to allocate a new BufferStrategy?)

** /edit **

Hey Abuse, thanks again. If only all reports were so thorough =)

I have a lot of info to digest now, but as a quick note - yes, we’re aware of the disposer crash, but I haven’t had time to look at it… I’ll see if we can squeeze the fix into 1.4.2-rc (beta is already out), since now I know at least two customers who run into this bug…

Dmitri

Well for commercial release of anything sleeps won’t cut it. Sun will have to provide a way of notifying you when its ok to proceed (boolean test) to the next set of changing your fullscreen mode. Whats 500ms on one system could be 2000ms on another system or 2000ms on the same system with other things going on.

This is probably one of the biggest problems I’ve run into with changing Fullscreen modes dynamically within the program.

Just thought I’d mention that any hack that fixes the problem will not be a workable solution unless the program can verify what the race conditions are and test for them.

indeed,

IMO the simplest, most obvious solution is for all the asynchronous method to block until the requested operation is complete.