Anti-aliasing on Mac OS X...

Greeting from Norway!

I have some problems while using JOGL 1.1.1 on Mac OS X machine. AFAIK it’s common problem. Code below doesn’t work:

private GLCapabilities createGLCapabilites() {

        GLCapabilities capabilities = new GLCapabilities();
        capabilities.setHardwareAccelerated(true);

        // try to enable 2x anti aliasing - should be supported on most hardware
        capabilities.setNumSamples(4);
        capabilities.setSampleBuffers(true);

        return capabilities;
    }

I find some information here.

[quote]The following issues remain with the Mac OS X port:

* Due to the mechanism by which the Cocoa graphics system selects OpenGL pixel formats, the GLCapabilitiesChooser mechanism can not be implemented on Mac OS X as on other platforms. Currently the underlying Cocoa pixel format selection is used on an NSOpenGLPixelFormat derived from the settings in the GLCapabilities, and the GLCapabilitiesChooser is ignored.

[/quote]
Bad news… :frowning:

So, how can I enable AA on OS X? May be there is more than one way to do it… :wink:

I’ve never had any problems with having it understand the number of sample buffers. If want multi-sampling to work, you must also enable it in your init() method of your GLEventListener with gl.glEnable(GL.GL_MULTISAMPLE) (this only works if you have at least one sample buffer).

To check the number of samples you’re using, use gl.glGetIntegerv(GL.GL_SAMPLES, store, 0);
To see the number of sample buffers, use gl.glGetIntegerv(GL.GL_SAMPLE_BUFFERS, store, 0); If the number of samples buffers > 0, then multi sampling should have an effect when it’s enabled.

lhkbob, I added line:

gl.glEnable(GL.GL_MULTISAMPLE);

in my init() method. But nothing has changed… :frowning:

This code

int buf[] = new int[1];
int sbuf[] = new int[1];
...
gl.glGetIntegerv(GL.GL_SAMPLES, buf, 0);
gl.glGetIntegerv(GL.GL_SAMPLE_BUFFERS, sbuf, 0);
System.out.println(buf[0]);
System.out.println(sbuf[0]);

always return two zeros.

What version of Mac are you running, how new is your graphics card, and what version of opengl does it say? I believe multi sampling was included later on, but maybe your specific computer doesn’t support it. Another option is to try a lower number (such as 2), and finally post a small test sample that illustrates the problem you’re having so I can test it on my computer.

lhkbob, I’m sorry for long absense. :persecutioncomplex:

MacBook 4th generation, Mac OS X 10.5.6, OpenGL 1.2 APPLE-1.5.36, JOGL 1.1.1, Java 6 (1.6.0_07).

For example, try this sample. I can’t see any differences. And of course this code

gl.glGetIntegerv(GL.GL_SAMPLE_BUFFERS, buf, 0);
System.out.println("number of sample buffers is " + buf[0]);
gl.glGetIntegerv(GL.GL_SAMPLES, sbuf, 0);
System.out.println("number of samples is " + sbuf[0]);

in init() method it returns two zeros:

number of sample buffers is 0
number of samples is 0

If mutlisampling does not work on your computer you may try alternative solutions to perform antialiasing:
http://www.opengl.org/resources/code/samples/sig99/advanced99/notes/node119.html.

However, they are less straightforward. These solutions are also old, so they maybe use deprecated features (especially the polygon antialiasing).

Are you using a GLCanvas or a GLJPanel? When using a GLJPanel under windows, I have experienced some weird things with the number of available sample buffers.
Actually, the higher the Panel size, the lower the number of sample I can use. For example in a small window, I can use 8 samples buffers and maybe more. But in full screen I can use only 2.
Maybe I’m doing something wrong but it’s very strange.

GLJPanel uses pbuffers and AFAIK GL does not support multisampled pbuffers yet (maybe as extension but not as a requirement).

Unfortunately for you, when I run that sample, I get the correct results. Here are the print outs from my Macbook Pro:
number of sample buffers is 1
number of samples is 2
OpenGL 2.0 NVIDIA-1.5.36 NVIDIA Corporation

I’m using a Macbook pro, 10.5.6 with a Geforce 8600, with java 1.6
According to the opengl specification, the multisample extension was promoted to core opengl in version 1.3. If I’m understanding your version string correctly, you only have version 1.2, which would imply that it isn’t supported, or it’s supported through the extension GL_ARB_multisample.

What does gl.isExtensionAvailable(“GL_ARB_multisample”) report? But even if it’s true, I don’t know if the GLCapabilities is smart enough to use the ARB or EXT extensions for multi-sampling.

You are lucky! :wink:

gl.isExtensionAvailable(“GL_ARB_multisample”) - False.
As I find here my MacBook with GMA X3100 has only OpenGL 1.2. And multisampling is not available. Sometimes I hate Apple! :frowning:

Anyway thanks to all for replies! :slight_smile:

P.S. Is there any option to check question solved?

I am having the same problem. The anti-alias sample looks identical to the non-anti-alias sample. However it is NOT a problem with the sample buffers, since my output is:

number of sample buffers is 1
number of samples is 2
OpenGL 2.0 ATI-1.5.36

I have done some more experiments and found that anti-aliasing is in fact working, but with two caveats:

  1. The demo uses only 2 samples, which doesn’t make a noticeable improvement. You have to use at least 8.

  2. glEnable(GL.GL_MULTISAMPLE) and gl.glEnable(GL.GL_MULTISAMPLE) are completely ignored. If you have sample buffers then you will get antialiasing. If you don’t, you won’t. There is no way to turn it on and off during drawing, and so the two shapes in the demo will always look identical.

That sounds like a driver error to me. When I ran the demo, there were definite differences when multi-sampling was enabled for one half. Also, from my experience, 2 samples is barely noticeable, but at 4 samples I’ve seen much improvement.

I also tried the demo and whatever the number of sample buffers I request, I only have 2x antialiasing.
A GLCapabilty with the right number of sample buffers (4,8 or 16) is selected. But when I ask OpenGL with glGetIntegerv, there are actually only 2 sample buffers.
I confirmed that on the screen it is 2x anti-aliasing.

My configuration is a Win XP 64 with a Quadro FX 550 (I’ve just updated to the latest drivers and it didn’t change anything).

Does any one has a similar problem? Do you think it is a driver related bug or that it comes from OpenGL?

The number of available samples is driver dependent. OpenGL only provides a way to enable and request the number of samples. A driver will then pick the maximum number of samples that it supports that’s less than or equal to the request.

For example, my Geforce 8600 only supports 2 or 4 samples, while some ati cards can get up to 8 or 16 samples.

Thanks for your answer, but I’m quite annoyed by having only 2 sample buffers.
The improvement is barely noticeable.

I created GLCapabilitiesChooser interface to see all the available display modes I could have in JOGL.
I found modes with 16 sample buffers, such as this one:


GLCapabilities [DoubleBuffered: true, Stereo: false, HardwareAccelerated: true, DepthBits: 24, StencilBits: 8, Red: 8, Green: 8, Blue: 8, Alpha: 8, Red Accum: 16, Green Accum: 16, Blue Accum: 16, Alpha Accum: 16, Multisample: true, Num samples: 16 ]

But even if I select them, I still got 2 sample buffers enable at the end.

I’m quite puzzled with all these contradictory information :-.

If you use that format exactly, how many stencil bits, depth bits, alpha bits, and accumX bits do you get? This may actually be some bug in JOGL and its usage of WGL, or a bug in WGL where it reports available formats that aren’t supported.

My inclination is that the other actual bit values don’t match the requested caps bits, then its a bug with WGL reporting an unavailable format that it only detects when actually setting the pixel formats.

Unfortunately, my knowledge of how all of this works together is limited to briefly browsing the source code, so a good answer will probably need to be supplied by someone else.

I modified the Multisample demo to create a test case in order to get the results.
Here is the differences from the capabilites I choose in the GLCapabilitiesChooser, the one actually used by JOGL and the values requested from OpenGL.


