2009-08-10 24 views
18

Il loop di rendering di OpenGL ES è posizionato su un thread separato nella mia applicazione iphone. Tutto va bene, tranne che il metodo presentRenderbuffer di EAGLContext ha esito negativo. Il risultato è uno schermo bianco vuoto. Quando lo stesso codice viene eseguito sul thread principale, presentRenderbuffer ha esito positivo e la grafica viene visualizzata correttamente. Qual è il modo corretto di fare OpenGL su un thread separato?Come utilizzare OpenGL ES su un thread separato su iphone?

risposta

14

È necessario creare un EAGLSharegroup.

Verificare this thread sulla condivisione di contesti OpenGL tra thread.

UPDATE
precedente per iOS5 ho condiviso contesti OpenGL tra fili per consentire il caricamento asincrono di texture dal disco. Ma gli CVOpenGLESTextureCaches di iOS5 essenzialmente rendono i caricamenti di texture gratuiti, quindi non ho più bisogno di shareGroups e il mio codice è più semplice e veloce.

+1

Cosa intendi per "rendere gratuiti i caricamenti di texture"? Ho provato a chiamare CVOpenGLESTextureCacheCreateTextureFromImage() con un risultato di CVPixelBufferCreateWithBytes() e ci sono voluti solo il tempo necessario per caricare la texture con glTexImage2D(). – MoDJ

+0

glTexImage2D fa l'equivalente di memcpy in una texture mentre TextureFromImage punta la texture sull'immagine - nessuna copia necessaria. È possibile risparmiare molta larghezza di banda della memoria. La tempistica da sola non rivelerà molto di quanto GL sia asincrono. È necessario esaminare l'utilizzo della GPU/CPU e la frequenza dei fotogrammi. –

+0

Vedere http://stackoverflow.com/questions/12813442/cvopenglestexturecache-vs-gltexsubimage2d-on-ios, non sembra funzionare come si descrive quando l'utente passa in un buffer. In effetti, sto vedendo un sacco di tempo della CPU speso in glTexImage2D in questo percorso di esecuzione. – MoDJ

2

Non è necessario eseguire il rendering del contesto su un thread diverso. Invece, eseguire tutti i calcoli su un thread diverso e assicurarsi che il rendering si verifichi sul thread di visualizzazione principale.

+0

Si può fare molto facilmente usando GCD. – Cthutu

13

Grazie, Fistman. L'ho fatto funzionare e ho ottenuto il guadagno di prestazioni che mi aspettavo dall'utilizzo di un thread separato. EAGLSharegroup ha risolto il problema.

Ho creato il contesto per il secondo thread come descritto here.

Ecco il codice standard:


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


Problemi correlati