views:

54

answers:

1

Dear developers,

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();
 }
}
+2  A: 

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();
    }
}
trashgod
Though I don't know why, implementing my main application based on your code example does solve the cpu-hungry-ness on Mac. I still have some artifacts to solve that show up when I add TextFields on top of the rendered content, but so far this seems like a great step forward! Thanks!
Mattijs
trashgod
Update: the artifacts (a small range of pixels around TextFields not repainting correctly) are solved by using JTextField instead.
Mattijs
@trashgod: as of yet I didn't use Timer but the conventional while loop with Thread.sleep(), but I might try the Timer approach to see if I notice any difference. Btw adding super.paintComponent(g) as you suggest appears to clear my rendered content. I keep some flags to indicate where repainting is necessary, which are set to false after repainting is done. Anyway, without this addition I seem to have everything running nicely. Thanks again.
Mattijs
A few more issues.. For a continued discussion on this topic, please have a look at http://stackoverflow.com/questions/3256269/jtextfields-on-top-of-active-drawing-on-jpanel-threading-problems
Mattijs