IOS Dev Intro - Opengl ES Context Share Group

104 篇文章 0 订阅
103 篇文章 0 订阅


https://developer.apple.com/library/ios/documentation/3DDrawing/Conceptual/OpenGLES_ProgrammingGuide/WorkingwithOpenGLESContexts/WorkingwithOpenGLESContexts.html


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, multiple apps can easily share the graphics hardware without interfering with the other’s state.

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

EAGL Is the iOS Implementation of an OpenGL ES Rendering Context

Before your app can call any OpenGL ES functions, it must initialize an EAGLContext object. The EAGLContext class also provides methods used to integrate OpenGL ES content with Core Animation.

The Current Context Is the Target for OpenGL ES Function Calls

Every thread in an iOS app has a current context; when you call an OpenGL ES function, this is the context whose state is changed by the call.

To set a thread’s current context, call the EAGLContext class method setCurrentContext: when executing on that thread.

[EAGLContext setCurrentContext: myContext];

Call the EAGLContext class method currentContext to retrieve a thread’s current context.

Note: If your app actively switches between two or more contexts on the same thread, call the glFlush function before setting a new context as the current context. This ensures that previously submitted commands are delivered to the graphics hardware in a timely fashion.

OpenGL ES holds a strong reference to the EAGLContext object corresponding to the current context. (If you are using manual reference counting, OpenGL ES retains this object.) When you call the setCurrentContext: method to change the current context, OpenGL ES no longer references the previous context. (If you are using manual reference counting, OpenGL ES releases the EAGLContext object.) To prevent EAGLContext objects from being deallocated when not the current context, your app must keep strong references to (or retain) these objects.

Every Context Targets a Specific Version of OpenGL ES

An EAGLContext object supports only one version of OpenGL ES. For example, code written for OpenGL ES 1.1 is not compatible with an OpenGL ES 2.0 or 3.0 context. Code using core OpenGL ES 2.0 features is compatible with a OpenGL ES 3.0 context, and code designed for OpenGL ES 2.0 extensions can often be used in an OpenGL ES 3.0 context with minor changes. Many new OpenGL ES 3.0 features and increased hardware capabilities require an OpenGL ES 3.0 context.

Your app decides which version of OpenGL ES to support when it creates and initializes the EAGLContext object. If the device does not support the requested version of OpenGL ES, the initWithAPI: method returns nil. Your app must test to ensure that a context was initialized successfully before using it.

To support multiple versions of OpenGL ES as rendering options in your app, you should first attempt to initialize a rendering context of the newest version you want to target. If the returned object is nil, initialize a context of an older version instead.Listing 2-1 demonstrates how to do this.

Listing 2-1  Supporting multiple versions of OpenGL ES in the same app

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

A context’s API property states which version of OpenGL ES the context supports. Your app should test the context’s API property and use it to choose the correct rendering path. A common pattern for implementing this behavior is to create a class for each rendering path. Your app 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.

A sharegroup is an opaque object; it has no methods or properties that your app can call. Contexts that use the sharegroup object keep a strong reference to it.

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

Sharegroups are most useful under two specific scenarios:

  • When most of the resources shared between the contexts are unchanging.

  • When you want your app 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. The GLKTextureLoader class uses this pattern to provide asynchronous texture loading.

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.

Important: All contexts associated with the same sharegroup must use the same version of the OpenGL ES API as the initial 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 app’s responsibility to manage state changes to OpenGL ES objects when the sharegroup is shared by multiple contexts. Here are the rules:

  • Your app 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 app 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.


https://developer.apple.com/library/ios/qa/qa1612/_index.html


Technical Q&A QA1612

OpenGL ES multithreading and EAGLSharegroup

Q:  In my multithreading OpenGL ES application, I load textures (or vertices) on a secondary thread then draw them onto screen on the main thread. Occasionally I see blank images or application freezes. What could be causing this?

A: In my multithreading OpenGL ES application, I load textures (or vertices) on a secondary thread then draw them onto screen on the main thread. Occasionally I see blank images or application freezes. What could be causing this?

It is very likely that the main and background threads are accessing the same OpenGL ES context simultaneously.

OpenGL ES commands for a specific context are not reentrant. You should never have more than one thread accessing a single context at the same time. It is highly recommended that you use only one thread per context.

Listing 1 demonstrates how to create and make current a context contextB using the sharegroup property (an EAGLSharegroup object) obtained from another already-allocated context contextA. Such contexts that belong to the same sharegroup can share resources, for example, textures, FBOs, etc. So you may use contextB on the secondary thread to create textures, and contextA on the main thread to draw the textures onto screen.

Listing 1  Creating a context belonging to the same sharegroup

contextB = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES1 
                                 sharegroup:contextA.sharegroup];
if (!contextB || ![EAGLContext setCurrentContext:contextB]) {
       // Handle errors here
}

Important: The only way to get a valid EAGLSharegroup object is to query it from an existing EAGLContext object. Any other method, such as explicitly creating it, will result in crashes or undefined behavior.

When you want to modify a resource on one context, you must first make sure it is not currently in use on another, even if you are accessing them from different threads. Once you modify it, its state is undefined until flushing and binding the object have been completed. You should never use an undefined object, whether you access it from a different context or not.

Take a texture as an example. Listing 2 shows the correct way to deal with multiple contexts. Any other ordering will not ensure consistent and correct behavior. It may result in data corruption, leaks, or crashes otherwise.

Listing 2  Modifying a texture on context B prior to using it on context A

// 1. Ensure context A is not bound to the texture
[EAGLContext setCurrentContext:contextA];
glBindTexture(GL_TEXTURE_2D, 0);

// 2. Call flush on context A 
glFlush(); 

// 3. Modify the texture on context B
[EAGLContext setCurrentContext:contextB];
glBindTexture(GL_TEXTURE_2D, texId);
//
// Modify the texture data here
//

// 4. Call flush on context B
glFlush(); 

// 5. Rebind the texture on context A
[EAGLContext setCurrentContext:contextA];
glBindTexture(GL_TEXTURE_2D, texId);

// 6. Use the texture as normal on context A

For more information on the EAGLContext/-initWithAPI:sharegroup: API and the sharegroup property, see the EAGLContext Class Reference




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值