VolatileImage slow

Hi,

we are trying to do hardware accelerated scaling of 2D images. So far we found out, that this should be available with VolatileImage.

We basically implemented the “Hello World” example of the docu. In generell it works, however we do not see any performance benefit. We want to scale a 32x32 image to 1600x1200 in less then 50ms. This is usally no problem using the texture mapping capabilities of commodity graphics hardware (It is less than 5 ms).
However, using VolatileImage we achieve usally 300ms, which is to slow for our application. Enabling and disabling the hardware acceleration directly in the java virtual machine did not show any performance difference.

How do we get more speed? Is there maybe another way to do 2D scaling (Java3D is not an option for us).

Thank you very much in advance!!!
We need help … we are quite stuck !!! ???

So you have tried it with :-

-Dsun.java.ddscale=true

you may also need :-

-Dsun.java2d.forceddvram=true

Hi,

Dsun.java2d.forceddvram=true did not work :frowning:

We are running the app with the follwing settings:

java -Dsun.java2d.noddraw=false -Dsun.java2d.ddoffscreen=true -Dsun.java2d.ddscale=true -Dsun.java2d.forceddvram=true -jar C:/cvs/test.jar

[quote]Hi,

we are trying to do hardware accelerated scaling of 2D images. So far we found out, that this should be available with VolatileImage.
[/quote]
What version of java are you using? Did you set the Dsun.java2d.ddscale=true flag?

I haven’t tested this, but try scaling your images directly with drawImage() calls - ie, drawImage(src, 0, 0, width, height, null) instead of using implicit AffineTransform method calls in the Graphics object such as rotate() and scale().

Also, make sure your destination image is in VRAM.

You could also try pre-rendering/scaling your images during startup, store them in memory and then just blit the pre-scaled images on screen when you need them.

We are running:

Version: java version “1.4.2_04”

java -Dsun.java2d.noddraw=false -Dsun.java2d.ddoffscreen=true -Dsun.java2d.ddscale=true -Dsun.java2d.forceddvram=true -jar C:/cvs/test.jar

The only thing what we want to do is to scale a 2D image. Basically what we have is high optimized 3D volume render in C/C++. Our application (GUI) is implemented in Java and is running in a heterogenous hardware environment (therefore we cannot use Java3D). Theoretically we would achieve about 15-20 fps. However, during interaction we sometimes generate 128x128 images (or less) which need then to be scaled to full image resolution of 1600x1200. Java2D so far performs the scaling with 300ms => limitation to 3 fps. This is by far to slow. Scaling the image in software (C/C++ side) is not a solution, because then we have to copy the large image to Java.

Could anybody give us an example, how to obtain hardware accerlerated 2D scaling. We are still stuck. We really need a solution for this.

We are basically trying the code from
http://java.sun.com/j2se/1.4.2/docs/api/java/awt/image/VolatileImage.html

An example of using a VolatileImage object follows:

// image creation
VolatileImage vImg = createVolatileImage(w, h);

// rendering to the image
void renderOffscreen() {
do {
if (vImg.validate(getGraphicsConfiguration()) ==
VolatileImage.IMAGE_INCOMPATIBLE)
{
// old vImg doesn’t work with new GraphicsConfig; re-create it
vImg = createVolatileImage(w, h);
}
Graphics2D g = vImg.createGraphics();
//
// miscellaneous rendering commands…
//
g.dispose();
} while (vImg.contentsLost());
}

// copying from the image (here, gScreen is the Graphics
// object for the onscreen window)
do {
int returnCode = vImg.validate(getGraphicsConfiguration());
if (returnCode == VolatileImage.IMAGE_RESTORED) {
// Contents need to be restored
renderOffscreen(); // restore contents
} else if (returnCode == VolatileImage.IMAGE_INCOMPATIBLE) {
// old vImg doesn’t work with new GraphicsConfig; re-create it
vImg = createVolatileImage(w, h);
renderOffscreen();
}
gScreen.drawImage(vImg, 0, 0, this);
} while (vImg.contentsLost());

That’s fine, but it would help better if you posted your code where you implemented your scaling.

This is how I did it, using 1.4.02_04:


import javax.swing.*; 
import java.awt.*; 
import java.awt.image.*; 
import java.util.Random; 
  
public class ImageTest3 extends JFrame implements Runnable 
{ 
 Image bb; 
 Image scaleImage; 
  
 static final boolean BUFFER_STRATEGY = true; 
  
 static final int BLITS_PER_FRAME = 1; 

 static final int WINDOW_WIDTH = 800, WINDOW_HEIGHT = 600; 
 static final int BEFORE_SCALE_WIDTH = 128, BEFORE_SCALE_HEIGHT = 128; 
 static final int AFTER_SCALE_WIDTH = WINDOW_WIDTH;
 static final int AFTER_SCALE_HEIGHT = WINDOW_HEIGHT;
 
 public static void main(String[] args) 
 { 
  System.setProperty("sun.java2d.ddscale", "true"); // TURN THIS OFF TO SEE THE BEFORE & AFTER HARDWARE SCALING FPS
  System.setProperty("sun.java2d.accthreshold", "0");
  System.setProperty("sun.java2d.translaccel", "true");
  Thread t = new Thread(new ImageTest3()); 
  t.setPriority(Thread.MIN_PRIORITY);    
  t.start(); 
 } 
   
 public ImageTest3() 
 { 
  setIgnoreRepaint(true); 
  getContentPane().setLayout(null); 
  setBounds(new Rectangle(0, 0, WINDOW_WIDTH, WINDOW_HEIGHT));   
  setVisible(true); 
  
  scaleImage = getGraphicsConfiguration().createCompatibleVolatileImage(BEFORE_SCALE_WIDTH, BEFORE_SCALE_HEIGHT);    
  
  Graphics g = scaleImage.getGraphics(); 
  g.setColor(Color.GREEN); 
 g.fillRect(0, 0, BEFORE_SCALE_HEIGHT, BEFORE_SCALE_HEIGHT); 
  g.dispose(); 
  
  if(BUFFER_STRATEGY) 
  { 
   createBufferStrategy(2); 
  } 
  else 
  { 
   bb = getGraphicsConfiguration().createCompatibleVolatileImage(WINDOW_WIDTH, WINDOW_HEIGHT); 
  } 
  
  setDefaultCloseOperation(EXIT_ON_CLOSE); 
 } 
  
 public void run() 
 { 
  Random rand = new Random(); 
  long lastTime = System.currentTimeMillis(); 
  int frameCount = 0; 
  String fps = "n/a"; 
  while(true) 
  { 
   frameCount++; 
    
   long time = System.currentTimeMillis(); 
   if(time-lastTime > 1000) //once a second 
   { 
    //update the fps counter 
    fps = Integer.toString(frameCount); 
    frameCount=0; 
    lastTime+=1000; 
   } 
   
   Graphics bg = BUFFER_STRATEGY?getBufferStrategy().getDrawGraphics():bb.getGraphics(); //buffers Graphics 
   bg.setColor(Color.WHITE);
   bg.fillRect(0, 0, WINDOW_WIDTH, WINDOW_HEIGHT);
   
   for(int i=0; i < BLITS_PER_FRAME; i++) 
   { 
    bg.drawImage(scaleImage, (WINDOW_WIDTH - AFTER_SCALE_WIDTH)/2,
                                         (WINDOW_HEIGHT - AFTER_SCALE_HEIGHT)/2, WINDOW_WIDTH, WINDOW_HEIGHT, null); 
   } 
   
   
   bg.setColor(Color.RED); 
   bg.drawString(fps, WINDOW_WIDTH/2 - 50, WINDOW_HEIGHT/2); 
   bg.dispose(); 
    
   if(BUFFER_STRATEGY) 
   { 
    getBufferStrategy().show(); 
   } 
   else 
   { 
    Graphics g = getGraphics(); 
    g.drawImage(bb, 0, 0, null); 
    g.dispose(); 
   } 
   Thread.yield(); 
   
   }  
 }  
} 

Just cut and paste. The scores you get when you turn off and on hardware scaling should be drastic.

Thanks a lot. The problem was somehow related to the flags.

You saved our day!! :slight_smile:

For future reference, you can use built-in graphics primitives tracing facility to see if the correct roots are being used:
java -Dsun.java2d.trace=log Test

Run with -Dsun.java2d.trace=help to get more info.

If you see Win32ScaleLoops in the output, the ddraw scale loops are used.