WPF使用BitmapSource的渲染性能

7
我创建了一个 WPF 控件(继承自 FrameworkElement),它显示一个平铺的图形,可以进行平移。每个瓦片大小为 256x256 像素,24bpp。我重写了 OnRender 方法,在那里,我加载任何新的瓷砖(作为 BitmapFrame),然后使用 drawingContext.DrawImage 绘制所有可见的瓷砖。

现在,每当渲染周期中有超过几个新瓷砖时,帧率将从 60fps 掉到零,持续约一秒钟。这不是由于载入图像(大约需要毫秒级别的时间),也不是 DrawImage(因为它仅填充一些中间渲染数据结构,所以不花费时间)。

我的猜测是,当渲染线程获得大量新的 BitmapSource 实例(即它尚未缓存的实例)时,渲染线程本身会受阻。要么它花费了大量时间将它们转换为某种内部 DirectX 兼容格式,要么是缓存问题。它不能耗尽视频 RAM;Perforator 显示峰值低于 60MB,我有 256MB 的 RAM。此外,Perforator 表明所有渲染目标都是硬件加速的,所以也不可能是这个原因。

如果您有任何见解,欢迎分享!

谢谢!

Daniel

@RandomEngy:
BitmapScalingMode.LowQuality 减轻了一些问题,但没有完全解决。我已经按预期分辨率加载了图块。也不可能是显卡驱动程序的问题(Nvidia 已为最新)。
我有点惊讶地发现缩放需要那么长时间。就我所理解的,无论大小如何,位图都只是作为 Direct3D 纹理加载,然后进行硬件缩放。事实上,一旦位图被首次渲染,我可以在不进一步冻结的情况下改变其旋转和缩放。

2个回答

3
不仅仅是大量图片,即使只有一张大图也足以阻塞渲染直到图像被加载完成,当您的图像尺寸达到数千像素时,这种情况会非常明显。我同意您的观点,这可能是渲染线程的问题:我进行了测试,当尝试显示完全预缓存的BitmapImage时,UI线程仍然可以快乐地分发消息,而此时发生了渲染延迟。它必须在图像上执行某种转换或准备工作,就像您所推测的那样。我曾尝试通过“渲染”但隐藏图像来减轻这种情况,然后在需要显示图像时再显示出来。但是,这并不理想,因为渲染冻结仍然会发生。一些后续跟进:在MS WPF别名上讨论之后,我找到了导致延迟的原因。在我的Server 2008机器上,这是旧视频驱动程序不支持新的WDDM驱动程序模型和调整图像大小的延迟的组合。如果源图像大小与显示大小不同,则会延迟渲染线程,直到图像显示出来。默认情况下,图像设置为最高质量,但是您可以通过调用RenderOptions.SetBitmapScalingMode(uiImage, BitmapScalingMode.LowQuality);更改呈现的缩放选项。一旦我这样做了,显示图像之前的神秘冻结就消失了。另一种选择是,如果您不喜欢缩放时的质量下降,则将DecodePixelWidth / Height设置为其将要显示的大小,然后在后台线程上加载BitmapImage,应该可以立即显示它而没有延迟。

0

还可以尝试这些;

/* ivis is declared in XAML <Image x:Name="iVis" UseLayoutRounding="True" SnapsToDevicePixels="True" /> */

iVis.Stretch = Stretch.None;
RenderOptions.SetBitmapScalingMode(iVis, BitmapScalingMode.NearestNeighbor);
RenderOptions.SetEdgeMode(iVis, EdgeMode.Aliased);
VisualBitmapScalingMode = BitmapScalingMode.NearestNeighbor;
iVis.Source = **** your bitmap source ****

当使用大量的"A"通道颜色时,我在性能方面遇到了一些问题,等待图像渲染完成后再进行缩放对我来说效果更好。

另外,你提到你正在使用平铺图形?

通常你可以使用TileBrush将其简单设置为FrameworkElement的画笔。如果你正在动态地添加或动画它们,你可以生成你的画笔,然后手动逐个应用于你的对象,确保尽可能冻结它们。同时,VisualBitmapScalingMode是任何Visual的一个属性。


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