opengl: glFlush () против glFinish () - PullRequest
       22

opengl: glFlush () против glFinish ()

100 голосов
/ 27 января 2010

У меня проблемы с распознаванием практической разницы между звонками glFlush() и glFinish().

В документах говорится, что glFlush() и glFinish() переместят все буферизованные операции в OpenGL, чтобы можно было быть уверенным, что все они будут выполнены, с той разницей, что glFlush() немедленно возвращается, где glFinish() блокируется, пока все операции завершены.

Прочитав определения, я решил, что если бы я использовал glFlush(), я бы, вероятно, столкнулся с проблемой отправки большего количества операций в OpenGL, чем он мог бы выполнить. Итак, просто чтобы попробовать, я поменял glFinish() на glFlush(), и вот, моя программа работала (насколько я мог судить), точно так же; частота кадров, использование ресурсов, все было одинаково.

Так что мне интересно, есть ли большая разница между двумя вызовами, или мой код заставляет их работать не иначе. Или где один должен быть использован против другого. Я также подумал, что у OpenGL будет какой-то вызов, такой как glIsDone(), чтобы проверить, завершены или нет все буферизованные команды для glFlush() или нет (поэтому нельзя отправлять операции в OpenGL быстрее, чем они могут быть выполнены), но Я не мог найти такую ​​функцию.

Мой код является типичным игровым циклом:

while (running) {
    process_stuff();
    render_stuff();
}

Ответы [ 8 ]

89 голосов
/ 27 января 2010

Имейте в виду, что эти команды существуют с первых дней OpenGL. glFlush гарантирует, что предыдущие команды OpenGL должны завершиться за конечное время ( Спецификации OpenGL 2.1 , стр. 245). Если вы рисуете прямо в передний буфер, это должно гарантировать, что драйверы OpenGL начнут рисовать без особых задержек. Вы можете подумать о сложной сцене, которая появляется объект за объектом на экране, когда вы вызываете glFlush после каждого объекта. Однако при использовании двойной буферизации glFlush практически не оказывает никакого влияния, так как изменения не будут видны, пока вы не поменяете местами буферы.

glFinish не возвращается, пока все эффекты от ранее выполненных команд [...] не будут полностью реализованы . Это означает, что выполнение вашей программы ожидает здесь до тех пор, пока не будет нарисован каждый последний пиксель, и OpenGL больше нечего делать. Если вы выполняете рендеринг непосредственно в передний буфер, glFinish - это вызов, который нужно выполнить перед использованием вызовов операционной системы для создания снимков экрана. Это гораздо менее полезно для двойной буферизации, потому что вы не видите изменений, которые вы вынуждены были завершить.

Так что, если вы используете двойную буферизацию, вам, вероятно, не понадобятся ни glFlush, ни glFinish. SwapBuffers неявно направляет вызовы OpenGL в правильный буфер, нет необходимости сначала вызывать glFlush . И не против того, чтобы подчеркивать драйвер OpenGL: glFlush не захлебнется слишком большим количеством команд. Не гарантируется, что этот вызов вернет немедленно (что бы это ни значило), поэтому для обработки ваших команд может потребоваться любое время.

21 голосов
/ 27 января 2010

Как подсказали другие ответы, действительно нет хорошего ответа согласно спецификации. Общее намерение glFlush() состоит в том, что после вызова его у центрального процессора не будет никакой работы, связанной с OpenGL - команды будут перенесены в графическое оборудование. Общее намерение glFinish() состоит в том, чтобы после его возврата нет оставшейся работы осталось, и результаты должны быть доступны также для всех соответствующих API, не являющихся OpenGL (например, чтения из кадрового буфера, снимков экрана и т. .). Действительно ли это происходит, зависит от драйвера. Спецификация допускает тонну широты относительно того, что является законным.

13 голосов
/ 11 июля 2016

Меня всегда смущали эти две команды, но это изображение прояснило мне все: Flush vs Finish По-видимому, некоторые драйверы графического процессора не отправляют введенные команды аппаратному обеспечению, пока не накоплено определенное количество команд. В этом примере это число 5 .
На рисунке показаны различные команды OpenGL (A, B, C, D, E ...), которые были выполнены. Как мы видим в верхней части, команды еще не выполняются, потому что очередь еще не заполнена.

Посередине мы видим, как glFlush() влияет на команды в очереди. Он сообщает драйверу отправлять все поставленные в очередь команды аппаратному обеспечению (даже если очередь еще не заполнена). Это не блокирует вызывающий поток. Это просто сигнализирует водителю, что мы не можем отправлять какие-либо дополнительные команды. Поэтому ожидание заполнения очереди будет пустой тратой времени.

Внизу мы видим пример использования glFinish(). Он почти делает то же самое, что и glFlush(), за исключением того, что заставляет вызывающий поток ждать, пока все команды не будут обработаны оборудованием.

Изображение взято из книги «Расширенное программирование графики с использованием OpenGL».

6 голосов
/ 27 января 2010

