Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
496 views
in Technique[技术] by (71.8m points)

animation - Why is Frame Rate in WPF Irregular and Not Limited To Monitor Refresh?

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:

  • Time between frames is fairly irregular
  • Time between frames is ~8ms. I had expected that the monitor's refresh rate would set a lower bound on time between frames (ie. 60Hz = 16.6ms between each frame, and anything faster is pointless).

DefaultFrameRate

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

Possible confounding factors

  • Timer inaccuracy
  • If CompositionTarget.Rendering doesn't actually correlate to the drawing of a single frame

The project I'm using: SimpleWindow.zip

===Edit

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

DefaultFrameRate

RenderingEventArgs.RenderingTime.Ticks

enter image description here

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

  • I'm not sure why DateTime.Now and RenderingEventArgs would produce such very different data.
  • Assuming RenderingEventArgs is producing correct times, it's still a bit disconcerting that those times are not the expected 16.6ms.

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.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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

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

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

  • 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.

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.

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.

Special thanks to Dwayne Need for explaining this to me.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...