简体   繁体   English

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

[英]How to use OpenGL ES on a separate thread on iphone?

The OpenGL ES rendering loop is placed on a separate thread in my iphone application. OpenGL ES渲染循环放在我的iphone应用程序中的一个单独的线程上。 Everything goes fine except that the EAGLContext's presentRenderbuffer method fails. 除了EAGLContext的presentRenderbuffer方法失败之外,一切都很顺利。 The result is a blank white screen. 结果是一个空白的白色屏幕。 When the same code is run on the main thread, presentRenderbuffer succeeds and the graphics is properly shown. 当在主线程上运行相同的代码时,presentRenderbuffer会成功并正确显示图形。 What is the correct way of doing OpenGL on a separate thread? 在单独的线程上执行OpenGL的正确方法是什么?

You need to create an EAGLSharegroup . 您需要创建一个EAGLSharegroup

Check out this thread on sharing OpenGL contexts between threads. 在线程之间共享OpenGL上下文时查看线程。

UPDATE UPDATE
Previous to iOS5 I shared OpenGL contexts between threads to allow asynchronous loading of textures from disk. 在iOS5之前,我在线程之间共享OpenGL上下文,以允许从磁盘异步加载纹理。 But iOS5's CVOpenGLESTextureCaches essentially make texture uploads free so I don't need shareGroups anymore and my code is simpler and faster. 但iOS5的CVOpenGLESTextureCaches本质上使纹理上传免费,所以我不再需要shareGroups,我的代码更简单,更快。

Thanks, Fistman. 谢谢,Fistman。 I made it work and got the performance gain that I expected from using a separate thread. 我使用了一个单独的线程,并且获得了预期的性能提升。 EAGLSharegroup solved the problem. EAGLSharegroup解决了这个问题。

I created the context for the second thread as described here . 我为这里描述的第二个线程创建了上下文。

Here is the boilerplate code: 这是样板代码:


#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");
    }   
}


You shouldn't render the context on a different thread. 您不应该在不同的线程上呈现上下文。 Instead, do all the calculations on a different thread, and then ensure the rendering occurs on the main display thread. 相反,在不同的线程上进行所有计算,然后确保在主显示线程上进行渲染。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM