【问题标题】:WPF BitmapImage creation extremely slow on Xeon/nVidia Quadro machineXeon/nVidia Quadro 机器上的 WPF 位图图像创建速度极慢
【发布时间】:2017-07-23 09:46:33
【问题描述】:

我写了一个 WPF 程序,它是事物的图形浏览器。它在 ListView 中显示了相当多的图像,每个图像都有图像控件。它还允许用户进行基本的图像编辑。

我已经在许多不同的机器上运行过这个软件:我的开发笔记本电脑、我同事的带有并行桌面的 MacBook、可以通过 Windows 远程桌面访问的 VirtualBox VM,甚至是使用了 10 年的笔记本电脑。它运行得很好。

不幸的是,我们的第一个客户是一家设计公司,拥有专为 CAD 设计而构建的工作站,配备 Xeon 处理器和 nVidia Quadro 2000 卡。 现在震惊了:我的程序在他们的机器上太慢了以至于无法使用。

我用过dotTrace,发现瓶颈是我的ImageToImageSourceConverter,这是最标准的一个:

  public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        Bitmap bmp = value as Bitmap;
        if (bmp == null)
            return null;

        using (MemoryStream memory = new MemoryStream())
        {
            memory.Seek(0, SeekOrigin.Begin);
            bmp.Save(memory, ImageFormat.Bmp);
            memory.Position = 0;
            BitmapImage bitmapImage = new BitmapImage();
            bitmapImage.BeginInit();
            bitmapImage.StreamSource = memory;
            bitmapImage.CacheOption = BitmapCacheOption.OnLoad;
            bitmapImage.EndInit();
            return bitmapImage;
        }

dotTrace 表明,在他们的机器上,带有 bitmapImage.EndInit() 的行占用了大部分计算时间。它也在 ui 线程上完成,因此应用程序冻结了一段时间。 dotTrace 告诉调用在 clr.dll 中结束

按比例显示:在我的笔记本电脑上,这个转换大约需要 5-10 毫秒,具体取决于位图。在他们的机器上(全部!)大约需要 800 毫秒,有时甚至更长。

在其他没有问题的机器上:它运行得很快,冻结不明显。更重要的是,显示的位图非常小(200x200px),当我将其更改为异步时,由于线程更改开销,它会变慢。

有人知道为什么会这样吗?

到目前为止我尝试过的事情:

  • 通过 RenderOptions.ProcessRenderMode = RenderMode.SoftwareOnly 禁用硬件渲染; - 没有区别
  • 更新显卡驱动:没有区别
  • 禁用显卡驱动程序和窗口兼容模式中的所有加速:没有区别
  • 以管理员身份运行 (why I did this):它的运行速度明显更快,但仍然不够。

问题很大:如果运行不快,我们将无法获得报酬:D

更奇怪的是,有时它可以在几秒钟内正常工作。

我的笔画是以这样一种方式实现的,即按下按钮的 onMouseMove 我创建了前一个图像的副本,并使用从上一个鼠标位置到新鼠标位置的预览颜色绘制了附加线,并跟踪这些点。当你释放 LMB 时,我在原始图像上用目标颜色绘制点之间的线。它可能看起来很慢,但在我测试的每台机器上都快得惊人。

在他们的,当你点击并等待片刻,然后移动鼠标它运行顺利。但是当您立即单击并移动鼠标时,它会冻结并在单击位置和最后一个位置之间绘制直线,因为它没有注册点之间的点。

那么,这是否与缓慢加载某些dll然后在一段时间不使用时释放它有关?如果是这样,它可以是哪一个?

工作站规格: Intel(R) Xeon(R) CPU E5-1650 0 @ 3.20GHz 英伟达 Quadro 2000 1GB 16 GB 内存

【问题讨论】:

  • here 的答案可能会有所帮助。除此之外,您还应该在bitmapImage.EndInit() 之后调用bitmapImage.Freeze()
  • 谢谢,我会检查的

标签: c# wpf image performance nvidia


【解决方案1】:

正如@Clemens 所建议的,我改变了Bitmap 和ImageSource 之间的转换方法。这是我的新转换器:

  [ValueConversion(typeof(Bitmap), typeof(ImageSource))]
public class BitmapToImageSourceConverter : IValueConverter
{

    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        Bitmap bitmap = value as Bitmap;
        if (bitmap == null)
            return null;

        var bitmapData = bitmap.LockBits(
            new System.Drawing.Rectangle(0, 0, bitmap.Width, bitmap.Height),
            System.Drawing.Imaging.ImageLockMode.ReadOnly, bitmap.PixelFormat);

        var bitmapSource = BitmapSource.Create(
            bitmapData.Width, bitmapData.Height, 96, 96, ConvertPixelFormat(bitmap.PixelFormat), null,
            bitmapData.Scan0, bitmapData.Stride * bitmapData.Height, bitmapData.Stride);

        bitmap.UnlockBits(bitmapData);
        return bitmapSource;
    }

    private static System.Windows.Media.PixelFormat ConvertPixelFormat(System.Drawing.Imaging.PixelFormat sourceFormat)
    {
        switch (sourceFormat)
        {
            case System.Drawing.Imaging.PixelFormat.Format24bppRgb:
                return PixelFormats.Bgr24;

            case System.Drawing.Imaging.PixelFormat.Format32bppArgb:
                return PixelFormats.Bgra32;

            case System.Drawing.Imaging.PixelFormat.Format32bppRgb:
                return PixelFormats.Bgr32;

            // .. as many as you need...
        }
        return new System.Windows.Media.PixelFormat();
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

这种方法在某些计算机上平均速度甚至快 20 倍。我的测量结果表明,它在几乎每台机器上的转换时间都在 1 毫秒以下,而之前的转换器总是在 5 毫秒以上,这在 5 到 50 之间的计算机之间变化,有时甚至是 800 毫秒,就像我在问题中所说的那样。

【讨论】:

  • 哇!谢谢!这比我今天的速度快十亿倍!!!
猜你喜欢
  • 1970-01-01
  • 2011-07-19
  • 1970-01-01
  • 2013-10-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-08-22
  • 2021-09-20
相关资源
最近更新 更多