Мне сложно различить практическую разницу между вызовом glFlush()
и glFinish()
.
В документации говорится, что glFlush()
и glFinish()
все буферизованные операции будут отправлены в OpenGL, чтобы можно было быть уверенным, что все они будут выполнены, с той лишь разницей, что glFlush()
сразу же возвращается, где как glFinish()
блоки, до тех пор, пока все операции не будут завершены.
Прочитав определения, я подумал, что если бы я использовал glFlush()
это, я, вероятно, столкнулся бы с проблемой отправки большего количества операций в OpenGL, чем он мог бы выполнить. Итак, просто чтобы попробовать, я поменял свой glFinish()
на a, glFlush()
и вот, моя программа запустилась (насколько я мог судить) точно так же; частота кадров, использование ресурсов, все было так же.
Так что мне интересно, есть ли большая разница между двумя вызовами или мой код заставляет их работать одинаково. Или где следует использовать один по сравнению с другим. Я также подумал, что у OpenGL будет какой-то вызов, например, glIsDone()
чтобы проверить, все ли буферизованные команды для a glFlush()
завершены или нет (поэтому никто не отправляет операции в OpenGL быстрее, чем они могут быть выполнены), но я не нашел такой функции .
Мой код представляет собой типичный игровой цикл:
while (running) {
process_stuff();
render_stuff();
}
Как указывали другие ответы, в соответствии со спецификацией действительно нет хорошего ответа. Общая цель
glFlush()
состоит в том, что после его вызова центральный процессор не будет выполнять никакой работы, связанной с OpenGL - команды будут отправлены на графическое оборудование. Общее намерениеglFinish()
состоит в том, чтобы после его возврата не оставалось никакой оставшейся работы, а результаты должны быть доступны также для всех соответствующих API, не относящихся к OpenGL (например, чтение из фреймбуфера, снимки экрана и т. Д.). Так ли это на самом деле, зависит от драйвера. Спецификация дает массу свободы в отношении того, что является законным.источник
Меня всегда смущали эти две команды, но этот образ прояснил мне все: по- видимому, некоторые драйверы графического процессора не отправляют выданные команды на оборудование, если не было накоплено определенное количество команд. В этом примере это число 5 .
На изображении показаны различные запущенные команды OpenGL (A, B, C, D, E ...). Как мы видим вверху, команды еще не выдаются, потому что очередь еще не заполнена.
Посередине мы видим, как
glFlush()
влияют поставленные в очередь команды. Он сообщает драйверу, что нужно отправить все поставленные в очередь команды на оборудование (даже если очередь еще не заполнена). Это не блокирует вызывающий поток. Это просто сигнализирует драйверу о том, что мы, возможно, не отправляем никаких дополнительных команд. Поэтому ожидание заполнения очереди было бы пустой тратой времени.Внизу мы видим пример использования
glFinish()
. Он делает почти то же самоеglFlush()
, за исключением того, что заставляет вызывающий поток ждать, пока все команды не будут обработаны оборудованием.Изображение взято из книги «Расширенное программирование графики с использованием OpenGL».
источник
glFlush
иglFinish
делаю, и я не могу сказать, что говорит этот образ. Что слева, а что справа? Кроме того, было ли это изображение выпущено в общественное достояние или по какой-либо лицензии, позволяющей размещать его в Интернете?Если вы не заметили разницы в производительности, значит, вы что-то делаете не так. Как упоминалось некоторыми другими, вам тоже не нужно вызывать, но если вы действительно вызываете glFinish, вы автоматически теряете параллелизм, которого могут достичь GPU и CPU. Позвольте мне погрузиться глубже:
На практике вся работа, которую вы передаете драйверу, группируется и отправляется на оборудование потенциально позже (например, во время SwapBuffer).
Итак, если вы вызываете glFinish, вы, по сути, заставляете драйвер отправлять команды на графический процессор (который до тех пор пакетировался и никогда не запрашивал работу графического процессора) и останавливаете процессор до тех пор, пока отправленные команды не будут полностью выполнен. Таким образом, в течение всего времени работы GPU, CPU - нет (по крайней мере, в этом потоке). И все время, пока процессор выполняет свою работу (в основном, пакетные команды), графический процессор ничего не делает. Так что да, glFinish должен повредить вашей производительности. (Это приблизительное значение, поскольку драйверы могут начать работу с графическим процессором над некоторыми командами, если многие из них уже были объединены в пакеты. Это не типично, поскольку командные буферы обычно достаточно велики, чтобы вместить довольно много команд).
Так зачем тогда вообще называть glFinish? Единственный раз я использовал его, когда у меня были ошибки в драйверах. Действительно, если одна из команд, которые вы отправляете аппаратному обеспечению, вызывает сбой графического процессора, то самый простой способ определить, какая команда является виновником, - это вызвать glFinish после каждого Draw. Таким образом вы сможете сузить круг вопросов, которые именно вызывают сбой.
Кстати, API, такие как Direct3D, вообще не поддерживают концепцию Finish.
источник
glFlush действительно восходит к модели клиент-сервер. Вы отправляете все команды gl через канал на сервер gl. Эта труба может буферизовать. Точно так же, как любой файл или сетевой ввод-вывод может буферизоваться. glFlush только говорит «отправить буфер сейчас, даже если он еще не заполнен!». В локальной системе это почти никогда не требуется, поскольку локальный API OpenGL вряд ли буферизует себя и просто выдает команды напрямую. Также все команды, которые вызывают фактический рендеринг, будут выполнять неявный сброс.
С другой стороны, glFinish был создан для измерения производительности. Вид PING на сервер GL. Он перехватывает команду и ждет, пока сервер не ответит «Я простаиваю».
Но в наши дни у современных местных водителей есть довольно творческие идеи, что значит бездействовать. Это «все пиксели нарисованы» или «в моей очереди команд есть место»? Также из-за того, что многие старые программы без причины добавляли glFlush и glFinish в свой код, поскольку кодирование вуду, многие современные драйверы просто игнорируют их как «оптимизацию». Не могу их за это винить.
Итак, подытожим: рассматривайте и glFinish, и glFlush как практические запреты на операции, если только вы не пишете код для древнего удаленного сервера SGI OpenGL.
источник
Взгляните сюда . Короче говоря:
В другой статье описаны другие отличия:
glFlush
glFinish
заставляет OpenGL выполнять выдающиеся команды, что является плохой идеей (например, с VSync)Подводя итог, это означает, что вам даже не нужны эти функции при использовании двойной буферизации, за исключением случаев, когда ваша реализация swap-buffers не сбрасывает команды автоматически.
источник
Кажется, нет способа запросить статус буфера. Есть это расширение Apple, которое может служить той же цели, но оно не кажется кроссплатформенным (не пробовал). На первый взгляд кажется, что до того, как
flush
вы вставите команду ограждения; затем вы можете запросить статус этого забора, когда он перемещается через буфер.Интересно, можно ли использовать команды
flush
до буферизации, но до начала рендеринга следующего вызываемого кадраfinish
. Это позволит вам начать обработку следующего кадра по мере работы графического процессора, но если это не будет сделано к тому времени, когда вы вернетесь,finish
произойдет блокировка, чтобы убедиться, что все в новом состоянии.Я не пробовал, но скоро попробую.Я пробовал это в старом приложении, в котором используются даже CPU и GPU. (Первоначально использовался
finish
.)Когда я изменил его на "
flush
в конце" и "finish
в начале", проблем не возникло. (Все выглядело нормально!) Скорость отклика программы увеличилась, вероятно, из-за того, что ЦП не остановился в ожидании работы ГП. Определенно лучший метод.Для сравнения я удалил
finished
начало кадра, оставивflush
, и он выполнил то же самое.Поэтому я бы сказал использовать
flush
иfinish
, потому что, когда буфер пуст при вызовеfinish
, нет снижения производительности. И я предполагаю, что если бы буфер был заполнен, вы быfinish
все равно захотели .источник
Вопрос в следующем: хотите ли вы, чтобы ваш код продолжал работать во время выполнения команд OpenGL или только после того, как ваши команды OpenGL были выполнены.
Это может иметь значение в тех случаях, когда, например, из-за сетевых задержек, определенный вывод на консоль выводится только после того, как изображения были отрисованы или тому подобное.
источник