在Linux上使用AMD驱动程序时,glDrawElements会发出GL_INVALID_OPERATION

时间:2013-08-18 13:34:40

标签: c++ opengl amd-processor

我有一些OpenGL 2.1渲染代码,在使用nVidia卡/驱动程序或开源AMD驱动程序时效果很好,但在使用官方fglrx驱动程序时不起作用。它只显示一个灰色屏幕(glClear颜色)并且不会绘制任何内容。

gDEBugger显示glDrawElements提供错误GL_INVALID_OPERATION。根据这个页面(What can cause glDrawArrays to generate a GL_INVALID_OPERATION error?),这个错误有很多可能的原因。着色器编译正常,缓冲区大小也应该很好,我没有使用几何着色器(显然)。它只是一个简单的绘制调用,只有一个顶点属性。代码如下。

glUseProgram(r->program->getProgram());

glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, r->texture->glID );
glUniform1i(r->program->getUniform("texture").location, GL_TEXTURE0);
glUniform4f(r->program->getUniform("colour").location, r->colour.x, r->colour.y, r->colour.z, r->colour.w);

glBindBuffer(GL_ARRAY_BUFFER, r->vbo);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, r->ibo);

glVertexAttribPointer(
    r->program->getAttribute("position").location,  // attribute
    3,                                  // size
    GL_FLOAT,                           // type
    GL_FALSE,                           // normalized?
    sizeof(GLfloat)*3,                  // stride
    reinterpret_cast<void*>(0)          // array buffer offset
);
glEnableVertexAttribArray(r->program->getAttribute("position").location);

glUniformMatrix4fv(r->program->getUniform("modelToCameraMatrix").location, 1, GL_FALSE, glm::value_ptr(modelToCameraMatrix));

glDrawElements(
    r->mesh->mode,                  // mode
    r->mesh->nrOfInds,              // count
    GL_UNSIGNED_SHORT,              // type
    reinterpret_cast<void*>(0)      // element array buffer offset
);

我不知道发生了什么或可能导致此错误的原因。如果有人指出fglrx驱动程序可能导致这种情况发生的原因,而不是任何其他驱动程序,我会很高兴听到它。如果您需要更多代码,我当然乐意提供它。

2 个答案:

答案 0 :(得分:0)

我想我已经发现上面代码有什么问题了。错误的行是

glUniform1i(r->program->getUniform("texture").location, GL_TEXTURE0 + i);

应该是

glUniform1i(r->program->getUniform("texture").location, i);

我真的无法确切地找到为什么它应该是这样的(glActiveTexture 需要GL_TEXTURE0前缀),为什么只有AMD的驱动程序才能解决它,所以如果有人可以详细说明,我很乐意听到它。 :)

答案 1 :(得分:0)

让我们剖析一下:

glUniform1i(r->program->getUniform("texture").location, GL_TEXTURE0 + i);

OpenGL 2.1 Spec在第2.15节中说明:

  

将采样器的值设置为i选择纹理图像单元号i。 i的值将从零到纹理图像单元的依赖于实现的最大支持数

设置采样器的值只有在调用glUniform1i {v}时才合法。

如果一个实现可以自由地允许如上所述的语句,它必须在封面下进行一些减法 - 即它必须将(GL_TEXTURE0 + i)映射到[0,MAX_UNITS - 1]中的某个值。 (注意:MAX_UNITS在这里只是象征性的,它不是实际的GL常数!)。

这只是不符合行为,因为GL_TEXTURE0定义了一个非常大的值,并且远远超出任何古代或现代GPU的可用纹理单元数量。

BTW,GL_TEXTURE0不是前缀,它是常量

在第7.10节中,GL 4.4核心规范对此更清楚:

  

如果使用Uniform1i {v}将采样器设置为小于零或大于或等于MAX_COMBINED_TEXTURE_IMAGE_UNITS的值,则会生成INVALID_VALUE错误。

关于glActiveTexture():此函数在[GL_TEXTURE0,GL_TEXTURE0 + MAX_UNITS - 1]中取值。它可能不一定是这样,但这是它的定义方式。

OpenGL社区并不是秘密,NVIDIA通常更宽松,他们的驱动程序有时会采用那些根本不适用于其他硬件和驱动程序的东西,因为它根本不适用。

作为一般规则:永远不要依赖特定于实现的行为。仅依靠规范。如果符合要求且正确的应用程序代码不能与特定实现一起使用,那么它就是实现中的一个错误。