PDA

View Full Version : Transform feedback to Texture



ropel
03-23-2007, 02:35 AM
Hi all,

I have my transform feedback working. Currently it feeds the data back to a vertex buffer object. I would like to have this data as a texture.

I prefer not to use a texture buffer object (does not support mipmapping). Could I somehow copy the data to a 'real' 2D texture?!

Thanks!

AlexN
03-23-2007, 11:08 AM
Yes, using PBO:

After using transform feedback, bind the VBO to the GL_PIXEL_UNPACK_BUFFER binding, bind your texture to GL_TEXTURE_2D, and call glTexImage2D (or TexSubImage) with the data pointer as an offset into your vertex buffer. Then call glGenerateMipmapEXT(GL_TEXTURE_2D) to build the mipmap chain.

http://www.opengl.org/registry/specs/ARB/pixel_buffer_object.txt
http://www.opengl.org/registry/specs/EXT/framebuffer_object.txt

ropel
03-24-2007, 10:59 AM
Ok, that seems to be a good way to transfer my data server side. I don't understand why I would use the GL_PIXEL_UNPACK_BUFFER as a binding object? Is that the only way to map it to a PBO?

Zengar
03-24-2007, 11:16 AM
PIXEL_UNPACK_BUFFER is the buffer that is the source of texture data. With other words, the functions like TexImage will fetch data from that buffer.

ropel
03-26-2007, 01:52 AM
Somehow the data does not seem to be copied to my texture. My feedback VBO is fine because I can render it with DrawArrays. It might have to do with the layout of the memory. How is that handled from a transform feedback?

Note that I quit the pipeline before rasterizing, since I get my data from the transform feedback.
So either I should be able to fill a PBO directly from my transfer feedback in order to bind that to texture. Or I should make a copy as proposed.

My current source:


// Init
// Grid of vertices
InitProxy();

// Activate Texture
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, this->srcTexture);
glEnable(GL_TEXTURE_2D);

// Create Texture from feedback ????
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, feedbackVBO);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, (particleCount/2), (particleCount/2), 0, GL_RGB, GL_UNSIGNED_BYTE, BUFFER_OFFSET(0));

// Activate Shader
glUseProgram(shadManager->shaderVisualize);
glUniform1i(glGetUniformLocation(shadManager->shaderVisualize, "TextureFromVBO"), 1);

// Render
glBindBuffer(GL_ARRAY_BUFFER, Proxy);

glVertexPointer(3, GL_FLOAT, 0, 0);

glEnableClientState(GL_VERTEX_ARRAY);

glDrawArrays(GL_POINTS, 0, proxySize);

glDisableClientState(GL_VERTEX_ARRAY);

// Cleanup
glUseProgram(0);
glDisable(GL_TEXTURE_2D);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
glBindTexture(GL_TEXTURE_2D, 0); Does someone see the problem here?

Bruce Merry
03-26-2007, 05:52 AM
This seems like a roundabout way to do things, unless you also want the data in a VBO. Why not just ignore transform feedback, bind the texture into a framebuffer object and render to it? You would need to write the current position channel to something else (colour?) and set the position to an address in the texture.

This probably won't work if you're outputting a variable number of primitives from a geometry shader, though.

ropel
03-26-2007, 06:31 AM
You've spotted my problem exactly!

The output comes from a geometry shader with a variable number of primitives. With the transform feedback I can store the required data into a buffer object.

In a second pass I would like to have this buffer object as a 2D texture, so I can gather the required data using vertex texture fetch.

The most logical approach seems to be to transform feedback to a PBO, and use TexImage2D to create the texture. However I can't get this to work.

Has anyone tried this before?

Zengar
03-26-2007, 06:50 AM
Just an idea, is it possible that you specify wrong dimensions for your texture? Size of (particleCount/2)x(particleCount/2) would assume that you wrote (up to) particleCount^2/4 particles, is this correct? Did you try to trace the error with glGetError?

ropel
03-26-2007, 07:13 AM
Ouch. That is stupid indeed. That should be a square root :rolleyes:

