什么可能导致glDrawArrays生成GL_INVALID_OPERATION错误?

Mic*_*ell 48 opengl shader glsl marching-cubes geometry-shader

我一直在尝试使用OpenGL和GLSL编写Marching Cubes算法的两遍GPU实现,类似于GPU Gems 3第一章中详述的算法.但是,glDrawArrays在我的第一次传球中的呼叫始终失败了GL_INVALID_OPERATION.

我查找了所有可以找到的文档,并发现这些条件glDrawArrays可以抛出该错误:

  1. GL_INVALID_OPERATION如果非零缓冲区对象名称绑定到已启用的数组或GL_DRAW_INDIRECT_BUFFER绑定,并且缓冲区对象的数据存储当前已映射,则会生成.
  2. GL_INVALID_OPERATION如果glDrawArrays在执行glBegin和相应的执行之间执行,则生成glEnd.
  3. GL_INVALID_OPERATION将由glDrawArraysglDrawElements当前程序对象中的任何两个活动采样器具有不同类型,但引用相同的纹理图像单元.
  4. GL_INVALID_OPERATION 如果几何着色器处于活动状态且模式与当前安装的程序对象中几何着色器的输入基元类型不兼容,则会生成.
  5. GL_INVALID_OPERATION如果模式是GL_PATCHES并且没有曲面细分控制着色器处于活动状态,则生成.
  6. GL_INVALID_OPERATION如果将基元的顶点记录到用于变换反馈目的的缓冲区对象,则会生成超出任何缓冲区对象大小的限制,或者超出结束位置偏移+大小-1,如下所示glBindBufferRange.
  7. GL_INVALID_OPERATIONglDrawArrays()如果不存在几何着色器,则生成变换反馈,并且模式不是允许的模式之一.
  8. GL_INVALID_OPERATIONglDrawArrays()如果存在几何着色器,则生成变换反馈,并且几何着色器的输出基元类型与变换反馈primitiveMode不匹配.
  9. GL_INVALID_OPERATION 如果绑定着色器程序无效,则生成.
  10. GL_INVALID_OPERATION如果正在使用变换反馈,则生成编辑10/10/12:绑定到变换反馈绑定点的缓冲区也绑定到数组缓冲区绑定点.这是我遇到的问题,因为我绑定了缓冲区的拼写错误.虽然规范确实声明这是非法的,但在我发现的任何文档中,它都没有列在glDrawArrays下作为它可以抛出错误的原因之一.

不幸的是,我找不到任何一份官方文档,其中包括超过3篇.我不得不从众多来源收集这份清单.第7点和第8点实际上来自文档glBeginTransformFeedback,第9点似乎根本没有记录.我发现它在某个论坛帖子中提到过.但是,我仍然不认为这个列表是完整的,因为这些似乎都没有解释我得到的错误.

  1. 我在任何地方的程序中都没有映射任何缓冲区.
  2. 我使用的是核心配置文件,所以glBeginglEnd没有提供连.
  3. 我有两个采样器,它们有不同的类型,但它们肯定映射到不同的纹理.
  4. 几何着色器处于活动状态,但它的输入布局是layout (points) in,并且glDrawArrays正在调用GL_POINTS.
  5. 我没有使用GL_PATCHES任何类型的镶嵌着色器.
  6. 我已经确定我正在分配我的几何着色器可能输出的最大空间量.然后我尝试了四倍.没有帮助.
  7. 有一个几何着色器.看下一点.
  8. 正在使用变换反馈,并且有一个几何着色器,但输出布局是layout (points) out并且glBeginTransformFeedback被调用GL_POINTS.
  9. 我试着在调用glValidateProgram之前插入一个调用glDrawArrays,然后返回GL_TRUE.

