Почему частота кадров в WPF нерегулярна и не ограничена для мониторинга обновления?

Я измеряю время между кадрами в простой анимации WPF. Перфоратор говорит, что приложение работает со скоростью ~ 60 кадров в секунду, поэтому я ожидал, что время между кадрами будет ~ 16,6 мс с небольшим отклонением.

public MainWindow() { ... CompositionTarget.Rendering += Rendering; } List FrameDurations = new List(); private long PreviousFrameTime = 0; private void Rendering(object o, EventArgs args) { FrameDurations.Add(DateTime.Now.Ticks - PreviousFrameTime); PreviousFrameTime = DateTime.Now.Ticks; } 

Меня удивили две вещи:

  • Время между кадрами довольно нерегулярно
  • Время между кадрами составляет ~ 8 мс. Я ожидал, что частота обновления монитора установит более низкую границу времени между кадрами (т. Е. 60 Гц = 16,6 мс между каждым фреймом, и что-то быстрее бессмысленно).

DefaultFrameRate

Y – время между кадрами в тиках (10 000 тиков = 1 мс)
X – количество кадров

Возможные смешающие факторы

  • Неточность таймера
  • Если CompositionTarget.Rendering фактически не коррелирует с рисунком одного кадра

Проект, который я использую: SimpleWindow.zip

=== Редактировать

Маркус указал, что я могу использовать RenderingEventArgs.RenderingTime.Ticks вместо DateTime.Now.Ticks. Я повторил пробег и получил очень разные результаты. Единственное различие заключается в методе синхронизации:

DateTime.Now.Ticks

DefaultFrameRate

RenderingEventArgs.RenderingTime.Ticks

введите описание изображения здесь

Данные RenderingEventArgs значительно улучшили данные, ожидаемые 16,6 мс / фрейм, и это согласовано.

  • Я не уверен, почему DateTime.Now и RenderingEventArgs будут создавать такие очень разные данные.
  • Предполагая, что RenderingEventArgs производит правильные времена, это все еще немного смущает, что эти времена не ожидаются 16.6ms.

Если дисплей обновляется каждые 16,6 мс, а WPF обновляется каждые 14,9 мс, мы можем ожидать состояние гонки, которое приведет к разрыву. То есть примерно каждый 10-й кадр WPF будет пытаться записать его изображение, пока дисплей пытается прочитать изображение.

Я поднял этот вопрос с командой WPF, и вот резюме ответа, который мне дал:

Вычисление частоты кадров из streamа пользовательского интерфейса затруднено. WPF отделяет stream пользовательского интерфейса от streamа рендеринга. Поток пользовательского интерфейса отобразит:

  • Всякий раз, когда что-то помечено как грязное, и мы спускаемся к приоритету Render. Это может происходить чаще, чем частота обновления.

  • Если ожидание анимации (или если кто-то подключил событие CompositionTarget.Rendering), мы будем отображать в streamе пользовательского интерфейса после каждого присутствия из streamа рендеринга. Это предполагает продвижение дерева синхронизации, поэтому анимация вычисляет их новые значения.

Из-за этого событие CompositionTarget.Rendering может быть увеличено несколько раз за «кадр». Мы сообщаем о предполагаемом «времени кадра» в RenderingEventArgs, и приложения должны работать только «за кадр», когда изменяется время отображения времени кадра.

Обратите внимание, что stream пользовательского интерфейса выполняет много вещей, поэтому нельзя считать, что обработчик событий CompositionTarget.Rendering работает с надежной каденцией. Используемая нами модель (разделение двух streamов) означает, что stream пользовательского интерфейса может немного отстать, поскольку он вычисляет анимацию для будущего времени кадра.

Особая благодарность Дуэйн Нужно объяснить это мне.

Сначала – «Кристофер Беннадж-ответ» имеет хорошее объяснение и дает подсказку:

«Выполнять операцию« только для каждого кадра »при изменении отображаемого времени кадра»

Это немного сложно, поскольку RenderingEventArgs скрыты как обычные EventArgs, и нужно сделать бросок.

Чтобы сделать это немного проще, удобное решение можно найти в «КЛАССАХ КОДА EVAN’S» http://evanl.wordpress.com/2009/12/06/efficient-optimal-per-frame-eventing-in-wpf/

Я взял его код и немного изменил его. Теперь просто возьмите мой снимок, добавьте class в свой проект, используйте CompositionTargetEx, вы использовали CompositionTarget, и вы в порядке 🙂

 public static class CompositionTargetEx { private static TimeSpan _last = TimeSpan.Zero; private static event EventHandler _FrameUpdating; public static event EventHandler Rendering { add { if (_FrameUpdating == null) CompositionTarget.Rendering += CompositionTarget_Rendering; _FrameUpdating += value; } remove { _FrameUpdating -= value; if (_FrameUpdating == null) CompositionTarget.Rendering -= CompositionTarget_Rendering; } } static void CompositionTarget_Rendering(object sender, EventArgs e) { RenderingEventArgs args = (RenderingEventArgs)e; if (args.RenderingTime == _last) return; _last = args.RenderingTime; _FrameUpdating(sender, args); } } 

WPF не предназначен для постоянной системы рендеринга частоты кадров. WPF отображает экран, когда элементы на экране помечены как измененные. Система рендеринга работает как цикл сообщения, поэтому нет способа гарантировать, что кадр будет отображаться через определенные промежутки времени.

  • jQuery для переключения анимации
  • Android View исчезает, когда выходит за пределы родителя
  • Как анимировать рукописный текст на веб-странице с помощью SVG?
  • css3 анимация on: hover; заставить всю анимацию
  • Анимированная иконка для ActionItem
  • CSS3 - 3D Flip Animation - IE10 transform-origin: сохранение-3d обходное решение
  • как я могу использовать анимацию в cocos2d?
  • Показать и скрыть вид с помощью анимации слайдов вверх / вниз
  • Как оживить просмотр с переводом анимации в Android
  • CSS ТОЛЬКО Анимация Кружок рисования с радиусом границы и прозрачным фоном
  • Как создать анимацию «Пожалуйста, подождите, загрузка ...» с помощью jQuery?
  • Interesting Posts

    C ++ Лучший способ получить целочисленное деление и остаток

    Ошибка: не был указан указатель по умолчанию и не было добавлено расширение

    Использование ggplot () в рамках другой функции в R

    перерыв петли, если Esc был нажат

    Как работают указатели функций в C?

    Получение исключения для classа, где оба classа одинаковы

    Почему я не могу использовать аргумент типа в параметре типа с несколькими ограничениями?

    Кнопка Android Fragment onClick Метод

    Получение учетных данных из хранилища учетных данных Windows с использованием C #

    Обратный отсчет персонажей, как на twitter

    Почему деление более дорого, чем умножение?

    Почему мне разрешено использовать переменную const, определенную как размер массива в C?

    В чем разница между html и html: lang (en) в CSS?

    Есть ли какая-либо авторская информация в формате PDF?

    RamMap «Пустой резервный список» резко ускоряет работу ПК. Есть лучший способ сделать это?

    Давайте будем гением компьютера.