Должен ли я вызывать glEnable и glDisable каждый раз, когда что-то рисую? - PullRequest
18 голосов
/ 29 апреля 2009

Как часто я должен вызывать функции OpenGL, такие как glEnable() или glEnableClientState() и их соответствующие аналоги glDisable? Они должны вызываться один раз в начале приложения, или я должен оставить их отключенными и включить только те функции, которые мне сразу нужны для рисования чего-либо? Есть ли разница в производительности?

Ответы [ 4 ]

15 голосов
/ 29 апреля 2009

Если вы обнаружите, что вы часто проверяете значение переменных состояния и впоследствии вызываете glEnable / glDisable, вы можете немного исправить ситуацию, используя стек атрибутов (glPushAttrib / glPopAttrib).

Стек атрибутов позволяет вам изолировать области вашего кода, чтобы изменения атрибута в одних разделах не влияли на состояние атрибута в других разделах.

void drawObject1(){
  glPushAttrib(GL_ENABLE_BIT);

  glEnable(GL_DEPTH_TEST);
  glEnable(GL_LIGHTING);    

  /* Isolated Region 1 */

  glPopAttrib();
}        

void drawObject2(){
  glPushAttrib(GL_ENABLE_BIT);

  glEnable(GL_FOG);
  glEnable(GL_GL_POINT_SMOOTH);    

   /* Isolated Region 2 */

  glPopAttrib();
}    

void drawScene(){
  drawObject1();
  drawObject2();
}

Хотя в drawObject1 установлены GL_LIGHTING и GL_DEPTH_TEST, их состояние не сохраняется в drawObject2. В отсутствие glPushAttrib это было бы не так. Также обратите внимание, что нет необходимости вызывать glDisable в конце вызовов функции, glPopAttrib выполняет свою работу.

Что касается производительности, накладные расходы, связанные с вызовами отдельных функций glEnable / glDisable, минимальны. Если вам нужно обрабатывать много состояний, вам, вероятно, потребуется создать свой собственный менеджер состояний или сделать многочисленные вызовы glGetInteger ... и затем действовать соответственно. Добавленные механизмы и поток управления могут сделать код менее прозрачным, сложным для отладки и более сложным в обслуживании. Эти проблемы могут затруднить другие, более плодотворные оптимизации.

Стек атрибуции может помочь в поддержании уровней абстракции и создании областей изоляции.

Страница руководства glPushAttrib

12 голосов
/ 29 апреля 2009

«Это зависит».

Если все ваше приложение использует только одну комбинацию состояний включения / выключения, тогда непременно установите его в начале и начинайте.

Большинство реальных приложений должны быть смешаны, и тогда вам придется звонить glEnable(), чтобы включить некоторые конкретные состояния, делать вызовы отрисовки, а затем glDisable() их снова, когда вы закончите " очистить сцену ".

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

8 голосов
/ 30 апреля 2009

Прежде всего, какую версию OpenGL вы используете? И какое поколение графического оборудования у вашей целевой группы? Знание этого поможет дать более правильный ответ. Мой ответ предполагает OpenGL 2.1.

OpenGL - это конечный автомат, означающий, что всякий раз, когда состояние изменяется, это состояние становится «текущим», пока программист не изменит его явно с новым вызовом API OpenGL. Существуют исключения из этого правила, например, вызовы массива состояний клиента, делающие текущий цвет вершины неопределенным. Но это исключения, которые определяют правило.

" один раз в начале приложения " не имеет особого смысла, потому что бывают случаи, когда вам нужно уничтожить контекст OpenGL, пока приложение еще работает. Я предполагаю, что вы имеете в виду только после каждого создания окна. Это работает для государства, которое вам не нужно менять позже. Пример: если все ваши вызовы отрисовки используют одни и те же данные массива вершин, вам не нужно впоследствии отключать их с помощью glDisableClientState.

Существует много состояний включения / выключения, связанных со старым конвейером с фиксированными функциями. Легкое искупление для этого: использовать шейдеры! Если вы нацелены на поколение карт, возраст которых не превышает пяти лет, это, вероятно, в любом случае имитирует конвейер с фиксированными функциями с помощью шейдеров. Используя шейдеры, вы более или менее полностью контролируете то, что происходит на этапах преобразования и растеризации, и вы можете создавать свои собственные «состояния» с помощью униформ, которые очень дешево менять / обновлять.

Знание того, что OpenGL является конечным автоматом, как я уже говорил выше, должно прояснить, что нужно стремиться к минимальным изменениям состояния, насколько это возможно. Однако, скорее всего, есть другие вещи, которые влияют на производительность гораздо больше, чем включение / отключение вызовов состояния. Если вы хотите узнать о них, прочитайте.


Расход состояния , а не , связанный со старыми вызовами состояния фиксированной функции и не являющийся простым состоянием включения / выключения, может значительно различаться по стоимости. В частности, связывание шейдеров и связывание имен («имен» текстур, программ, объектов буфера) обычно довольно дорого. Вот почему многие игры и приложения использовали для сортировки порядка рисования своих сеток в соответствии с текстурой. Таким образом, им не нужно было связывать одну и ту же текстуру дважды. Однако в настоящее время то же самое относится и к шейдерным программам. Вы не хотите связывать одну и ту же шейдерную программу дважды, если вам это не нужно. Кроме того, не все функции в конкретной версии OpenGL аппаратно ускоряются на всех картах, даже если производители этих карт заявляют, что они совместимы с OpenGL. Быть совместимым означает, что они следуют спецификации, а не то, что они обязательно должны эффективно выполнять все функции. В этом отношении следует помнить некоторые функции, такие как glHistogram и glMinMax из GL__ ARB __imaging.


Вывод: если нет явной причины не использовать шейдеры! Это избавляет вас от множества ненужных вызовов состояния, поскольку вместо этого вы можете использовать униформу. Знаете, шейдеры OpenGL существуют уже около шести лет. Кроме того, накладные расходы на включение / отключение изменений состояния могут быть проблемой, но обычно есть гораздо больше преимуществ от оптимизации других более дорогих изменений состояния, таких как glUseProgram, glCompileShader, glLinkprogram, glBindBuffer и glBindTexture.

P.S: OpenGL 3.0 убрал состояние клиента для включения / выключения вызовов. Они неявно включены, поскольку рисовать массивы - единственный способ рисовать в этой версии. Немедленный режим был удален. Вызовы gl..Pointer также были удалены, поскольку на самом деле нужен только glVertexAttribPointer.

0 голосов
/ 29 апреля 2009

Практическое правило, которому меня учили, гласило, что почти всегда дешевле просто включать / отключать по желанию, чем проверять текущее состояние и изменять только при необходимости.

Тем не менее, ответ Марка должен определенно сработать.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...