Отображение изображения с помощью qt и opengl, проблемы с точностью синхронизации и вертикальной синхронизацией, С++

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

Из своего исследования я пришел к выводу, что QGLWidget является подходящим инструментом для этой задачи после включения вертикальной синхронизации с вызовами openGL (семейство SwapInterval).

Тем не менее, я не уверен, как на самом деле реализовать механизм подкачки - должен ли я использовать таймер? Если я установлю таймер на 333,3 мс (3 Гц), когда частота обновления составляет 60 Гц (16,67 за цикл, таким образом, таймер составляет 20 циклов), и я уверен, что время будет в порядке? И если частота должна быть 9 Гц, мне нужно установить таймер на 100 + 16,67, потому что это лучшее, что я могу получить? И если таймер в порядке, должен ли я просто вызывать paintGL(), когда он отправляет мне событие тайм-аута?

Спасибо


person JLev    schedule 02.02.2017    source источник


Ответы (1)


я должен использовать таймер?

Да, но не в наивной форме. Если вы просто используете таймер для точного определения представления изображений, частота вашего таймера будет биться с генератором вертикальной синхронизации/обновления дисплея — программные таймеры запускаются от источника синхронизации, отличного от вывода дисплея.

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

Вместо этого вам следует сделать следующее: использовать буферную подкачку V-Synced (SwapBuffers¹) в качестве контрольной точки для запуска высокоточного таймера измерения времени.

Затем визуализируйте кадр для следующей презентации в будущем, к которому вы стремитесь; примите во внимание, что интервалы кадров входят в детализацию интервала обновления дисплея — если только не используются G-Sync или FreeSync. Используйте glFinish для принудительного завершения процесса рендеринга кадра, затем остановите таймер и определите, сколько времени потребовалось для рендеринга кадра. Если кадр был завершен раньше, чем период обновления, вы стремились добавить (задержку с высоким разрешением), которая задерживает вашу программу на целевой период отображения (цель на середину периода), за которым следует SwapBuffers, который будет ссылкой точку для следующей итерации.


¹: Это будет надежно работать только для карт Nvidia и AMD и их проприетарных драйверов. Драйверы для графических процессоров Intel имеют другое поведение синхронизации.

person datenwolf    schedule 02.02.2017
comment
Спасибо, но что вы подразумеваете под подкачкой буфера с вертикальной синхронизацией? Как я могу начать измерения, когда это произойдет? Это что-то, что я могу контролировать или получить доступ? Насколько я понимаю, подкачка буфера вызывается неявно, а не мной. - person JLev; 05.02.2017
comment
@JLev: Вы используете QGLWidget, который технически является наследием Qt-4, и вы правы, что в Qt-5 с QOpenGLWindow все стало немного сложнее. Так или иначе, QGLWidget имеет функцию-член QGLWidget::swapBuffers, которая делает именно то, что следует из ее названия. Однако для фактической синхронизации V-Sync должен быть включен. Это можно включить/запретить в настройках графического драйвера, а поведение, запрошенное во время выполнения, тонко настроить с помощью расширений …swap_control (см. opengl.org/ реестр найдите swap_control). - person datenwolf; 05.02.2017
comment
Пытаясь реализовать ваше предложение, мне трудно добиться согласованности вертикальной синхронизации. Я думаю, возможно, проблема заключается в инициализации первого запуска таймера - если я вызываю swapbuffers только для справки, я получаю вызов QOpenGLContext::swapBuffers() с неоткрытым окном, поведение не определено. Должен ли я просто сделать что-то пустым и использовать его? - person JLev; 08.02.2017
comment
И еще одна вещь: когда вы говорите «добавить задержку», подходит ли для этого sleep()? - person JLev; 08.02.2017
comment
@JLev: вы должны использовать usleep, разрешение в микросекундах определенно требуется, и Qt достаточно умен, чтобы выбрать правильные системные таймеры с высоким разрешением для его реализации. Я также предлагаю, чтобы для начального интервала кадра вы пропустили тайминг и задержку, и только для последующих кадров реализовали это. - person datenwolf; 08.02.2017
comment
Извините, что снова беспокою, попробовал, но у меня постоянно зависает графический интерфейс, и я даже могу измерить фактическую скорость отображения. Я подозреваю, что это как-то связано с циклом событий Qt, но не совсем уверен, как это решить. void paintGL() { glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); glEnable(GL_TEXTURE_2D); drawTexture((0,0,1,1),texture,GL_TEXTURE_2D); swapBuffers(); t1 = chrono::high_resolution_clock::now(); glDisable(GL_TEXTURE_2D); swapImages(); } Это правильный способ рисования? В настоящее время я получаю разрыв соединения X11: ошибка ввода-вывода (код 1) при принудительном выходе - person JLev; 09.02.2017