Does not solve my the problem though. And I have a check for glError, which does not provide any errors.

ropel
03-26-2007, 08:04 AM
Ok, I'm getting close now.
I have the output buffer bound as PBO and created the texture succesfully. It seemed to be the memory layout that was the main problem.
Now I have still have to convert my buffer to a power of two size.

Thanks for your help guys!

ropel
03-27-2007, 02:43 AM
Yet another question concerning this topic.

I would like to read out the data, just to verify my buffer. I've tried glGetBufferSubData, but without succes. It returns me zeros!


GLint srcTexSize = (GLint)ceil(sqrt(particleCount));

glBindBuffer(GL_PIXEL_UNPACK_BUFFER, feedbackPBO);

glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, srcTexSize, srcTexSize, 0, GL_RGBA, GL_FLOAT, BUFFER_OFFSET(0));

glGetBufferSubData(GL_PIXEL_UNPACK_BUFFER, 0, srcTexSize*srcTexSize*4*sizeof(GLfloat), &tmpPointer);
cout << tmpPointer[0] << tmpPointer[1] << tmpPointer[2] << tmpPointer[3] << endl;Finally I would like to know if someone managed to dynamically allocate the buffer for transform feedback after the geometry shader. Since we don't know the number of primitives, how can we preallocate a buffer?

Bruce Merry
03-27-2007, 03:08 AM
Don't trust glGetBufferSubData - it's broken in recent NVIDIA drivers and they aren't planning to fix it before 100.xx (!?!). I've had to work around this by mapping the buffer and doing a memcpy.

I haven't played with transform feedback myself, but looking at the spec it looks like you can get the buffer size by doing two passes. There is a query (as in glBeginQuery) that says how many primitives were generated, so if you get an overflow on the first pass (which is not considered an error, the feedback just truncates) then you can reallocate a larger buffer and make a second pass. Of course, if you have a good estimate for the size you can often avoid the second pass.

ropel
03-27-2007, 03:45 AM
Thanks for this hint. Saves me a lot of time figuring out why the GetBufferSubData does not provide me with the right information.

I'm trying the MapBuffer approach. Again all zero's.


// Create Texture from feedback
GLint srcTexSize = (GLint)ceil(sqrt(particleCount));

glBindBuffer(GL_PIXEL_UNPACK_BUFFER, feedbackPBO);
tmpPoint = glMapBuffer(GL_PIXEL_UNPACK_BUFFER,GL_READ_ONLY);
memcpy(tmpPoint, tmpBuf, srcTexSize*srcTexSize*4);
glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER);

for(int i=0; i<srcTexSize*srcTexSize; i+=4) cout << tmpBuf[i] << tmpBuf[i+1] << tmpBuf[i+2] << tmpBuf[i+3] << endl;

glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, srcTexSize, srcTexSize, 0, GL_RGBA, GL_FLOAT, BUFFER_OFFSET(0)); Any good examples?

ropel
03-28-2007, 03:52 AM
OK..got it fixed...pointer problem...

ehart
03-29-2007, 09:02 PM
I don't know if you have considered it, but you can also use a TextureBufferObject to avoid the copy to a 2D texture. It is like a 1D texture that always has nearest filtering and is addressed with non-normalized coordinates.

One word of warning, TeXBO was not supported with GLSL until the 100 series drivers.

-Evan

ropel
03-29-2007, 11:58 PM
Ok, you've just answered one of my remaining questions! I was wondering if the glTexImage2d performed a copy internally, or that it would change a pointer.

I did consider a TBO, however the capacity is limited and I can't perform automatic mipmapping on this texture.

Thanks for the suggestion.

ropel
06-25-2007, 07:42 AM
This was actually an old topic, but I'm currently back to this subject a bit. I have now a buffer object bound to GL_PIXEL_UNPACK_BUFFER and I call glGenerateMipmapEXT.

Is there a way to easily get the 'highest' mipmap value? (1 texel)