Page Flipping with Buffer Strategy

First time poster here. :slight_smile:

Ever since I managed to get full-screen exclusive mode working, I’ve noticed that the faster moving objects tear like crazy. I’ve scoured the net for one decent example of a simple page-flipping code and came up with nothing. Everyone keeps linking to the “examples” ::slight_smile: on Sun’s site, but there is no code whatsoever demonstrating the use of page-flipping.

Having a couple of words and pictures doesn’t do it for this programmer. Wish it did, but it doesn’t. :wink:

I would be very grateful if any kind soul here could point me in the right direction – that one, single example!

It’s actually pretty easy. Java does most of the work for you. This little thread outlines it, and I believe in the shared code forum there are other, more detailed, examples.

http://www.java-gaming.org/cgi-bin/JGNetForums/YaBB.cgi?board=newbies;action=display;num=1057373581

Just keep in mind you have to call that setupBuffering() method after the frame is fully created and visible.

The strategy.show() is where the magic happens. Java will either page flip or blit, depending on what the hardware is capable of.

Ah, thanks. Looks like it’s working. Multi-buffer and page-flipping both return as true.

However, there’s horrible full-screen flickering now. I can tell that there’s no more tearing, but the whole screen flashes with the background color. It isn’t exactly the “flickering” that you’d see in the old days when you didn’t use the old-fashioned double-buffering, but it’s more of a flashing.

The background itself doesn’t clear out the area; I have to do a setColor(Color.blue) and fillRect(0,0,640,480), otherwise you get that effect like in Doom when you walk out of the walls.

import java.awt.event.*;
import java.awt.image.*;
import java.awt.geom.*;
import java.applet.*;
import java.util.*;
import java.net.*;
import java.applet.Applet;
import javax.swing.*;
import java.io.*;


public class Gamer extends Frame implements KeyListener, MouseListener, MouseMotionListener
{
      BufferStrategy strategy;
      BufferCapabilities bufCap;

      GraphicsDevice device;
      GraphicsConfiguration gc;
      boolean inFullScreen;

      DisplayMode newDisplayMode;
      DisplayMode oldDisplayMode;

      public Gamer (String title, GraphicsDevice device)
      {
            super(device.getDefaultConfiguration());
                   this.device = device;

            oldDisplayMode = device.getDisplayMode();

            boolean isFullScreen = device.isFullScreenSupported();
              setUndecorated(isFullScreen);
              setResizable(!isFullScreen);

              if (isFullScreen) 
            {
                        device.setFullScreenWindow(this);
                       validate();
                  inFullScreen = true;
                   }
            
            else 
            {
                        pack();
                        setVisible(true);
                  inFullScreen = false;
              }

            

            newDisplayMode = new DisplayMode(640, 480, 32, 60);
            device.setDisplayMode(newDisplayMode);
            gc = device.getDefaultConfiguration();
            bufCap = gc.getBufferCapabilities();

            createBufferStrategy(3);
            strategy = getBufferStrategy();

            setBackground(Color.blue);

            while (true)
            {
                  if (loaded)
                  {
                        runningUpdate();
                        render();
                  }

                  try
                  {
                        Thread.sleep(20);
                  }

                  catch (InterruptedException e) {}
            }            
      }

      public void render ()
      {
            Graphics g1 = strategy.getDrawGraphics();

            Graphics2D g = (Graphics2D) g1;

            g.setColor(Color.blue);
            g.fillRect(0,0,640,480);

            // DRAWING

            g.dispose();
            strategy.show();
      }
            
      public static void main (String[] args)
      {
            GraphicsEnvironment env = GraphicsEnvironment.getLocalGraphicsEnvironment();
            GraphicsDevice myDevice = env.getDefaultScreenDevice();

            Gamer gamer = new Gamer("Gamer", myDevice);
            gamer.setSize(640, 480);
            gamer.setVisible(true);
      }
}

Could someone please tell me what I’m doing wrong here? That’s all the code relevant to the graphical aspect of my program.

[quote]Ah, thanks. Looks like it’s working. Multi-buffer and page-flipping both return as true.

However, there’s horrible full-screen flickering now. I can tell that there’s no more tearing, but the whole screen flashes with the background color. It isn’t exactly the “flickering” that you’d see in the old days when you didn’t use the old-fashioned double-buffering, but it’s more of a flashing.

The background itself doesn’t clear out the area; I have to do a setColor(Color.blue) and fillRect(0,0,640,480), otherwise you get that effect like in Doom when you walk out of the walls.

Could someone please tell me what I’m doing wrong here? That’s all the code relevant to the graphical aspect of my program.
[/quote]
You arn’t doing anything wrong, Unless you specify otherwise, that is the default behaviour for BufferStrategy. (BufferCapabilities.FlipContents UNDEFINED)

If you want the BufferStrategy to clear to the background color, you should construct the BufferStrategy using a BufferCapabilities object set to BufferCapabilities.FlipContents BACKGROUND.

However, its no slower than filling it yourself with a fillRect(0,0,getWidth,getHeight()); so i’d just stick with what you are doing atm.

I’m still wondering about that flashing effect that’s going on. I’ve noticed that the more buffers I use – createBufferStrategy(numBuffers) – the slower the frequency of the flash.

I’m doing something wrong here to cause this flashing effect. It is definitely the background color that’s doing it. When the background is set to red, it’ll flash red, etc. Leaving it alone will flash white.