Requested capabilites
GLCapabilities [DoubleBuffered: true, Stereo: false, HardwareAccelerated: true, DepthBits: 24, StencilBits: 8, Red: 8, Green: 8, Blue: 8, Alpha: 8, Red Accum: 16, Green Accum: 16, Blue Accum: 16, Alpha Accum: 16, Multisample: true, Num samples: 4 ]
JOGL capabilities 
GLCapabilities [DoubleBuffered: true, Stereo: false, HardwareAccelerated: true, DepthBits: 24, StencilBits: 8, Red: 8, Green: 8, Blue: 8, Alpha: 8, Red Accum: 16, Green Accum: 16, Blue Accum: 16, Alpha Accum: 16, Multisample: true, Num samples: 4 ]
Real capabilites 
[DoubleBuffered: 1, Stereo : 0, DepthBits : 24, StencilBits : 8, Red : 8, Green : 8, Blue : 8, Alpha : 8, Red Accum : 16, Green Accum : 16, Blue Accum : 16, Alpha Accum : 16, Multisample : 1, Num samples : 2]

The only difference is the number of sample between the capabilities and the values queried from OpenGL.
I’ve also looked at the WindowsGLDrawable.java file and the code seems OK for me.
It’s probably a driver bug then. I hope it’s just happening on Win XP 64.

I will try my test case on other computers to see if there are any differences.

Here is the test case:


import java.awt.*;
import java.awt.event.*;
import javax.media.opengl.*;

public class Multisample {
  private GLCanvas canvas;

  // Simple class to warn if results are not going to be as expected
  static class MultisampleChooser extends DefaultGLCapabilitiesChooser {
    public int chooseCapabilities(GLCapabilities desired,
                                  GLCapabilities[] available,
                                  int windowSystemRecommendedChoice) {
      boolean anyHaveSampleBuffers = false;
      System.err.println("Quering");
      for (int i = 0; i < available.length; i++) {
        GLCapabilities caps = available[i];
        
        if (caps == null) {
        	continue;
        }
        
        if (caps.getNumSamples() == 4
        	&& caps.getDepthBits() == 24
        	&& caps.getRedBits() == 8
        	&& caps.getAlphaBits() == 8
        	&& caps.getStencilBits() == 8
        	&& !caps.getStereo()
        	&& caps.getDoubleBuffered()
        	&& caps.getAccumAlphaBits() == 16
        	&& caps.getSampleBuffers()
        	&& caps.getHardwareAccelerated())
        {
        	System.err.println("Requested capabilites\n" + caps);
        	return i;
        }
      }
      return windowSystemRecommendedChoice;
    }
  }

  public static void main(String[] args) {
    new Multisample().run(args);
  }

  public void run(String[] args) {
    GLCapabilities caps = new GLCapabilities();
    GLCapabilitiesChooser chooser = new MultisampleChooser();
    
    caps.setSampleBuffers(true); 

    canvas = new GLCanvas(caps, chooser, null, null);
    canvas.addGLEventListener(new Listener());
    
    Frame frame = new Frame("Full-scene antialiasing");
    frame.setLayout(new BorderLayout());
    canvas.setSize(512, 512);
    frame.add(canvas, BorderLayout.CENTER);
    frame.pack();
    frame.show();
    canvas.requestFocus();

    frame.addWindowListener(new WindowAdapter() {
        public void windowClosing(WindowEvent e) {
          runExit();
        }
      });
  }

