2009-08-10 12 views
18

El bucle de renderizado de OpenGL ES se coloca en una hebra separada en mi aplicación de iphone. Todo va bien, excepto que el presente método EAGLContextRenderbuffer falla. El resultado es una pantalla blanca en blanco. Cuando se ejecuta el mismo código en el subproceso principal, presentRenderbuffer tiene éxito y los gráficos se muestran correctamente. ¿Cuál es la forma correcta de hacer OpenGL en un hilo separado?¿Cómo usar OpenGL ES en un hilo separado en iphone?

Respuesta

14

Necesita crear un EAGLSharegroup.

Consulte this thread sobre cómo compartir contextos OpenGL entre hilos.

ACTUALIZACIÓN
anterior a IOS5 que comparten contextos OpenGL entre hilos para permitir la carga asíncrona de texturas de disco. Pero el CVOpenGLESTextureCaches de iOS5 básicamente hace que las cargas de texturas sean gratuitas, así que ya no necesito compartir grupos y mi código es más simple y rápido.

+1

¿Qué quiere decir con "hacer cargas de texturas gratis"? Intenté llamar a CVOpenGLESTextureCacheCreateTextureFromImage() con un resultado de CVPixelBufferCreateWithBytes() y me llevó el mismo tiempo cargar la textura con glTexImage2D(). – MoDJ

+0

glTexImage2D hace el equivalente de memcpy en una textura, mientras que TextureFromImage apunta la textura a su imagen, no necesita copiar. Puede guardar una gran cantidad de ancho de banda de memoria. El tiempo por sí solo no revelará tanto como GL es asincrónico. Necesita ver el uso de la GPU/CPU y la velocidad de cuadros. –

+0

Consulte http://stackoverflow.com/questions/12813442/cvopenglestexturecache-vs-gltexsubimage2d-on-ios, parece que no funciona de la manera que describe cuando el usuario pasa en un búfer. De hecho, estoy viendo mucho tiempo de CPU gastado en glTexImage2D en esta ruta de ejecución. – MoDJ

2

No debe representar el contexto en un hilo diferente. En su lugar, haga todos los cálculos en un hilo diferente, y luego asegúrese de que el renderizado ocurra en el hilo de la pantalla principal.

+0

Puede hacerlo muy fácilmente usando GCD. – Cthutu

13

Gracias, Fistman. Lo hice funcionar y obtuve la ganancia de rendimiento que esperaba al usar un hilo por separado. EAGLSharegroup resolvió el problema.

Creé el contexto para el segundo subproceso como se describe here.

Aquí está el código repetitivo:


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


Cuestiones relacionadas