我有一个使用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写入“前端”缓冲区,不需要锁。
我不知道您是否还有其他理由要锁定它(其他线程在做某事),但是对于这里的代码,我不知道您为什么需要这样做。

07-24 09:43
查看更多