Идеальная реализация V-sync для облегченной игры OpenGL: нужен один кусочек информации

В игре, которую собирает наша интернет-команда, программируем, мы предполагаем, что у всех из нашей аудитории будет ПУТЬ в полной скорости в игре.

Таким образом, для экономии видеопамяти и, как мы надеемся, для видеокарты немного больше времени простоя, использование V-sync без двойной буферизации было бы нашим лучшим вариантом. Итак, в OpenGL нам нужно знать, как это сделать.

Насколько я понимаю, V-синхронизация - это когда видеокарта ставится на паузу, когда завершается рендеринг одного кадра, пока этот кадр не будет отправлен на устройство отображения. Двойная буферизация не приостанавливает операции рендеринга (или, может быть, делает это, или, может быть, это зависит от реализации; не уверен), потому что вместо этого он рисует во второй буфер перед копированием в кадровый буфер, так что монитор либо получает полный кадр, либо нет новый кадр вообще (в частности, последнее сохраненное изображение в кадровом буфере). Ну, нам не нужна эта функция, если видеокарта просто пишет в фрейм-буфер ТОЛЬКО тогда, когда это необходимо.

Это довольно медленная онлайн игра (но она ОЧЕНЬ креативная ^_^). Там очень мало действий в реальном времени. Поэтому чрезвычайно точный пользовательский ввод не является необходимостью; он может быть записан из ОС как единое целое в любое время перед рендерингом кадра.

Итак, чтобы сделать именно это, мне нужно иметь возможность получить сообщение "Кадр завершил отправку на монитор" из OpenGL. Является ли это возможным? Если нет, то какова лучшая альтернатива?

Игра на данный момент программируется для Windows, но для Linux она должна была закончиться через несколько месяцев.

2 ответа

Решение

Вы страдаете от неправильного представления о том, что делает V-Sync. В видео-ОЗУ есть часть, которая постоянно отправляется на дисплей с постоянной частотой, частота обновления кадров. Таким образом, сразу после отправки полного кадра следующий кадр отправляется через очень короткое время. Но время между отправкой кадров намного короче, чем время, необходимое для отправки полного кадра.

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

Что подводит нас к тому, что делает двойной буфер. Без двойной буферизации мало что пригодится для V-Sync. Действие, запускаемое V-Sync, должно происходить очень и очень быстро. Таким образом, это сводится к замене указателя или к очень быстрой операции блитинга (возможно, просто путем установки атрибутов CoW для MMU графического процессора).

Без двойной буферизации и без V-Sync эффект состоит в том, что можно увидеть процесс, в котором изображение визуализируется по частям в кадровый буфер. Конечно, если рендеринг происходит быстрее, чем период кадра, это приводит к тому, что сверху вниз вы увидите только малонаселенное изображение с большим и большим количеством контента, видимого в нижней части, и где-то между ними оно достигнет нижней границы экрана, валяется наверх. Линия пересечения будет двигаться.

TL; DR: просто используйте двойную буферизацию и включите V-Sync для замены буфера. Не бойтесь потребления памяти. Сегодня все графические процессоры имеют более чем достаточно оперативной памяти, чтобы легко обеспечить память для цветовых плоскостей с двойной буферизацией. Просто посчитайте: 1920x1200 * RGB = 6 МБ, даже самые маленькие графические процессоры на сегодняшний день обеспечивают по крайней мере 128 МБ ОЗУ. Мобильные устройства, скажем, iPad 1024*768 * RGB = 2 МБ против 32 МБ для графики. Интерфейс iPad в любом случае имеет двойной буфер.

Ты можешь использовать wglGetProcAddress получить адрес wglSwapIntervalEXT, а затем позвоните wglSwapIntervalEXT(1); синхронизировать обновления с вертикальной синхронизацией. Когда вы делаете это, вы не получаете сообщение при вертикальной синхронизации - вместо этого glFlush просто не возвращается до тех пор, пока не произойдет вертикальный возврат, и экран не будет обновлен. Итак, у вас есть WM_PAINT обработчик, который выглядит примерно так:

BeginPaint
wglMakeCurrent
do drawing
glFlush
EndPaint

glFlush необходимо в любом случае, чтобы гарантировать, что сделанный вами рисунок будет отправлен на экран.

Другие вопросы по тегам