Configuring OpenGL ES Contexts

Every implementation of OpenGL ES provides a way to create rendering contexts to manage the state required by the OpenGL ES specification. By placing this state in a context, it makes it easy for multiple applications to share the graphics hardware without interfering with the other’s state.

This chapter details how to create and configure contexts on iOS.

An EAGL Context is the iOS Implementation of an OpenGL ES Rendering Context

Before your application can call any OpenGL ES functions, it must initialize an EAGLContext object and set it as the current context. The EAGLContext class also provides methods your application uses to integrate OpenGL ES content with Core Animation. Without these methods, your application would be limited to working with offscreen images.

The Current Context Acts as the Target for OpenGL ES Function Calls Made on a Thread

Every thread in an iOS application maintains a current context. When your application makes an OpenGL ES function call, that thread’s context is modified by the call.

To set the current context, you call the EAGLContext class method setCurrentContext:.

[EAGLContext setCurrentContext: myContext];

Your application can retrieve a thread’s current context by calling the EAGLContext class method currentContext.

When your application sets a new context, EAGL releases the previous context (if any) and retains the new context.

Every Context Targets a Specific Version of OpenGL ES

An EAGLContext object supports either OpenGL ES 1.1 or OpenGL ES 2.0, but never both. The reason for this lies in the design of OpenGL ES 2.0. OpenGL ES 2.0 removed all functions from OpenGL ES 1.1 that dealt with the fixed-function graphics pipeline and added many new functions to provide a clean shader-based interface. If your application attempts to call an OpenGL ES 2.0 function on an OpenGL ES 1.1 context (or vice versa), the results are undefined.

Your application decides which version of OpenGL ES to support when it creates and initializes the EAGLContext object. To create an OpenGL ES 2.0 context, your application would initialize it as shown:

EAGLContext* myContext = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];

If your application wants to use OpenGL ES 1.1 instead, it initializes it using a different constant:

EAGLContext* myContext = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES1];

If the device does not support the requested version of OpenGL ES, the initWithAPI: method returns nil. Your application should always test to ensure a context was initialized successfully before using it.

To support both an OpenGL ES 2.0 and OpenGL ES 1.1 rendering option, your application should first attempt to initialize an OpenGL ES 2.0 rendering context. If the returned object is nil, it should initialize an OpenGL ES 1.1 context instead. Listing 2-1 demonstrates how to do this.

Listing 2-1  Supporting OpenGL ES 1.1 and OpenGL ES 2.0 in the same application

EAGLContext* CreateBestEAGLContext()
{
   EAGLContext *context;
   context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];
   if (context == nil)
   {
      context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES1];
   }
   return context;
}

A context’s API property states which version of OpenGL ES the context supports. Your application would test the context’s API property and use it to choose the correct rendering path. A common pattern for implementing this is to create a class for each rendering path; your application tests the context and creates a renderer once, on initialization.

An EAGL Sharegroup Manages OpenGL ES Objects for the Context

Although the context holds the OpenGL ES state, it does not directly manage OpenGL ES objects. Instead, OpenGL ES objects are created and maintained by an EAGLSharegroup object. Every context contains an EAGLSharegroup object that it delegates object creation to.

The advantage of a sharegroup becomes obvious when two or more contexts refer to the same sharegroup, as shown in Figure 2-1. When multiple contexts are connected to a common sharegroup, OpenGL ES objects created by any context are available on all contexts; if you bind to the same object identifier on another context than the one that created it, you reference the same OpenGL ES object. Resources are often scarce on mobile devices; creating multiple copies of the same content on multiple contexts is wasteful. Sharing common resources makes better use of the available graphics resources on the device.

Your application can treat a sharegroup as an opaque object; it has no methods or properties that your application can call, and it is retained and released automatically by the referencing contexts.

Figure 2-1  Two contexts sharing OpenGL ES objects
Core Animation-based renderbuffer

Sharegroups are most useful under two specific scenarios:

To create multiple contexts that reference the same sharegroup, the first context is initialized by calling initWithAPI:; a sharegroup is automatically created for the context. The second and later contexts are initialized to use the first context’s sharegroup by calling the initWithAPI:sharegroup: method instead. Listing 2-2 shows how this would work. The first context is created using the convenience function defined in Listing 2-1. The second context is created by extracting the API version and sharegroup from the first context.

Listing 2-2  Creating two contexts with a common sharegroup

EAGLContext* firstContext = CreateBestEAGLContext();
EAGLContext* secondContext = [[EAGLContext alloc] initWithAPI:[firstContext API] sharegroup: [firstContext sharegroup]];

It is your application’s responsibility to manage state changes to OpenGL ES objects when the sharegroup is shared by multiple contexts. Here are the rules:

Here are the steps your application should follow to update an OpenGL ES object:

  1. Call glFlush on every context that may be using the object.

  2. On the context that wants to modify the object, call one or more OpenGL ES functions to change the object.

  3. Call glFlush on the context that received the state-modifying commands.

  4. On every other context, rebind the object identifier.


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