2013-08-20 15 views
8

Sto sviluppando un'applicazione iOS openGL per iOS.- [EAGLContext renderbufferStorage: fromDrawable:] Fallita la seconda volta?

Sto facendo la solita roba EAGLView/ES2Render.

All'avvio, la creazione framebuffer riesce, utilizzando il seguente codice:

- (BOOL) createFramebuffers 
{ 
    [EAGLContext setCurrentContext:_mainContext]; 

    // [ A ] On-screen 

    // 1. Framebuffer 
    glGenFramebuffers(1, &_mainFramebuffer); 
    bindFramebuffer(_mainFramebuffer); 

    // 2. Color buffer 
    glGenRenderbuffers(1, &_mainColorbuffer); 
    bindRenderbuffer(_mainColorbuffer); 

    // Adjust size to view's layer: 
    CAEAGLLayer* layer = (CAEAGLLayer*)[_view layer]; 

    if (![_mainContext renderbufferStorage:GL_RENDERBUFFER fromDrawable:layer]) { 
     // something went horribly wrong 
     NSLog(@"-[ES2Renderer createFramebuffers]: Failed to obtain renderbuffer storage from layer!"); 
     return NO; 
    } 

    // Query new size: 
    glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_WIDTH, &_backingWidth); 
    glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_HEIGHT, &_backingHeight); 

    // Attach to color: 
    glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, _mainColorbuffer); 

    // 3. Depth buffer 
    glGenRenderbuffers(1, &_depthBuffer); 
    bindRenderbuffer(_depthBuffer); 

    if (_useStencilBuffer) { 
     // Depth + Stencil 

     // Allocate storage: 
     glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8_OES, _backingWidth, _backingHeight); 

     // Attach to depth: 
     glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, _depthBuffer); 

     // Attach to stencil: 
     glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, _depthBuffer); 
    } 
    else{ 
     // Depth only 

     // Allocate storage: 
     glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24_OES, _backingWidth, _backingHeight); 

     // Attachto depth: 
     glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, _depthBuffer); 

    } 

    // 4. Validate the set: 
    GLenum framebufferStatus = glCheckFramebufferStatus(GL_FRAMEBUFFER); 

    if (framebufferStatus != GL_FRAMEBUFFER_COMPLETE) { 
     // Something went wrong! 

     NSLog(@"-[ES2Renderer createFramebuffers]: Failed to make complete framebuffer object: %@", 
       [self stringFromFramebufferStauts:framebufferStatus]); 

     return NO; 
    } 

    // [ B ] Off-screen (Render-to-texture) 

    // 1. Framebuffer 
    glGenFramebuffers(1, &_transFramebuffer); 
    bindFramebuffer(_transFramebuffer); 

    // 2. Depth buffer 
    glGenRenderbuffers(1, &_transDepthBuffer); 
    bindRenderbuffer(_transDepthBuffer); 

    if (_useStencilBuffer) { 
     // Allocate storage: 
     glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8_OES, _backingWidth, _backingHeight); 

     // Attach to depth: 
     glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, _transDepthBuffer); 

     // Attach to stencil: 
     glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, _transDepthBuffer); 
    } 
    else{ 
     // Allocate storage 
     glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24_OES, _backingWidth, _backingHeight); 

     // Attach to depth: 
     glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, _transDepthBuffer); 
    } 


    // 3. Textures (color buffers) 

    GLuint* texPtrs[2] = {&_transTexture1, &_transTexture2}; 

    for (NSUInteger i=0; i < 2; i++) { 

     GLuint* texPtr = texPtrs[i]; 

     // Create: 
     glGenTextures(1, texPtr); 

     // Bind: 
     bindTexture2D(*texPtr); 

     // Configure for pixel-aligned use: 
     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); 
     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); 
     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 
     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 

     // Allocate storage: 
     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, _backingWidth, _backingHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); 

     // Attach: 
     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, *texPtr, 0); 

     framebufferStatus = glCheckFramebufferStatus(GL_FRAMEBUFFER); 

     // Validate: 
     if (framebufferStatus != GL_FRAMEBUFFER_COMPLETE) { 
      // Something went wrong! 

      NSLog(@"-[ES2Renderer createFramebuffers]: Failed to make complete framebuffer object: %@", 
        [self stringFromFramebufferStauts:framebufferStatus]); 

      return NO; 
     } 
    } 

    // Final State: 

    bindFramebuffer(_mainFramebuffer); 
    bindRenderbuffer(_mainColorbuffer); 
    bindTexture2D(0); 


    NSLog(@"-[ES2Renderer createFramebuffers] Succeeded."); 
    return YES; 
} 

Poco dopo, UIView s' -layoutSubviews si chiama e io, a sua volta eseguire -resizeFromLayer::

