前言:
閃爍問題,之前的經驗是使用雙緩沖,借此機會,把雙緩沖的研究心得總結下。
雙緩沖的含義:
緩沖這個詞,相信大家都不陌生,Cache。主要是為了解決上下游(或者模塊、或者系統)等性能不匹配問題。如果把上游看成“生產者”,下游看成“消費者”,當“生產者”與“消費者”的處理速度不同時,為了避免干等,中間會加一些緩沖區。
無緩沖,雙方都容易阻塞。
最常用的生產者-消費者模型,增加彈性緩沖,缺點是每生產+每消費都需要加鎖
雙緩沖,等消費者隊列為空時加鎖,執行exchange(如swap方法),大大減少了加鎖次數。
雙緩沖在界面的使用:
GDI雙緩沖:
WM_ERASEBKGND : 返回1,禁止背景重繪
HDC hDc = ::GetDC( m_hWnd) ; RECT rcDest; HDC hMemDc = CreateCompatibleDC(hDc); HBITMAP hMemBitmap = CreateCompatibleBitmap(hDc); //內存畫布,放到內存DC中就可以在內存中畫圖了 HBITMAP hOldBitmap = ::SelectObject (hDC, hBitmap); //....hMemDc作畫 ::BitBlt (m_hDestDC, rc.left, rc.top, rc.Width(), rc.Height(), hDC, rc.left, rc.top, SRCCOPY); //拷貝到顯示器緩沖 //資源釋放與還原 ::SelectObject (hDC, hOldBitmap); DeleteObject(hMemBitmap); DeleteDC(hMemDc); ReleaseDC(m_hWnd,hDc);
WTL雙緩沖:
CDoubleBufferImpl 在AtlFrame.h中。
1.首先繼承自CDoubleBufferImpl
class TCtrl: public CWindowImpl< TCtrl>, public WTL::CDoubleBufferImpl<TCtrl> // 繼承雙緩沖類
2.由於雙緩沖類中已經處理了WM_ERASEBKGND 和WM_PAINT消息,所以需要從你的代碼中刪除對這些消息的處理。然后加上雙緩沖的消息處理即可。
BEGIN_MSG_MAP(TCtrl) // MESSAGE_HANDLER(WM_PAINT, OnPaint) CHAIN_MSG_MAP( WTL::CDoubleBufferImpl<TCtrl>) END_MSG_MAP()
3.增加一個DoPaint函數,函數聲明如下:
void DoPaint(CDCHandle dc);
4.將原來OnPaint函數中的代碼移到DoPaint中,注意原來的CPaintDC需要改用參數中的CDCHandler
void TCtrl::DoPaint( CDCHandle dc ) { //CPaintDC dc(m_hWnd);
dc.MoveTo( xx… )
}
Duilib雙緩沖:
Duilib使用的GDI+引擎,也已經支持雙緩沖,這里簡單介紹下它的實現過程
1、Duilib也默認處理了WM_REASEBKGND 並返回1;
2、IRenderContext 類負責渲染。
目前由RenderContext_GdiPlus來實現。
1)構造函數中,創建內存DC
2) 獲取繪圖區域后,創建內存Bitmap
然后作畫,細節暫時略,后續源碼剖析會補充,敬請期待。
最后,拷貝到顯示器緩沖。