У меня есть простое тестовое приложение OpenGL на C, которое рисует разные вещи в ответ на ввод ключа. (Mesa 8.0.4, пробовал с Mesa-EGL и с GLFW, Ubuntu 12.04LTS на ПК с NVIDIA GTX650). Ничья довольно простая / быстрая (вращающийся треугольник). Мой тестовый код никоим образом не ограничивает частоту кадров, он просто выглядит так:
while (true)
{
draw();
swap_buffers();
}
Я очень тщательно рассчитал время и обнаружил, что время от одного eglSwapBuffers()
(или того glfwSwapBuffers
же) вызова до следующего составляет ~ 16,6 миллисекунды. Время от после звонка eglSwapBuffers()
до следующего звонка лишь немного меньше этого, хотя то, что нарисовано, очень просто. Время, которое занимает вызов буферов подкачки, значительно меньше 1 мс.
Тем не менее, время от приложения, изменяющего то, что оно рисует в ответ на нажатие клавиши, до изменения, фактически отображаемого на экране, составляет> 150 мс (приблизительно 8-9 кадров). Это измеряется записью экрана и клавиатуры с частотой 60 кадров в секунду.
Поэтому вопросы:
Где находятся буферизованные отрисовки между вызовом для замены буферов и фактическим отображением на экране? Почему задержка? Похоже, приложение всегда рисует много кадров впереди экрана.
Что может сделать приложение OpenGL, чтобы вызвать немедленный вывод на экран? (т.е.: нет буферизации, просто блокируйте, пока не завершится отрисовка; мне не нужна высокая пропускная способность, мне нужна низкая задержка)
Что может сделать приложение, чтобы вышеуказанная немедленная ничья произошла как можно быстрее?
Как приложение может узнать, что на самом деле сейчас на экране? (Или как долго / сколько кадров составляет текущая задержка буферизации?)
Ответы:
Любая функция API рисования, вызываемая из ЦП, будет передана в буфер кольца команд графического процессора для последующего выполнения графическим процессором. Это означает, что функции OpenGL являются в основном неблокирующими функциями. Таким образом, процессор и графический процессор будут работать параллельно.
Самая важная вещь, на которую стоит обратить внимание, это то, что ваше приложение может быть связано с процессором или графическим процессором как только вы вызовете glFinish, процессор должен будет ждать, пока графический процессор завершит выполнение команд рисования, если графический процессор отнимает больше времени и может / вызывает остановку центрального процессора, тогда ваши приложения привязаны к графическому процессору. Если графический процессор завершает свои команды рисования, а процессору требуется слишком много времени для glFinish, тогда ваше приложение привязано к процессору.
И обратите внимание, что есть разница между
glFlush
иglFinish
.glFlush
: указывает, что все команды, которые ранее были отправлены в GL, должны завершиться за конечное время.glFinish
: принудительно завершает все предыдущие команды GL. Finish не возвращается до тех пор, пока не будут полностью реализованы все эффекты от ранее выполненных команд для GL-клиента и состояния сервера и кадрового буфера. "glXSwapBuffers выполняет неявный glFlush перед его возвратом. Последующие команды OpenGL могут быть выполнены сразу после вызова glXSwapBuffers, но не выполняются до тех пор, пока не будет завершен обмен буферами.
Фактическое время кадра, скорее всего, будет определяться тем, какой из двух CPU / GPU тратит больше времени для завершения своей работы.
источник
both low framerate (exactly same as monitor refresh rate??
Нет, если вы явно не используете VSync.Технически, OpenGL никогда не обновляет экран.
Для этого существует API оконной системы, отдельный от GL (например, GLX, WGL, CGL, EGL). Перестановки в буфере с использованием этих API обычно неявно вызывают,
glFlush (...)
но в некоторых реализациях (например, растеризатор GDI в Windows) он выполняет полный циклglFinish (...)
:* С левой стороны, ICD (аппаратный) путь через
SwapBuffers (...)
. Справа - путь к GDI (программному обеспечению).Если у вас включен VSYNC и двойная буферизация, то любая команда, которая изменит задний буфер до того, как произойдет отложенный обмен, должна прерваться до обмена. Глубина очереди команд ограничена, поэтому эта остановленная команда в конечном итоге приведет к пробке в конвейере. Это может означать, что вместо блокировки
SwapBuffers (...)
вашего приложения фактически блокируется какая-то не связанная команда GL, пока VBLANK не развернется. На самом деле все сводится к тому, сколько обратных буферов у вас есть в цепочке обмена.Пока все задние буферы заполнены законченными кадрами, которые еще предстоит перенести на передний план, буферы подкачки будут неявно вызывать блокировку. К сожалению, нет способа явно контролировать количество обратных буферов, используемых большинством API оконных систем GL (кроме 0 с одиночной буферизацией или 1 с двойной буферизацией). Драйвер может свободно использовать 2 обратных буфера, если он хочет (тройная буферизация), но вы не можете запросить это на уровне приложения, используя что-то вроде GLX или WGL.
источник
glFinish (...)
сразу после замены буферов. Это очистит очередь команд, но это также означает, что графический процессор и процессор будут синхронизированы (что не очень хорошо, если вы хотите, чтобы графический процессор всегда работал).Я полагаю, вы знакомы с этим экспериментом ?
По сути, Джон Кармак делал что-то подобное, записывая экран и синхронизируя пиксели, отправленные на экран. Он обнаружил, что большая часть задержки пришла с экрана. Другими факторами были задержка ввода с клавиатуры, видеодрайверов и / или ход выполнения самой программы.
источник