Transform Feedback Captures Incorrect Vertices After First Frame

Description: I am experiencing an issue with OpenGL transform feedback where the correct vertices are captured only during the first pass of the render loop. In subsequent frames, the transform feedback captures a duplicate of one vertex instead of the expected unique vertices for two triangles that form a square.

Vertex Shader:

GLSL

#version 330 core
layout(location = 0) in vec3 position;
out vec3 vertexPosition; // Custom varying for transform feedback
void main() {
   vertexPosition = position; // Pass position to custom varying
   gl_Position = vec4(position, 1.0);
}

Index Buffer Content (confirmed correct):

GLuint squareindices[] = {
    0, 1, 2, // First triangle
    2, 3, 0  // Second triangle
};

// Define the vertices present in square...
    GLfloat squareVertices[] = {
        -0.9f, -0.9f, 0.0f, // Bottom left
        0.9f, -0.9f, 0.0f, // Bottom right
        0.9f, 0.9f, 0.0f, // Top right
        -0.9f, 0.9f, 0.0f // Top left
    };

Here’s the pertinent snippet (I hope this is clear enough)

    // Compile shaders and create shader program with transform feedback
    GLuint shaderProgram = createShaderProgram(vertexShaderSource, fragmentShaderSource);
    // Set up VAO, VBO, and EBO
    GLuint VAO, VBO, EBO;
    glGenVertexArrays(1, &VAO);
    glGenBuffers(1, &VBO);
    glGenBuffers(1, &EBO);
    // Bind VAO
    glBindVertexArray(VAO);
    // Bind and set VBO
    glBindBuffer(GL_ARRAY_BUFFER, VBO);
    glBufferData(GL_ARRAY_BUFFER, sizeof (squareVertices), squareVertices, GL_STATIC_DRAW);
    // Bind and set EBO
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof (squareindices), squareindices, GL_STATIC_DRAW);
    // Set vertex attribute pointers
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof (GLfloat), (void*) 0);
    glEnableVertexAttribArray(0);
    // Unbind VBO (not EBO, as it's stored in VAO)
    glBindBuffer(GL_ARRAY_BUFFER, 0);
    glBindVertexArray(0);
    // Calculate the number of indices
    size_t numIndices = sizeof (squareindices) / sizeof (squareindices[0]);
    // Calculate the number of components per vertex (x, y, z)
    size_t numComponentsPerVertex = 3;
    // Calculate the total size for the buffer
    size_t totalSize = numIndices * numComponentsPerVertex * sizeof (GLfloat);
    // Create a buffer for transform feedback
    GLuint tbo;
    glGenBuffers(1, &tbo);
    glBindBuffer(GL_ARRAY_BUFFER, tbo);
    glBufferData(GL_ARRAY_BUFFER, totalSize, NULL, GL_DYNAMIC_COPY);
    glBindBuffer(GL_ARRAY_BUFFER, 0);

    // Create a query object to count the number of primitives
    GLuint primitivesQuery;
    glGenQueries(1, &primitivesQuery);
    // Bind the EBO and read back the indices
    GLuint readBackIndices[6]; // Adjust the size based on the number of indices
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
    glGetBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, sizeof (readBackIndices), readBackIndices);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); // Unbind the EBO
 glUseProgram(shaderProgram);
    // Print the indices to verify their content
    std::cout << "Index Buffer Content:" << std::endl;
    for (int i = 0; i < 6; ++i) { // Adjust the loop based on the number of indices
        std::cout << "Index " << i << ": " << readBackIndices[i] << std::endl;
    }
     // Render loop
    while (!glfwWindowShouldClose(window)) { //&& !WindowShouldClose()) {

        glfwMakeContextCurrent(window);
        glClear(GL_COLOR_BUFFER_BIT);
        // Set up transform feedback buffer and query object
        glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, tbo);
        glBeginQuery(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN, primitivesQuery);
        glBindVertexArray(VAO);
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
        // Enable transform feedback
        glEnable(GL_RASTERIZER_DISCARD);
        glBeginTransformFeedback(GL_TRIANGLES);
        // Draw the square using elements
        glDrawElements(GL_TRIANGLES, sizeof (squareIndices) / sizeof (GLint), GL_UNSIGNED_INT, 0);
        // End transform feedback
        glEndTransformFeedback();
        // Ensure all transform feedback operations are complete
        glFinish(); // or glFinish() for a stronger guarantee
        // End the query 
        glEndQuery(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN);
        // Fetch the number of primitives generated
        GLuint primitivesCount;
        glGetQueryObjectuiv(primitivesQuery, GL_QUERY_RESULT, &primitivesCount);
        // Now map the buffer
        glBindBuffer(GL_ARRAY_BUFFER, tbo);
        capturedVertices = (GLfloat *) glMapBuffer(GL_ARRAY_BUFFER, GL_READ_ONLY);
        // Check for errors after mapping the buffer
        GLenum err = glGetError();
        if (err != GL_NO_ERROR) {
            std::cerr << "OpenGL Error: " << std::hex << err << std::endl;
        }
        if (capturedVertices) {
            // Process the captured vertices here
            for (GLuint i = 0; i < primitivesCount * 3; ++i) {// 3 vertices per primitive (triangle)
                std::cout << "Vertex " << i << ": "
                        << capturedVertices[i * 3] << ", " // x-coordinate
                        << capturedVertices[i * 3 + 1] << ", " // y-coordinate
                        << capturedVertices[i * 3 + 2] << std::endl; // z-coordinate
            }

            // Unmap the buffer after you're done processing
            glUnmapBuffer(GL_ARRAY_BUFFER);
        } else {
            std::cerr << "Error mapping the buffer." << std::endl;
        }

        glDisable(GL_RASTERIZER_DISCARD);
        // Enable the vertex attribute array for position data
        glEnableVertexAttribArray(0);
        // Specify the format of the vertex data
        glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void*) 0);
        // Set the point size to make it clearly visible
        glPointSize(10.0f);
        // Draw the points using the captured vertex data
        glDrawArrays(GL_POINTS, 0, primitivesCount * 3);
        // Unbind the VAO
        glBindBuffer(GL_ARRAY_BUFFER, 0);
        glBindVertexArray(0);
        glfwSwapBuffers(window);
        glfwPollEvents();
  //      while (1 == 1) {
      //  }
    }

