Jeshua Lacock
Jeshua Lacock

Reputation: 6668

How to restore a GL_RENDERBUFFER?

I am working on storing and restoring my OpenGL ES based application's state.

I have a function to save the GL_RENDERBUFFER to dump the data with the following code:

glBindFramebuffer(GL_FRAMEBUFFER, fboTextureBufferData.framebuffer);
glBindRenderbuffer(GL_RENDERBUFFER, fboTextureBufferData.colorbuffer);

GLint x = 0, y = 0, width2 = backingWidth, height2 = backingHeight;
NSInteger dataLength = width * height * 4;
GLubyte *data = (GLubyte*)malloc(dataLength * sizeof(GLubyte));

// Read pixel data from the framebuffer
glPixelStorei(GL_PACK_ALIGNMENT, 4);
glReadPixels(x, y, width, height, GL_RGBA, GL_UNSIGNED_BYTE, data);

I don't see a glWritePixels function. What is the best way to repopulate the GL_RENDERBUFFER with the GLubyte data populated above? An example would be greatly appreciated.

EDIT 3:

Here is how I am attempting to configure the texture render buffer, and the function used to draw it. As noted in the code, if I specify GL_COLOR_ATTACHMENT1 for the glFramebufferTexture2D parameter, the stored pixel data is restored but I can't get any updates to draw. But if I use GL_COLOR_ATTACHMENT0 instead, I get drawing updates but no pixel data restored.

I have tried various combinations (for instance also using GL_COLOR_ATTACHMENT1 for the glFramebufferRenderbuffer parameter) but then I get an invalid frame buffer error when attempting to render. It seems I am so close, but can't figure out how to get them both restoring and rendering working together.

- (bool)configureRenderTextureBuffer {

    [EAGLContext setCurrentContext:context];

    glBindRenderbuffer(GL_RENDERBUFFER, viewRenderbuffer);
    [context renderbufferStorage:GL_RENDERBUFFER fromDrawable:(CAEAGLLayer*)self.layer];

    glBindRenderbuffer(GL_RENDERBUFFER, viewRenderbuffer);
    [context renderbufferStorage:GL_RENDERBUFFER fromDrawable:(CAEAGLLayer*)self.layer];

    glGenFramebuffers(1, &fboTextureBufferData.framebuffer);
    glBindFramebuffer(GL_FRAMEBUFFER, fboTextureBufferData.framebuffer);

    glGenRenderbuffers(1, &fboTextureBufferData.colorbuffer);
    glBindRenderbuffer(GL_RENDERBUFFER, fboTextureBufferData.colorbuffer);

    glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, backingWidth, backingHeight);
    glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, fboTextureBufferData.colorbuffer);

    // Generate texture name, stores in .textureID
    glGenTextures(1, &fboTextureBufferData.textureID);

    glBindTexture(GL_TEXTURE_2D, fboTextureBufferData.textureID);

    ////////////////// Read Existing texture data //////////////////
    NSString *dataPath = [TDTDeviceUtilitesLegacy documentDirectory]; //This just returns the app's document directory
    NSData *data = [NSData dataWithContentsOfFile:[NSString stringWithFormat:@"%@/buffer.data", dataPath]];
    GLubyte *pixelData = (GLubyte*)[data bytes];

    // If I use GL_COLOR_ATTACHMENT1 here, my existing pixel data is restored
    // but no drawing occurs. If I use GL_COLOR_ATTACHMENT0, then data isn't
    // restored but drawing updates work
    glFramebufferTexture2D ( GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, fboTextureBufferData.textureID, 0 );

    // Populate with existing data
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, backingWidth, backingHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, &pixelData[0]); //&image[0]

    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);

    GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER) ;
    if(status != GL_FRAMEBUFFER_COMPLETE) {
        NSLog(@"failed to make complete render texture framebuffer object %x", status);
        return false;
    }

    return true;
}

Here is the code for rendering. The viewFramebuffer is attached to GL_COLOR_ATTACHMENT0 and is used so the texture frame buffer can be zoomed and positioned inside the view.

- (void)renderTextureBuffer {

    //Bind the texture frame buffer, if I don't use this, I can't get it to draw
    //glBindFramebuffer(GL_FRAMEBUFFER, fboTextureBufferData.framebuffer);

    //If I use this instead of binding the framebuffer above, I get no drawing and black background
    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, fboTextureBufferData.textureID, 0);

    renderParticlesToTextureBuffer();

    //Bind the view frame buffer.
    glBindFramebuffer(GL_FRAMEBUFFER, viewFramebuffer);
    glBindRenderbuffer(GL_RENDERBUFFER, viewRenderbuffer);

    drawFboTexture();

    [context presentRenderbuffer:GL_RENDERBUFFER];
}

Upvotes: 9

Views: 1307

Answers (1)

Reto Koradi
Reto Koradi

Reputation: 54592

If you need to write data directly to a render target, using a renderbuffer is not a good option. In this case, it's much better to use a texture instead.

Using a texture as a FBO attachment works very similarly to using a renderbuffer. Where you currently use glRenderbufferStorage() to allocate a renderbuffer of the needed dimensions, you create a texture instead, and allocate its storage with:

GLuint texId = 0;
glGenTextures(1, &texId);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0,
    GL_RGBA, GL_UNSIGNED_SHORT_5_6_5, 0);

Then you attach it to the framebuffer with:

glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texId, 0);

Now, if you later want to fill your render target with data, you can simply call glTexImage2D() again, or even better glTexSubImage2D() if the size is unchanged, to do that.

Upvotes: 3

Related Questions