为什么 WPF 中的帧速率不规则且不限于监视器刷新? [英] Why is Frame Rate in WPF Irregular and Not Limited To Monitor Refresh?

查看:90
本文介绍了为什么 WPF 中的帧速率不规则且不限于监视器刷新?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在一个简单的 WPF 动画中测量帧之间的时间.Perforator 表示该应用的运行速度约为 60 fps,因此我预计帧之间的时间约为 16.6 毫秒,几乎没有偏差.

I'm measuring the time between frames in a simple WPF animation. Perforator says the app performs at ~60fps, so I expected the time between frames to be ~16.6ms with little deviation.

    public MainWindow()
    {
    ...
        CompositionTarget.Rendering += Rendering;
    }

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

有两件事让我感到惊讶:

Two things surprised me:

  • 帧之间的时间相当不规则
  • 帧之间的时间约为 8 毫秒.我原以为显示器的刷新率会设置帧之间的时间下限(即每帧之间 60Hz = 16.6 毫秒,任何更快的速度都是毫无意义的).

Y - 以滴答为单位的帧之间的时间(10,000 滴答 = 1 毫秒)
X - 帧数

Y - Time between frames in ticks (10,000 ticks = 1ms)
X - Frame count

可能的混杂因素

  • 计时器不准确
  • 如果 CompositionTarget.Rendering 实际上与单帧的绘制无关

我正在使用的项目:SimpleWindow.zip

===编辑

Markus 指出我可以使用 RenderingEventArgs.RenderingTime.Ticks 而不是 DateTime.Now.Ticks.我重复了运行,得到了截然不同的结果.唯一的区别是计时方法:

Markus pointed out I could be using RenderingEventArgs.RenderingTime.Ticks instead of DateTime.Now.Ticks. I repeated the run and got very different results. The only difference is timing method:

DateTime.Now.Ticks

RenderingEventArgs.RenderingTime.Ticks

来自 RenderingEventArgs 的数据产生的数据更接近预期的 16.6 毫秒/帧,并且是一致的.

Data from RenderingEventArgs produced data much closer the expected 16.6ms/frame, and it is consistent.

  • 我不知道为什么 DateTime.Now 和 RenderingEventArgs 会产生如此不同的数据.
  • 假设 RenderingEventArgs 产生正确的时间,但这些时间不是预期的 16.6 毫秒仍然有点令人不安.

如果显示每 16.6 毫秒更新一次,而 WPF 每 14.9 毫秒更新一次,我们可以预期会出现导致撕裂的竞争条件.也就是说,大约每 10 帧 WPF 将尝试写入其图像,而显示器正在尝试读取图像.

If the display is updating every 16.6ms and WPF is updating every 14.9ms, we can expect a race condition that would result in tearing. That is to say, roughly every 10th frame WPF will be trying to write its image while the display is trying to read the image.

推荐答案

我向 WPF 团队提出了这个问题,以下是我得到的答复的摘要:

I raised this question with the WPF team and here is a summary of the response I was given:

从用户界面计算帧率线程很难.WPF 解耦来自渲染线程的 UI 线程.UI 线程将呈现:

Calculating the framerate from the UI thread is difficult. WPF decouples the UI thread from the render thread. The UI thread will render:

  • 每当某些东西被标记为脏时,我们就会将其消耗到 Render优先事项.这可能会更频繁地发生比刷新率.

  • Whenever something is marked as dirty and we drain down to Render priority. This can happen more often than the refresh rate.

如果动画正在等待中(或者如果有人上钩了CompositionTarget.Rendering 事件)我们将在 UI 线程上呈现来自渲染线程的每个礼物.这涉及提前时间树所以动画计算他们的新值.

If an animation is pending (or if someone hooked the CompositionTarget.Rendering event) we will render on the UI thread after every present from the render thread. This involves advancing the timing tree so animations calculate their new values.

因此,CompositionTarget.Rendering 事件可以每帧"多次提升.我们报告预期的帧时间"RenderingEventArgs,和应用程序应该只做每帧"工作时报告帧时间变化.

Because of this, the CompositionTarget.Rendering event can be raised multiple times per "frame". We report the intended "frame time" in the RenderingEventArgs, and applications should only do "per-frame" work when the reported frame time changes.

注意 UI 线程做了很多事情,所以不可靠假设 CompositionTarget.Rendering事件处理程序以可靠的方式运行节奏.我们使用的模型(解耦两个线程)表示 UI线程可能有点落后,因为它正在计算动画未来的帧时间.

Note that the UI thread is doing many things, so it is not reliable to assume the CompositionTarget.Rendering event handler runs at a reliable cadence. The model we use (decoupling the two threads) means that the UI thread can be a little behind, since it is calculating animations for a future frame time.

特别感谢 Dwayne Need 向我解释了这一点.

Special thanks to Dwayne Need for explaining this to me.

这篇关于为什么 WPF 中的帧速率不规则且不限于监视器刷新?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