繁体   English   中英

WriteableBitmap.Lock()性能问题

[英]WriteableBitmap.Lock() Performance Issue

我有一个应用程序,使用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写入“前”缓冲区并且不需要锁定。 我不知道你是否有其他理由来锁定它(其他线程正在做某事),但对于那里的代码我不明白为什么你需要。

我想我不需要锁从BackBuffer(* pixData)读取 - 我认为它只适用于写入,但我很肯定你不需要为WritePixels调用Lock。

据我所知,你正在做:

  1. 锁定后缓冲区
  2. 将其中的内容复制到数组中
  3. 使用这个新数组调用WritePixels
  4. 解锁后台缓冲区。

切换3和4怎么样?

WritePixels可能在内部导致渲染线程(在消息队列中具有更高的优先级)代表它获得锁定,这可能是您所看到的延迟的一个因素。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM