Regarding transfrm feedbk with gemetry shader

Hi all,
I am trying to use transform feedback with geometry shaders. This is how it is setup.
Vertex stage:
The vertex shader is only input a single attribute (index a ivec4) which are the indices of tetrahedron’s vertices. I simply pass them through to the geometry shader.
Geometry shader stage:
Here I look up the position from a texture buffer object to get the tetrahedral vertices and then do some transformation on the positions to get new positions.
Buffer handling
I have setup two position vertex buffer objects each attached to a vertex array object and an index vertex buffer (not element array buffer) for storing indices. The texture buffers are associated to the position buffer objects.
So this is how buffers are setup in pseudocode.


for i:0 to 2
   bind updateVAO[i]
      bind vboPos[i]
      push positions to buffer data 
      
      bind vboInd
      push tetrahedral indices to buffer data
end for

for i:0 to 2
   bind texture_buffer vboPos[i]
   ...
end for

When rendering, I simply render N points where N is the total tetrahedra. I have renderd tetrahedra using this approach and it works fine. Now I intend to use tf along with this however, I get error 1282 invalid operation when I call drawArrays in the transform feedback code.
My tf code is something like this.


bind shader
   bind updateVAO[0]
      bindbufferbase 0 vboPos[1]
         enable rasterizer discard
            begin tf points
               drawArrays points //i get 1282 here
            end tf
         disable rasterizer discard      
   bind renderVAO
      drawArrays points
unbind shader     

My question is that is it possible to use tf with an attribute that is generated in the geometry shader? And what am i doing wrong in the above code snippet? Any ideas references or weblinks on this much appreciated.

Thanks.
Mobeen

You didn’t post a snippet of code; you posted a snippet of pseudo-code.

Yes, you can use transform feedback with geometry shaders. But you haven’t showed us the actual problem.

transform feedback tutorial, i think this is pretty much what your trying to do

There’s a several reasons why transform feedback would return INVALID_OPERATION:
[ul][]begin/endTransformFeedback isn’t paired properly,[]the shader is changed between begin… and endTransformFeedback, []the output primitive type of the geometry shader doesn’t match the transform feedback primitive specified in beginTransformFeedback[]not all the varyings specified for transform feedback have buffers bound to the transform feedback binding points[/ul]There may be a few more I’ve forgotten, but those are the common ones that have tripped me up in the past.

Thanks for the replies. I have noted the references as well.

OK here are the actual codes and shaders.
Vertex shader:<div class=“ubbcode-block”><div class=“ubbcode-header”>Click to reveal… (warning) <input type=“button” class=“form-button” value=“Show me!” onclick=“toggle_spoiler(this, ‘Yikes, my eyes!’, ‘Show me!’)” />]<div style=“display: none;”>
#version 330 core
layout( location = 0 ) in ivec4 vVertex;
void main()
{
gl_Position = vVertex;
}
[/QUOTE]</div>
Geometry shader:<div class=“ubbcode-block”><div class=“ubbcode-header”>Click to reveal… (warning) <input type=“button” class=“form-button” value=“Show me!” onclick=“toggle_spoiler(this, ‘Yikes, my eyes!’, ‘Show me!’)” />]<div style=“display: none;”>
#version 330 core
#extension EXT_gpu_shader4 : require
uniform samplerBuffer positionTex;
uniform samplerBuffer velocityTex;

layout (points) in;
layout (triangle_strip) out;
layout (max_vertices = 12) out;

uniform mat4 MVP;
out vec4 out_position; //Transform feedback attributes
out vec3 out_velocity;

void main(void)
{
ivec4 index = ivec4(gl_in[0].gl_Position);

//extract tetrahedra positions
vec4 p0 = texelFetchBuffer(positionTex, index.x);
vec4 p1 = texelFetchBuffer(positionTex, index.y);
vec4 p2 = texelFetchBuffer(positionTex, index.z);
vec4 p3 = texelFetchBuffer(positionTex, index.w);

//extract tetrahedra velocities
vec3 v0 = texelFetchBuffer(velocityTex, index.x).xyz;
vec3 v1 = texelFetchBuffer(velocityTex, index.y).xyz;
vec3 v2 = texelFetchBuffer(velocityTex, index.z).xyz;
vec3 v3 = texelFetchBuffer(velocityTex, index.w).xyz;

//do some processing using p0,p1,p2,p3 & v0,v1,v2,v3

gl_Position = MVP*p0;
out_position = p0;
out_velocity = v0;
EmitVertex();

gl_Position = MVP*p1;
out_position = p1;
out_velocity = v1;
EmitVertex();

gl_Position = MVP*p3;
out_position = p3;
out_velocity = v3;
EmitVertex();

gl_Position = MVP*p2;
out_position = p2;
out_velocity = v2;
EmitVertex();

gl_Position = MVP*p0;
out_position = p0;
out_velocity = v0;
EmitVertex();

gl_Position = MVP*p1;
out_position = p1;
out_velocity = v1;
EmitVertex();
EndPrimitive();
}
[/QUOTE]</div>
Shader loading is through a custom class and the attributes/uniforms are setup like this
<div class=“ubbcode-block”><div class=“ubbcode-header”>Click to reveal… (warning) <input type=“button” class=“form-button” value=“Show me!” onclick=“toggle_spoiler(this, ‘Yikes, my eyes!’, ‘Show me!’)” />]<div style=“display: none;”>
shader.LoadFromFile(GL_VERTEX_SHADER, “shaders/shader.vert”);
shader.LoadFromFile(GL_FRAGMENT_SHADER, “shaders/shader.frag”);
shader.LoadFromFile(GL_GEOMETRY_SHADER, “shaders/shader.geom”);
shader.CreateAndLinkProgram();
shader.Use();
shader.AddAttribute(“vVertex”);
shader.AddUniform(“MVP”);
shader.AddUniform(“positionTex”);
shader.AddUniform(“velocityTex”);
glUniform1i(shader(“positionTex”), 0);
glUniform1i(shader(“velocityTex”), 1);
shader.UnUse();
[/QUOTE]</div>
Setup code for vbo/vao
<div class=“ubbcode-block”><div class=“ubbcode-header”>Click to reveal… (warning) <input type=“button” class=“form-button” value=“Show me!” onclick=“toggle_spoiler(this, ‘Yikes, my eyes!’, ‘Show me!’)” />]<div style=“display: none;”>
glGenVertexArrays(2, updateVAOID);
glGenBuffers (2, vboPosID);
glGenBuffers (2, vboVelID);
glGenBuffers (1, &vboIndicesID);

for(int i=0;i<2;i++) {
glBindVertexArray(updateVAOID[i]);
glBindBuffer (GL_ARRAY_BUFFER, vboPosID[i]);
glBufferData (GL_ARRAY_BUFFER, sizeof(glm::vec4)*positions.size(), &positions[0], GL_DYNAMIC_COPY);

glBindBuffer( GL_ARRAY_BUFFER, vboVelID[i]);
glBufferData( GL_ARRAY_BUFFER, velocities.size()*sizeof(glm::vec3), &(velocities[0].x), GL_DYNAMIC_COPY);

glBindBuffer (GL_ARRAY_BUFFER, vboIndicesID);
glBufferData (GL_ARRAY_BUFFER, sizeof(glm::ivec4)*indices.size(), &indices[0], GL_STATIC_DRAW);

GL_CHECK_ERRORS
glEnableVertexAttribArray(0);
glVertexAttribIPointer(0, 4, GL_INT, 0,0);
}

//setup texture buffer object
glGenTextures(2,positionTexID);
glGenTextures(2,velocityTexID);
for(int i=0;i<2;i++) {
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_BUFFER, vboPosID[i]);
glTexBuffer( GL_TEXTURE_BUFFER, GL_RGBA32F, vboPosID[i]);

glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_BUFFER, vboVelID[i]);
glTexBuffer( GL_TEXTURE_BUFFER, GL_RGBA32F, vboVelID[i]);
}

//setup transform feedback
const char* varying_names[]={“out_position”, “out_velocity”};
glTransformFeedbackVaryings(shader.GetProgram(), 2, varying_names, GL_SEPARATE_ATTRIBS);
glLinkProgram(shader.GetProgram());
[/QUOTE]</div>
Transform feedback code
<div class=“ubbcode-block”><div class=“ubbcode-header”>Click to reveal… (warning) <input type=“button” class=“form-button” value=“Show me!” onclick=“toggle_spoiler(this, ‘Yikes, my eyes!’, ‘Show me!’)” />]<div style=“display: none;”>
shader.Use();
//set uniforms
//bind TBOs
glActiveTexture( GL_TEXTURE0);
glBindTexture( GL_TEXTURE_BUFFER, positionTexID[writeID]);