Observed Behavior:

  • On the first frame, the transform feedback captures the following vertices correctly:
Vertex 0: -0.9, -0.9, 0
Vertex 0: -0.9, -0.9, 0
Vertex 1: 0.9, -0.9, 0
Vertex 2: 0.9, 0.9, 0
Vertex 3: 0.9, 0.9, 0
Vertex 4: -0.9, 0.9, 0
Vertex 5: -0.9, -0.9, 0
  • From the second frame onwards, the transform feedback captures the following vertices:

Vertex 0: -0.9, -0.9, 0
Vertex 1: 0.9, -0.9, 0
Vertex 2: 0.9, 0.9, 0
Vertex 3: 0.9, 0.9, 0
Vertex 4: 0.9, 0.9, 0
Vertex 5: -0.9, -0.9, 0
Vertex 0: -0.9, -0.9, 0
Vertex 1: 0.9, -0.9, 0
Vertex 2: 0.9, 0.9, 0
Vertex 3: 0.9, 0.9, 0
Vertex 4: 0.9, 0.9, 0
Vertex 5: -0.9, -0.9, 0
Vertex 0: -0.9, -0.9, 0
Vertex 1: 0.9, -0.9, 0
Vertex 2: 0.9, 0.9, 0
Vertex 3: 0.9, 0.9, 0
Vertex 4: 0.9, 0.9, 0
Vertex 5: -0.9, -0.9, 0

Note the duplicate capture of the top-right vertex and the missing top-left vertex.
i.e vertex 4 should be: -0.9, 0.9, 0

Questions:

  • What could be causing the transform feedback to capture incorrect vertices after the first frame?
  • Are there any common pitfalls or state changes that could affect transform feedback behaviour between frames?
  • How can I ensure that the transform feedback captures the correct vertices consistently in every frame?

With an ngon. A similar result but this time the corrupted vertices increases every frame. (all I can say is about about 2/3 are corrupted each frame until (as before) the first 4 are the only ones that are correct…
Untitled video

What function caused them? If you’re getting errors, you can’t expect valid behavior.

sorry I think I added the wrong code and `GL_INVALID_OPERATION no longer applies. I have changed it and the problem is still the same. I’m sorry about uploading the wrong/erroneous code.

With an ngon. A similar result but this time the corrupted vertices increases every frame. (all I can say is about about 2/3 are corrupted each frame until (as before) the first 4 are the only ones that are correct…
Untitled video

Solved the issue:
By removing the drawing of the points (it was a visual check and is not needed anyhoo)
Removed glEnableVertexAttribArray , glVertexAttribPointer , glPointSize , and glDrawArrays calls, and the subsequent glBindVertexArray(0) from the render loop.
Was the problem related to the state changes introduced by these calls, affecting the transform feedback results?