Red–Blue–Red flashing looks pretty cool and seizure-inducing, but it’s not what I wanted for the game, exactly. :wink:

I’ll try experimenting with a few other ideas I have, but so far, no luck.

You are redrawing the entire screen every repaint, arn’t you?

Don’t you need to override paint() and update() to prevent the standard AWT stuff redrawing the screen?

Kev

that’s probably it, a setIgnoreRepaint(true) could do the trick. I’ve never had the flashing problems but I also always set to ignore repaints.

Whew! Thanks everyone! ;D ;D ;D

The setIgnoreRepaint(true) did the trick. Now everything runs perfectly in fullscreen and without a single tear effect.

Seems like I’ve run into a totally different snag now. :wink:

I implemented the BufferStrategy as opposed to the old update() and paint() methods, and now my .png graphics – which make extensive use of an alpha channel and partial transparency – slow the game down considerably. The more of them there are on the screen, the worse it is.

Before, without using strategy.show(), the performance was as quick as the Gingerbread Man, no matter how many of them I had on the screen at any given time.

I’d hate to have to go back to high-speed ripping and tearing, but I love my large corona effects.

Does anyone know what it is about using BufferStrategy that significantly downgrades the performance of images that utilize the alpha channel?

If you’re on windows you might try these:

-Dsun.java2d.translaccel=true 
-Dsun.java2d.ddforcevram=true  

Java accelerated graphics arn’t keen on the alpha channel.

Kev

Also make sure the BufferedImage that results from loading the png is actually accelerated. If you load your pngs via ImageIO, then they’re not accelerated in my experience (is that truly the case?)

I always load them via ImageIO, create a blank accelerated BufferedImage (via GraphicsConfiguration.createCompatibleImage( width, height, transparency ) ), then copy the ImageIO made image into the blank one.

When you later notice your game running like jerky molasses in Linux, that’s when you may rethink Java2D altogether ;D

That being said, the accelerated graphics alpha will get fixed eventually.

Kev

eventually

I tried it. I loaded the .png image through the ImageIO and then brought it over to a BufferedImage via createCompatibleImage. I set both flags to true. One rocketship didn’t seem to do that much damage to the framerate. But a few more certainly did. :frowning:

http://members.lycos.co.uk/riker1864/jets.jpg

When all I used was update() and paint(), I could get 60+ fps on a PIII 750mhz with this many rocketships on the screen. (Same level of transparency.)

Now, even with accelerated BufferedImages, I barely get 3 fps on a PIV 2.4ghz in the same situation.

You’d think that if hardware mode wasn’t faster than software, it’d be at least within the ballpark. :wink:

So a buffered image created with createCompatibleImage is automatically sent to VRAM if ImageCapabilities.isAccelerated() returns true?

[quote]I tried it. I loaded the .png image through the ImageIO and then brought it over to a BufferedImage via createCompatibleImage. I set both flags to true. One rocketship didn’t seem to do that much damage to the framerate. But a few more certainly did. :frowning:

When all I used was update() and paint(), I could get 60+ fps on a PIII 750mhz with this many rocketships on the screen. (Same level of transparency.)

Now, even with accelerated BufferedImages, I barely get 3 fps on a PIV 2.4ghz in the same situation.

You’d think that if hardware mode wasn’t faster than software, it’d be at least within the ballpark. :wink:
[/quote]
There lies part of the dilemma, drawing an image with an alpha channel to a vram backBuffer when alpha composite is not accelerated is incredibly slow. (the image has to be read back from vram, before the alpha composite can begin)

So, on a system without hardware AlphaCompositing, performance will be far far better by keeping the backBuffer in main mem.
However, this obviously eliminates the potencial for hardware acceleration on regular OPAQUE, and BITMASK images as well.

I think what Sun need to add, is a ‘request capabilities’ type interface, where by you specify what type of images you intend on drawing (OPAQUE,BITMASK, TRANSLUCENT), the api will then pick the best back buffer for you situation.

[quote]So a buffered image created with createCompatibleImage is automatically sent to VRAM if ImageCapabilities.isAccelerated() returns true?
[/quote]
Not exactly, when a ManagedImage (the type of Image elligable for hardware acceleration, that is returned from createCompatibleImage) is drawn 2 times, it is cached in vram.
If the image (the version in main memory) is subsequently modified, the vram cached version becomes useless, and is disgarded. (and has to be recached on a subsequent blit)

Incidentaly, you must have something not quite right in your code, cos hardware accelerated AlphaCompositing does work [in windows, with 1.4.1_02 or later] :smiley:

I am such an idiot! :smiley: :smiley: :smiley:

Know what I did with the flags? I put them after Java MyProgram. :wink:

Now the game runs just as fast as it did in the first place! Thanks very much for the help. Now that I’ve got everything technologically speaking, I can finally buckle down and concentrate on the game itself. ;D

Na, an idiot wouldn’t have found it. Its just the sorta thing that screws things up for ages…

Well done, good luck, etc…

Kev

[quote]I am such an idiot! :smiley: :smiley: :smiley:

Know what I did with the flags? I put them after Java MyProgram. :wink:
[/quote]
hehe, I thought you might have set them after an AWT component had been initialised. (I believe they have to be set before the AWT is initialised)
But putting them after the program… well… yeah LOL

hope you’ll post the game when its complete? :wink: