Part of the Khronos Group
OpenGL.org

The Industry's Foundation for High Performance Graphics

from games to virtual reality, mobile phones to supercomputers

Results 1 to 6 of 6

Thread: Problem with FBO->PBO->main memory transfer

  1. #1
    Junior Member Newbie
    Join Date
    Feb 2009
    Posts
    9

    Problem with FBO->PBO->main memory transfer

    Hello people,

    I'm trying to get my code to work in Linux, but I have yet to see it work unfortunately. I use 2 color attachments on an FBO to do some GPGPU work and I want to use asynchronous PBO transfers to transfer the results from the FBO back to main memory so that I can do something with it. My code works perfectly on my macbook pro (Nvidia 9600GT) but it fails to properly execute on Ubuntu using the latest FGLRX driver with an AMD-Ati HD4870.

    Code :
    glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo);
    glReadBuffer(colorAttachment);
    glBindBuffer(GL_PIXEL_PACK_BUFFER_ARB, pbo);
    glBufferData(GL_PIXEL_PACK_BUFFER_ARB, 4*sizeof(float), NULL, GL_STREAM_READ);
    glReadPixels (0, 0, 1, 1, GL_RGBA, GL_FLOAT, 0);
     
    mem = glMapBuffer(GL_PIXEL_PACK_BUFFER_ARB, GL_READ_ONLY);   
    assert(mem);
     
    for (i = 0; i < 4; i++)
    {
      ((float *)output->data)[i] = ((float *)mem)[i];
    }
     
    glUnmapBuffer(GL_PIXEL_PACK_BUFFER_ARB);
    glBindBuffer(GL_PIXEL_PACK_BUFFER_ARB, 0);
    glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);

    I call this code twice but with different PBOs and different color attachments to retrieve all the results. This works as it should on Mac OS X, but Linux only shows me the data on the first call properly. The second call I make to retrieve the data in a different color attachment doesn't work. Anyone got an idea as to why Linux gives me something different than Mac OS X? (any comments/improvements on my code are always welcome )

  2. #2
    Senior Member OpenGL Guru
    Join Date
    May 2009
    Posts
    4,726

    Re: Problem with FBO->PBO->main memory transfer

    The code seems fine.

    I'm somewhat curious as to exactly what you expect to get from using PBOs here. If the very first thing after glReadPixels is a map buffer call to that buffer object, then it's not going to be any different from just calling glReadPixels to your own memory. The purpose of using PBOs is to make glReadPixels (and other pixel transfers) asynchronous. In order for the async call to be useful, you must put some distance between glReadPixels and any code that accesses the buffer.

  3. #3
    Junior Member Newbie
    Join Date
    Feb 2009
    Posts
    9

    Re: Problem with FBO->PBO->main memory transfer

    Yea that's true. I did some benchmarking and I found out that PBO transfers do seem to be the fastest way to read from textures. And using this method I still have the possibility to do something inbetween the read/map calls.

  4. #4
    Junior Member Newbie
    Join Date
    Feb 2009
    Posts
    9

    Re: Problem with FBO->PBO->main memory transfer

    Well, it seems that internal non-clamped formats like GL_RGBA32F and GL_RGBA16F don't work with PBO transfers in Linux/ATI driver version 9.10. When I used the same code for GL_RGBA, it worked perfectly.

    I sure hope this is not a driver bug :S

  5. #5
    Junior Member Regular Contributor
    Join Date
    Nov 2009
    Location
    France
    Posts
    117

    Re: Problem with FBO->PBO->main memory transfer

    hi,

    would it be possible to send us a standalone test case so that we can investigate your issue ?

    regards,

    Pierre B.
    AMD Fellow.
    Pierre B.
    AMD Fellow

  6. #6
    Junior Member Newbie
    Join Date
    Feb 2009
    Posts
    9

    Re: Problem with FBO->PBO->main memory transfer

    This code should display something like this:
    Normal readback : 201.000000 201.000000 201.000000 201.000000
    PBO readback : 201.000000 201.000000 201.000000 201.000000
    Normal readback : 201.000000 201.000000 201.000000 201.000000
    PBO readback : 201.000000 201.000000 201.000000 201.000000

    But it instead does something like this:
    Normal readback : 201.000000 201.000000 201.000000 201.000000
    PBO readback : 201.000000 201.000000 201.000000 201.000000
    Normal readback : 201.000000 201.000000 201.000000 201.000000
    PBO readback : -1619085020624977094633163538024103936.000000 nan nan -24778363146118103040.000000

    The last numbers from the PBO readback are kinda random actually. Sometimes it gives me the same numbers back when I execute the test a couple of times without too much pause inbetween. But when I wait a bit it gives me other numbers, never the right ones though

    Code :
    #include <GL/glut.h>
    #include <GL/glu.h>
    #include <GL/gl.h>
     
    #include <stdio.h>
    #include <stdlib.h>
    #include <assert.h>
     
    static int width  = 1;
    static int height = 1;
     
    static GLuint texidFBO;
    static GLuint texidInput;
    static GLuint pboid[1];
    static GLuint fbo;
    static GLuint shaderProgram;
     
    const char* vertSource = "" \
      "#version 120\n" \
      "\n" \
      "void main()\n" \
      "{\n" \
      "  gl_Position    = ftransform();\n" \
      "  gl_TexCoord[0] = gl_MultiTexCoord0;\n" \
      "}\n";
     
    const char* fragSource = "" \
      "#version 120\n" \
      "#extension GL_ARB_texture_rectangle : enable\n" \
      "\n" \
      "uniform sampler2DRect input_image;\n" \
      "\n" \
      "void main()\n" \
      "{\n" \
      "  gl_FragData[0] = vec4(texture2DRect(input_image, gl_TexCoord[0].xy)+200.0);\n" \
      "}\n";
     
    GLuint compileProgram(void)
    {
      GLuint program, fragment_shader, vertex_shader;
     
      program = glCreateProgramObjectARB();
     
      vertex_shader = glCreateShaderObjectARB(GL_VERTEX_SHADER);
      glShaderSourceARB(vertex_shader, 1, &amp;vertSource, NULL);
      glCompileShaderARB(vertex_shader);
     
      fragment_shader = glCreateShaderObjectARB(GL_FRAGMENT_SHADER);
      glShaderSourceARB(fragment_shader, 1, &amp;fragSource, NULL);
      glCompileShaderARB(fragment_shader);
     
      glAttachObjectARB(program, vertex_shader);
      glAttachObjectARB(program, fragment_shader);
     
      glLinkProgramARB(program);
      glValidateProgramARB(program);
     
      glDeleteObjectARB(vertex_shader);
      glDeleteObjectARB(fragment_shader);
     
      return program;
    }
     
    void initGL(int w, int h)
    {
      int i;
      GLfloat texdata[4*width*height];
     
      glMatrixMode(GL_PROJECTION);
      glLoadIdentity();
      glOrtho(0.0, width, height, 0.0, -1.0, 1.0);
     
      glMatrixMode(GL_MODELVIEW);
      glLoadIdentity();
      glViewport(0,0, width, height);
     
      glEnable(GL_TEXTURE_RECTANGLE_ARB);
     
      for (i = 0; i < 4*width*height; i++)
      {
        texdata[i] = 0.f;
      }
     
      glGenTextures(1, &amp;texidFBO);
      glBindTexture(GL_TEXTURE_RECTANGLE_ARB, texidFBO);
      glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA32F_ARB, width, height, 0, GL_RGBA, GL_FLOAT, texdata);
     
      glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0);
      glGenFramebuffersEXT(1, &amp;fbo);
      glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo);
     
      glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_RECTANGLE_ARB, texidFBO, 0);
      glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
     
      glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
      glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0);
     
      glGenBuffers(1, pboid);
    }
     
    void initTextureAndShader(void)
    {
      GLfloat texdata[4*width*height];
      int i;
      GLuint input_image;
     
      for (i = 0; i < 4*width*height; i++)
      {
        texdata[i] = 1.f;
      }
     
      texidInput = 0;
     
      glGenTextures(1, &amp;texidInput);
      glBindTexture(GL_TEXTURE_RECTANGLE_ARB, texidInput);
      glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGB32F_ARB, width, height, 0, GL_RGB, GL_FLOAT, texdata);
     
      glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0);
     
      shaderProgram = compileProgram();
     
      glUseProgramObjectARB(shaderProgram);
      input_image = glGetUniformLocationARB(shaderProgram, "input_image");
      glUniform1iARB(input_image, 0);
      glUseProgramObjectARB(0);
    }
     
    void doRender(void)
    {
      glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo);
     
      glEnable(GL_TEXTURE_RECTANGLE_ARB);
      glBindTexture(GL_TEXTURE_RECTANGLE_ARB, texidInput);
     
      glUseProgramObjectARB(shaderProgram);
     
      glBegin(GL_QUADS);
      glTexCoord2f(width, 0);
      glVertex2f(0, 0);
      glTexCoord2f(0, 0);
      glVertex2f(width, 0);
      glTexCoord2f(0, height);
      glVertex2f(width, height);
      glTexCoord2f(width, height);
      glVertex2f(0, height);
      glEnd();
     
      glUseProgramObjectARB(0);
      glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
    }
     
    void readBackWithoutPBO(void)
    {
      GLfloat data[4*width*height];
     
      glBindTexture(GL_TEXTURE_RECTANGLE_ARB, texidFBO);
      glGetTexImage(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA, GL_FLOAT, data);
      glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0);
     
      printf("Normal readback : %f %f %f %f\n", data[0], data[1], data[2], data[3]);
    }
     
    void readBackWithPBO(void)
    {
      int i;
      GLfloat* mem;
     
      glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo);
      glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
     
      glBindBuffer(GL_PIXEL_PACK_BUFFER_ARB, pboid[0]);
      glBufferData(GL_PIXEL_PACK_BUFFER_ARB, 4*sizeof(GLfloat), NULL, GL_STREAM_READ);
      glReadPixels(0, 0, 1, 1, GL_RGBA, GL_FLOAT, NULL);
     
      mem = (GLfloat*)glMapBuffer(GL_PIXEL_PACK_BUFFER_ARB, GL_READ_ONLY);
      assert(mem);
     
      printf("PBO readback : %f %f %f %f\n", ((GLfloat *)mem)[0], ((GLfloat *)mem)[1], ((GLfloat *)mem)[2], ((GLfloat *)mem)[3]);
     
      glUnmapBuffer(GL_PIXEL_PACK_BUFFER_ARB);
     
      glBindBuffer(GL_PIXEL_PACK_BUFFER_ARB, 0);
      glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
    }
     
    int main ( int argc, char** argv ) 
    {
      glutInit(&amp;argc, argv);
      glutInitDisplayMode(GLUT_RGBA | GLUT_DEPTH | GLUT_DOUBLE);
      glutInitWindowSize(width, height);
      glutCreateWindow("PBO transfer test");
     
      initGL(width, height);
      initTextureAndShader();
     
      doRender();
      readBackWithoutPBO();
      readBackWithPBO();
     
      readBackWithoutPBO();
      readBackWithPBO();
     
      return 0;
    }

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •