Imagination PowerVR SDK Blog

The quest for setting up a stencil buffer on iOS


#1

It seems almost impossible to find a correctly set-up front+back+depth+stencil buffers arrangement that does not return an error while setting the buffers up in both the Simulator and the Device (iPhone 3GS running iOS 4.0.2 and related SDK).

Quote:
2010-08-12 14:11:54.292 ___PROJECTNAME___[41343:207] failed to make complete framebuffer object 8cd6


Stencil buffer is a supported feature on iPhone and iPad devices powered by the PowerVR SGX GPU even under OpenGL ES 1.1 CM (both the official OpenGL ES guide as well as the extensions reported by the device and the simulator support stencil related options required to support a stencil buffer).

It is known, and can be checked by examining the extensions supported by the Simulator and the Device, that the simulator does not offer the GL_OES_packed_depth_stencil extension and it is also known that separated depth and stencil buffers are not supported under iOS 4.x (they result in an incomplete buffer) while only packed depth-stencil is... so two code paths must be used to support a stencil buffer under both device and simulator.

The following code returns no framebuffer initialization error when running

Code:
    isSimulator = ( 0 == sio2StringCmp((const char*)"Apple Software Renderer",
                                       (const char*) glGetString(GL_RENDERER)) )?TRUE:FALSE;
   
    printf("nWe are running on the iOS %sn", (isSimulator?"simulator":"device"));
   
    if (isSimulator) {
        glGenFramebuffersOES(1, &viewFramebuffer);
        glGenRenderbuffersOES(1, &viewRenderbuffer);
       
        glBindFramebufferOES(GL_FRAMEBUFFER_OES, viewFramebuffer);
        glBindRenderbufferOES(GL_RENDERBUFFER_OES, viewRenderbuffer);
        [context renderbufferStorage:GL_RENDERBUFFER_OES fromDrawable:(CAEAGLLayer*)self.layer];
        glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_OES, GL_RENDERBUFFER_OES, viewRenderbuffer);
        glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_WIDTH_OES, &backingWidth);
        glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_HEIGHT_OES, &backingHeight);
       
        glGenRenderbuffersOES(1, &depthRenderbuffer);
        glBindRenderbufferOES(GL_RENDERBUFFER_OES, depthRenderbuffer);
        glRenderbufferStorageOES(GL_RENDERBUFFER_OES, GL_DEPTH_COMPONENT16_OES, backingWidth, backingHeight);
        glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_DEPTH_ATTACHMENT_OES, GL_RENDERBUFFER_OES, depthRenderbuffer);
       
        glGenFramebuffersOES(1, &stencilRenderbuffer);
        glBindRenderbufferOES(GL_RENDERBUFFER_OES, stencilRenderbuffer);
        glRenderbufferStorageOES(GL_RENDERBUFFER_OES, GL_STENCIL_INDEX8_OES, backingWidth, backingHeight);
        glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_STENCIL_ATTACHMENT_OES, GL_RENDERBUFFER_OES, stencilRenderbuffer);
         
    }
    else {
        glGenFramebuffersOES(1, &viewFramebuffer);
        glGenRenderbuffersOES(1, &viewRenderbuffer);
       
        glBindFramebufferOES(GL_FRAMEBUFFER_OES, viewFramebuffer);
        glBindRenderbufferOES(GL_RENDERBUFFER_OES, viewRenderbuffer);
        [context renderbufferStorage:GL_RENDERBUFFER_OES fromDrawable:(CAEAGLLayer*)self.layer];
        glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_OES, GL_RENDERBUFFER_OES, viewRenderbuffer);
        glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_WIDTH_OES, &backingWidth);
        glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_HEIGHT_OES, &backingHeight);
       
        glGenRenderbuffersOES(1, &depthStencilBuffer);
        glBindRenderbufferOES(GL_RENDERBUFFER_OES, depthStencilBuffer);
        glRenderbufferStorageOES(GL_RENDERBUFFER_OES, GL_DEPTH24_STENCIL8_OES, backingWidth, backingHeight);
        glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_DEPTH_ATTACHMENT_OES, GL_RENDERBUFFER_OES, depthStencilBuffer);
        glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_STENCIL_ATTACHMENT_OES, GL_RENDERBUFFER_OES, depthStencilBuffer);
    }
   
    if ( GL_NO_ERROR == glGetError()) NSLog(@"No error while creating the buffers so far..."); //no error printed out
   
    GLenum status = glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES) ;
    if(status != GL_FRAMEBUFFER_COMPLETE_OES) {
        NSLog(@"failed to make complete framebuffer object %x", status);
    }


P.S.:

changing

glRenderbufferStorageOES(GL_RENDERBUFFER_OES, GL_DEPTH_COMPONENT24_OES, backingWidth, backingHeight);

to

glRenderbufferStorageOES(GL_RENDERBUFFER_OES, GL_DEPTH_COMPONENT16_OES, backingWidth, backingHeight);

