0

I am trying to write a 16bit texture rendered with OpenGL using OpenEXR, following the example in page 4 from the documentation, but for some reason my code crashes when executing file_exr.writePixels(512). Is there anything I am missing here?

Update: I did check that fboId and pboId are well initialized and no OpenGL errors exist until this point.

const Imf::Rgba * dest;
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fboId);                                            
glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, pboId);
glReadPixels(0, 0, 512, 512,  GL_BGRA, GL_HALF_FLOAT_NV, 0);    
dest = (const Imf::Rgba *)glMapBuffer(GL_PIXEL_PACK_BUFFER_ARB, GL_READ_ONLY_ARB);

Imf::RgbaOutputFile file_exr("/tmp/file.exr", 512, 512, Imf::WRITE_RGBA);
file_exr.setFrameBuffer(dest, 1, 512);
file_exr.writePixels(512);

glUnmapBufferARB(GL_PIXEL_PACK_BUFFER_ARB);
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, 0);
Dan
  • 1,466
  • 1
  • 13
  • 27

1 Answers1

0

Did you just copy and paste that code (and just that code)? Then the reason for it failing is that:

  • The buffer object you want to read the pixels from OpenGL into does not exist; hence mapping it will fail, which meant you point OpenEXR to a null pointer
  • There's no single error condition check at all in above code.

Do this instead:

First a helper, to clean up the OpenGL error stack (which may accumulate multiple error conditions):

int check_gl_errors()
{
    int errors = 0;
    while( GL_NO_ERROR != glGetError() ) { errors++; }
    return errors;
}

Then this

int const width  = 512;
int const height = 512;
size_t const sizeof_half_float = 2;

glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fboId);
glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, pboId);
glBufferDataARB(GL_PIXEL_PACK_BUFFER_ARB,
      width * height * sizeof_half_float,
      NULL,
      GL_STATIC_READ_ARB);

if( !check_gl_errors() ) {    
    glPixelStorei(GL_PACK_ALIGNMENT, 1);
    glPixelStorei(GL_PACK_ROW_LENGTH, 0);
    glPixelStorei(GL_PACK_SKIP_PIXELS, 0);
    glPixelStorei(GL_PACK_SKIP_ROWS, 0);

    /* BTW: You have to check that your system actually supports the
       GL_HALF_FLOAT_NV format extension at all. */
    glReadPixels(0, 0, width, width,  GL_BGRA, GL_HALF_FLOAT_NV, 0);

    if( !check_gl_errors() ) {
        Imf::Rgba const * const dest = (Imf::Rgba const*)
            glMapBufferARB(GL_PIXEL_PACK_BUFFER_ARB, GL_READ_ONLY_ARB);
        if( !check_gl_errors() && nullptr != dest ) {
            Imf::RgbaOutputFile file_exr(
                "/tmp/file.exr",
                width, height,
                Imf::WRITE_RGBA);
            file_exr.setFrameBuffer(dest, 1, width);
            file_exr.writePixels(height);

            glUnmapBufferARB(GL_PIXEL_PACK_BUFFER_ARB);
        }
        else {
            /* glMapBuffer failed */
        }
    }
    else {
        /* glReadPixels failed */
    }
}
else {
    /* glBufferDataARB failed => no valid buffer object
       to work with in the first place */
}

All these error checks are important. They make your program not crash, but give diagnostics, what went wrong.

Anyway, the use of a PBO in the very order of operations doesn't help anyway, because it gets mapped immediately after the glReadPixels operation, which makes the whole thing synchronous.

datenwolf
  • 159,371
  • 13
  • 185
  • 298
  • of course I have a `fboId` and `pboId` set up properly at this point, and I also check for the errors when I create and populate them, although I should have made it clear in my question. I am thinking that it is probably related to the `GL_HALF_FLOAT_NV` support... I will double check this later on today. Thanks! – Dan Sep 11 '14 at 17:02