- (BOOL) resizeFromLayer:(CAEAGLLayer *)layer 
{ 
    // [ A ] On screen framebuffer 

    bindFramebuffer(_mainFramebuffer); 

    // 1. Resize color buffer 
    bindRenderbuffer(_mainColorbuffer); 

    if (![_mainContext renderbufferStorage:GL_RENDERBUFFER fromDrawable:layer]) { 
     // Something went wrong 
     return NO; // <-- SECOND TIME ON, THIS HAPPENS 
    } 

    // Query new size: 
    glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_WIDTH, &_backingWidth); 
    glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_HEIGHT, &_backingHeight); 

    // 2. Resize depth buffer 
    bindRenderbuffer(_depthBuffer); 

    if (_useStencilBuffer) { 
     // (Depth & Stencil) 

     glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8_OES, _backingWidth, _backingHeight); 
    } 
    else{ 
     // (Depth only) 

     glRenderbufferStorage(GL_FRAMEBUFFER, GL_DEPTH_COMPONENT24_OES, _backingWidth, _backingHeight); 
    } 

    // ...Validate: 
    GLenum framebufferStatus = glCheckFramebufferStatus(GL_FRAMEBUFFER); 

    if (framebufferStatus != GL_FRAMEBUFFER_COMPLETE) { 
     // Something went wrong! 

     NSLog(@"-[ES2Renderer resizeFromLayer:]: Failed to make complete framebuffer object: %@", 
       [self stringFromFramebufferStauts:glCheckFramebufferStatus(GL_FRAMEBUFFER)]); 

     return NO; 
    } 

    // [ B ] Off screen (render-to-terxture) framebuffer 

    bindFramebuffer(_transFramebuffer); 

    // 1. Resize depth buffer 

    bindRenderbuffer(_transDepthBuffer); 

    if (_useStencilBuffer) { 
     glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8_OES, _backingWidth, _backingHeight); 
    } 
    else{ 
     glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24_OES, _backingWidth, _backingHeight);   
    } 


    // 2. Resize textures 

    GLuint* texPtrs[2] = {&_transTexture1, &_transTexture2}; 

    for (NSUInteger i=0; i < 2; i++) { 

     GLuint* texPtr = texPtrs[i]; 

     // Bind: 
     bindTexture2D(*texPtr); 

     // Configure for pixel-aligned use: 
     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); 
     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); 
     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 
     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 

     // Allocate storage: 
     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, _backingWidth, _backingHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); 

     // Attach: 
     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, *texPtr, 0); 


     // Validate: 
     if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { 
      // Something went wrong! 
      NSString* statusString = [self stringFromFramebufferStauts:glCheckFramebufferStatus(GL_FRAMEBUFFER)]; 
      NSLog(@"-[ES2Renderer resizeFromLayer:]: Failed to make complete framebuffer object: %@", statusString); 
      return NO; 
     } 
    } 

    bindFramebuffer(_mainFramebuffer); 
    bindRenderbuffer(_mainColorbuffer); 


    // Pass new ortho projection to shaders 
    [self initializeModelViewMatrix]; 
    [self initializeSpriteProgram]; 

    // Set new viewport 
    glViewport(0, 0, _backingWidth, _backingHeight); 

    NSLog(@"-[ES2Renderer resizeFromLayer:]: Succeeded."); 

    return YES; 
} 

Nulla di quello che ho sto facendo è speciale Ho un framebuffer separato per il rendering delle transizioni di scena, con due trame da attaccare al colore e alla profondità.

La seconda volta -renderbufferStorage:fromDrawable: si chiama (-layoutSubviews ->resizeFromLayer:), non riesce immancabilmente (restituisce NO); Chiamando il numero glGetError() subito prima non si ottiene alcun errore, ma chiamandolo subito dopo restituisce GL_INVALID_OPERATION. Se ignoro questo e procedo, glGetRenderbufferParameteriv() mi ottiene ancora la larghezza e l'altezza corrette (rispettivamente 640 e 1136 su un iPhone 5), ma glCheckFramebufferStatus() restituirà GL_FRAMEBUFFER_UNSUPPORTED.

alternativa, ho saltato sopra resizeFromLayer: e sostituito con questo:

- (BOOL) resizeFromLayer:(CAEAGLLayer *)layer 
{ 
    [self destroyFramebuffers]; 

    return [self createFramebuffers]; 
} 

... ma lo stesso errore persiste (-renderStorage:fromDrawable: fallisce, questa volta all'interno -createFramebuffers).

Per ora, restituisco solo YES (la mia app supporta solo il ritratto, quindi nessuna modifica della dimensione dello schermo si verifica effettivamente mai), ma voglio davvero risolverlo perché un giorno avrò bisogno di supportare il panorama, ecc ...

+0

Recentemente ho incontrato questo problema, ma solo se in esecuzione su un dispositivo iOS 7 (non simulatore). Purtroppo non so cosa l'abbia causato, ma il riavvio del dispositivo è apparso per risolvere il problema. Molto fastidioso, e non garantisce che non accadrà di nuovo ... – Stuart

risposta

1

Uno possibile ragione che renderbufferStorage:fromDrawable: sta fallendo è che il _mainContext non è il contesto attuale in quel momento. Anche se può sembrare che nessun altro contesto possa aver rubato lo stato "attuale", consiglio di chiamare [EAGLContext setCurrentContext:_mainContext] prima di qualsiasi codice gl o EAGL che funzioni sugli oggetti associati a tale contesto (ad esempio all'inizio del metodo resizeFromLayer:).

1

Un altro motivo possibile è che la dimensione del livello è troppo grande. Inoltre assicurati di utilizzare un nuovo framebuffer e renderbuffer ogni volta. E hai distrutto i tuoi vecchi prima di crearne di nuovi.

Si possono eliminare in questo modo

if let displayFramebuffer = self.displayFramebuffer { 
    var temporaryFramebuffer = displayFramebuffer 
    glDeleteFramebuffers(1, &temporaryFramebuffer) 
    self.displayFramebuffer = nil 
} 

if let displayRenderbuffer = self.displayRenderbuffer { 
    var temporaryRenderbuffer = displayRenderbuffer 
    glDeleteRenderbuffers(1, &temporaryRenderbuffer) 
    self.displayRenderbuffer = nil 
}