У меня есть немного кода рендеринга 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, а не с любым другим драйвером, я был бы рад услышать это. Если вам нужно больше кода, я с радостью предоставлю его, конечно.
Давайте рассмотрим это:
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 часто более снисходительна, а их драйверы иногда берут вещи, которые просто не работают на другом оборудовании и драйверах, потому что они просто не должны работать.
Как правило: никогда не полагайтесь на осуществление конкретных поведение. Положитесь только на спецификацию. Если соответствующий и правильный код приложения не работает с конкретной реализацией, это ошибка в реализации.
Я думаю, что выяснил, что не так с приведенным выше кодом. Неисправная линия
glUniform1i(r->program->getUniform("texture").location, GL_TEXTURE0 + i);
который должен быть
glUniform1i(r->program->getUniform("texture").location, i);
Я не могу точно выяснить, Зачем так должно быть (glActiveTexture
делает нужен GL_TEXTURE0
префикс), и почему только драйвер AMD высовывается из этого, так что если кто-то может уточнить это, я хотел бы услышать это. 🙂