версия OpenGL: glFlush() и glFinish()
у меня возникли проблемы с различением практической разницы между вызовом glFlush() и glFinish().
врачи говорят, что glFlush() и glFinish() будет толкать все буферизованные операции в OpenGL, так что можно быть уверенным, что они все будут выполнены, разница в том, что glFlush() сразу возвращается, где, как glFinish() блокирует, пока все операции не будут завершены.
прочитав определения, я понял, что если бы я использовал glFlush() что я бы, наверное, столкнитесь с проблемой отправки большего количества операций в OpenGL, чем он мог бы выполнить. Так что, просто чтобы попробовать, я поменял мой glFinish() на glFlush() и вот, моя программа работала (насколько я мог судить), точно так же; частота кадров, использование ресурсов, все было одинаково.
поэтому мне интересно, есть ли большая разница между этими двумя вызовами, или если мой код заставляет их работать не иначе. Или где одно должно быть использовано против другого.
Я также подумал, что OpenGL будет иметь какой-то вызов, например glIsDone() чтобы проверить, все ли буферизованные команды для glFlush() являются полными или нет (поэтому никто не отправляет операции в OpenGL быстрее, чем они могут быть выполнены), но я не мог найти такой функции.
мой код-это типичный цикл игры:
while (running) {
process_stuff();
render_stuff();
}
8 ответов:
имейте в виду, что эти команды существуют с первых дней OpenGL. glFlush гарантирует, что предыдущие команды OpenGL должен завершиться за конечное время (спецификации OpenGL 2.1, 245 стр.). Если вы рисуете непосредственно в передний буфер, это должно гарантировать, что драйверы OpenGL начнут рисовать без слишком большой задержки. Вы можете подумать о сложной сцене, которая появляется объект за объектом на экране, когда вы вызываете glFlush после каждого объекта. Однако, при использовании двойной буферизации, glFlush практически не влияет на все, так как изменения не будут видны, пока вы не поменяете буферы.
glFinish не возвращается до тех пор, пока все эффекты от ранее выданных команд [...] полностью реализованы. Это означает, что выполнение вашей программы ждет здесь, пока не будет нарисован каждый последний пиксель, и OpenGL больше ничего не нужно делать. Если вы визуализируете непосредственно в передний буфер, glFinish-это вызов, который нужно сделать перед использованием вызовов операционной системы для создания скриншотов. Это гораздо менее полезно для двойной буферизации, потому что вы не видите изменений, которые вы вынуждены завершить.
поэтому, если вы используете двойную буферизацию, вам, вероятно, не понадобится ни glFlush, ни glFinish. SwapBuffers неявно направляет вызовы OpenGL в правильный буфер,нет необходимости сначала вызывать glFlush. И не стесняйтесь подчеркивать драйвер OpenGL: glFlush не будет подавляться слишком многими командами. Это не гарантирует, что этот вызов возвращает тут (что бы это ни значило), поэтому он может занять любое время, необходимое для обработки ваших команд.
как намекнули другие ответы, на самом деле нет хорошего ответа в соответствии со спецификацией. Общее намерение
glFlush()Это то, что после его вызова у хост-процессора не будет работы, связанной с OpenGL, - команды будут перенесены на графическое оборудование. Общее намерениеglFinish()это после того, как он возвращается,нет оставшаяся работа остается, и результаты должны быть доступны также все соответствующие API-интерфейсы без OpenGL (например, чтение из буфера кадров, скриншоты и т. д...). Действительно ли это происходит, зависит от драйвера. Спецификация позволяет тонну широты относительно того, что является законным.
Я всегда был смущен этими двумя командами тоже, но этот образ сделал все ясно для меня:
По-видимому, некоторые драйверы GPU не отправляют выданные команды на аппаратное обеспечение, если не было накоплено определенное количество команд. В этом примере это число 5.
На изображении показаны различные команды OpenGL (A, B, C, D, E...) которые были выданы. Как мы видим наверху, команды еще не выдаются, потому что очередь еще не заполнена.В середине мы видим, как
glFlush()влияет на команды в очереди. Он сообщает драйверу отправить все команды в очередь на аппаратное обеспечение (даже если очередь еще не заполнена). Это не блокирует вызывающий поток. Это просто сигнализирует водителю, что мы, возможно, не посылаем никаких дополнительных команд. Поэтому ожидание заполнения очереди было бы пустой тратой времени.внизу мы видим пример использования
glFinish(). Он почти делает то же самое, что иglFlush(), за исключением это заставляет вызывающий поток ждать, пока все команды не будут обработаны аппаратным обеспечением.Изображение взято из книги "Advanced Graphics Programming Using OpenGL".
Если вы не видите никакой разницы в производительности, это означает, что вы делаете что-то неправильно. Как упоминалось в некоторых других случаях, вам также не нужно звонить, но если вы вызываете glFinish, то вы автоматически теряете параллелизм, который могут достичь GPU и CPU. Позвольте мне нырнуть глубже:
на практике вся работа, которую вы отправляете драйверу, пакетируется и отправляется на аппаратное обеспечение потенциально позже (например, во время SwapBuffer).
Итак, если вы звоните glFinish, вы по сути, заставляя драйвер нажимать команды на GPU (что он паковал до тех пор и никогда не просил GPU работать) и останавливать процессор, пока команды не будут полностью выполнены. Поэтому в течение всего времени работы GPU процессор не работает (по крайней мере, в этом потоке). И все время, пока процессор выполняет свою работу (в основном команды дозирования), GPU ничего не делает. Так что да, glFinish должен повредить вашему выступлению. (Это приближение, так как драйверы могут начать работать с GPU некоторые команды, если многие из них уже были пакетированы. Однако это не типично, поскольку буферы команд, как правило, достаточно велики, чтобы содержать довольно много команд).
теперь, почему вы вообще называете glFinish ? Единственный раз, когда я использовал его, когда у меня были ошибки драйвера. Действительно, если одна из команд, которые вы отправляете вниз к аппаратным сбоям GPU, то ваш самый простой вариант определить, какая команда является виновником, - это вызвать glFinish после каждой ничьей. Таким образом, вы можете сузить то, что точно запускает сбой
в качестве примечания, API, такие как Direct3D, вообще не поддерживают концепцию отделки.
glFlush действительно восходит к модели клиент-сервер. Вы отправляете все команды gl через канал на сервер gl. Эта труба может буферизоваться. Так же, как любой файл или сетевой ввод-вывод может буферизоваться. glFlush только говорит: "отправьте буфер сейчас, даже если он еще не заполнен!". В локальной системе это почти никогда не требуется, потому что локальный API OpenGL вряд ли будет буферизовать себя и просто выдает команды напрямую. Также все команды, которые вызывают фактическую визуализацию, будут выполнять неявный сброс.
glFinish с другой стороны было сделано для измерения производительности. Своего рода пинг на сервер GL. Он округляет команду и ждет, пока сервер не ответит "Я простаиваю".
В настоящее время современные, местные водители имеют довольно творческие идеи, что значит быть праздным, хотя. Это "все пиксели нарисованы"или" моя очередь команд имеет пространство"? Также потому, что многие старые программы посыпали glFlush и glFinish по всему их коду без причины, поскольку кодирование вуду многие современные драйверы просто игнорируют их как "оптимизация." Не могу винить их за это, правда.
Итак, вкратце: рассматривайте как glFinish, так и glFlush как отсутствие ops на практике, если вы не кодируете для древнего удаленного сервера SGI OpenGL.
посмотреть здесь. Короче говоря, он говорит:
glFinish () имеет тот же эффект, что и glFlush (), с добавлением, что glFinish () будет блокировать до тех пор, пока все представленные команды не будут выполнены.
другое статьи описывает другие различия:
- функции подкачки (используемые в приложениях с двойной буферизацией) автоматически очищают команды, поэтому нет необходимости вызывать
glFlushglFinishсил OpenGL для выполнения выдающихся команд, что является плохой идеей (например, с VSync)подводя итог, это означает, что вам даже не нужны эти функции при использовании двойной буферизации, за исключением случаев, когда ваша реализация swap-buffers автоматически не очищает команды.
там, кажется, не существует способа запроса состояния буфера. Есть такое расширение Apple который может служить той же цели, но это не кажется кросс-платформенным (не пробовал.) На это быстрый взгляд, кажется до
flushвы бы нажали команду fence; затем вы можете запросить статус этого забора, когда он перемещается через буфер.интересно, если бы вы могли использовать
flushперед буферизацией команд, но до начала визуализации следующий кадр вы называетеfinish. Это позволит вам начать обработку следующего кадра по мере работы GPU, но если это не будет сделано к тому времени, когда вы вернетесь,finishбудет блокировать, чтобы убедиться, что все в свежем состоянии.
я не пробовал это, но я скоро буду.Я пробовал его на старом приложении, которое имеет довольно даже CPU & GPU использования. (Он первоначально использовал
finish.)когда я изменил его на
flushи в концеfinishв начале, непосредственных проблем не было. (Все выглядело прекрасно!) Отзывчивость программы увеличилась, вероятно, потому, что процессор не был заглушен ожиданием на GPU. Определенно лучший метод.Для сравнения, я убрал
finishedС начала кадра, оставляяflush, и он выполнил то же самое.поэтому я бы сказал использовать
flushиfinish, потому что, когда буфер пуст на вызовfinishнет работы. И я предполагаю, что если буфер был полон вы должны хотетьfinishв любом случае.
вопрос: вы хотите, чтобы ваш код продолжал работать во время выполнения команд OpenGL или только для запуска после ваши команды OpenGL были выполнены.
Это может иметь значение в случаях, например, по сетевым задержкам, чтобы иметь определенный консольный вывод только после изображения были нарисованы или такие.

Comments