簡體   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