PDA

View Full Version : Regarding transfrm feedbk with gemetry shader



mobeen
08-06-2011, 03:28 AM
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

Alfonse Reinheart
08-06-2011, 03:38 AM
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.

zeoverlord
08-06-2011, 01:00 PM
transform feedback tutorial (http://www.flashbang.se/archives/326), i think this is pretty much what your trying to do

malexander
08-06-2011, 05:52 PM
There's a several reasons why transform feedback would return INVALID_OPERATION:
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 pointsThere may be a few more I've forgotten, but those are the common ones that have tripped me up in the past.

mobeen
08-07-2011, 07:33 PM
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, &amp;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(), &amp;positions[0], GL_DYNAMIC_COPY);

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

glBindBuffer (GL_ARRAY_BUFFER, vboIndicesID);
glBufferData (GL_ARRAY_BUFFER, sizeof(glm::ivec4)*indices.size(), &amp;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_WRIT TEN, query);
glDrawArrays(GL_POINTS, 0, indices.size());
glEndQuery(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTE N);
glEndTransformFeedback();
glFlush();
glEndQuery(GL_TIME_ELAPSED);
glDisable(GL_RASTERIZER_DISCARD);
glGetQueryObjectui64v(t_query, GL_QUERY_RESULT, &amp;elapsed_time);
delta_time = elapsed_time / 1000000.0f;
glGetQueryObjectuiv(query, GL_QUERY_RESULT, &amp;primitives_written);

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

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

mobeen
08-07-2011, 08:09 PM
There's a several reasons why transform feedback would return INVALID_OPERATION:

the output primitive type of the geometry shader doesn't
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.

Alfonse Reinheart
08-07-2011, 08:11 PM
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.

mobeen
08-07-2011, 08:34 PM
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?

Alfonse Reinheart
08-07-2011, 10:25 PM
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.

mobeen
08-07-2011, 10:38 PM
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.

Alfonse Reinheart
08-08-2011, 12:09 AM
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.

mobeen
08-08-2011, 12:42 AM
Hi Alfonse,
Thanks for the detailed response. I think TF would not help me in doing what I intend to do.

mobeen
08-08-2011, 02:34 PM
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.

Alfonse Reinheart
08-08-2011, 02:41 PM
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.

mobeen
08-08-2011, 06:14 PM
OK got it. That was what I expected it to be.

Thanks for the responses Alfonse.