makes no difference :(...



#2

The following code setups a valid framebuffer set-up with both depth and stencil in addition to front and back buffers and it works on both Device and Simulator.

The application I am using stencil support in works well on iPhone 3GS (Simulator and Device) and on the iPad Simulator, but on the iPad device it does suffer a bit the second time you open the application… and sometimes the problem with SGX hanging happens the third time you launch the app on the device… when it runs, it runs well and at 60 FPS though.

Code:
    isSimulator = ( 0 == sio2StringCmp((const char*)"Apple Software Renderer",
                                       (const char*) glGetString(GL_RENDERER)) )?TRUE:FALSE;
   
    printf("nWe are running on the iOS %sn", (isSimulator?"simulator":"device"));
   
    if (isSimulator) {
       
        NSLog(@"Simulator path");
       
        glGenFramebuffersOES(1, &viewFramebuffer);       
        glBindFramebufferOES(GL_FRAMEBUFFER_OES, viewFramebuffer);
       
        glGenRenderbuffersOES(1, &viewRenderbuffer);
        glBindRenderbufferOES(GL_RENDERBUFFER_OES, viewRenderbuffer);
       
        [context renderbufferStorage:GL_RENDERBUFFER_OES fromDrawable:(CAEAGLLayer*)self.layer];
        glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_OES, GL_RENDERBUFFER_OES, viewRenderbuffer);
        glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_WIDTH_OES, &backingWidth);
        glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_HEIGHT_OES, &backingHeight);
       
        glGenRenderbuffersOES(1, &depthRenderbuffer);
        glBindRenderbufferOES(GL_RENDERBUFFER_OES, depthRenderbuffer);
        glRenderbufferStorageOES(GL_RENDERBUFFER_OES, GL_DEPTH_COMPONENT24_OES, backingWidth, backingHeight);
        glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_DEPTH_ATTACHMENT_OES, GL_RENDERBUFFER_OES, depthRenderbuffer);
       
        glGenRenderbuffersOES(1, &stencilRenderbuffer);
        glBindRenderbufferOES(GL_RENDERBUFFER_OES, stencilRenderbuffer);
        glRenderbufferStorageOES(GL_RENDERBUFFER_OES, GL_STENCIL_INDEX8_OES, backingWidth, backingHeight);
        glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_STENCIL_ATTACHMENT_OES, GL_RENDERBUFFER_OES, stencilRenderbuffer);
    }
    else {
       
        NSLog(@"Device path");
       
        glGenFramebuffersOES(1, &viewFramebuffer);       
        glGenRenderbuffersOES(1, &viewRenderbuffer);
       
        glBindFramebufferOES(GL_FRAMEBUFFER_OES, viewFramebuffer);
        glBindRenderbufferOES(GL_RENDERBUFFER_OES, viewRenderbuffer);
       
        [context renderbufferStorage:GL_RENDERBUFFER_OES fromDrawable:(id<EAGLDrawable>)self.layer];
        glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_OES, GL_RENDERBUFFER_OES, viewRenderbuffer);
        glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_WIDTH_OES, &backingWidth);
        glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_HEIGHT_OES, &backingHeight);
       
        glGenRenderbuffersOES(1, &depthStencilBuffer);
        glBindRenderbufferOES(GL_RENDERBUFFER_OES, depthStencilBuffer);
        glRenderbufferStorageOES(GL_RENDERBUFFER_OES, GL_DEPTH24_STENCIL8_OES, backingWidth, backingHeight);
        glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_DEPTH_ATTACHMENT_OES, GL_RENDERBUFFER_OES, depthStencilBuffer);
        glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_STENCIL_ATTACHMENT_OES, GL_RENDERBUFFER_OES, depthStencilBuffer);
    }


#3

Just wanted to say that the issue was solved. I had a problem with not properly tracking OpenGL ES state… disabling VBO’s and related arrays at the client level (each glEnableClientState(GL_VERTEX_ARRAY) call or similar must be matched by the appropriate function which disables the array.

Useful resources for this topic:
http://www.idevgames.com/forum/showpost.php?p=144269&postcount=2

https://devforums.apple.com/message/294752#294752 (thread in which I was offered the right pointers [no pun intended]) that helped me fix the problem mentioned here.

Also, a video of the scene in action now (texture projection with backprojection fix and culling fix): http://www.youtube.com/watch?v=LQztCFA2k04

More details on the implementation available at: http://forum.sio2interactive.com/viewtopic.php?f=3&t=841&start=10#p4442 (not only in that post, but in the whole thread)

Code is available at: http://code.google.com/p/si02-r-n-d/source/browse/#svn/trunk/SIO2_PVRTC_iPhone_iPad_Application




#4

I’m not sure how I missed this post so completely, but I’m glad that you sorted your issues out. The demo looks good.

In the our SDK there is setup code in the PVRShell for enabling the stencil buffer on iOS platforms and there is a StencilBuffer training course (and some other demos) that use this.