WPF:如何使用WriteableBitmap避免撕裂?

9
我正在使用WriteableBitmap以每秒约20帧的速度显示我自己处理的图像。
这个问题(WPF: More efficient way of displaying quickly-changing images?)和这个问题(How to display quick-updating images without large memory allocation?)表明,最好的方法是使用WriteableBitmapWriteableBitmap的文档指出,在UI线程上调用WritePixels()将导致渲染线程重新绘制图像: MSDN文档: UI线程将内容写入后备缓冲区。渲染线程从前缓冲区读取内容并将其复制到视频内存中。对后备缓冲区的更改通过更改的矩形区域进行跟踪。 <snip /> 当更新发送到渲染线程时,渲染线程将更改的矩形从后备缓冲区复制到前缓冲区。渲染系统控制此交换以避免死锁和重新绘制伪影,例如"撕裂"。 我在后台线程上处理我的图像,然后使用Dispatcher.BeginInvoke()调用WritePixels(),以确保在UI线程上调用WritePixels()
我发现即使使用WriteableBitmap仍会出现"撕裂",并且在我正在开发的应用程序中,它看起来很糟糕(这是一款医学成像应用程序)。有什么可以做的吗?

这么多年过去了,你解决了这个问题吗? - qakmak
@qakmak,很难回忆起那个时候,但我相信转移到更现代的操作系统是答案。请参见被接受的答案。 - Rob
这个答案对我来说不够好,但还是谢谢。 - qakmak
很遗憾,恐怕你不会得到比这更好的答案了。所有迹象都表明这是一个操作系统级别的问题。 - Rob
3个回答

5

在WriteableBitmap中,有很多工作被投入到避免撕裂的问题上,但在某些系统配置下,这是不可避免的。主要发生在Windows XP或Vista关闭Aero(DWM)时。


我们正在使用Windows XP操作系统。我从来没有想过操作系统会是问题,但这很有道理——我在家里写的WPF应用程序在Vista和Windows 7上运行比在XP上快得多。只是出于好奇,你是怎么知道这个的? - Rob
我在WPF中做了很多关于视频的工作,所以有些知识就随着领域和自己的经验而来。不确定技术原因是什么,但带Aero的Vista可确保(大部分情况下)你的WPF应用程序与你的显卡以相同频率绘制,因此不会出现撕裂。对于XP而言,这似乎取决于显卡和驱动程序,有时候好,有时候坏。许多人认为Aero/DWM会减慢计算机速度,但事实并非如此。它会大大地影响整体性能。 - Jeremiah Morrill

1

在调用WritePixels()时,您可能会覆盖位图。使用Dispatcher.Invoke()而不是BeginInvoke()可能会有所帮助。


我同意。BeginInvoke() 是异步的。使用 Invoke(),它应该可以很好地同步(尽管你可能会注意到延迟)。 - apandit
不行 - 使用Invoke()而不是BeginInvoke()仍然会出现相同的撕裂效果 :-( - Rob
WritePixels 应该锁定后备缓冲区,以防止渲染线程将部分后备缓冲区复制到前置缓冲区(从而导致撕裂)。根据 WritePixels 的文档行为,BeginInvoke 与 Invoke 不应有任何区别。 - James Schek

0

我知道这是一个旧的线程,但我们遇到了完全相同的问题,在我们的情况下,它是由于使用Dispatcher.BeginInvoke调用我们的更新显示方法引起的 - 当我们改为使用Dispatcher.Invoke时,它立即清除了。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接