简体   繁体   English

WriteableBitmap.Lock()性能问题

[英]WriteableBitmap.Lock() Performance Issue

I have an application where performance-sensitive drawings occur using a WriteableBitmap . 我有一个应用程序,使用WriteableBitmap发生性能敏感的绘图。 An event is called with CompositionTarget.Rendering to actually update the back buffer of the WriteableBitmap . 使用CompositionTarget.Rendering调用事件以实际更新WriteableBitmap的后台缓冲区。 From the MSDN documentation, that means the event is fired once per frame, right before the control is rendered. 从MSDN文档中,这意味着在呈现控件之前每帧触发一次事件。

The issue that I am having is that the WriteableBitmap's Lock() function takes an extremely long time, especially at larger bitmap sizes. 我遇到的问题是WriteableBitmap的Lock()函数需要很长时间,特别是在较大的位图大小时。 I have previously read that AddDirtyRegion() has a bug that causes the entire bitmap to invalidate, leading to poor performance. 我之前已经读过AddDirtyRegion()有一个错误导致整个位图无效,导致性能不佳。 However, that doesn't seem to be the case here. 但是,这似乎并非如此。 From a good bit of low-level checking, it seems that Lock() opens the bitmap's backbuffer for writing on the render thread, which means every time my event handler is called, it has to thread block until the render thread is ready for it. 从一个很好的低级检查,似乎Lock()打开位图的后台缓冲区,用于在渲染线程上写入,这意味着每次调用我的事件处理程序时,它都必须进行线程阻塞,直到渲染线程为它准备好。 This leads to a noticeable lag when updating the graphics of the bitmap. 这会在更新位图图形时导致明显的延迟。

I have already tried adding a timeout to the event handler, using TryLock() , so that it won't block for such a long time and cause the performance degradation. 我已经尝试使用TryLock()向事件处理程序添加超时,这样它就不会阻塞这么长时间并导致性能下降。 This, however, causes a similar effect in that it appears to lag, because larger numbers of bitmap updates get lumped together. 然而,这会产生类似的效果,因为它似乎滞后,因为大量的位图更新被集中在一起。

Here is the relevant code from the event handler to show what exactly I am doing. 以下是来自事件处理程序的相关代码,以显示我正在做什么。 The UpdatePixels() function was written to avoid using the potentially bugged AddDirtyRect() : 编写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);
}

I can't seem to figure out how to avoid the issue of thread blocking with the WriteableBitmap, and I can't see any obvious faults in the code I have written. 我似乎无法弄清楚如何避免使用WriteableBitmap的线程阻塞问题,我在我编写的代码中看不到任何明显的错误。 Any help or pointers would be much appreciated. 任何帮助或指针将不胜感激。

Looks like you are not actually using the BackBuffer to write - only to read. 看起来你实际上并没有使用BackBuffer来编写 - 只是为了阅读。
WritePixels writes to the "front" buffer and does not require a lock. WritePixels写入“前”缓冲区并且不需要锁定。 I don't know if you have some other reason to lock it (other threads doing something), but for the code that's here i don't see why you would need to. 我不知道你是否有其他理由来锁定它(其他线程正在做某事),但对于那里的代码我不明白为什么你需要。

I guess I was wrong about not needing a lock to read from BackBuffer (*pixData) - I thought it was only for writes, but I am positive you do not need to to call Lock for WritePixels. 我想我不需要锁从BackBuffer(* pixData)读取 - 我认为它只适用于写入,但我很肯定你不需要为WritePixels调用Lock。

As far as I can tell, you are doing: 据我所知,你正在做:

  1. Lock the back buffer 锁定后缓冲区
  2. Copy something from it to an array 将其中的内容复制到数组中
  3. Call WritePixels using this new array 使用这个新数组调用WritePixels
  4. Unlock the back buffer. 解锁后台缓冲区。

How about switching 3 and 4? 切换3和4怎么样?

WritePixels may internally cause rendering thread (which has higher priority on the message queue) to get a lock on its behalf which is probably a factor in the delay you are seeing. WritePixels可能在内部导致渲染线程(在消息队列中具有更高的优先级)代表它获得锁定,这可能是您所看到的延迟的一个因素。

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

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