2013-08-20 210 views
8

我正在開發一個iOS openGL ES應用程序。- [EAGLContext renderbufferStorage:fromDrawable:]第二次失敗?

我在做通常的EAGLView/ES2Render的東西。

在啓動時,對應的FrameBuffer創建成功,使用下面的代碼:

- (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; 
} 

不久之後,UIView-layoutSubviews叫我反過來執行-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; 
} 

沒有我做得很特別。我有一個單獨的幀緩衝區來渲染場景轉換,其中兩個紋理附加到顏色和深度。

第二次調用-renderbufferStorage:fromDrawable:-layoutSubviews - >resizeFromLayer:),它總是失敗(返回NO);在此之前調用glGetError()將導致無錯誤,但在返回GL_INVALID_OPERATION之後立即調用它。 如果我忽略這個並繼續,glGetRenderbufferParameteriv()仍然會得到我正確的寬度和高度(iPhone 5上分別爲640和1136),但glCheckFramebufferStatus()將返回GL_FRAMEBUFFER_UNSUPPORTED

可替換地,我跳過上述resizeFromLayer:和與此替換它:

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

    return [self createFramebuffers]; 
} 

...但相同的錯誤仍然存​​在(-renderStorage:fromDrawable:失敗;此時內部-createFramebuffers)。

現在,我只是返回YES(我的應用程序只支持肖像,所以實際上沒有發生屏幕尺寸變化),但我真的想修復它,因爲有一天我需要支持風景等...

+0

最近我遇到了這個問題,但只能在iOS 7設備上運行時(不是仿真器)。不幸的是,我不知道是什麼造成的,但重啓設備似乎解決了這個問題。雖然很煩人,但不保證它不會再發生... – Stuart

回答

1

一個可能原因renderbufferStorage:fromDrawable:失敗的是,_mainContext是不是當時的當前上下文。儘管看起來沒有其他上下文可能會竊取「當前」狀態,但我建議在對與該上下文相關聯的對象(例如在resizeFromLayer:方法的開頭)操作的任何glEAGL代碼之前調用[EAGLContext setCurrentContext:_mainContext]

1

另一個可能的原因是您的圖層的大小太大。另外請確保您每次都使用新的幀緩衝區和渲染緩衝區。在創建新的之前,你已經摧毀了你的舊的。

你可以將它們刪除這樣

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 
}