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

时间:2013-08-20 03:39:55

标签: ios opengl-es-2.0 framebuffer eaglcontext

我正在开发一个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的{​​{1}}被调用,然后我执行-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: - &gt; -layoutSubviews),它总是失败(返回resizeFromLayer:);在此之前调用NO会导致错误,但在返回glGetError()后立即调用它。 如果我忽略了这一点并继续,GL_INVALID_OPERATION仍然可以获得正确的宽度和高度(iPhone 5上分别为640和1136),但glGetRenderbufferParameteriv()将返回glCheckFramebufferStatus()

或者,我跳过上述GL_FRAMEBUFFER_UNSUPPORTED并将其替换为:

resizeFromLayer:

...但同样的错误仍然存​​在(- (BOOL) resizeFromLayer:(CAEAGLLayer *)layer { [self destroyFramebuffers]; return [self createFramebuffers]; } 失败;这次是-renderStorage:fromDrawable:}。

现在,我只返回-createFramebuffers(我的应用只支持肖像,所以实际上没有发生屏幕尺寸变化),但我真的想修复它,因为有一天我需要支持景观等...

3 个答案:

答案 0 :(得分:2)

另一个可能的原因是图层的尺寸太大。此外,请确保每次都使用新的帧缓冲区和渲染缓冲区。在创建新的之前,你已经摧毁了旧的。

你可以像这样删除它们

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
}

答案 1 :(得分:1)

renderbufferStorage:fromDrawable:失败的一个可能的原因是_mainContext不是当时的当前上下文。即使看起来似乎没有其他背景可能会偷走当前的&#39;状态,我建议在操作与该上下文关联的对象的任何[EAGLContext setCurrentContext:_mainContext]gl代码之前调用EAGL(例如,在resizeFromLayer:方法的开头)。

答案 2 :(得分:1)

Josh Bernfeld的回答激发了我的灵感。我检查MyView的大小,其范围是CGRect.zero。与CAEAGLLayer相同。 对我来说,使用非零MyView的初始CGRect解决了这个问题。

希望它适合你。