-[EAGLContext renderbufferStorage:fromDrawable:] 第二次失败?

Posted

技术标签:

【中文标题】-[EAGLContext renderbufferStorage:fromDrawable:] 第二次失败?【英文标题】:-[EAGLContext renderbufferStorage:fromDrawable:] Failing the second time on? 【发布时间】:2013-08-20 03:39:54 【问题描述】:

我正在开发一个 ios openGL ES 应用程序。

我正在做通常的 EAGLView / ES2Render 工作。

启动时,frambuffer 创建成功,使用以下代码:

- (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(我的应用只支持纵向,因此实际上不会发生屏幕尺寸更改),但我真的很想修复它,因为有一天我需要支持横向等。 .

【问题讨论】:

我最近遇到了这个问题,但只是在 iOS 7 设备(不是模拟器)上运行时。不幸的是,我不知道是什么原因造成的,但重新启动设备似乎可以解决问题。虽然很烦人,但不能保证它不会再次发生...... 【参考方案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

【讨论】:

【参考方案2】:

renderbufferStorage:fromDrawable: 失败的一个可能原因是_mainContext 不是当时的当前上下文。尽管看起来没有其他上下文可以窃取“当前”状态,但我建议在任何glEAGL 代码之前调用[EAGLContext setCurrentContext:_mainContext] 操作与该上下文关联的对象(例如,在@的开头987654326@方法)。

【讨论】:

【参考方案3】:

Josh Bernfeld 的回答启发了我。我检查了MyView 的大小,它的边界是CGRect.zeroCAEAGLLayer 也是如此。 对我来说,使用非零 CGRect 初始化 MyView 解决了这个问题。

希望它对你有用。

【讨论】:

以上是关于-[EAGLContext renderbufferStorage:fromDrawable:] 第二次失败?的主要内容,如果未能解决你的问题,请参考以下文章

Android 的 RenderBuffer 可以优化吗?

FrameBuffer与RenderBuffer基本认识

OpenGL中Framebuffer和Renderbuffer的概念和区别是啥?

Framebuffer 和 Renderbuffer 的 Webgl 绑定

FrameBuffer & RenderBuffer

我是不是需要在我的 FBO 中使用 RenderBuffer 对象来渲染到保留 Alpha 通道的纹理?