ответ datenwolf отличный. Я просто хотел добавить к этому обсуждению одну вещь, касающуюся тройной буферизации на уровне компоновщика, поскольку я хорошо знаком с компоновщиком рабочего стола Microsoft Windows.
Я знаю, что вы спрашиваете здесь об OS X, но детали реализации, которые я собираюсь обсудить, являются наиболее разумным способом реализации этого материала, и я ожидаю, что другие системы будут работать таким же образом.
Тройная буферизация, которую вы можете включить на уровне приложения, добавляет в цепочку обмена третий буфер, который синхронизируется с обновлением. Такой способ выполнения тройной буферизации увеличивает задержку, потому что этот третий буфер должен отображаться, и ничто не может касаться его, пока это не произойдет (это обязательное поведение D3D — поведение и сама функция не определены в OpenGL эм>); но способ работы диспетчера окон рабочего стола (Windows) немного отличается.
Поведение, которое я видел в большинстве драйверов для композиции рабочего стола, — это пропуск кадров. В любой ситуации, когда несколько кадров завершаются между обновлениями, все эти кадры, кроме одного, отбрасываются. На самом деле вы получаете более низкую задержку, используя окно, а не полноэкранную + тройную буферизацию, потому что она не блокирует обмен буферами, когда в третьем буфере (принадлежащем компоновщику) есть готовый кадр, ожидающий отображения.
Это создает совершенно другой набор визуальных проблем, если частота кадров недостаточно постоянна. Технически пиксели, принадлежащие пропущенным кадрам, имеют бесконечную задержку, поэтому преимущества от сокращения задержки, сделанного таким образом, могут быть бесполезными, если вам нужно, чтобы каждый отрисованный кадр отображался на экране.
Я считаю, что вы можете добиться такого поведения в OS X (если хотите), отключив VSYNC и рисуя в окне. VSYNC в основном служит только формой синхронизации кадров (обмен задержкой на согласованность) в этом сценарии, и разрыв устраняется самим компоновщиком независимо от того, с какой скоростью вы рисуете.
Что касается задержки курсора мыши:
Курсор в любой современной оконной системе всегда будет отслеживаться с минимальной задержкой. В графическом оборудовании буквально есть функция, называемая аппаратным курсором, когда драйвер сохраняет положение курсора, а затем один раз при обновлении аппаратно накладывает курсор поверх того, что находится в буфере кадра, ожидая сканирования. Таким образом, даже если ваше приложение рисует со скоростью 30 кадров в секунду на дисплее с частотой 60 Гц, курсор обновляется каждые 16 мс, когда используется аппаратный курсор.
Это полностью обходит все графические API, но весьма ограничено (например, он использует курсор, определенный ОС).
TL;DR: задержка проявляется во многих формах.
Если ваша проблема заключается в задержке ввода, вы можете смягчить ее, уменьшив количество предварительно обработанных кадров и избегая тройной буферизации. Я не могу начать рассказывать вам, как уменьшить количество предварительно обработанных драйвером кадров в OS X.
- Минимизируйте время до того, как что-то появится на экране
Если ваша проблема заключается в количестве времени, которое проходит между выполнениями вашего цикла рендеринга, вы бы пошли другим путем. Увеличьте предварительно обработанные кадры, отрисуйте окно и отключите VSYNC. В этом сценарии вы можете столкнуться со множеством фреймов, которые рисуются, но никогда не отображаются.
- Минимизировать время блокировки (увеличить FPS); некоторые кадры никогда не будут отображаться
Предварительно визуализированные кадры — это небольшая мощная функция, которую вы не можете контролировать на уровне API OpenGL. Он устанавливает, насколько глубоко драйверу разрешено конвейеризировать все, и в зависимости от желаемой задачи вы будете торговать различными типами задержки, возясь с ней. Многие геймеры клянутся, что устанавливают это значение равным 1, чтобы свести к минимуму задержку ввода за счет общей плавности кадров.
ОБНОВИТЬ:
Предварительно отрендеренные кадры являются одной из причин вашей многокадровой задержки. Исправить это кросс-платформенным способом сложно (это настройка драйвера), но если у вас есть доступ к Fence Sync Objects, вы можете добиться того же поведения, что и принудительное значение 1.
Я могу объяснить это более подробно, если это необходимо, общая идея заключается в том, что вы вставляете синхронизацию ограждения после замены буфера, а затем ждете, пока она будет сигнализирована, прежде чем будет разрешено начать первую команду в следующем кадре. Производительность может упасть, но задержка будет сведена к минимуму, поскольку ЦП больше не будет выполнять рендеринг раньше, чем ГП.
person
Andon M. Coleman
schedule
05.08.2015