Search code examples
opengl-esopengl-es-2.0glreadpixelsmultisampling

glResolveMultisampleFramebufferAPPLE() generate GL_INVALID_OPERATION on iOS (OpenGL ES 2.0)


I want to use function glReadPixels() to do screenshot of my scene. And it works great if I don't use multisampling. But if I do I get GL_INVALID_OPERATION in glResolveMultisampleFramebufferAPPLE(). Is there a way to resolve this problem?

My save function:

    var wid = GLint()
    var hei = GLint()
    glGetRenderbufferParameteriv(GLenum(GL_RENDERBUFFER), GLenum(GL_RENDERBUFFER_WIDTH), &wid)
    glGetRenderbufferParameteriv(GLenum(GL_RENDERBUFFER), GLenum(GL_RENDERBUFFER_HEIGHT), &hei)
    let byteLength = Int(hei * wid) * 4
    let bytes = UnsafeMutablePointer<GLubyte>.alloc(byteLength)

    // init non-multisampled frame buffer
    var framebuffer: GLuint = 0
    var colorRenderbuffer: GLuint = 0

    glGenFramebuffersOES(1, &framebuffer)
    glBindFramebufferOES(GLenum(GL_FRAMEBUFFER_OES), framebuffer)

    glGenRenderbuffersOES(1, &colorRenderbuffer)
    glBindRenderbufferOES(GLenum(GL_RENDERBUFFER_OES), colorRenderbuffer)
    glRenderbufferStorageOES(GLenum(GL_RENDERBUFFER_OES), GLenum(GL_RGBA8_OES), wid, hei)
    glFramebufferRenderbufferOES(GLenum(GL_FRAMEBUFFER_OES), GLenum(GL_COLOR_ATTACHMENT0_OES), GLenum(GL_RENDERBUFFER_OES), colorRenderbuffer)

    glBindFramebufferOES(GLenum(GL_DRAW_FRAMEBUFFER_APPLE), framebuffer)

    var default: GLint = 0
    glGetIntegerv(GLenum(GL_FRAMEBUFFER_BINDING_OES), &default)
    glBindFramebufferOES(GLenum(GL_READ_FRAMEBUFFER_APPLE), GLuint(default));

    myglGetError() // OK
    glResolveMultisampleFramebufferAPPLE()
    myglGetError() // GL_INVALID_OPERATION

    glBindFramebuffer(GLenum(GL_FRAMEBUFFER), framebuffer)

    glReadPixels(0, 0, GLsizei(wid), GLsizei(hei), GLenum(GL_RGBA), GLenum(GL_UNSIGNED_BYTE), bytes)

    glBindFramebuffer(GLenum(GL_FRAMEBUFFER), GLuint(default));
    glDeleteFramebuffers(1, &framebuffer)

I use default frame buffer initialized by GLKit with glkView.drawableMultisample = GLKViewDrawableMultisample.Multisample4X


Solution

  • I have tried your sample and it seems that after some modifications it works. Modificated code:

            var wid = GLint()
        var hei = GLint()
        glGetRenderbufferParameteriv(GLenum(GL_RENDERBUFFER), GLenum(GL_RENDERBUFFER_WIDTH), &wid)
        glGetRenderbufferParameteriv(GLenum(GL_RENDERBUFFER), GLenum(GL_RENDERBUFFER_HEIGHT), &hei)
        var def: GLint = 0
        glGetIntegerv(GLenum(GL_FRAMEBUFFER_BINDING_OES), &def)
    
        // init non-multisampled frame buffer
        var framebuffer: GLuint = 0
        var colorRenderbuffer: GLuint = 0
    
        glGenFramebuffersOES(1, &framebuffer)
        glBindFramebufferOES(GLenum(GL_FRAMEBUFFER_OES), framebuffer)
    
        glGenRenderbuffersOES(1, &colorRenderbuffer)
        glBindRenderbufferOES(GLenum(GL_RENDERBUFFER_OES), colorRenderbuffer)
        glRenderbufferStorageOES(GLenum(GL_RENDERBUFFER_OES), GLenum(GL_RGBA8_OES), wid, hei)
        glFramebufferRenderbufferOES(GLenum(GL_FRAMEBUFFER_OES), GLenum(GL_COLOR_ATTACHMENT0_OES), GLenum(GL_RENDERBUFFER_OES), colorRenderbuffer)
    
        glBindFramebufferOES(GLenum(GL_DRAW_FRAMEBUFFER_APPLE), framebuffer)
    
        //commented
        //here GL_FRAMEBUFFER_BINDING_OES will be overrided by previous call of
        // 'glBindRenderbufferOES(GLenum(GL_RENDERBUFFER_OES), colorRenderbuffer)'
        //var def: GLint = 0
        //glGetIntegerv(GLenum(GL_FRAMEBUFFER_BINDING_OES), &def
        glBindFramebufferOES(GLenum(GL_READ_FRAMEBUFFER_APPLE), GLuint(def));
    
        var err = glGetError()
        print(String(format: "Error %X",  err))
        glResolveMultisampleFramebufferAPPLE()
        err = glGetError()
        print(String(format: "Error %X",  err)) // GL_INVALID_OPERATION
    
        glBindFramebuffer(GLenum(GL_FRAMEBUFFER), framebuffer)
    

    Also here is quote from APPLE_framebuffer_multisample.txt extension description which explains why modified code works, as far as I understand.

    Calling BindFramebuffer with set to FRAMEBUFFER binds the framebuffer to both DRAW_FRAMEBUFFER_APPLE and READ_FRAMEBUFFER_APPLE.

    APPLE_framebuffer_multisample