TAGS :Viewed: 9 - Published at: a few seconds ago

[ BufferedImage performance ]

I was taking a look at Notch's code from ludum dare(minicraft) and i noticed he uses :

private BufferedImage image = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_RGB);
private int[] pixels = ((DataBufferInt) image.getRaster().getDataBuffer()).getData();

So i made a simple test program, and i noticed my perfomance lowers by a lot when compared to the method i was previously using. With this method, just drawing a completely white screen, i get 800 fps and when i draw a test image i get more then 1200, which seems a bit odd. Even if i dont declare anything on the pixels[] and just leave the default one it's still 800 fps. I wonder if someone could explain me the reason for that. This is the test code i wrote and i used fraps to get my fps:

public class Test extends Canvas implements Runnable{

private static final long serialVersionUID = 1L;

private boolean running = false;

public  final int HEIGHT = 300;
public  final int WIDTH = 360;
private final int SCALE = 3;

private BufferedImage image = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_RGB);
private BufferedImage testImage;
private int[] pixels = ((DataBufferInt) image.getRaster().getDataBuffer()).getData();

JFrame frame;
public Test(){
    Dimension size = new Dimension(WIDTH*SCALE, HEIGHT*SCALE);
    frame = new JFrame();
    this.frame.setResizable(false);
    this.setPreferredSize(size);
    this.setMaximumSize(size);
    this.setMinimumSize(size);
    this.frame.add(this);
    this.frame.pack();
    this.frame.setLocationRelativeTo(null);
    this.frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    this.setFocusable(true);
    this.frame.setVisible(true);

    try {
        testImage = ImageIO.read(new File("res/test.jpg"));
    } catch (IOException e) {
        e.printStackTrace();
    }
    for(int i = 0; i < pixels.length; i++){
    pixels[i] = 0xffffff;
    }
    running = true;
}

public void run() {
    while(running){
        render();
    }
}

private void render() {
    BufferStrategy bs = getBufferStrategy();
    if(bs == null){
        createBufferStrategy(3);
        return;
    }

    Graphics g = bs.getDrawGraphics();
    //Draw stuff
    g.setColor(Color.BLACK);
    g.fillRect(0, 0, getWidth(), getHeight());
    g.drawImage(testImage, 0, 0, getWidth(), getHeight(), null);
    g.dispose();
    bs.show();
}

public static void main(String args[]){
    Test test = new Test();
    test.run();
}

}

I simply replace testImage by image. Thanks all and happy holidays

Edit: I noticed that simply calling int[] pixels = ((DataBufferInt) image.getRaster().getDataBuffer()).getData(); slows down the application by a lot. Could someone please explain me why that is? do i need to dispose of the pixels or something? thank you

Answer 1


As far as I know, BufferedImages are treated as VolatileImages behind the scenes. This means that they receive a huge hardware-acceleration boost. This is because the image is copied straight into your video-card's memory, allowing for the fast drawing.

The moment you want to access the pixel matrix, the image will be placed in your regular RAM, and accessed from there, hence causing a significant slow-down.

Realistically, if you disable all hardware acceleration in the JVM, the white image will be drawn the fastest.

If you want to update your screen efficiently, apply setIgnoreRepaint(true) to your window and only draw the parts of the screen that have changed.