leopardGeckos
leopardGeckos

Reputation: 91

Using a depth and stencil renderbuffer attachment for framebuffer in OpenGL ES

I want to create a framebuffer in OpenGL ES 2 with a color texture and depth and stencil renderbuffers. However, OpenGL ES doesn't seem to have GL_DEPTH24_STENCIL8 or GL_DEPTH_STENCIL_ATTACHMENT. Using two separate renderbuffers gives the error "Stencil and z buffer surfaces have different formats! Returning GL_FRAMEBUFFER_UNSUPPORTED!" Is this not possible in OpenGL ES?

My FBO creation code:

private int width, height;

private int framebufferID,
            colorTextureID,
            depthRenderBufferID,
            stencilRenderBufferID;

public FBO(int w, int h) {
    width = w;
    height = h;
    int[] array = new int[1];

    //Create the FrameBuffer and bind it
    glGenFramebuffers(1, array, 0);
    framebufferID = array[0];
    glBindFramebuffer(GL_FRAMEBUFFER, framebufferID);

    //Create the texture for color, so it can be rendered to the screen
    glGenTextures(1, array, 0);
    colorTextureID = array[0];
    glBindTexture(GL_TEXTURE_2D, colorTextureID);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, (java.nio.ByteBuffer) null);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    // attach the texture to the framebuffer
    glFramebufferTexture2D( GL_FRAMEBUFFER,       // must be GL_FRAMEBUFFER
                            GL_COLOR_ATTACHMENT0, // color attachment point
                            GL_TEXTURE_2D,        // texture type
                            colorTextureID,       // texture ID
                            0);                   // mipmap level
    glBindTexture(GL_TEXTURE_2D, 0);

    // is the color texture okay? hang in there buddy
    FBOUtils.checkCompleteness(framebufferID);

    //Create the depth RenderBuffer
    glGenRenderbuffers(1, array, 0);
    depthRenderBufferID = array[0];
    glBindRenderbuffer(GL_RENDERBUFFER, depthRenderBufferID);
    glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, width, height);

    //Create stencil RenderBuffer
    glGenRenderbuffers(1, array, 0);
    stencilRenderBufferID = array[0];
    glBindRenderbuffer(GL_RENDERBUFFER, stencilRenderBufferID);
    glRenderbufferStorage(GL_RENDERBUFFER, GL_STENCIL_INDEX8, width, height);

    // bind renderbuffers to framebuffer object
    glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depthRenderBufferID);
    glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, stencilRenderBufferID);

    // make sure nothing screwy happened
    FBOUtils.checkCompleteness(framebufferID);
    glBindFramebuffer(GL_FRAMEBUFFER, 0);
}

Upvotes: 2

Views: 4182

Answers (2)

Reto Koradi
Reto Koradi

Reputation: 54592

In short, this is implementation dependent. What you try in the posted code with using a separate renderbuffer for depth and stencil is basically legal in ES 2.0. But then there's this paragraph in the spec:

[..] some implementations may not support rendering to particular combinations of internal formats. If the combination of formats of the images attached to a framebuffer object are not supported by the implementation, then the framebuffer is not complete under the clause labeled FRAMEBUFFER_UNSUPPORTED.

That's exactly the GL_FRAMEBUFFER_UNSUPPORTED error you are seeing. Your implementation apparently does not like the combination of depth and stencil buffer, and is at liberty to refuse supporting it while still being spec compliant.

There's one other aspect that makes your code device dependent. The combination of format and type you're using for your texture:

glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0,
             GL_RGBA, GL_UNSIGNED_BYTE, (java.nio.ByteBuffer) null);

basically corresponds to an RGBA8 internal format (even though that naming is not used in the ES 2.0 spec). In base ES 2.0, this is not a color-renderable format. If you want something that is supported across the board, you'll have to use GL_UNSIGNED_SHORT_5_6_5, GL_UNSIGNED_SHORT_4_4_4_4, or GL_UNSIGNED_SHORT_5_5_5_1 for the type. Well, theoretically a device can refuse to support almost any format. The only strict requirement is that it supports at least one format combination.

Rendering to RGBA8 formats is available on many devices as part of the OES_rgb8_rgba8 extension.

As already pointed out in another answer, combined depth/stencil formats are not part of base ES 2.0, and only available with the OES_packed_depth_stencil extension.

Upvotes: 2

solidpixel
solidpixel

Reputation: 12069

Packed depth/stencil surfaces are not a standard part of OpenGL ES 2.0, but are added via this extension:

https://www.khronos.org/registry/gles/extensions/OES/OES_packed_depth_stencil.txt

If the extension is supported on your platform (it usually is), the token names from OpenGL will generally work, but note that most have an _OES postfix because it is an OES extension, e.g. the internal format token is GL_DEPTH24_STENCIL8_OES.

The extension doesn't define a single combined attachment point such as GL_DEPTH_STENCIL_ATTACHMENT (that is added in OpenGL ES 3.0), but you can attach the same renderbuffer to one or both of the single attachment points. Note that it is not allowed to attach two different depth or stencil surfaces to the depth and stencil attachment points if you have attached a packed depth/stencil surface to the other (i.e. if you attach a packed depth/stencil to one attachment point, the other can either be attached to the same packed surface or unused).

Upvotes: 2

Related Questions