0

我有一些 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 驱动程序而不是任何其他驱动程序可能导致这种情况的原因有任何指示,我会很高兴听到它。如果您需要更多代码,我当然会很乐意提供。

4

2 回答 2

0

我想我已经发现上面的代码有什么问题了。故障线路是

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

应该是

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

我真的不知道为什么它应该是这样的(glActiveTexture 确实需要GL_TEXTURE0前缀),以及为什么只有 AMD 驱动程序在它上面胡扯,所以如果有人能详细说明,我很想听听。:)

于 2013-08-19T09:58:51.480 回答
0

让我们剖析一下:

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

OpenGL 2.1 规范在第 2.15 节中指出:

将采样器的值设置为 i 选择纹理图像单元编号 i。i 的值范围从零到与实现相关的最大支持纹理图像单元数。

只有调用 glUniform1i{v} 才能设置采样器的值。

如果一个实现冒昧地允许像上面这样的语句,它必须在幕后做一些减法 - 即它必须将 (GL_TEXTURE0 + i) 映射到 [0, MAX_UNITS - 1] 中的某个值。(注意:MAX_UNITS 在这里只是象征性的,它不是实际的 GL 常量!)。

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

顺便说一句, GL_TEXTURE0 不是前缀,而是常量


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

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

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

在 OpenGL 社区中已经不是什么秘密了,NVIDIA 通常更宽容,他们的驱动程序有时会采用在其他硬件和驱动程序上根本无法工作的东西,因为它根本不应该工作。

作为一般规则:永远不要依赖特定于实现的行为。只依赖规范。如果一致且正确的应用程序代码不适用于特定实现,则它是实现中的错误。

于 2013-08-21T10:40:43.443 回答