  class Listener implements GLEventListener {
    public void init(GLAutoDrawable drawable) {
      GL gl = drawable.getGL();

      gl.glClearColor(0, 0, 0, 0);
      
      gl.glEnable(GL.GL_MULTISAMPLE);

      gl.glMatrixMode(GL.GL_MODELVIEW);
      gl.glLoadIdentity();
      gl.glMatrixMode(GL.GL_PROJECTION);
      gl.glLoadIdentity();
      gl.glOrtho(-1, 1, -1, 1, -1, 1);
      
      /* Getting info from JOGL */
      System.err.println("JOGL capabilities \n" + drawable.getChosenGLCapabilities() );
      
      
      /* Getting info from OpenGL */
      int[] buf = new int[1];
	  byte[] bbuf = new byte[1];
	  
	  gl.glGetBooleanv(GL.GL_DOUBLEBUFFER, bbuf,0);
	  String realCaps = "[DoubleBuffered: " + bbuf[0];
	  gl.glGetBooleanv(GL.GL_STEREO, bbuf,0);
	  realCaps += ", Stereo : " + bbuf[0];
	  gl.glGetIntegerv(GL.GL_DEPTH_BITS, buf, 0);
	  realCaps += ", DepthBits : " + buf[0];
	  gl.glGetIntegerv(GL.GL_STENCIL_BITS, buf, 0);
	  realCaps += ", StencilBits : " + buf[0];
	  gl.glGetIntegerv(GL.GL_RED_BITS, buf, 0);
	  realCaps += ", Red : " + buf[0];
	  gl.glGetIntegerv(GL.GL_GREEN_BITS, buf, 0);
	  realCaps += ", Green : " + buf[0];
	  gl.glGetIntegerv(GL.GL_BLUE_BITS, buf, 0);
	  realCaps += ", Blue : " + buf[0];
	  gl.glGetIntegerv(GL.GL_ALPHA_BITS, buf, 0);
	  realCaps += ", Alpha : " + buf[0];
	  gl.glGetIntegerv(GL.GL_ACCUM_RED_BITS, buf, 0);
	  realCaps += ", Red Accum : " + buf[0];
	  gl.glGetIntegerv(GL.GL_ACCUM_GREEN_BITS, buf, 0);
	  realCaps += ", Green Accum : " + buf[0];
	  gl.glGetIntegerv(GL.GL_ACCUM_BLUE_BITS, buf, 0);
	  realCaps += ", Blue Accum : " + buf[0];
	  gl.glGetIntegerv(GL.GL_ACCUM_ALPHA_BITS, buf, 0);
	  realCaps += ", Alpha Accum : " + buf[0];
	  gl.glGetIntegerv(GL.GL_SAMPLE_BUFFERS, buf, 0);
	  realCaps += ", Multisample : " + buf[0];
      gl.glGetIntegerv(GL.GL_SAMPLES, buf, 0);
      realCaps += ", Num samples : " + buf[0];
	  realCaps += "]";
	    
      System.err.println("Real capabilites \n" + realCaps);

	    
    }

    public void display(GLAutoDrawable drawable) {
      GL gl = drawable.getGL();

      gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT);

      int numSteps = 20;
      double increment = Math.PI / numSteps;
      double radius = 1;

      gl.glBegin(GL.GL_LINES);
      for (int i = numSteps - 1; i >= 0; i--) {
        gl.glVertex3d(radius * Math.cos(i * increment),
                      radius * Math.sin(i * increment),
                      0);
        gl.glVertex3d(-1.0 * radius * Math.cos(i * increment),
                      -1.0 * radius * Math.sin(i * increment),
                      0);
      }
      gl.glEnd();
    }

    // Unused routines
    public void reshape(GLAutoDrawable drawable, int x, int y, int width, int height) {}
    public void displayChanged(GLAutoDrawable drawable, boolean modeChanged, boolean deviceChanged) {}
  }

  private void runExit() {
    // Note: calling System.exit() synchronously inside the draw,
    // reshape or init callbacks can lead to deadlocks on certain
    // platforms (in particular, X11) because the JAWT's locking
    // routines cause a global AWT lock to be grabbed. Instead run
    // the exit routine in another thread.
    new Thread(new Runnable() {
        public void run() {
          System.exit(0);
        }
      }).start();
  }
}


I can confirm that it is a driver bug.

I tried to enable anti-aliasing for all applications with the Nvidia control panel.
And wathever the quality I tried, the result is the same, it’s 2x anti-aliasing.

I tried on computer running with Vista and you can clearly see the difference.

Thanks for your help anyway.

Btw, do you know how multisampling is done for the GLJPanel? I curious why I can get up to 16 sample buffers in a small window but any in full screen.
I will have a look at the code to see if there is any difference with the GLCanvas.

I’m glad you figured it out, unfortunately I don’t use GLJPanel ever so I couldn’t tell much about it and multi-sampling.