glActiveTexture( GL_TEXTURE1);
glBindTexture( GL_TEXTURE_BUFFER, velocityTexID[writeID]);
glBindVertexArray( updateVAOID[writeID]);
glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, vboPosID[readID]);
glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 1, vboVelID[readID]);
glEnable(GL_RASTERIZER_DISCARD);
glBeginQuery(GL_TIME_ELAPSED,t_query);
glBeginTransformFeedback(GL_POINTS);
glBeginQuery(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN, query);
glDrawArrays(GL_POINTS, 0, indices.size());
glEndQuery(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN);
glEndTransformFeedback();
glFlush();
glEndQuery(GL_TIME_ELAPSED);
glDisable(GL_RASTERIZER_DISCARD);
glGetQueryObjectui64v(t_query, GL_QUERY_RESULT, &elapsed_time);
delta_time = elapsed_time / 1000000.0f;
glGetQueryObjectuiv(query, GL_QUERY_RESULT, &primitives_written);

//swap the buffers
int tmp = readID;
readID=writeID;
writeID = tmp;

glutSwapBuffers();
[/QUOTE]</div>

I just checked my gs for this and I think this is why it is not working. My output type is trianglestrip and input is points. So for this to work the output type of gs should be point. Thanks this removes the invalid operation error. So to do what I want to achieve, i think i would need two gs one for modification and other for rendering.

So for this to work the output type of gs should be point.

For it to work, you need to call glBeginTransformFeedback(GL_TRIANGLE_STRIP). Which is what your GS outputs.

I tried this but it gives me error 1280 (invalid enum) after the call to glBeginTransformFeedback? I just checked the quick reference and it says the allowed primitive modes are TRIANGLES, LINES, POINTS so this wont work.
Now how do u do transform feedback with triangle strips since this is the only triangle output mode from geometry shaders?

I think the only solution is to use points for tf and use another geometry shader for rendering?

OK i think I have got it working using points for tf and using a separate gs for rendering; only that the output is not what I intended. The reason for this being that the output positions do not correspond to the locations from where the positions are being fetched from the buffer object.

When we output to a transform feedback buffer, what order are the positions written? is this exactly to the position from where the input is read? For my case, 1 vertex is sent per tetrahedron and since i am reading from 4 locations for the given input vertex,
Q1) what is the location to which the output position from tf will be written to in the buffer object?
Q2) how can I redirect my outputs (new positions/velocities) to go to the correct location in the buffer object?

This is where reading the spec is better than reading the reference.

Transform feedback unstrips/fans inputs, if you render with GL_TRIANGLE_STRIP, it comes out in TF as a list of triangles. So you should just use glBeginTransformFeedback(GL_TRIANGLES), which will convert the output strips into individual triangles.

Hi Alfonse,
Yeah using triangles works fine too. Few more quesitons:

When we output to a transform feedback buffer, what order are the positions written? is this exactly to the position from where the input is read? For my case, 1 vertex is sent per tetrahedron and since i am reading from 4 locations for the given input vertex,
Q1) what is the location to which the output position from tf will be written to in the buffer object?
Q2) how can I redirect my outputs (new positions/velocities) to go to the correct location in the buffer object?

Just another insight. The total tetrahedra that i push in are 3614 but the total transfrm feedbck output primitives are 371.

I’m not sure that I can answer your questions, as they don’t really make sense with transform feedback.

All transform feedback does is take the shader outputs you specify and write primitives of them to a buffer. In order. As you specify them. So that if you fed them back through pass-through shaders, with a glDrawArrays(*) call (where * is the type given to glBeginTransformFeedback), you will get the exact same appearance as if you had render them in the first place.

This means that winding order is preserved. And general vertex order is preserved.

So there is no redirecting outputs (not without transform_feedback_3). The location where each output is written is exactly where you tell it. They are written sequentially to the buffer object(s) you specify. Up until the glEndTransformFeedback() call.

Hi Alfonse,
Thanks for the detailed response. I think TF would not help me in doing what I intend to do.

So there is no redirecting outputs (not without transform_feedback_3).

Hmm I went through the details about this extension. It does allow attaching a unique stream to one/more tf outputs but then again how would this allow me to output to a variable address for each input value? Any links tutorials would be appreciated.

It doesn’t. Transform feedback is not “write arbitrary data to arbitrary locations of arbitrary buffer objects.” That’s not what it’s for. It’s for capturing the output of the vertex and primitive transformation pipeline.

TF3 allows you to redirect primitives to different feedback streams. But that’s it; it doesn’t let you just write to “somewhere”. Streams are well-defined locations, and streams are written sequentially, just like regular transform feedback.

If you want that, then you should be using either OpenCL or ARB_shader_image_load_store. Just don’t expect the latter to be exceedingly fast, particularly if you have to do a lot of synchronization.

OK got it. That was what I expected it to be.

Thanks for the responses Alfonse.