Gábor Fekete
Gábor Fekete

Reputation: 1358

OpenGL 4.4 transform feedback layout specifier

I'm having problems using Transform Feedback buffers with OpenGL version 4.4.

I'm using geometry shader output for capturing and drawing triangles.

The triangles will be culled by some algorithm in the geometry shader and I want to capture the resulting triangles.

So the result triangle count should be less than the input count.

When I specify the in-shader layout specifiers(xfb_buffer,etc.), no primitive is captured.

I changed it back to glTransformFeedbackVaryings, and now primitives are being captured but instead of 3 vertices per triangle (9 floats) it captures less as the resulting buffer's size is not dividible by 3.

Initialization:

// ---------------
// VERTEX BUFFER
// ---------------
glGenBuffers(1, &vertexBufferObjectId_);
// Init vertex data
unsigned int numVerts = width * height;
size_t vertexSize = (3 + 2) * sizeof(GLfloat); // position, texcoord
glBindBuffer(GL_ARRAY_BUFFER, vertexBufferObjectId_);
glBufferData(GL_ARRAY_BUFFER, numVerts * vertexSize, 0, GL_STATIC_DRAW);
uint8_t* vertices = (uint8_t*)glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY);
for (unsigned int y = 0; y < height; ++y)
{
    for (unsigned int x = 0; x < width; ++x)
    {
        *(float*)(vertices+0) = x; // x
        *(float*)(vertices+4) = y; // y
        *(float*)(vertices+8) = 0; // z
        *(float*)(vertices+12) = (float)x / (width - 1);  // u
        *(float*)(vertices+16) = (float)y / (height - 1); // v
        vertices += vertexSize;
    }
}
glUnmapBuffer(GL_ARRAY_BUFFER);
glBindBuffer(GL_ARRAY_BUFFER, 0);

// ---------------
// INDEX BUFFER
// ---------------
glGenBuffers(1, &indexBufferObjectId_);
glEnable(GL_PRIMITIVE_RESTART);
glPrimitiveRestartIndex(-1); // accepts GLuint, so this will be the largest possible value
// Init index data
unsigned int numPolys = 2 * (width - 1) * (height - 1) * 2;
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBufferObjectId_);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, numPolys * 3 * sizeof(GLuint), 0, GL_STATIC_DRAW);
GLuint* indices = (GLuint*)glMapBuffer(GL_ELEMENT_ARRAY_BUFFER, GL_WRITE_ONLY);
for (unsigned int y = 0; y < height-1; ++y)
{
    for (unsigned int x = 0; x < width-1; ++x)
    {
        // i11 is at (x,y)
        //         i20
        //     i11 i21 i31
        // i02 i12 i22
        //     i13

        uint32_t i20 = get_index(width,height,x+1,y-1);
        uint32_t i11 = get_index(width,height,x,y);
        uint32_t i21 = get_index(width,height,x+1,y);
        uint32_t i31 = get_index(width,height,x+2,y);
        uint32_t i02 = get_index(width,height,x-1,y+1);
        uint32_t i12 = get_index(width,height,x,y+1);
        uint32_t i22 = get_index(width,height,x+1,y+1);
        uint32_t i13 = get_index(width,height,x,y+2);

        // first triangle: i12,i22,i21
        //         i21
        //     i12 i22

        // with adjacency: i12,i13,i22,i31,i21,i11
        //     i11 i21 i31
        //     i12 i22
        //     i13
        *(indices++) = i12;
        *(indices++) = i13;
        *(indices++) = i22;
        *(indices++) = i31;
        *(indices++) = i21;
        *(indices++) = i11;

        // second triangle: i12,i21,i11
        //     i11 i21
        //     i12

        // with adjacency: i12,i22,i21,i20,i11,i02
        //         i20
        //     i11 i21
        // i02 i12 i22

        *(indices++) = i12;
        *(indices++) = i22;
        *(indices++) = i21;
        *(indices++) = i20;
        *(indices++) = i11;
        *(indices++) = i02;
    }
}
glUnmapBuffer(GL_ELEMENT_ARRAY_BUFFER);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);

// ---------------
// TRANSFORM FEEDBACK BUFFER
// ---------------
if (feedbackVertexBufferObjectId_)
    glDeleteBuffers(1, &feedbackVertexBufferObjectId_);

