< Previous PageNext Page > Hide TOC

OpenGL on the Mac Platform

You can tell that Apple has an implementation of OpenGL on its platform just by looking at the user interface for many of the applications that are installed with Mac OS X. The reflections built into iChat (Figure 1-1) provide one of the more notable examples. The responsiveness of the windows, the instant results of applying an effect in iPhoto, and many, many other operations in Mac OS X v10.4 are due to the use of OpenGL. OpenGL isn't restricted to just the operating system and Apple applications. Any Mac developer can use OpenGL. In fact, Apple's implementation is available to every Macintosh user as part of Mac OS X.

OpenGL for Mac OS X is implemented as a set of frameworks that contain the OpenGL runtime engine and its drawing software. These frameworks use platform-neutral virtual resources to free your programming as much as possible from hardware considerations. Mac OS X provides a set of application programming interfaces (APIs) that Cocoa and Carbon applications can use to support OpenGL drawing.


Figure 1-1  OpenGL provides the reflections in iChat

OpenGL provides the reflections in iChat

This chapter describes the OpenGL frameworks and the associated APIs, defines the terminology that is Apple-specific, describes how data flows through OpenGL, and provides an overview of the tasks necessary for a Cocoa or Carbon application to tap into that pipeline.

In this section:

Structure of OpenGL in Mac OS X
Programming Interfaces
Terminology
Running an OpenGL Program in Mac OS X
See Also


Structure of OpenGL in Mac OS X

Mac OS X supports a display space that can consist of multiple dissimilar displays, each driven by different graphics cards with different capabilities. In addition, multiple OpenGL renderers can drive each graphics card. To accommodate this versatility, OpenGL for Mac OS X is segmented into three well-defined layers: a window system layer, a framework layer, and a driver layer, as shown in Figure 1-2. This segmentation allows for plug-in interfaces to both the window system layer and the framework layer. Plug-in interfaces offer flexibility in software and hardware configuration without violating the OpenGL standard.


Figure 1-2  Layers of OpenGL for Mac OS X

Layers of OpenGL for Mac OS X

The window system layer is what allows your OpenGL program to become a reality onscreen. You'll use the Apple-specific OpenGL APIs provided in this layer—the NSOpenGL classes and the AGL and CGL APIs—to direct where OpenGL drawing takes place and control a variety of aspects of rendering. These APIs contain functions and methods specific to the Mac OS X windowing system. (See “OpenGL APIs Specific to Mac OS X” for more information.) This layer also includes the OpenGL libraries—GL, GLU, and GLUT. (See “Apple-Implemented OpenGL Libraries” for details.)

The common OpenGL framework layer is the software interface to the graphics hardware. This layer contains Apple's implementation of the OpenGL specification.

The driver layer contains the optional GLD plug-in interface and one or more GLD plug-in drivers, which may have different software and hardware support capabilities. The GLD plug-in interface supports third-party plug-in drivers, allowing third-party hardware vendors to take advantage of newer driver technology.

Programming Interfaces

The programming interfaces that you'll use fall into two categories—those specific to the Macintosh platform and those defined by the OpenGL Architecture Review Board. The Apple-specific programming interfaces are what Cocoa and Carbon applications use to communicate with the Mac OS X windowing system. These APIs don't create OpenGL content, they simply manage content, direct it to a drawing destination (onscreen or offscreen), and control various aspects of the rendering operation. The OpenGL APIs actually create content. OpenGL routines accept vertex, pixel, and texture data and assemble the data to create content that has the illusion of being three-dimensional. The final content resides in a framebuffer, where it will languish unseen by the user unless your application uses a windowing-system specific API to direct the content onscreen.


Figure 1-3  The programing interfaces used for OpenGL content

The programing interfaces used for OpenGL content

OpenGL APIs Specific to Mac OS X

Mac OS X offers three easy-to-use application programming interfaces (APIs) that are specific to the Macintosh platform: the NSOpenGL classes, the AGL API, and the CGL API. Throughout this document, these three APIs are referred to as the Apple-specific OpenGL APIs.

Cocoa provides four classes specifically for OpenGL—NSOpenGLView, NSOpenGLContext, NSOpenGLPixelFormat, and NSOpenGLPixelBuffer. The NSOpenGLView class provides easy access to a basic OpenGL context that can be set up in Interface Builder. NSOpenGLView is a subclass of NSView and has the expected facilities to display OpenGL content in a view. NSOpenGLContext and NSOpenGLPixelFormat, along with NSView, are the building blocks for the NSOpenGLView class. Applications that subclass NSOpenGLView do not need to directly subclass NSOpenGLPixelFormat or NSOpenGLContext. Applications that need customization or flexibility, can subclass NSView. The NSOpenGLPixelBuffer class provides hardware-accelerated offscreen drawing. Using the NSOpenGL classes, you can also draw to the full screen.

For detailed information on the NSOpenGL classes, see the following reference documentation:

Apple Graphics Library (AGL) is the Apple interface to OpenGL for Carbon applications. It can be used by both Mach-O and CFM binaries, although CFM binaries are not recommended in Mac OS X because it's not possible to generate a universal binary with them. (A universal binary runs natively on both PowerPC and Intel-based Macintosh computers.) AGL supports drawing to the full screen as well as to Carbon windows and offscreen locations. In addition to the standard functionality, AGL provides full support for hardware-accelerated offscreen drawing, bitmap font rendering, and the ability to render content directly to a texture (also called render-to-texture functionality). The AGL API resides in the AGL framework. Applications must include the AGL.h header file (System/Library/Frameworks/AGL.framework/AGL.h) to access AGL functionality. AGL Reference provides a complete description of this API.

The Core OpenGL API (CGL) is the basis for the NSOpenGL classes and AGL. CGL offers the most direct access to system functionality and provides the highest level of graphics performance and control for drawing to the full screen. CGL is windowing-system agnostic but is accessible from both Cocoa and Carbon applications. The CGL API resides in the OpenGL framework. Applications must include the OpenGL.h header file (System/Library/Frameworks/OpenGL.framework/OpenGL.h) to access CGL functionality. CGL Reference provides a complete description of this API.

Apple-Implemented OpenGL Libraries

Mac OS X also provides the full suite of graphics libraries that are part of every implementation of OpenGL: GL, GLU, GLUT, and GLX. Two of these—GL and GLU—provide low-level drawing support. The other two—GLUT and GLX—support drawing to the screen.

Your application typically interfaces directly with the core OpenGL library (GL), the OpenGL Utility library (GLU), and the OpenGL Utility Toolkit (GLUT). The GL library provides a low-level modular API that allows you to define graphical objects. It supports the core functions that are common to all OpenGL implementations, as mandated by the OpenGL specification. It provides support for two fundamental types of graphics primitives: objects defined by sets of vertices, such as line segments and simple polygons, and objects that are pixel-based images, such as filled rectangles and bitmaps. The GL API does not handle complex custom graphical objects; your application must decompose them into simpler geometries.

The GLU library combines functions from the GL library to support more advanced graphics features. It runs on all conforming implementations of OpenGL. GLU is capable of creating and handling complex polygons (including quartic equations), processing nonuniform rational b-spline curves (NURBs), scaling images, and decomposing a surface to a series of polygons (tessellation).

The GLUT library provides a cross-platform API for performing operations associated with the user windowing environment—displaying and redrawing content, handling events, and so on. It is implemented on most UNIX, Linux, and Windows platforms. As such, any code that you write with GLUT can be reused across multiple platforms. However, such code is constrained by a generic set of user interface elements and event-handling options. This book does not show how to use GLUT. If you are interested in GLUT, see the sample code in the ADC Reference Library. GLUT Basics is a simple example that will get you started.

GLX is an OpenGL extension that supports using OpenGL within a window provided by the X Window system. X11 for Mac OS X is available as an optional installation using the Mac OS X installation DVD. (It's not shown in Figure 1-3.) See OpenGL Programming for the X Window System, published by Addison Wesley for more information.

This document does not show how to use these libraries. For detailed information, either go to the OpenGL Foundation website http://www.opengl.org, or see the most recent version of "The Redbook"—OpenGL Programming Guide, published by Addison Wesley.

Terminology

There are a number of terms that you’ll want to understand so that you can write code effectively using OpenGL: renderer, renderer attributes, buffer attributes, pixel format objects, rendering contexts, drawable objects, and virtual screens. As an OpenGL programmer some of these may seem familiar to you. However, understanding the Apple-specific nuances of these terms will help you get the most out of OpenGL on the Macintosh platform.

Renderer

A renderer is the combination of the hardware and software that OpenGL uses to create an image from a view and a model. (A software renderer is an exception; it does not use graphics hardware and is typically used as a fallback.) The characteristics of the final image depends on the capabilities of the graphics hardware associated with the renderer and the device used to display the image. A particular renderer supports specific capabilities—for example, the ability to produce environmental effects such as fog.

Mac OS X supports graphics accelerator cards with varying capabilities as well as systems without graphics acceleration hardware. It is possible for multiple renderers, each with different capabilities or features, to drive a single set of graphics hardware.

Renderer and Buffer Attributes

Renderer and buffer attributes are operating system-dependent extensions that communicate to OpenGL the renderer and buffer requirements for your application. The Apple implementation of OpenGL dynamically selects the best renderer for the current rendering task and does so transparently to your application. But, if your application has very specific rendering requirements and wants to control renderer selection, it can do so by supplying the appropriate renderer attributes. Buffer attributes describe such things as color and depth buffer sizes, and whether the data is stereoscopic or monoscopic.

Renderer and buffer attributes are represented by constants defined in the Apple-specific OpenGL APIs. OpenGL uses the attributes you supply to perform the setup work needed prior to drawing content. “Drawing to a Window or View” provides simple example that show how to use renderer and buffer attributes. “Techniques for Choosing Attributes” provides tips on choosing renderer and buffer attributes to achieve specific rendering goals.

Pixel Format Objects

A pixel format describes pixel data storage in memory. The description includes the pixel components (that is, red, blue, green, alpha), the number and order of components, and other relevant information, such as whether a pixel contains stencil and depth values. A pixel format object is an opaque data type designed to hold a pixel format along with a list of renderers and display devices that satisfy the requirements specified by an application.

Each of the Apple-specific OpenGL APIs defines a pixel format data type and accessor routines that you can use to obtain the information referenced by this object. See “Virtual Screens” for more information on renderer and display devices.

Rendering Contexts

A rendering context, or simply context, contains state information for the rendering target of your application. The context affects the rendered result much in the same way that the characteristics of a drawing pen (ink color, point size, type of ink, and so forth) affect what's drawn on a piece of paper. State variables are set per context. Once set, a value remains as such until you change it. State variables include such things as drawing color, the viewing and projection transformations, lighting characteristics, and material properties.

Although your application can maintain more than one context, only one context can be the current context in a thread. The current context is the rendering context that receives OpenGL commands issued by your application. The system initializes the context to the default OpenGL state. The context then tracks all state changes made while it is the current context.

Drawable Objects

A drawable object refers to an object allocated outside of OpenGL, but that can serve as an OpenGL framebuffer. A drawable object can be the target of OpenGL drawing operations. The behavior of drawable objects is not part of the OpenGL specification. Rather, a drawable object is a platform-specific construct provided by the Mac OS X windowing system.

A drawable object can be any of the following: a Carbon window, a Cocoa view, offscreen memory, a full-screen graphics device, or a pixel buffer (available starting in Mac OS X v10.3).

Note: A pixel buffer (pbuffer) is an OpenGL buffer designed for hardware-accelerated offscreen drawing and as a source for texturing. An application can render an image into a pixel buffer once and then use the buffer contents multiple times to texture a variety of surfaces without copying the image data.

Before OpenGL can draw to a drawable object, the object must be attached to a rendering context. The characteristics of the drawable object narrow the selection of hardware and software specified by the rendering context. OpenGL automatically allocates buffers, creates surfaces, and specifies which renderer is the current renderer.

The logical flow of data from an application through OpenGL to a drawable object is shown in Figure 1-4. The application issues OpenGL commands that are sent to the current rendering context. The current context, which contains state information, constrains how the commands are interpreted by the appropriate renderer. The renderer converts the OpenGL primitives to an image in the framebuffer. (See also “Running an OpenGL Program in Mac OS X .”)


Figure 1-4  Data flow through OpenGL

Data flow through OpenGL

Virtual Screens

The characteristics and quality of the OpenGL content that the user sees depends on both the renderer and the physical display used to view the content. The combination of renderer and physical display is called a virtual screen. This important concept has implications for any application that might run on a system that has more than one renderer or more than one display.

A simple system, with one graphics card and one physical display, typically has two virtual screens. One virtual screen consists of a hardware-based renderer and the physical display and the other virtual screen consists of a software-based renderer and the physical display. Mac OS X provides a software-based renderer as a fallback. It's possible for your application to decline the use of this fallback. You'll see how in “Techniques for Choosing Attributes.”

The green rectangle around the OpenGL image in Figure 1-5 surrounds a virtual screen for a system with one graphics card and one display. Note that a virtual screen is not the physical display, which is why the green rectangle is drawn around the application window that shows the OpenGL content. In this case, it is the renderer provided by the graphics card combined with the characteristics of the display.


Figure 1-5  A virtual screen displays what the user sees

A virtual screen displays what the user sees

Because a virtual screen is not simply the physical display, a system with one display can use more than one virtual screen at a time, as shown in Figure 1-6. The green rectangles are drawn to point out each virtual screen. Imagine that the virtual screen on the right side uses a software-only renderer and that the one on the left uses a hardware-dependent renderer. Although this is a contrived example, it illustrates the point.


Figure 1-6  Two virtual screens

Two virtual screens

It's also possible to have a virtual screen that can represent more than one physical display. The green rectangle in Figure 1-7 is drawn around a virtual screen that spans two physical displays. In this case, the same graphics hardware drives a pair of identical displays. This is also true when mirroring is enabled.


Figure 1-7  A virtual screen can represent more than one physical screen

A virtual screen can represent more than one physical screen

The concept of a virtual screen is particularly important when the user drags an image from one physical screen to another. When this happens, the virtual screen may change, and with it, a number of attributes of the imaging process, such as the current renderer, may change. With the dual-headed graphics card shown in Figure 1-7, dragging between displays preserves the same virtual screen. However, Figure 1-8 shows the case for which two displays represent two unique virtual screens. Not only are the two graphics cards different, but it's possible that the renderer, buffer attributes, and pixel characteristics are different. A change in any of these three items can result in a change in the virtual screen.

When the user drags an image from one display to another, and the virtual screen is the same for both displays, the image quality should appear similar. However, for the case shown in Figure 1-8, the image quality can be quite different.


Figure 1-8  Two virtual screens and two graphics cards

Two virtual screens and two graphics cards

OpenGL for Mac OS X transparently manages rendering across multiple monitors. A user can drag a window from one monitor to another, even though their display capabilities may be different or they may be driven by dissimilar graphics cards with dissimilar resolutions and color depths.

OpenGL dynamically switches renderers when the virtual screen that contains the majority of the pixels in an OpenGL window changes. When a window is split between multiple virtual screens, the framebuffer is rasterized entirely by the renderer driving the screen that contains the largest segment of the window. The regions of the window on the other virtual screens are drawn by copying the rasterized image. When the entire OpenGL drawable object is displayed on one virtual screen, there is no performance impact from multiple monitor support.

Applications need to track virtual screen changes and, if appropriate, update the current application state to reflect changes in renderer capabilities. See “Techniques for Working with Rendering Contexts.”

Running an OpenGL Program in Mac OS X

Figure 1-9 shows the flow of data in an OpenGL program, regardless of the platform that the program runs on. Pixel data and vertex data can be sent to OpenGL for processing in two ways. The first is by issuing OpenGL commands that are executed immediately, either to assemble a model from vertex data or a texture from pixel data. When an application issues OpenGL commands that are executed immediately, OpenGL is said to be operating in immediate mode. There are two immediate mode paths in the figure: one from vertex data to per-vertex operations and the other from pixel data to per-pixel operations.

The "display lists" rectangle in the figure represents the second way that an application can send data to OpenGL. A display list is a set of OpenGL commands that is assembled and named by an application. The display list is then stored on the OpenGL server. The application can refer to the list by its assigned name when the data defined by the list is needed. Display lists are ideal for computing-intensive operations because at the time you need to use the data, it is already uploaded to the GPU and is usually preprocessed. There are two display list paths in the figure, one for vertex data and one for pixel data.


Figure 1-9   The flow of data through OpenGL

The OpenGL pipeline

Per-vertex operations include such things as applying transformation matrices to add perspective or to clip and applying lighting effects. Per-pixel operations include such things as color conversion and applying blur and distortion effects. Pixels destined for textures are sent to texture assembly where OpenGL stores textures until it needs to apply them onto an object.

OpenGL rasterizes the processed vertex and pixel data, meaning that the data are converged to create fragments. A fragment encapsulates all the values for a pixel, including color, depth, and sometimes texture values. These values are used during anti-aliasing and any other calculations needed to fill shapes and to connect vertices.

Per-fragment operations include applying environment effects, depth and stencil testing, and performing other operations such as blending and dithering. Some operations—such as hidden-surface removal—end the processing of a fragment. OpenGL draws fully processed fragments into the appropriate location in the framebuffer.

The dashed arrows in Figure 1-9 indicate reading pixel data back from the framebuffer. They represent operations performed by OpenGL functions such as glReadPixels, glCopyPixels, and glCopyTexImage2D.

So far you've seen how OpenGL operates on any platform. But how do Cocoa and Carbon applications provide data to the OpenGL for processing? Regardless of the application environment (Cocoa or Carbon), a Mac OS X application must perform these tasks:

The tasks described in the first five bullet items are platform-specific. “Drawing to a Window or View” provides simple examples of how to perform them. As you read other parts of this document, you'll see there are a number of other tasks that, although not mandatory for drawing, are really quite necessary for any application that wants to use OpenGL to perform complex 3D drawing efficiently on a wide variety of Macintosh systems.

See Also

Reference documentation for the Apple-specific OpenGL programming interfaces:

The Apple Developer Connection OpenGL technology page links to high-level technical articles on OpenGL and Mac OS X.



< Previous PageNext Page > Hide TOC


© 2004, 2008 Apple Inc. All Rights Reserved. (Last updated: 2008-06-09)


Did this document help you?
Yes: Tell us what works for you.
It’s good, but: Report typos, inaccuracies, and so forth.
It wasn’t helpful: Tell us what would have helped.