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


person KillerSponge    schedule 18.08.2013    source источник
comment
Хм, мне этот код кажется нормальным (для GL 2.1). Если вы по какой-то причине получили контекст ядра ›=3.x, ошибка может быть результатом отсутствия привязки VAO. Другая возможность может заключаться в том, что шейдерная программа на самом деле не может связать/скомпилировать (драйверы AMD довольно строгие, в то время как nvidia особенно принимает довольно много нестандартных конструкций). Но это также привело бы к сообщенному поведению только в контексте ядра = 3.x, с 2.x или совместимостью он должен вернуться к конвейеру с фиксированной функцией и не должен генерировать ошибку.   -  person derhass    schedule 18.08.2013


Ответы (2)


Давайте разберем это:

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

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

person thokra    schedule 21.08.2013

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

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

что должно быть

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

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

person KillerSponge    schedule 19.08.2013