glGenBuffers(1, &feedbackVertexBufferObjectId_);
glBindBuffer(GL_ARRAY_BUFFER, feedbackVertexBufferObjectId_);
glBufferData(GL_ARRAY_BUFFER, numPolys * 3 * 3 * sizeof(GLfloat), 0, GL_STREAM_READ);

Rendering:

meshRenderShader_.enable();
// Set to write to the framebuffer.
glBindFramebuffer(GL_FRAMEBUFFER, camData.framebuffer_.framebufferId_);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

// ----------------------------------
// Render projected mesh

// Binding vertex buffer
size_t vertexSize = (3 + 2) * sizeof(GLfloat);
glBindBuffer(GL_ARRAY_BUFFER, camData.mesh_.vertexBufferObjectId_);
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, vertexSize, (const GLvoid*)0);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, vertexSize, (const GLvoid*)(sizeof(GLfloat) * 3));

// Binding index buffer
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, camData.mesh_.indexBufferObjectId_);

// Bind transform feedback and target buffer
glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, 0);
glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, camData.mesh_.feedbackVertexBufferObjectId_);

GLuint query;
glGenQueries(1, &query);

//      glEnable(GL_RASTERIZER_DISCARD);

// Begin transform feedback
glBeginQuery(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN, query);
glBeginTransformFeedback(GL_TRIANGLES);

// Set shader uniforms
meshRenderShader_.setUniformMat4("ModelViewProjection", (viewProjMatrix * camData.transform_).data());

// Binding texture
meshRenderShader_.setUniformTexture("colorTexture", camData.mesh_.textureId_, 0);
meshRenderShader_.setUniformTexture("depthTexture", camData.mesh_.depthTextureId_, 1);
meshRenderShader_.setUniform2f("depthSize", camData.intrinsic_.width, camData.intrinsic_.height);
meshRenderShader_.setUniform2f("intrinsic_f", camData.intrinsic_.fx, camData.intrinsic_.fy);
meshRenderShader_.setUniform2f("intrinsic_c", camData.intrinsic_.cx, camData.intrinsic_.cy);

// Drawing elements to textures
glDrawElements(GL_TRIANGLES_ADJACENCY, camData.mesh_.numPolys_ * 3, GL_UNSIGNED_INT, (const GLvoid*) 0);

// End transform feedback
glEndTransformFeedback();
glEndQuery(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN);
//      glDisable(GL_RASTERIZER_DISCARD);
//      glFlush();


glGetQueryObjectuiv(query, GL_QUERY_RESULT, &camData.mesh_.primitivesWritten_);

//      glDrawTransformFeedback(GL_TRIANGLES_ADJACENCY, camData.mesh_.feedbackbufferId_);

glDeleteQueries(1, &query);

// Unbinding buffers
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
glBindFramebuffer(GL_FRAMEBUFFER,0);

// Disable shader
meshRenderShader_.disable();

Relevant part of GLSL geometry shader:

layout(xfb_buffer = 0) out vec3 xPosition;
    
if (cull)
{
    gl_Position = ModelViewProjection * gl_in[0].gl_Position;
    fTexCoord = gTexCoord[0];
    xPosition = gl_Position.xyz;
    EmitVertex();
    gl_Position = ModelViewProjection * gl_in[2].gl_Position;
    fTexCoord = gTexCoord[2];
    xPosition = gl_Position.xyz;
    EmitVertex();
    gl_Position = ModelViewProjection * gl_in[4].gl_Position;
    fTexCoord = gTexCoord[4];
    xPosition = gl_Position.xyz;
    EmitVertex();
    EndPrimitive();
}

What can be the solution?

Upvotes: 2

Views: 420

Answers (1)

Mick Charles Beaver
Mick Charles Beaver

Reputation: 11

When you specify the transform feedback qualifiers, xfb_buffer needs to be accompanied by xfb_offset. From the OpenGL Wiki:

Variables can have xfb_buffer assigned to them without xfb_offset. This does nothing and will be ignored.

In short, changing your shader to the following should avoid the need to call glTransformFeedbackVaryings():

layout(xfb_buffer = 0, xfb_offset = 0) out vec3 xPosition;

Upvotes: 1

Related Questions