Choosing Renderer and Buffer Attributes

Renderer and buffer attributes determine the renderers that the system chooses for your application. Each of the Apple-specific OpenGL APIs provides constants that specify a variety of renderer and buffer attributes. You supply a list of attribute constants to one of the Apple OpenGL functions for choosing a pixel format object. The pixel format object maintains a list of renderers that meet the requirements defined by those attributes.

In a real-world application, selecting attributes is an art because you don't know the exact combination of hardware and software that your application will run on. An attribute list that is too restrictive may miss out on future capabilities or it may fail to return renderers on some systems. For example, if you specify a buffer of a specific depth, your application won't be able to take advantage of a larger buffer when more memory is available in the future. In this case, you might specify a required minimum and direct OpenGL to use the maximum available.

Although you might specify attributes that make your OpenGL content look and run its best, you also need to consider whether your application should run on a less-capable system with less speed or detail. If tradeoffs are acceptable, you need to set the attributes accordingly.

OpenGL Profiles (OS X v10.7)

When your application is running on OS X v10.7, it should always include the kCGLPFAOpenGLProfile attribute, followed by a constant for the profile whose functionality your application requires. A profile affects different parts of OpenGL in OS X:

Follow these guidelines to choose an OpenGL profile:

For more information on migrating an application to OpenGL 3.2, see “Updating an Application to Support the OpenGL 3.2 Core Specification.”

Buffer Size Attribute Selection Tips

Follow these guidelines to choose buffer attributes that specify buffer size:

Ensuring That Back Buffer Contents Remain the Same

When your application uses a double-buffered context, it displays the rendered image by calling a function to flush the image to the screen— theNSOpenGLContext class’s flushBuffer method or the CGL function CGLFlushDrawable. When the image is displayed, the contents of the back buffer are not preserved. The next time your application wants to update the back buffer, it must completely redraw the scene.

Your application can add a backing store attribute (NSOpenGLPFABackingStore or kCGLPFABackingStore) to preserve the contents of the buffer after the back buffer is flushed. Adding this attribute disables some optimizations that the system can perform, which may impact the performance of your application.

Ensuring a Valid Pixel Format Object

The pixel format routines (the initWithAttributes: method of the NSOpenGLPixelFormat class and the CGLChoosePixelFormat function) return a pixel format object to your application that you use to create a rendering context. The buffer and renderer attributes that you supply to the pixel format routine determine the characteristics of the OpenGL drawing sent to the rendering context. If the system can't find at least one pixel format that satisfies the constraints specified by the attribute array, it returns NULL for the pixel format object. In this case, your application should have an alternative that ensures it can obtain a valid object.

One alternative is to set up your attribute array with the least restrictive attribute first and the most restrictive attribute last. Then, it is fairly easy to adjust the attribute list and make another request for a pixel format object. The code in Listing 6-1 illustrates this technique using the CGL API. Notice that the initial attributes list is set up with the supersample attribute last in the list. If the function CGLChoosePixelFormat returns NULL, it clears the supersample attribute to NULL and tries again.

Listing 6-1  Using the CGL API to create a pixel format object

int last_attribute = 6;
CGLPixelFormatAttribute attribs[] =
{
    kCGLPFAAccelerated,
    kCGLPFAColorSize, 24
    kCGLPFADepthSize, 16,
    kCGLPFADoubleBuffer,
    kCGLPFASupersample,
    0
};
 
CGLPixelFormatObj pixelFormatObj;
GLint numPixelFormats;
long value;
 
CGLChoosePixelFormat (attribs, &pixelFormatObj, &numPixelFormats);
 
if( pixelFormatObj == NULL ) {
    attribs[last_attribute] = NULL;
    CGLChoosePixelFormat (attribs, &pixelFormatObj, &numPixelFormats);
}
 
if( pixelFormatObj == NULL ) {
    // Your code to notify the user and take action.
}

Ensuring a Specific Type of Renderer

There are times when you want to ensure that you obtain a pixel format that supports a specific renderer type, such as a hardware-accelerated renderer. Table 6-1 lists attributes that support specific types of renderers. The table reflects the following tips for setting up pixel formats:

Table 6-1  Renderer types and pixel format attributes

Renderer type

CGL

Cocoa

Hardware-accelerated onscreen

kCGLPFAAccelerated

kCGLPFANoRecovery

NSOpenGLPFAAccelerated

NSOpenGLPFANoRecovery

Software (floating-point)

kCGLPFARendererID

kCGLRendererGenericFloatID

NSOpenGLPFARendererID

kCGLRendererGenericFloatID

System memory (not accelerated)

kCGLPFAOffScreen

NSOpenGLPFAOffScreen

Hardware-accelerated offscreen

kCGLPFAPBuffer

NSOpenGLPFAPixelBuffer

Ensuring a Single Renderer for a Display

In some cases you may want to use a specific hardware renderer and nothing else. Since the OpenGL framework normally provides a software renderer as a fallback in addition to whatever hardware renderer it chooses, you need to prevent OpenGL from choosing the software renderer as an option. To do this, specify the no-recovery attribute for a windowed drawable object.

Limiting a context to use a specific display, and thus a single renderer, has its risks. If your application runs on a system that uses more than one display, dragging a windowed drawable object from one display to the other is likely to yield a less than satisfactory result. Either rendering fails, or OpenGL uses the specified renderer and then copies the result to the second display. The same unsatisfactory result happens when attaching a full-screen context to another display. If you choose to use the hardware renderer associated with a specific display, you need to add code that detects and handles display changes.

The code examples that follow show how to use each of the Apple-specific OpenGL APIs to set up a context that uses a single renderer. Listing 6-2 shows how to set up an NSOpenGLPixelFormat object that supports a single renderer. The attribute NSOpenGLPFANoRecovery specifies to OpenGL not to provide the fallback option of the software renderer.

Listing 6-2  Setting an NSOpenGLContext object to use a specific display

#import <Cocoa/Cocoa.h>
+ (NSOpenGLPixelFormat*)defaultPixelFormat
{
    NSOpenGLPixelFormatAttribute attributes [] = {
                        NSOpenGLPFAScreenMask, 0,
                        NSOpenGLPFANoRecovery,
                        NSOpenGLPFADoubleBuffer,
                        (NSOpenGLPixelFormatAttribute)nil };
CGDirectDisplayID display = CGMainDisplayID ();
// Adds the display mask attribute for selected display
attributes[1] = (NSOpenGLPixelFormatAttribute)
                    CGDisplayIDToOpenGLDisplayMask (display);
return [[(NSOpenGLPixelFormat *)[NSOpenGLPixelFormat alloc] initWithAttributes:attributes]
                                       autorelease];
}

Listing 6-3 shows how to use CGL to set up a context that uses a single renderer. The attribute kCGLPFANoRecovery ensures that OpenGL does not provide the fallback option of the software renderer.

Listing 6-3  Setting a CGL context to use a specific display

#include <OpenGL/OpenGL.h>
CGLPixelFormatAttribute attribs[] = { kCGLPFADisplayMask, 0,
                                 kCGLPFANoRecovery,
                                 kCGLPFADoubleBuffer,
                                  0 };
CGLPixelFormatObj pixelFormat = NULL;
GLint numPixelFormats = 0;
CGLContextObj cglContext = NULL;
CGDirectDisplayID display = CGMainDisplayID ();
// Adds the display mask attribute for selected display
attribs[1] = CGDisplayIDToOpenGLDisplayMask (display);
CGLChoosePixelFormat (attribs, &pixelFormat, &numPixelFormats);

Allowing Offline Renderers

Adding the attribute NSOpenGLPFAAllowOfflineRenderers allows OpenGL to include offline renderers in the list of virtual screens returned in the pixel format object. Apple recommends you include this attribute, because it allows your application to work better in environments where renderers come and go, such as when a new display is plugged into a Mac.

If your application includes NSOpenGLPFAAllowOfflineRenderers in the list of attributes, your application must also watch for display changes and update its rendering context. See “Update the Rendering Context When the Renderer or Geometry Changes.”

OpenCL

If your applications uses OpenCL to perform other computations, you may want to find an OpenGL renderer that also supports OpenCL. To do this, add the attribute NSOpenGLPFAAcceleratedCompute to the pixel format attribute list. Adding this attribute restricts the list of renderers to those that also support OpenCL.

More information on OpenCL can be found in the OpenCL Programming Guide for Mac.

Deprecated Attributes

There are several renderer and buffer attributes that are no longer recommended either because they are too narrowly focused or no longer useful. Your application should move away from using any of these attributes: