Rendering with transform feedback

I’m implementing a vegetation rendering system using GPU-based frustum culling with transform feedback. I write the instance IDs into a texture during the culling pre-pass, and then I read the IDs back in the rendering pass.

On Nvidia hardware this works fine. On AMD hardware I am receiving an INVALID_OPERATION error on glDrawElements() during the rendering pass. I’m not seeing anything in the documentation that really explains this:

I also notice that if the pre-pass shader emits no vertices, the error does not occur. An error only occurs when data has been written into the transform feedback buffer.

This is my pre-pass function. Is there something else I need to call to make the transform feedback texture ready for reading?

    void VegetationLayer::PrePass(Camera* camera)    {
        if (variationmatrices == NULL) BuildVariationMatrices();
        model->surfaces[0]->material->SetTexture(variationmap, 5);

        if (query[camera] == 0)
            glGenQueries(1, &query[camera]);
            glGenTransformFeedbacks(1, &transformfeedback[camera]);
            glGenBuffers(1, &feedbackbuffer[camera]);
            glBindBuffer(GL_TEXTURE_BUFFER, feedbackbuffer[camera]);
            glBufferData(GL_TEXTURE_BUFFER, maxinstancesdrawn * 4, NULL, GL_DYNAMIC_COPY);
            glGenTextures(1, &buffertexture);
            glBindTexture(GL_TEXTURE_BUFFER, buffertexture);
            glTexBuffer(GL_TEXTURE_BUFFER, GL_R32UI, feedbackbuffer[camera]);

        Mat4 mat;
        Vec4 color = Vec4(1.0);
        Vec3 campos = camera->GetPosition(true);
        int count = cellresolution * cellresolution * cellcount * cellcount;

        for (int n = 0; n < 6; n++)
            shader_frustumcull->SetVec4("frustumplane" + String(n), Vec4(camera->frustum->face[n]->plane.x, camera->frustum->face[n]->plane.y, camera->frustum->face[n]->plane.z, camera->frustum->face[n]->plane.d));
        shader_frustumcull->SetVec3("aabbmin", model->localaabb.min);
        shader_frustumcull->SetVec3("aabbmax", model->localaabb.max);
        shader_frustumcull->SetFloat("TerrainSize", terrain->resolution * terrain->scale.x);
        shader_frustumcull->SetFloat("TerrainHeight", terrain->scale.y);
        shader_frustumcull->SetFloat("TerrainResolution", terrain->resolution);
        shader_frustumcull->SetFloat("CellResolution", cellresolution * cellcount);
        shader_frustumcull->SetFloat("Density", density);
        shader_frustumcull->SetFloat("BillboardDistance", billboarddistance);
        shader_frustumcull->SetVec2("InstanceOffset", Vec2(0));
        shader_frustumcull->SetInt("VBOSize", instancesurface->CountVertices());
        shader_frustumcull->SetInt("NumInstances", count);


        glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, feedbackbuffer[camera]);
        glBeginQuery(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN, query[camera]);

        int passsize = instancesurface->CountVertices();
        int passes = ceil((float)count / (float)passsize);



If the buffer still bound to GL_TRANSFORM_FEEDBACK_BUFFER when you try to use it as a source texture?

I think that this shouldn’t matter provided that transform-feedback is disabled (and according to the documentation, the only thing that should result in an error is if the buffer is mapped), but I make a habit of unbinding objects as soon as the binding isn’t strictly required.

Also: have you confirmed that the error is originating from glDrawElements() (I.e. glGetError() returns GL_NO_ERROR immediately prior to that call)?

It’s definitely occurring on glDrawElements(), and it’s definitely due to the texture lookup in the vertex shader. Adding a call to glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, 0) at the end of the prepass function has no effect.

I got it working by switching over to render into vertex buffers. This probably didn’t directly do anything, but it simplified the code:

I also found that Intel drivers produce an INVALID_OPERATION error if no fragment shader is present. No other explanation, they just throw the error on any glDraw function.

1.6 million polys on Intel integrated graphics. No billboarding yet, but zero mem usage and zero client-side culling expense: