c# - WriteableBitmap.Lock() 性能问题

标签 c# .net wpf .net-4.0 writeablebitmap

我有一个应用程序,其中使用 WriteableBitmap 进行对性能敏感的绘图。使用 CompositionTarget.Rendering 调用一个事件来实际更新 WriteableBitmap 的后台缓冲区。根据 MSDN 文档,这意味着事件在每帧触发一次,就在呈现控件之前。

我遇到的问题是 WriteableBitmap 的 Lock() 函数需要很长时间,尤其是在位图尺寸较大的情况下。我之前读到 AddDirtyRegion() 有一个错误,会导致整个位图无效,从而导致性能不佳。但是,这里似乎并非如此。从大量的低级检查来看,Lock() 似乎打开了位图的后台缓冲区以在渲染线程上写入,这意味着每次调用我的事件处理程序时,它都必须线程阻塞直到渲染线程已准备就绪。这会导致更新位图图形时明显滞后。

我已经尝试使用 TryLock() 向事件处理程序添加超时,这样它就不会阻塞这么长时间而导致性能下降。然而,这会导致类似的效果,因为它看起来滞后,因为大量的位图更新被集中在一起。

这是事件处理程序中的相关代码,以显示我在做什么。编写 UpdatePixels() 函数是为了避免使用可能有问题的 AddDirtyRect():

void updateBitmap(object sender, EventArgs e)
{
    if (!form.ResizingWindow)
    {
        // Lock and unlock are important... Make sure to keep them outside of the loop for performance reasons.
        if (canvasUpdates.Count > 0)
        {
            //bool locked = scaledDrawingMap.TryLock(bitmapLockDuration);
            scaledDrawingMap.Lock();
            //if (locked)
            //{
            unsafe
            {
                int* pixData = (int*)scaledDrawingMap.BackBuffer;
                foreach (Int32Rect i in canvasUpdates)
                {
                    // The graphics object isn't directly shown, so this isn't actually necessary.  We do a sort of manual copy from the drawingMap, which acts similarly
                    //    to a back buffer. 
                    Int32Rect temp = GetValidDirtyRegion(i);
                    UpdatePixels(temp, pixData);
                }
                scaledDrawingMap.Unlock();
                canvasUpdates.Clear();
            }
            //}
        }
    }
}

private unsafe void UpdatePixels(Int32Rect temp, int* pixData)
{
    //int* pixData = (int*)scaledDrawingMap.BackBuffer;
     // Directly copy the backbuffer into a new buffer, to use WritePixels().
    var stride = temp.Width * scaledDrawingMap.Format.BitsPerPixel / 8;
    int[] relevantPixData = new int[stride  * temp.Height];
    int srcIdx = 0;
    int pWidth = scaledDrawingMap.PixelWidth;
    int yLess = temp.Y + temp.Height;
    int xLess = temp.X + temp.Width;
    for (int y = temp.Y; y < yLess; y++)
    {
        for (int x = temp.X; x < xLess; x++)
        {
            relevantPixData[srcIdx++] = pixData[y * pWidth + x];
        }
    }
    scaledDrawingMap.WritePixels(temp, relevantPixData, stride, 0);
}

我似乎无法弄清楚如何避免 WriteableBitmap 的线程阻塞问题,而且我在我编写的代码中看不到任何明显的错误。任何帮助或指示将不胜感激。

最佳答案

看起来您实际上并没有使用 BackBuffer 进行写入 - 仅用于读取。
WritePixels 写入“前端”缓冲区并且不需要锁定。 我不知道您是否有其他原因要锁定它(其他线程正在做某事),但是对于此处的代码,我不明白您为什么需要这样做。

关于c# - WriteableBitmap.Lock() 性能问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21291233/

相关文章:

c# - 寻找将负整数归零的 .NET Math 方法

c# - 组合框上的 IsEditable 没有效果

c# - Directory.GetFiles searchPattern 与文档不一致

c# - 用于上传数据的Web服务 : security considerations

c# - 高质量图像缩放

c# - 将一个泛型参数约束为另一个的子类型

c# - 如果 wpf 应用程序没有响应,则自动重启

c# - 为什么有时 WebBrowser.Dispose() 会启动 Internet Explorer?

.net - 获取文本框中字符的坐标?

c# - 使用 WPF/C# : how to define a threshold to tell apart clicks from panning 的触摸输入