Если вы не видели никакой разницы в производительности, значит, вы что-то делаете не так. Как уже упоминали некоторые другие, вам не нужно звонить, но если вы вызываете glFinish, то вы автоматически теряете параллелизм, которого могут достичь GPU и CPU. Позвольте мне погрузиться глубже:

На практике вся работа, которую вы отправляете драйверу, пакетируется и потенциально отправляется на аппаратное обеспечение позже (например, во время SwapBuffer).

Итак, если вы вызываете glFinish, вы, по сути, заставляете драйвер выдавать команды на графический процессор (который он пакетировал до тех пор и никогда не просил графический процессор работать), и останавливать процессор до команд толкаемые полностью выполнены. Таким образом, в течение всего времени работы графического процессора не работает процессор (по крайней мере, в этом потоке). И все время, когда процессор выполняет свою работу (в основном, пакетные команды), графический процессор ничего не делает. Так что да, glFinish должен повредить вашей производительности. (Это приблизительное значение, поскольку драйверы могут начать работу графического процессора с некоторыми командами, если многие из них уже были упакованы. Однако это не типично, поскольку буферы команд имеют тенденцию быть достаточно большими, чтобы содержать довольно много команд).

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

В качестве примечания, такие API, как Direct3D, вообще не поддерживают концепцию Finish.

5 голосов
/ 22 мая 2012

glFlush действительно восходит к модели клиент-сервер. Все команды gl отправляются через канал на сервер gl. Эта труба может буферизоваться. Так же, как любой файл или сеть ввода-вывода может буферизироваться. glFlush только говорит: «Отправьте буфер сейчас, даже если он еще не заполнен!». В локальной системе это почти никогда не требуется, потому что локальный API OpenGL вряд ли буферизует себя и просто выдает команды напрямую. Также все команды, которые вызывают фактический рендеринг, будут выполнять неявную очистку.

glFinish, с другой стороны, был сделан для измерения производительности. Вид ПИНГА на GL сервер. Он выполняет обход команды и ждет, пока сервер не ответит «Я бездействую».

В настоящее время у современных местных водителей есть достаточно креативные идеи, что значит быть без дела. Это «все пиксели нарисованы» или «моя очередь команд имеет место»? Кроме того, потому что многие старые программы без всяких причин разбрасывали glFlush и glFinish по коду, как при кодировании вуду, многие современные драйверы просто игнорируют их как «оптимизацию». Не могу их за это винить.

Итак, подведем итоги: рассматривайте как glFinish, так и glFlush на практике без всяких операций, если только вы не программируете старый удаленный сервер SGI OpenGL.

4 голосов
/ 27 января 2010

Посмотрите здесь .Короче говоря, он говорит:

glFinish () имеет тот же эффект, что и glFlush (), с добавлением, что glFinish () будет блокировать до тех пор, пока все представленные команды не будут выполнены.

Другая статья описывает другие различия:

  • Функции подкачки (используемые в приложениях с двойной буферизацией) автоматически сбрасывают команды, поэтому нет необходимости вызывать glFlush
  • glFinish заставляет OpenGL выполнять выдающиеся команды, что является плохой идеей (например, с VSync)

Подводя итог, это означает, что вам даже не нужны эти функции при использовании doubleбуферизация, за исключением случаев, когда ваша реализация swap-buffers не сбрасывает команды автоматически.

3 голосов
/ 27 января 2010

Похоже, нет способа узнать состояние буфера. Существует это расширение Apple , которое может служить той же цели, но оно не кажется кроссплатформенным (не пробовал). На первый взгляд кажется, что до flush вы бы вставьте команду забора; затем вы можете запросить состояние этого забора, когда он перемещается через буфер.

Интересно, вы могли бы использовать flush до буферизации команд, но до начала рендеринга следующего кадра, который вы вызываете finish. Это позволит вам начать обработку следующего кадра по мере того, как работает графический процессор, но если это не будет сделано к тому времени, когда вы вернетесь, finish заблокирует, чтобы убедиться, что все в свежем состоянии.

Я не пробовал это, но скоро сделаю.

Я пробовал это на старом приложении, которое довольно равномерно использует CPU и GPU. (Первоначально использовал finish.)

Когда я изменил его на flush в конце и finish в начале, не было никаких непосредственных проблем. (Все выглядело хорошо!) Скорость отклика программы увеличилась, возможно, потому, что процессор не остановился в ожидании на GPU. Определенно лучший метод.

Для сравнения я удалил finished с начала кадра, оставив flush, и он выполнил то же самое.

Так что я бы сказал, используйте flush и finish, потому что, когда буфер пуст при вызове finish, производительность не падает. И я предполагаю, что если буфер заполнен, вы все равно должны захотеть finish.

0 голосов
/ 27 января 2010

Вопрос в следующем: хотите ли вы, чтобы ваш код продолжал выполняться во время выполнения команд OpenGL, или только после выполнения ваших команд OpenGL.

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

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