Reading data from GPU with FBO

Hi,

I’m trying to do some GPGPU calculations with OpenGL 3.1 (forward compatible context), but I have hard time retrieving results from GPU.

Ive tried to google some tutorials/howtos on FBO and render buffers, but they are mostly too general and just confusing.

Is there a good and reliable (and preferably purely OGL3.1 or higher) way to download calculation results from GPU?

I know that for GPGPU I should use OpenCL/CUDA, but unfortunately it’s out of the question.

Is there a good and reliable (and preferably purely OGL3.1 or higher) way to download calculation results from GPU?

There is only one way to read pixel data from a buffer. Namely, glReadPixels. You can read directly into a memory buffer you allocate, or you can read into a buffer object.

If that buffer happens to be a texture, you could also use glGetTexSubImage. But it does the same thing.

Is there something bad or unreliable about glReadPixels?

I know that for GPGPU I should use OpenCL/CUDA, but unfortunately it’s out of the question.

Any particular reason? Is it the same reason that you’re using GL 3.1 instead of 3.3 (even though all 3.1 hardware now has 3.3 drivers)?

Thanks for reply.

There is only one way to read pixel data from a buffer. Namely, glReadPixels. You can read directly into a memory buffer you allocate, or you can read into a buffer object.

Any suggestions what’s better - using render buffers or rendering to texture?

Is there something bad or unreliable about glReadPixels?

Not bad or unreliable - just blocking main thread.

Any particular reason? Is it the same reason that you’re using GL 3.1 instead of 3.3 (even though all 3.1 hardware now has 3.3 drivers)?

I wish all cards had 3.3 drivers - I’m stuck on mobile card with just 3.1 support.

One more question: Are PBOs supported in OGL3 or not? I’m asking because I read somewhere that they are deprecated. On the other hand most examples (even declaring usage of OGL3) still use PBO to speed up transfers (doing them asynchronously).

Any suggestions what’s better - using render buffers or rendering to texture?

Better at what? If you need to use the image as a texture, then you render to a texture. If you don’t, then use a render buffer.

Are PBOs supported in OGL3 or not? I’m asking because I read somewhere that they are deprecated

I don’t know where you read that, but it’s wrong.

PBO are supported since older versions of OpenGL than 3.x. See here: http://www.opengl.org/registry/specs/ARB/pixel_buffer_object.txt

I don’t think that PBO are deprecated, at least not from what I know.

Question: I have never done calculations and took results back with the GPU. For me, OpenGL / CUDA look like the thing I would use since there might have latencies with glReadPixel. Am I wrong ?

Thanks for comments.

Now I’m able to download data from GPU.
But here comes another obstacle - I do not know why, but glVertexAttribPointer is throwing GL_INVALID_OPERATION error.

Here is the code. First I generate an array buffer and populate it with some data (GLfloat xyTCoords[8] array):


GLuint tCoords;
glGenBuffers( 1, &tCoords );
glBindBuffer(GL_ARRAY_BUFFER, tCoords);
glBufferData(GL_ARRAY_BUFFER, 8 * sizeof(GLfloat), xyTCoords, GL_STATIC_DRAW );

Then I get handle to ‘texCoord’ variable from vertex shader and want to send data from tCoords buffer.


GLuint tCoordLoc = glGetAttribLocation( shader, "texCoord" );
glBindBuffer( GL_ARRAY_BUFFER, tCoords );
glVertexAttribPointer( tCoordLoc, 2, GL_FLOAT, GL_FALSE, 0, 0);
gl3Error("Send texture coordinates");
glEnableVertexAttribArray(texCoordLocation);

Unfortunately, I always get GL_INVALID_OPERATION after glVertexAttribPointer. Retreiving attrib location and binding buffer goes ok.

I suspect I’m making some stupid rookie mistake, but I just cannot find where.

EDIT: I suspected wrong - it’s just ATI specific issue.
Just need to add


GLuint ArrayObject;
glGenVertexArrays(1, &ArrayObject);
glBindVertexArray(ArrayObject);

after glGenBuffers. Details here: ATI forum

Do you have a VAO bound? If you’re using core profile then according to the appendix of the spec it’s a requirement that a VAO is bound when calling glVertexAttribPointer etc. ATI enforces this, but NVidia doesn’t.

GLuint vaoID;
glGenVertexArrays(1, &vaoID);
glBindVertexArray(vaoID);

Do you have a VAO bound?

Now yes - and glVertexAttribPointer is working ok.

I still have one, hopefully last, question - what is the correct sequence of binding and generating FBO/VBO/shader in order to get following data flow:

  1. Generate texture from image
  2. Create necessary FBOs/RBOs etc.
  3. Send input textur to shader
  4. Render to texture
  5. Get output texture

I cannot get GLSL programs to work with FBO - all I get is either input texture or empty output texture.

Right now my code does it like that:
0. Compiles & links GLSL program

  1. Creates FBO and RBO (GL_RGB)
  2. Binds RBO to FBO (as GL_COLOR_ATTACHMENT0)
  3. Generates empty and image textures
  4. Generates vertices/texture-coordinates/indices for vertex shader
  5. Buffers vertex data and sends it to shader-program
  6. Binds FBO + glViewport + glClear
  7. glDrawElements with indices element array
  8. Downloads from FBO’s GL_COLOR_ATTACHMENT0

And, in the end, I get the empty texture, with values I set with memset :stuck_out_tongue:

I’m running in circles trying to make my vertex/shader do anything.

I have render to texture and PBO download mechanisms ready. But I after app runs output texture is empty (well, almost - while creating I set all its values to 64 and after passing through shader there are 4 pixels with 0 value in the middle).

Fragment shader is just a plain dummy, i.e:


#version 150

in vec2 fragmentTexCoord;
out uvec3 fragColor;

void main(void)
{
    fragColor = uvec3(8,16,24);
}

Vertex is just pass-through:


#version 150

uniform mat4 projectionMatrix;
uniform mat4 modelViewMatrix;

in vec4 vertex;
in vec2 texCoord;
out vec2 fragmentTexCoord;

void main(void)
{
    fragmentTexCoord = texCoord;

    gl_Position = projectionMatrix*modelViewMatrix*vertex;
}

All input variables are passed to shader correctly (checked with gDEbugger). Output texture is defined as GL_RGB/GL_UNSIGNED_BYTE and I read it with


glReadPixels( 0, 0, imageWidth, imageHeight, GL_RGB, GL_UNSIGNED_BYTE, 0 );
GLubyte* bufferData = (GLubyte*)glMapBuffer( GL_PIXEL_PACK_BUFFER, GL_READ_ONLY );

Shader is called by glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0), after binding buffer with xyIndices = { 0, 1, 2, 1, 3, 2 }.

glGetError does not catch anything and based on gDEbugger state during drawing is ok (correct FBO and texture bound, drawbuffer set to output texture).

Where is the mistake, where do I err?