Size matters? A managed image problem...

hahahahaha, /me is an idiot.

I was indeed running with OPAQUEs not BITMASKs, well noticed.

With it set to BITMASK i get results similar to yours, and consistent with trembovetski bad news :frowning:

I get slightly closer results :-

16x16 256 times ~360
256x256 1 time ~750

I guess its driver/hardware related. (though it is disturbing a machine almost 3 times faster can’t blit 16x16 as fast; have you got a crappy gfx card in it?)

Okay, so it is official then :P. Someone should put this ommision in the docs.

Not exactly. I’ve got an ATI Radeon 9800 pro with the latest catalyst 4.4 drivers. This IS disturbing…

Are you sure you are running your test with the same variables set? This is the exact code I tested with (basically the same as your modified version except that it now erases the fps text and avoids a divide by 0 error), running on JVM 1.4.2_04:

import javax.swing.*; 
import java.awt.*; 
import java.awt.image.*; 
import java.util.Random; 
  
public class ImageTest2 extends JFrame implements Runnable 
{ 
 Image bb; 
 BufferedImage bitmaskImage; 
  
 static final boolean BUFFER_STRATEGY = true; 
  
 static final int BITMASK_BLITS_PER_FRAME = 256; 
  
 static final int WINDOW_WIDTH = 800, WINDOW_HEIGHT = 600; 
 static final int BITMASK_WIDTH = 16, BITMASK_HEIGHT = 16; 
  
 public static void main(String[] args) 
 { 
  System.setProperty("sun.java2d.accthreshold", "0");
  System.setProperty("sun.java2d.translaccel", "true");
  Thread t = new Thread(new ImageTest2()); 
  t.setPriority(Thread.MIN_PRIORITY);    
  t.start(); 
 } 
   
 public ImageTest2() 
 { 
  setIgnoreRepaint(true); 
  getContentPane().setLayout(null); 
  setBounds(new Rectangle(0, 0, WINDOW_WIDTH, WINDOW_HEIGHT));   
  setVisible(true); 
  
  bitmaskImage = getGraphicsConfiguration().createCompatibleImage(BITMASK_WIDTH, BITMASK_HEIGHT, Transparency.BITMASK);    
  
  Graphics2D g = bitmaskImage.createGraphics(); 
  g.setColor(Color.GREEN); 
 g.fillRect(0, 0, BITMASK_WIDTH, BITMASK_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; 
     
     
    Graphics2D bitmaskG = bitmaskImage.createGraphics(); //and alter the bitmask image so it isn't accelerated for awhile
    bitmaskG.setColor(Color.GREEN); 
    bitmaskG.fillRect(0, 0, BITMASK_WIDTH, BITMASK_HEIGHT); 
    bitmaskG.setColor(Color.BLUE); 
    for(int i=0; i < 10; i++) 
    { 
          if((BITMASK_WIDTH-25) <= 0)
                break;
     bitmaskG.fillOval(rand.nextInt(BITMASK_WIDTH-25), rand.nextInt(BITMASK_HEIGHT-25), 50, 50); 
    } 
    bitmaskG.dispose(); 
   }  
    
   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 < BITMASK_BLITS_PER_FRAME; i++) 
   { 
    bg.drawImage(bitmaskImage, (WINDOW_WIDTH - BITMASK_WIDTH)/2, (WINDOW_HEIGHT- BITMASK_HEIGHT)/2, 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(); 
   
   }  
 }  
} 

That code gives :-

16x16 256 times = 370 to 400
256x256 1 time = 490 to 530

The reduced fps on the 256x256x1 is due to the clearing of the background. (removing it gives the 700fps I got earlier)

16x16 256 times
256x256 1 time

Hm… you could try 32x32 (64 times - should be a good trade-off). Heh wait a minute… I suggested 32x32 in first place :stuck_out_tongue:

Remember that after we decide to accelerate the image for the first time, a lot of stuff has to be done: we need to process the image and find an unused color to be used as color key in ddraw blit operation, then the image needs to be transferred from system memory to VRAM, and only after that the HW handles the blit from the new accelerated surface to the destination.

For larger images this overhead is, of course, higher.
BTW, this process has to be repeated each time after you render to that image.

But once the image gets accelerated, the speed of the consequent copies should be comparable for 32x32 and 256x256 images.

[quote] And is this opengl pipeline available on 1.4.2 on windows? How would I use/enable it if it is?
[/quote]
The opengl pipeline will be available in release 1.5 (beta1 is out now - with opengl pipeline implemented on Linux/Solaris only - see the release notes for requirements, or search the forum for sun.java2d.opengl property). Beta2 is coming out soon, and it’ll have ogl on windows.

[quote]Remember that after we decide to accelerate the image for the first time, a lot of stuff has to be done: we need to process the image and find an unused color to be used as color key in ddraw blit operation, then the image needs to be transferred from system memory to VRAM, and only after that the HW handles the blit from the new accelerated surface to the destination.

For larger images this overhead is, of course, higher.
BTW, this process has to be repeated each time after you render to that image.

But once the image gets accelerated, the speed of the consequent copies should be comparable for 32x32 and 256x256 images.
[/quote]
What I was trying to demonstrate was that the overhead in calling drawImage() for an already HW accelerated image is quite hefty.

For example, if we imagined a single 256 x 256 image as the equivalent of 256 16 x 16 portions, and tried to blit the whole image onto the screen in a single frame, using the test I mentioned in a previous post, we get the following FPS:

For a P4 3.0ghz with ATI Radeon 9800 PRO,

16 x 16, 256 drawImage() per frame: 280+ FPS
256 x 256, 1 drawImage() per frame: 1700+ FPS

For a Athlon 1.33ghz with GF2,

16 x 16, 256 drawImage() per frame: 360+ FPS
256 x 256, 1 drawImage() per frame: 750+ FPS

For the first case, the difference is 6x (why so large? Hardware issue?). For the second, 2x.

So, for the most part, I would rather blit entire images on screen in a single drawImage() call rather than use multiple drawImage() calls with “dirty rectangles”.

Aha, I see what you mean it now.

Yes, we’re aware that the overhead of a blit call is pretty high, unfortunately. Part of it is JNI overhead, which is surprisingly high, and the rest is our pipelines.

One of the goals we have for our next release is to reduce the pipeline overhead (the time it takes from java render call to the time we issue the command to hw), and make sure the vm team works on JNI’s.