Search code examples
javamacosdoublebuffering

Java page flipping not supported on Mac OS?


I'm hoping someone happens to have stumbled upon the following issue before.

My Java application has graphics performance issues on Mac, so I made a simple test application (code below). When I run this on Windows, the console tells me:

GraphicsConfiguration flipping? true
BufferStrategy flipping? true

When I run the exact same code on Mac OS, I get:

GraphicsConfiguration flipping? true
BufferStrategy flipping? false

Does this mean that on Mac OS, page flipping is simply not supported in a windowed application? Are there any tricks to make page flipping work on Mac OS without going full screen?

All pointers are very welcome,
Mattijs

Using JDK 1.6 on Windows XP and Mac OS 10.5.

The code:

import java.awt.image.BufferStrategy;
import javax.swing.*;
import java.awt.*;

public class Test {
 int width = 640;
 int height = 480;

 GraphicsEnvironment graphEnv = GraphicsEnvironment.getLocalGraphicsEnvironment();
 GraphicsDevice graphDevice = graphEnv.getDefaultScreenDevice();
 GraphicsConfiguration graphicConf = graphDevice.getDefaultConfiguration();

 public Test() {
  JFrame jFrame = new JFrame(graphicConf);
  jFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
  jFrame.setTitle("double buffer test");
  jFrame.setResizable(false);
  jFrame.setFocusTraversalKeysEnabled(false);

  Canvas canvas = new Canvas();
  canvas.setSize(width, height);
  canvas.setIgnoreRepaint(true);

  jFrame.getContentPane().add(canvas);
  jFrame.pack();
  jFrame.setVisible(true);

  System.out.println("GraphicsConfiguration flipping? " + graphicConf.getBufferCapabilities().isPageFlipping());
  canvas.createBufferStrategy(2);
  BufferStrategy bufferStrategy = canvas.getBufferStrategy();
  System.out.println("BufferStrategy flipping? " + bufferStrategy.getCapabilities().isPageFlipping());

  while(true) {
    Graphics g = bufferStrategy.getDrawGraphics();
    g.setColor(Color.BLACK);
    g.fillRect(0,0,width,height);
    g.setColor(Color.RED);
    g.drawLine((int)(Math.random()*width),(int)(Math.random()*height),
               (int)(Math.random()*width),(int)(Math.random()*height));
    bufferStrategy.show();
    g.dispose();
  }
 }

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

Solution

  • The bad news: I get the same result on the same Mac OS X configuration. The good news: isAccelerated() is true.

    System.out.println("BufferStrategy accelerated? " + bufferStrategy
        .getCapabilities().getFrontBufferCapabilities().isAccelerated());
    

    Instead of Canvas and BufferStrategy, I just use new JPanel(true).

    Addendum: For example,

    import java.awt.Color;
    import java.awt.Dimension;
    import java.awt.EventQueue;
    import java.awt.Graphics;
    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;
    import java.util.Random;
    import javax.swing.JFrame;
    import javax.swing.JPanel;
    import javax.swing.Timer;
    
    public class NewTest extends JPanel implements ActionListener, Runnable {
    
        private Random r = new Random();
        private Timer t = new Timer(10, this);
    
        public static void main(String[] args) {
            EventQueue.invokeLater(new NewTest());
        }
    
        @Override
        public void run() {
            JFrame f = new JFrame("NewTest");
            f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            f.add(this);
            f.pack();
            f.setLocationRelativeTo(null);
            f.setVisible(true);
            t.start();
        }
    
        public NewTest() {
            super(true);
            this.setPreferredSize(new Dimension(640, 480));
        }
    
        @Override
        protected void paintComponent(Graphics g) {
            int width = this.getWidth();
            int height = this.getHeight();
            g.setColor(Color.BLACK);
            g.fillRect(0, 0, width, height);
            g.setColor(Color.RED);
            g.drawLine(r.nextInt(width), r.nextInt(height),
                r.nextInt(width), r.nextInt(height));
    
        }
    
        @Override
        public void actionPerformed(ActionEvent e) {
            this.repaint();
        }
    }