如何在iphone上的单独线程上使用OpenGL ES?

时间:2009-08-10 04:49:17

标签: iphone multithreading opengl-es

OpenGL ES渲染循环放在我的iphone应用程序中的一个单独的线程上。除了EAGLContext的presentRenderbuffer方法失败之外,一切都很顺利。结果是一个空白的白色屏幕。 当在主线程上运行相同的代码时,presentRenderbuffer会成功并正确显示图形。 在单独的线程上执行OpenGL的正确方法是什么?

3 个答案:

答案 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)

您不应在其他线程上呈现上下文。相反,在不同的线程上进行所有计算,然后确保在主显示线程上进行渲染。