OpenGL ES渲染循环放在我的iphone应用程序中的一个单独的线程上。除了EAGLContext的presentRenderbuffer方法失败之外,一切都很顺利。结果是一个空白的白色屏幕。 当在主线程上运行相同的代码时,presentRenderbuffer会成功并正确显示图形。 在单独的线程上执行OpenGL的正确方法是什么?
答案 0 :(得分:14)
您需要创建EAGLSharegroup
。
在线程之间签署关于共享OpenGL上下文的this thread。
<强>更新强>
在iOS5之前,我在线程之间共享OpenGL上下文,以允许从磁盘异步加载纹理。但iOS5的CVOpenGLESTextureCaches
本质上使纹理上传免费,所以我不再需要shareGroups了,我的代码更简单,更快。
答案 1 :(得分:14)
谢谢,Fistman。我使用了一个单独的线程,并且获得了预期的性能提升。 EAGLSharegroup解决了这个问题。
我为here所描述的第二个线程创建了上下文。
这是样板代码:
#import <UIKit/UIKit.h>
#import <OpenGLES/EAGL.h>
#import <OpenGLES/ES1/gl.h>
#import <OpenGLES/ES1/glext.h>
#import <QuartzCore/QuartzCore.h>
#import <OpenGLES/EAGLDrawable.h>
struct OpenGLContext
{
GLint Width;
GLint Height;
GLuint RenderBuffer;
GLuint FrameBuffer;
GLuint DepthBuffer;
UIView* View;
EAGLContext* MainContext;
EAGLContext* WorkingContext;
EAGLSharegroup* Sharegroup;
// Trivial constructor.
OpenGLContext();
// Call on the main thread before use.
// I call it in layoutSubviews.
// view must not be nil.
void MainInit(UIView* view);
// Call on the rendering thread before use, but
// after MainInit();
void InitOnSecondaryThread();
// Call before any OpenGL ES calls, at the
// beginning of each frame.
void PrepareBuffers();
// Present frame. Call at the end of each
// frame.
void SwapBuffers();
};
OpenGLContext::OpenGLContext()
{
Width = 0;
Height = 0;
RenderBuffer = 0;
FrameBuffer = 0;
DepthBuffer = 0;
View = 0;
MainContext = 0;
WorkingContext = 0;
Sharegroup = 0;
}
void OpenGLContext::InitOnSecondaryThread()
{
EAGLSharegroup* group = MainContext.sharegroup;
if (!group)
{
NSLog(@"Could not get sharegroup from the main context");
}
WorkingContext = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES1 sharegroup:group];
if (!WorkingContext || ![EAGLContext setCurrentContext:WorkingContext]) {
NSLog(@"Could not create WorkingContext");
}
}
void OpenGLContext::MainInit(UIView* view)
{
View = view;
MainContext = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES1];
if (!MainContext || ![EAGLContext setCurrentContext:MainContext]) {
NSLog(@"Could not create EAGLContext");
return;
}
NSLog(@"Main EAGLContext created");
glGenFramebuffersOES(1, &FrameBuffer);
glGenRenderbuffersOES(1, &RenderBuffer);
glGenRenderbuffersOES(1, &DepthBuffer);
glBindFramebufferOES(GL_FRAMEBUFFER_OES, FrameBuffer);
glBindRenderbufferOES(GL_RENDERBUFFER_OES, RenderBuffer);
if (![MainContext renderbufferStorage:GL_RENDERBUFFER_OES fromDrawable:(CAEAGLLayer*)View.layer])
{
NSLog(@"error calling MainContext renderbufferStorage");
return;
}
glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_OES, GL_RENDERBUFFER_OES, RenderBuffer);
glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_WIDTH_OES, &Width);
glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_HEIGHT_OES, &Height);
glBindRenderbufferOES(GL_RENDERBUFFER_OES, DepthBuffer);
glRenderbufferStorageOES(GL_RENDERBUFFER_OES, GL_DEPTH_COMPONENT16_OES, Width, Height);
glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_DEPTH_ATTACHMENT_OES, GL_RENDERBUFFER_OES, DepthBuffer);
glFlush();
if(glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES) != GL_FRAMEBUFFER_COMPLETE_OES) {
NSLog(@"failed to make complete framebuffer object %x", glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES));
}
WorkingContext = MainContext;
}
void OpenGLContext::PrepareBuffers()
{
if (!WorkingContext || [EAGLContext setCurrentContext:WorkingContext] == NO)
{
NSLog(@"PrepareBuffers: [EAGLContext setCurrentContext:WorkingContext] failed");
return;
}
glBindFramebufferOES(GL_FRAMEBUFFER_OES, FrameBuffer);
}
void OpenGLContext::SwapBuffers()
{
if (!WorkingContext || [EAGLContext setCurrentContext:WorkingContext] == NO)
{
NSLog(@"SwapBuffers: [EAGLContext setCurrentContext:WorkingContext] failed");
return;
}
glBindRenderbufferOES(GL_RENDERBUFFER_OES, RenderBuffer);
if([WorkingContext presentRenderbuffer:GL_RENDERBUFFER_OES] == NO)
{
NSLog(@"SwapBuffers: [WorkingContext presentRenderbuffer:GL_RENDERBUFFER_OES] failed");
}
}
答案 2 :(得分:2)
您不应在其他线程上呈现上下文。相反,在不同的线程上进行所有计算,然后确保在主显示线程上进行渲染。