glDrawElements выдает GL_INVALID_OPERATION при использовании драйвера AMD в Linux

У меня есть немного кода рендеринга OpenGL 2.1, который прекрасно работает при использовании карты / драйвера nVidia или драйвера AMD с открытым исходным кодом, но не работает при использовании официального драйвера fglrx. Он просто отображает серый экран (цвет glClear) и ничего не рисует.

gDEBugger показывает, что glDrawElements выдает ошибку GL_INVALID_OPERATION. По этой странице (Что может заставить glDrawArrays генерировать ошибку GL_INVALID_OPERATION?) Есть много недокументированных возможных причин этой ошибки. Шейдер прекрасно компилируется, и размер буфера тоже должен быть хорошим, и я не использую геометрические шейдеры (очевидно). Это всего лишь простой вызов отрисовки для куба с одним атрибутом вершины. Код ниже.

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, а не с любым другим драйвером, я был бы рад услышать это. Если вам нужно больше кода, я с радостью предоставлю его, конечно.

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 определяет очень большое значение, которое далеко выходит за пределы диапазона доступных текстурных блоков любого древнего или современного графического процессора.

Кстати, GL_TEXTURE0 не является префикс, это постоянная.

Основная спецификация GL 4.4 гораздо яснее об этом в разделе 7.10:

Ошибка INVALID_VALUE генерируется, если Uniform1i {v} используется для установки сэмплера на значение меньше нуля или больше или равно значению MAX_COMBINED_TEXTURE_IMAGE_UNITS.

Относительно glActiveTexture (): эта функция принимает значение в [GL_TEXTURE0, GL_TEXTURE0 + MAX_UNITS — 1]. Наверное, так не должно быть, но так оно и определяется.

Не секрет среди сообщества OpenGL, что NVIDIA часто более снисходительна, а их драйверы иногда берут вещи, которые просто не работают на другом оборудовании и драйверах, потому что они просто не должны работать.

Как правило: никогда не полагайтесь на осуществление конкретных поведение. Положитесь только на спецификацию. Если соответствующий и правильный код приложения не работает с конкретной реализацией, это ошибка в реализации.

0

Другие решения

Я думаю, что выяснил, что не так с приведенным выше кодом. Неисправная линия

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

который должен быть

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

Я не могу точно выяснить, Зачем так должно быть (glActiveTexture делает нужен GL_TEXTURE0 префикс), и почему только драйвер AMD высовывается из этого, так что если кто-то может уточнить это, я хотел бы услышать это. 🙂

0