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
[EAGLContext setCurrentContext: myContext];
Your application can retrieve a thread’s current context by calling the
EAGLContext class method
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
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
context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];
if (context == nil)
context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES1];
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.
Sharegroups are most useful under two specific scenarios:
When most of the resources shared between the contexts are unchanging.
When you want your application to be able to create new OpenGL ES objects on a thread other than the main thread for the renderer. In this case, a second context runs on a separate thread and is devoted to fetching data and creating resources. After the resource is loaded, the first context can bind to the object and use it immediately.
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:
Your application may access the object across multiple contexts simultaneously provided the object is not being modified.
While the object is being modified by commands sent to a context, the object must not be read or modified on any other context.
After an object has been modified, all contexts must rebind the object to see the changes. The contents of the object are undefined if a context references it before binding it.
Here are the steps your application should follow to update an OpenGL ES object:
glFlushon every context that may be using the object.
On the context that wants to modify the object, call one or more OpenGL ES functions to change the object.
glFlushon the context that received the state-modifying commands.
On every other context, rebind the object identifier.
© 2013 Apple Inc. All Rights Reserved. (Last updated: 2013-04-23)