Double buffering in a windowed game

the main problem is with the sprites flickering back and forth as two diferent components are updating their display (i want this to be done onto a buffer and then flip the buffer once it’s all done)

how do i go about doing double buffering in something like this?

it’s been updated slightly since the last posting, now displays FPS and LPS info

http://members.austarmetro.com.au/~juddman/files/java/JarioBrosNew.zip

How big is the area and how often will the screen update. I have had zero luck getting java to double buffer a 640x480 window that updates each frame. I can only get about 8 FPS in windowed mode on a fast machine with a $400 video card.

At any rate it is normal double buffering, create a back buffer image and get it’s Graphics object then drw everything to that and then draw the back buffer to the window. Good luck. BTW this is what the BufferStrategy does in windowed mode so you could just use that.

Ahh there’s my problem… i tried BufferStrategy, but got some error… something about the window “Must have a valid peer”

i put it onto a fullscreen window, worked good, but then if i move it so that Explorer is exposed it crashes.

i have just got a demo from someone which uses BufferStrategy in a window, i just have to sit and read it and try to work it out.

If i can get the swing objects to paint themselves to the buffer in the same way they usually paint themselves to the screen (which is not using Repaint or update) it’d be a very smooth game. at the moment it runs at a max of about 80 fps but it’s capped at 50, and on a p II 450 mhz system it runs about 30-45 fps depending on the window size.
It’s frame based logic but can catch up if it drops behind

The window size is default to 500x500 (approximately) and the tile map is 14 tiles high, using 32x32 tiles, and can be up to 1000 tiles long. I’ve looked at levels with diferent lengths, gone right up to the max length and it still runs good, just flickery…

This’ll be an even bigger problem when i start introducing enemy sprites, coin sprites, block smash sprites etc…

Are you setting the JFrame to be visible before initializing BufferStrategy in windowed mode?

-Jason Thomas.

I my case, yes.

This is just some simple code to demonstrait a windowed BufferStrategy.
I flung most of it together, just to check if I was right.

If you remove the “setVisible(true)” statement, you will get the same peer error. The window obviously needs to be showing before you can draw into it. This is the same error you get when you try to load an Image and you haven’t yet set the Frame to visible.

/**

  •  Simple BufferStrategy Accelerated Graphics Engine.
    
  • @author Jason Thomas.
    */

import java.awt.Graphics;
import java.awt.GraphicsConfiguration;
import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment;
import java.awt.Rectangle;
import java.awt.image.BufferStrategy;
import javax.swing.JFrame;

public class TestBufferStrat
{

JFrame mainFrame;

BufferStrategy bufferStrategy;
Graphics myGraphics;
int x;
int y;
  
  
public TestBufferStrat(int numBuffers, GraphicsDevice device)
{
        try
        {
              GraphicsConfiguration gc = device.getDefaultConfiguration();
              
              mainFrame = new JFrame(gc);
              //mainFrame.setBackground(Color.blue);
              //mainFrame.setUndecorated(true);
              mainFrame.setIgnoreRepaint(true);
              mainFrame.setSize(500,500);
              mainFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
              mainFrame.setVisible(true);
              mainFrame.setIgnoreRepaint(true);
              //mainFrame.setUndecorated(true);
              
              
              //device.setFullScreenWindow(mainFrame);                  mainFrame.setUndecorated(true);
              mainFrame.setIgnoreRepaint(true);

              
              Rectangle bounds = mainFrame.getBounds();
              mainFrame.createBufferStrategy(numBuffers, gc.getBufferCapabilities());
              bufferStrategy = mainFrame.getBufferStrategy();
              
              System.out.println(bufferStrategy);
              
              
              myGraphics = bufferStrategy.getDrawGraphics();
        }
        catch (Exception e)
        {
              e.printStackTrace();
        }
        
        x = 0;
        y = 0;
        /*
         ActionListener taskPerformer = new ActionListener()
         {
         public void actionPerformed(ActionEvent evt)
         {
         
         if (!bufferStrategy.contentsLost())
         {
         myGraphics.setColor(Color.black);
         myGraphics.fillRect(x,y,50,50);
         x+=5;
         y+=5;
         bufferStrategy.show ();
         }
         }
         };
        
         new Timer(32, taskPerformer).start();*/
        while(true)
        {
              if(!bufferStrategy.contentsLost())
              {
                    myGraphics.fillRect(x,y,50,50);
                    x+=5;
                    y+=5;
                    bufferStrategy.show();
                    /*
                     try
                     {
                     Thread.sleep(20);
                     }
                     catch(InterruptedException e)
                     {
                     e.printStackTrace();
                     }*/
                    Thread.yield();
              }
              
        }
        
        
}
  
public static void main(String[] args)
{
        try
        {
              int numBuffers = 2;
              
              GraphicsEnvironment env = GraphicsEnvironment.
                    getLocalGraphicsEnvironment();
              GraphicsDevice device = env.getDefaultScreenDevice();
              TestBufferStrat myStrat = new TestBufferStrat(numBuffers, device);
        }
        catch (Exception e)
        {
              e.printStackTrace();
        }
}

}

Oops :stuck_out_tongue: Change the animation loop to this:

        Thread myThread = new Thread()
        {
              public void run()
              {
                    while(true)
                    {
                          if(!bufferStrategy.contentsLost())
                          {
                                myGraphics.fillRect(x,y,50,50);
                                x+=5;
                                y+=5;
                                bufferStrategy.show();
                          }
                          
                    }
              }
        };
        myThread.start();

That way your GUI doesn’t get locked up when it animates.

java.awt.AWTException: The operation requested is only supported on a full-screen exclusive window

GraphicsConfiguration.getBufferCapabilities() only works in fullscreen mode.

I’m pretty sure I’m doing it right because it doesn’t blow up. It’s just that the whole thing sucks in windowed mode when using a buffer stategy, Imean 6 FPS is pointless.

if you don’t get >500fps with this example, there is something wrong with your setup. :o


import java.util.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
public class BSFrame extends Frame implements Runnable
{
   volatile boolean running;
   BufferStrategy bs;
   public BSFrame()
   {
      addWindowListener(new WindowAdapter()
      {
         public void windowClosing(WindowEvent we)
         {
            running = false;
         }
      });

      setBounds(0,0,512,384);
      show();
      createBufferStrategy(2);
      bs = getBufferStrategy();
      running = true;
      Thread t= new Thread(this);
      t.setPriority(Thread.MIN_PRIORITY); //so the AWT Thread actually runs :P
      t.start();
   }

   Random r = new Random();
   public void run()
   {
      String fpsString = "n/a";
      int paints = 0;
      long lastTime = System.currentTimeMillis();
      while(running)
      {
         Graphics g = bs.getDrawGraphics();
         g.setColor(new Color(r.nextInt()));
         g.fillRect(0,0,getWidth(),getHeight());
         g.setColor(Color.black);
         g.drawString(fpsString,10,50);
         g.dispose();
         bs.show();
         paints++;
         if(System.currentTimeMillis()-lastTime>1000)
         {
            lastTime+=1000;
            fpsString = Integer.toString(paints);
            paints=0;
         }
      }
      dispose();
   }

   public static void main(String [] args)
   {
      new BSFrame();
   }
}

Your example: over 3000 FPS

In practice with f15-strike 6 FPS. Would you care to take a look at the code. I would love to be proved wrong. I mean shown what I’m am doing wrong, if anything. :smiley:

[quote]Your example: over 3000 FPS

In practice with f15-strike 6 FPS. Would you care to take a look at the code. I would love to be proved wrong. I mean shown what I’m am doing wrong, if anything. :smiley:
[/quote]
are you doing any per-pixel operations (such as AlphaCompositing), or are you using any images with an AlphaChannel?

at current, the only per pixel operation that is hardware accelerated (apart from straight copy) is bitmask transparency.

If you attempt to do unaccelerated pixel operations onto an image being held in vram, the performance will completely die.
(the image in vram has to be read back across the agp bus, copied into main memory, the operation applied, and the image copied back again)

If you are doing unaccelerated pixel ops. , you should NOT use BufferStrategy. (its abit of a flaw in the api atm, that a backBuffer stored in vram can actually be ALOT slower than a backBuffer stored in main memory :o)

Yeah there are a couple of images that use alpha blending when they are drawn. However what I don’t understand is that I’m getting 75 FPS in fullscreen mode doing exactly the same thing.

I tried not using BufferStrategy and creating my own back buffer, both volatile and non-volatile. Got the same results around 6 FPS.

I just tried changing the desktop video mode. 32 bit=6FPS, 16 bit=12FPS, 8 bit=20FPS.

I had a version that simply didn’t do any double buffering in windowed mode. got over 100FPS but flickered like hell so that is useless.

I’m completely confused. Obviously I’m getting full acceloration in fullscreen mode, what is up with windowed mode? Any of the SUN guys around to explain this?

thx. i found out… the valid peer message is a bit cryptic, and i looked at the example here and another one someone posted in another post here. i was trying to create the bufferstrategy before i set the frame visible.

just out of curiousity… why is it that when you do this, and get it working, if you resize the window to be larger than it was, it’ll freeze the drawing, but if you shrink it, it’ll be fine, until you go to make it bigger again when it wont work. seems that the buffers can be reduced in size dynamically but not made larger.

also, is it possible to override paintComponent to get a component to draw itself onto something else (such as the buffer)

i tried this and got absolutely nothing drawn, even after looping it at intervals, and bufferstrategy.show

Does anyone know where I can find the sample code of BufferStrategy in window mode which constantly paints screen but does not have screen flicking problem ? I have never sucessfully made BufferStrategy in window mode work properly. I use double buffer in my application which draws background first and then all the sprites into a back buffer. The application works fine with double buffer. But screen starts to flick when I change to BufferStrategy.

Jay