Fullscreen Slowness

I have an app that creates and draws an image on the screen every frame. Every frame a slightly modified image is computed and scrolled slowly across the screen.

If I run the app in a 640x480 window, I see frame rates of 50 fps+.
If I run the app in full-screen mode, I get about 10 fps.

In fullscreen mode: When most of the image is clipped by the screen edges, the frame rate is high and the animation is smooth. As more of the image is visible on the screen the frame rate drops dramatically. This leads me to believe that the bottleneck is the Graphics.drawImage call.

I’ll post some code below to show what I’m doing.

So can anyone suggest ways to speed up the full-screen rendering? Any ideas on why the full-screen rendering is so much slower than the windowed rendering?

Any help would be very appreciated!

Thanks in advance!

Brian.

Code: (edited to keep only the relevant bits and make them understandable)

setup:


window.createBufferStrategy(2);
bufferStrategy = window.getBufferStrategy();
drawImg = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
imgData = ((DataBufferInt)drawImg.getRaster().getDataBuffer()).getData();

every frame:


drawGraphics = bufferStrategy.getDrawGraphics(); 
drawGraphics.setColor(backColor);
drawGraphics.fillRect(0, 0, getWidth(), getHeight());

...

int index = 0;
for (int i=0; i < width; i++) {
      for (int j=0; j < height; j++) {
            int rgb = calculateRGB(i,j);

            imgData[index] = rgb;

            index++;
      }
}

drawGraphics.drawImage(drawImg, x, y, null); // x, y are updated every frame
drawGraphcs.dispose();
bufferStrategy.show();

A fullscreen BufferedImage with direct raster access -> unaccerlated copying of about 7-10megs*10 = 100mb/s.
Not too bad.

I would suggest to use BufferedImage only for small images, otherwise theres not much you can do for higher performance…

lg Clemens

Sorry, should have mentioned:

The image that gets drawn each frame is approx 512x512.
Full-screen mode is also running at 640x480.

So, ok, that’s a lot of data, but then 2 questions:

  1. Why is fullscreen slower?

  2. How can I make it faster?

Anyone?

Thanks again,
Brian.

INT_ARGB is probably compatible with the desktop colormodel, but not the colormodel used in fullscreen mode.

use gc.createCompatibleImage(width,height,transparency), and make your per-pixel algorithm capable of coping with different pixel formats.

Thanks for the advice, Abuse. I’ll post my results here once I’ve had a chance to try it.

When you do the getData() you tag that buffered image to never be accelerated ever again. Just so that you know. See Chet’s excellent tutorials on that.

Cheers,
Mikael Grev

I’m aware that the BufferedImage.getData() call causes the image to never be accelerated. The image is completely recreated every frame (every pixel is set to a new value). I thought that doing things this way would be fastest, since it means I don’t have to create any new objects every frame, and I especially don’t need to allocate large amounts of image memory. Thus there is no (or insignificant) garbage collection happening.

That said, I don’t fully understand all the various permutations and implications of java image types (I’ve read some of Chet’s articles, but probably not in the detail I need to). Is there a better way to do things for this situation?

Finally, I did some further testing this weekend and believe I have found the cause of the slowness: My fullscreen resolution is not being set correctly. So when I run full-screen, I’m not running at the same 640x480 resolution of the window, but at a much higher resolution (1024x768 or higher). The images I’m drawing are sized according to the window size, so I end up throwing around much larger amounts of pixel data – hence the lower fps.

I need to do a bit more testing of my code for setting the display resolution. If I can’t figure things out, I’ll post back here.

Oh and Abuse, TYPE_INT_ARGB is the compatible image type for both the windowed and full-screen mode (at least on my laptop – just FYI).

Thanks for the support so far! This forum is an invaluable resource!

I had similar symptoms. With a 640x480 window, I had a frame rate of 130. In full-screen mode (640x480) it dropped to about 60. Fortunately, it was 60 both for 10 and for 200 blitted objects, so I concluded (possibly wrongly, I don’t know) that the BufferStrategy takes the screen’s refresh rate into account (syncing on vertical refresh), which is good.

Strange that you get only 10 fps, though.

[quote]I had similar symptoms. With a 640x480 window, I had a frame rate of 130. In full-screen mode (640x480) it dropped to about 60. Fortunately, it was 60 both for 10 and for 200 blitted objects, so I concluded (possibly wrongly, I don’t know) that the BufferStrategy takes the screen’s refresh rate into account (syncing on vertical refresh), which is good.
[/quote]
You’re problem is different tban his. Your frame rate didn’t drop, it just stopped drawing at unnecessary time. i.e. The monitor only updates at 60 times per second. Updating it faster is pointless and may cause artifacts. In liminal’s case, his problem is caused by moving massive amounts of data between main memory and the video card.

just to add to this thread, im just playing with a scroll etc in fullscreen, yet if I replace the gagetimer with a Thread.yield(); its showing as over 100fps even when im ‘supposed’ to be in 640x480 fullscreen mode.
using the gagetimer, im capping the redrawing at 60fps (also have set the display mode to 60Hz too as to remove any jitters etc)

I thought that when you go into fullscreen mode, it automatically locks the refresh to the vsync? also ive noticed im getting the raster scan slowly going up the screen which also leads me to believe that its not locked to the vsync as if it was, then the screen would be redrawn when the raster scanline is off the bottom of the screen.

does it make a difference if you start in a window mode first? as i tried to make it call my swap screen routine once it set the window up etc, but still get the same results.

here is my fullscreen swapper routine just in case im missing something obvious! (quite possible with me! hehe)


protected void swap_view()
{
      if(FULL_SCREEN==0)
      {
            if ( DEVICE.isFullScreenSupported() )
            {
                  DEVICE.setFullScreenWindow(this);
                  if (DEVICE.isDisplayChangeSupported())
                    {
                    
                        DEVICE.setDisplayMode(new DisplayMode( WIDTH, HEIGHT,BPP,Hz));
                 }
            }
            keys[KeyEvent.VK_F1&0xff] =0;
            FULL_SCREEN=1;
      }
      else
      {
            Thread.yield();
            DEVICE.setFullScreenWindow(null);
            setVisible(true);
            toFront();
            FULL_SCREEN=0;
      }
}

when in fullscreen, it is in 640x480 as the cursor is bigger than it is in my normal desktop (1280x1024) so I know its not just stretching the window and filling my desktop with a window.

Nasty naming convention you got there, you should see a doctor.

hehehe just been and he gave me a good slapping and told me not to do it again! ;D
have since changed the naming and looks a lot neater now :-[ but still not sorted out the fullscreen/vsync prob though!