实际的OpenGL代码在这里:

    const int SECTOR_SIZE = 32;
    const int SECTOR_SIZE_CUBED = SECTOR_SIZE * SECTOR_SIZE * SECTOR_SIZE;
    const int CACHE_SIZE = SECTOR_SIZE + 3;
    const int CACHE_SIZE_CUBED = CACHE_SIZE * CACHE_SIZE * CACHE_SIZE;

    MarchingCubesDoublePass::MarchingCubesDoublePass(ServiceProvider* svc, DensityMap* sourceData) {
        this->sourceData = sourceData;
        densityCache = new float[CACHE_SIZE_CUBED];
    }

    MarchingCubesDoublePass::~MarchingCubesDoublePass() {
        delete densityCache;
    }

    void MarchingCubesDoublePass::InitShaders() {
        ShaderInfo vertShader, geoShader, fragShader;

        vertShader = svc->shader->Load("data/shaders/MarchingCubesDoublePass-Pass1.vert", GL_VERTEX_SHADER);
        svc->shader->Compile(vertShader);
        geoShader = svc->shader->Load("data/shaders/MarchingCubesDoublePass-Pass1.geo", GL_GEOMETRY_SHADER);
        svc->shader->Compile(geoShader);
        shaderPass1 = glCreateProgram();
        static const char* outputVaryings[] = { "triangle" };
        glTransformFeedbackVaryings(shaderPass1, 1, outputVaryings, GL_SEPARATE_ATTRIBS);
        assert(svc->shader->Link(shaderPass1, vertShader, geoShader));

        uniPass1DensityMap = glGetUniformLocation(shaderPass1, "densityMap");
        uniPass1TriTable = glGetUniformLocation(shaderPass1, "triangleTable");
        uniPass1Size = glGetUniformLocation(shaderPass1, "size");
        attribPass1VertPosition = glGetAttribLocation(shaderPass1, "vertPosition");

        vertShader = svc->shader->Load("data/shaders/MarchingCubesDoublePass-Pass2.vert", GL_VERTEX_SHADER);
        svc->shader->Compile(vertShader);
        geoShader = svc->shader->Load("data/shaders/MarchingCubesDoublePass-Pass2.geo", GL_GEOMETRY_SHADER);
        svc->shader->Compile(geoShader);
        fragShader = svc->shader->Load("data/shaders/MarchingCubesDoublePass-Pass2.frag", GL_FRAGMENT_SHADER);
        svc->shader->Compile(fragShader);
        shaderPass2 = glCreateProgram();
        assert(svc->shader->Link(shaderPass2, vertShader, geoShader, fragShader));

        uniPass2DensityMap = glGetUniformLocation(shaderPass2, "densityMap");
        uniPass2Size = glGetUniformLocation(shaderPass2, "size");
        uniPass2Offset = glGetUniformLocation(shaderPass2, "offset");
        uniPass2Matrix = glGetUniformLocation(shaderPass2, "matrix");
        attribPass2Triangle = glGetAttribLocation(shaderPass2, "triangle");
    }

    void MarchingCubesDoublePass::InitTextures() {
        for (int x = 0; x < CACHE_SIZE; x++) {
            for (int y = 0; y < CACHE_SIZE; y++) {
                for (int z = 0; z < CACHE_SIZE; z++) {
                    densityCache[x + y*CACHE_SIZE + z*CACHE_SIZE*CACHE_SIZE] = sourceData->GetDensity(Vector3(x-1, y-1, z-1));
                }
            }
        }
        glGenTextures(1, &densityTex);
        glBindTexture(GL_TEXTURE_3D, densityTex);
        glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
        glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
        glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
        glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
        glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
        glTexImage3D(GL_TEXTURE_3D, 0, GL_R32F, CACHE_SIZE, CACHE_SIZE, CACHE_SIZE, 0, GL_RED, GL_FLOAT, densityCache);

        glGenTextures(1, &triTableTex);
        glBindTexture(GL_TEXTURE_RECTANGLE, triTableTex);
        glTexParameteri(GL_TEXTURE_RECTANGLE, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
        glTexParameteri(GL_TEXTURE_RECTANGLE, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
        glTexParameteri(GL_TEXTURE_RECTANGLE, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
        glTexParameteri(GL_TEXTURE_RECTANGLE, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
        glTexImage2D(GL_TEXTURE_RECTANGLE, 0, GL_R16I, 16, 256, 0, GL_RED_INTEGER, GL_INT, triTable);
    }

    void MarchingCubesDoublePass::InitBuffers() {
        float* voxelGrid = new float[SECTOR_SIZE_CUBED*3];
        unsigned int index = 0;
        for (int x = 0; x < SECTOR_SIZE; x++) {
            for (int y = 0; y < SECTOR_SIZE; y++) {
                for (int z = 0; z < SECTOR_SIZE; z++) {
                    voxelGrid[index*3 + 0] = x;
                    voxelGrid[index*3 + 1] = y;
                    voxelGrid[index*3 + 2] = z;
                    index++;
                }
            }
        }

        glGenBuffers(1, &bufferPass1);
        glBindBuffer(GL_ARRAY_BUFFER, bufferPass1);
        glBufferData(GL_ARRAY_BUFFER, SECTOR_SIZE_CUBED*3*sizeof(float), voxelGrid, GL_STATIC_DRAW);
        glBindBuffer(GL_ARRAY_BUFFER, 0);

        glGenBuffers(1, &bufferPass2);
        glBindBuffer(GL_ARRAY_BUFFER, bufferPass2);
        glBufferData(GL_ARRAY_BUFFER, SECTOR_SIZE_CUBED*5*sizeof(int), NULL, GL_DYNAMIC_COPY);
        glBindBuffer(GL_ARRAY_BUFFER, 0);

        glGenVertexArrays(1, &vaoPass1);
        glBindVertexArray(vaoPass1);
        glBindBuffer(GL_ARRAY_BUFFER, bufferPass1);
        glVertexAttribPointer(attribPass1VertPosition, 3, GL_FLOAT, GL_FALSE, 0, (void*)0);
        glBindBuffer(GL_ARRAY_BUFFER, 0);
        glEnableVertexAttribArray(attribPass1VertPosition);
        glBindVertexArray(0);

        glGenVertexArrays(1, &vaoPass2);
        glBindVertexArray(vaoPass2);
        glBindBuffer(GL_ARRAY_BUFFER, bufferPass2);
        glVertexAttribIPointer(attribPass2Triangle, 1, GL_INT, 0, (void*)0);
        glBindBuffer(GL_ARRAY_BUFFER, 0);
        glEnableVertexAttribArray(attribPass2Triangle);
        glBindVertexArray(0);

        glGenQueries(1, &queryNumTriangles);
    }

    void MarchingCubesDoublePass::Register(Genesis::ServiceProvider* svc, Genesis::Entity* ent) {
        this->svc = svc;
        this->ent = ent;
        svc->scene->RegisterEntity(ent);

        InitShaders();
        InitTextures();
        InitBuffers();
    }

    void MarchingCubesDoublePass::Unregister() {
        if (!ent->GetBehavior<Genesis::Render>()) {
            svc->scene->UnregisterEntity(ent);
        }
    }

    void MarchingCubesDoublePass::RenderPass1() {
        glEnable(GL_RASTERIZER_DISCARD);

        glUseProgram(shaderPass1);
        glActiveTexture(GL_TEXTURE0);
        glBindTexture(GL_TEXTURE_3D, densityTex);
        glActiveTexture(GL_TEXTURE1);
        glBindTexture(GL_TEXTURE_RECTANGLE, triTableTex);
        glUniform1i(uniPass1DensityMap, 0);
        glUniform1i(uniPass1TriTable, 1);
        glUniform1i(uniPass1Size, SECTOR_SIZE);

        glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, bufferPass2);

        glBindVertexArray(vaoPass2);
        glBeginQuery(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN, queryNumTriangles);
        glBeginTransformFeedback(GL_POINTS);
            GLenum error = glGetError();
            glDrawArrays(GL_POINTS, 0, SECTOR_SIZE_CUBED);
            error = glGetError();
        glEndTransformFeedback();
        glEndQuery(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN);
        glBindVertexArray(0);

        glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, 0);

        glUseProgram(0);

        glDisable(GL_RASTERIZER_DISCARD);

        glGetQueryObjectuiv(queryNumTriangles, GL_QUERY_RESULT, &numTriangles);
    }

    void MarchingCubesDoublePass::RenderPass2(Matrix mat) {
        glUseProgram(shaderPass2);

        glActiveTexture(GL_TEXTURE0);
        glBindTexture(GL_TEXTURE_3D, densityTex);

        glUniform1i(uniPass2DensityMap, 0);
        glUniform1i(uniPass2Size, SECTOR_SIZE);
        glUniform3f(uniPass2Offset, 0, 0, 0);
        mat.UniformMatrix(uniPass2Matrix);

        glBindVertexArray(vaoPass2);
        glDrawArrays(GL_POINTS, 0, numTriangles);
        glBindVertexArray(0);

        glUseProgram(0);
    }

    void MarchingCubesDoublePass::OnRender(Matrix mat) {
        RenderPass1();
        RenderPass2(mat);
    }
Run Code Online (Sandbox Code Playgroud)

实际错误是对glDrawArraysin 的调用RenderPass1.值得注意的是,如果我注释掉调用glBeginTransformFeedbackglEndTransformFeedback,则glDrawArrays停止生成错误.所以无论如何,它可能与变换反馈有某种关系.

编辑8/18/12,9:00:

我刚刚在gDEBugger中找到了NVIDIA GLExpert功能,我之前并不熟悉它.当我把这个,它介绍了几分较大幅度的信息GL_INVALID_OPERATION,具体The current operation is illegal in the current state: Buffer is mapped..所以我正在进入上面的第1点.虽然我不知道怎么做.

glMapBuffer我的代码中的任何地方都没有调用或任何相关函数.我设置gDEBugger打破上的任何来电glMapBuffer,glMapBufferARB,glMapBufferRange,glUnmapBufferglUnmapBufferARB,和它没有任何地方断裂.然后我添加了代码到RenderPass1明确取消映射烦恼缓冲区的开始.这个错误不仅没有消失,而且glUnmapBuffer现在的调用都会产生The current operation is illegal in the current state: Buffer is unbound or is already unmapped..因此,如果我正在使用的缓冲区都没有映射,那么错误来自哪里?

编辑2012年8月19日上午12点:

根据我在gDEBugger中从GLExpert中获取的错误消息,调用似乎glBeginTransformFeedback导致绑定的缓冲区GL_TRANSFORM_FEEDBACK_BUFFER被映射.具体来说,当我点击"纹理,缓冲区和图像查看器"中的缓冲区时,它会输出消息The current operation is illegal in the current state: Buffer must be bound and not mapped..但是,如果我在glBeginTransformFeedback和之间添加glEndTransformFeedback:

int bufferBinding;
glGetBufferParameteriv(GL_TRANSFORM_FEEDBACK_BUFFER, GL_BUFFER_MAPPED, &bufferBinding);
printf("Transform feedback buffer binding: %d\n", bufferBinding);
Run Code Online (Sandbox Code Playgroud)

它输出0,表示GL_TRANSFORM_FEEDBACK_BUFFER未映射.如果此缓冲区映射到另一个绑定点,它仍会返回0吗?为什么会glBeginTransformFeedback映射缓冲区,从而使其无法用于转换反馈?

我在这里学的越多,我就越困惑.

编辑10/10/12:

正如我在下面对Nicol Bolas的解决方案的回答中所指出的,我发现了问题,并且他发现了同一个问题:由于一个愚蠢的错字,我将相同的缓冲区绑定到输入和输出绑定点.

我发现它可能在发布问题后两周.我沮丧地放弃了一段时间,最终回来了,基本上从零开始重新实现了整个事情,经常比较旧的,不工作的一点点零碎.当我完成后,新版本起作用了,当我搜索出我发现的差异时,我一直在绑定错误的缓冲区.

Nic*_*las 18

我发现了你的问题:你正在渲染到你正在寻找顶点数据的缓冲区.

glBindVertexArray(vaoPass2);

我想你的意思 vaoPass1

从规格:

缓冲区不应受限于或用于GL中的变换反馈和其他目的.具体来说,如果缓冲区对象同时绑定到转换反馈缓冲区绑定点以及GL中的其他位置,则对缓冲区的任何写入或读取都会生成未定义的值.此类绑定的示例包括到像素缓冲区对象绑定点的ReadPixel和对使用MapBuffer映射的缓冲区的客户端访问.

现在,你应该得到未定义的值; 我不确定GL错误是否合格,但它可能应该是一个错误.

  • 是的,就是这样.我实际上发现了一段时间,但忘记发布编辑或评论.好眼! (4认同)

smo*_*ris 7

另一个(显然是无证件的)案件在哪里glDrawArraysglDrawElements失败GL_INVALID_OPERATION:

  • GL_INVALID_OPERATION如果采样器均匀设置为无效纹理单元标识符,则生成.(glUniform1i(location, GL_TEXTURE0);当我的意思是,我错误地表演了glUniform1i(location, 0);.)