Прежде всего, какую версию 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.