我在一个简单的WPF动画中测量帧之间的时间.穿孔器说该应用程序的执行速度约为60fps,因此我预计帧之间的时间约为16.6ms,偏差很小.
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;
}
Run Code Online (Sandbox Code Playgroud)
有两件事让我惊讶:

Y - 以滴答为单位的帧之间的时间(10,000滴答= 1ms)
X - 帧计数
可能的混杂因素
我正在使用的项目:SimpleWindow.zip
===编辑
Markus指出我可以使用RenderingEventArgs.RenderingTime.Ticks而不是DateTime.Now.Ticks.我重复了这次跑步并得到了截然不同的结果.唯一的区别是计时方法:
DateTime.Now.Ticks

RenderingEventArgs.RenderingTime.Ticks

来自RenderingEventArgs的数据产生的数据更接近预期的16.6ms /帧,并且它是一致的.
如果显示器每16.6ms更新一次并且WPF每14.9ms更新一次,我们可以预期会出现导致撕裂的竞争条件.也就是说,当显示器试图读取图像时,大约每第10帧WPF将尝试写入其图像.
Chr*_*age 20
我向WPF团队提出了这个问题,这里是我给出的回复的摘要:
从UI线程计算帧速率很困难.WPF将UI线程与渲染线程分离.UI线程将呈现:
只要某些东西被标记为脏,我们就会降低渲染优先级.这可能比刷新率更频繁地发生.
如果动画处于挂起状态(或者有人挂钩了CompositionTarget.Rendering事件),我们将在渲染线程中的每个存在之后在UI线程上进行渲染.这涉及推进时序树,以便动画计算其新值.
因此,每个"帧"可以多次引发CompositionTarget.Rendering事件.我们在RenderingEventArgs中报告预期的"帧时间",并且应用程序应该仅在报告的帧时间发生变化时执行"每帧"工作.
请注意,UI线程正在做很多事情,因此假设CompositionTarget.Rendering事件处理程序以可靠的节奏运行是不可靠的.我们使用的模型(解耦两个线程)意味着UI线程可能稍微落后,因为它正在计算未来帧时间的动画.
特别感谢Dwayne Need向我解释这个问题.
首先 - 'Christopher Bennage的答案有一个很好的解释并提供解决方案的提示:
"当报告的帧时间发生变化时,只执行"每帧"工作"
这有点难,因为RenderingEventArgs被隐藏为正常的EventArgs并且必须完成转换.
为了使这更容易一些,可以在"EVAN'S CODE CLUNKERS"中找到一个方便的解决方案 http://evanl.wordpress.com/2009/12/06/efficient-optimal-per-frame-eventing-in-wpf/
我拿了他的代码并修改了一下.现在只需要我剪切,将类添加到您的项目中,使用CompositionTargetEx您使用的是CompositionTarget,你很好:)
public static class CompositionTargetEx {
private static TimeSpan _last = TimeSpan.Zero;
private static event EventHandler<RenderingEventArgs> _FrameUpdating;
public static event EventHandler<RenderingEventArgs> 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);
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
8702 次 |
| 最近记录: |