OpenGL ES on iOS

OpenGL ES provides a procedural API for submitting primitives to be rendered by a hardware accelerated graphics pipeline. Graphics commands are consumed by OpenGL to generate images that can be displayed to the user or retrieved for further processing outside of OpenGL ES.

The OpenGL ES specification defines the precise behavior for each function. Most commands in OpenGL ES perform one of the following activities:

Which Version(s) of OpenGL ES Should I Target?

When designing your OpenGL ES application, a critical question you must answer is whether your application should support OpenGL ES 2.0, OpenGL ES 1.1 or both.

If you choose to implement an OpenGL ES 1.1 application primarily for compatibility with older devices, consider adding an OpenGL ES 2.0 rendering option that takes advantage of the greater power of OpenGL ES 2.0-capable graphics processors found on newer iOS devices.

Understanding the OpenGL ES Architecture

OpenGL ES works on a few key principles. To design efficient OpenGL ES applications, you need to understand the underlying architecture.

Client-Server Model

OpenGL ES uses a client-server model, as shown in Figure 1-1. When your application calls an OpenGL ES function, it talks to an OpenGL ES client. The client processes the function call and, where necessary, converts it into commands to deliver to the OpenGL server. A client-server model allows the work to process a function call to be divided between the client and the server. The nature of the client, the server, and the communication path between them is specific to each implementation of OpenGL ES; on an iOS device, the workload is divided between the CPU and a dedicated graphics processor.

Figure 1-1  OpenGL ES client-server model

OpenGL ES Relies on Platform-Specific Libraries For Critical Functionality

The OpenGL ES specification defines how OpenGL ES works, but does not define functions to manage the interaction between OpenGL ES and the hosting operating system. Instead, the specification expects each implementation to provide functions to allocate rendering contexts and system framebuffers.

A rendering context stores the internal state for the OpenGL ES state machine. Rendering contexts allow each OpenGL ES application to each maintain a copy of the state data without worrying about other applications. See “Configuring OpenGL ES Contexts.” You can also use multiple rendering contexts in a single application.

A system framebuffer is a destination for OpenGL ES drawing commands, and is typically associated with the host operating system’s graphics subsystem. iOS does not provide system framebuffers. Instead, iOS extends the framebuffer object provided by OpenGL ES to allow framebuffers that share data with Core Animation. See “Framebuffer Objects are the Only Rendering Target on iOS” for more information on framebuffer objects and “Drawing With OpenGL ES” for a detailed discussion on creating and using framebuffers in your application.

Commands May Be Executed Asynchronously

A benefit of the OpenGL ES client-server model is that an OpenGL ES function can return control to the application before the requested operation completes. If OpenGL ES required every function to complete before returning control to your application, the CPU and GPU would run in lockstep, eliminating many opportunities for parallelism in your application. On iOS, deferring execution of drawing commands is quite common. By deferring several drawing commands and handling them simultaneously, the graphics hardware can remove hidden surfaces before performing costly fragment calculations.

Many OpenGL ES functions implicitly or explicitly flush commands to the graphics hardware. Other OpenGL functions flush commands to the graphics processor and wait until some or all pending commands have completed. Whenever possible, design your application to avoid client-server synchronizations.

Commands Are Executed In Order

OpenGL ES guarantees that the results of function calls made to a rendering context act as if they executed in the same order that the functions were called by the client application. When your application makes a function call to OpenGL ES, your application can assume the results from previous functions are available, even if some of the commands have not finished executing.

Parameters are Copied at Call-Time

To allow commands to be processed asynchronously, when your application calls an OpenGL ES function, any parameter data required to complete the function call must be copied by OpenGL ES before control is returned to your application. If a parameter points at an array of vertex data stored in application memory, OpenGL ES must copy the vertex data before returning. This has a couple of important implications. First, an application is free to change any memory it owns regardless of the calls it makes to OpenGL ES, because OpenGL ES and your application never access the same memory simultaneously. Second, copying parameters and reformatting them so that the graphics hardware can read the data adds overhead to every function call. For best performance, your application should define its data in format that are optimized for the graphics hardware, and it should use buffer objects to explicitly manage memory copies between your application and OpenGL ES.

Implementations May Extend the Capabilities Defined in the Specification

An OpenGL ES implementation may extend the OpenGL ES specification in one of two ways. First, the specification sets specific minimum requirements that implementations must meet, such as the size of a texture or the number of texture units that the application may access. An OpenGL ES implementation is free to support larger values — a larger texture, or more texture units. Second, OpenGL ES extensions allow an implementation to provide new OpenGL ES functions and constants. Extensions allow an implementation to add entirely new features. Apple implements many extensions to allow applications to take advantage of hardware features and to help you improve the performance of your applications. The actual hardware limits and the list of extensions offered by each implementation may vary depending on which device your application runs on and the version of iOS running on the device. Your application must test the capabilities at runtime and alter its behavior to match.

OpenGL ES Objects Encapsulate Resources on Behalf of Your Application

Objects are opaque containers that your application uses to hold configuration state or data needed by the renderer. Because the only access to objects is through the procedural API, the OpenGL ES implementation can choose different strategies when allocating objects for your application. It can store your data in a format or memory location that is optimal for the graphics processor. Another advantage to objects is that they are reusable, allowing your application to configure the object once and use it multiple times.

The most important OpenGL ES object types include:

Although each object type in OpenGL ES has its own functions to manipulate it, all objects share a similar programming model:

  1. Generate an object identifier.

    An identifier is a plain integer used to identify a specific object instance. Whenever you need a new object, call OpenGL ES to create a new identifier. Creating the object identifier does not actually allocate an object, it simply allocates a reference to it.

  2. Bind your object to the OpenGL ES context.

    Most OpenGL ES functions act implicitly on an object, rather than requiring you to explicitly identify the object in every function call. You set the object to be configured by binding it to the context. Each object type uses different functions to bind it to the context. The first time you bind an object identifier, OpenGL ES allocates and initializes the object.

  3. Modify the state of the object.

    Your application makes one or more function calls to configure the object. For example, after binding a texture object, you typically would configure how the texture is filtered and then load image data into the texture object.

    Changing an object can potentially be expensive, as it may require new data to be sent to the graphics hardware. Where reasonable, create and configure your objects once, and avoid changing them afterwards for the duration of your application.

  4. Use the object for rendering.

    Once you’ve created and configured all the objects needed to render a scene, you bind the objects needed by the pipeline and execute one or more drawing functions. OpenGL ES uses the data stored in the objects to render your primitives. The results are sent to the bound framebuffer object.

  5. Delete the object.

    When you are done with an object, your application should delete it. When an object is deleted, its contents are destroyed and the object identifier is recycled.

Framebuffer Objects are the Only Rendering Target on iOS

Framebuffer objects are the destination for rendering commands. OpenGL ES 2.0 provides framebuffer objects as part of the core specification; they are provided on OpenGL ES 1.1 by the OES_framebuffer_object extension. Because framebuffer objects are the only rendering target on iOS, Apple guarantees that the OES_framebuffer_object extension will always be provided by every OpenGL ES 1.1 implementation on iOS.

Framebuffer objects provide storage for color, depth and/or stencil data by attaching images to the framebuffer, as shown in Figure 1-2. The most common image attachment is a renderbuffer object. However, a OpenGL ES texture can be attached to the color attachment point of a framebuffer instead, allowing image to be rendered directly into a texture. Later, the texture can act as an input to future rendering commands.

Figure 1-2  Framebuffer with color and depth renderbuffers
Framebuffer with attachments.

Creating a framebuffer uses the following steps:

  1. Generate and bind a framebuffer object.

  2. Generate, bind, and configure an image.

  3. Attach the image to one of the framebuffer’s attachment points.

  4. Repeat steps 2 and 3 for other images.

  5. Test the framebuffer for completeness. The rules for completeness are defined in the OpenGL ES specification. These rules ensure the framebuffer and its attachments are well-defined.


Did this document help you? Yes It's good, but... Not helpful...