作者:朱金燦
來源:http://blog.csdn.net/clever101
這個問題很普遍景用。最近在研究這個問題沿腰,在網(wǎng)上搜了一些資料,再結(jié)合自己的經(jīng)驗哀蘑,談?wù)勛约旱囊恍┫敕ā?/p>
一厘贼、雙緩存能提高繪圖效率嗎界酒?
網(wǎng)上有篇文章:繪圖效率完整解決方案——三種手段提高GDI/GDI+繪圖效率,其中提到一種方法是:緩存——Bitmap或者DoubleBuffer嘴秸。緩存就是先把繪制的圖形繪制到一張內(nèi)存位圖上毁欣,然后在一次性的貼位圖庇谆,他可以提高繪圖速度,也能避免閃爍凭疮。DoubleBuffer=true是C#窗體的屬性饭耳,設(shè)置了此屬性估計系統(tǒng)本身會起用無效區(qū)的內(nèi)存位圖緩存,而不需要程序員Bitmap處理执解。
這里對雙緩存的通常做法不作介紹寞肖,網(wǎng)上的相關(guān)資料很多。說實話衰腌,我對使用雙緩存能提升繪圖效率表示懷疑逝淹,理由很簡單,同是DC桶唐,同是繪制1000條線段,有什么理由內(nèi)存DC就比窗口DC快(當(dāng)然這個我沒有作具體的測試茉兰,這個有空可以測試下)尤泽。我還稍微懷疑使用雙緩存繪圖比直接使用窗口DC繪圖還慢一些,理由有二:一是使用雙緩存需要增加創(chuàng)建內(nèi)存DC和內(nèi)存位圖的操作规脸;二是使用雙緩存還需要增加一個把內(nèi)存DC拷貝到窗口DC的操作坯约。那么雙緩存的主要作用是什么?其實就是解決繪圖過程的閃爍問題莫鸭,改善繪圖效果闹丐。
二、Windows環(huán)境下二維繪圖引擎的選取
和繪圖效率的一個重要相關(guān)因素是繪圖引擎被因。Windows環(huán)境下二維繪圖引擎有多種選擇:GDI卿拴、GDI+、DirectDraw梨与、QT堕花、Agg、Cairo粥鞋、skia缘挽、Direct2D、Direct3D呻粹、OpenGL等壕曼。下面我逐一作一個簡單的分析:
【GDI】
微軟原生的二維繪圖引擎。
優(yōu)點:微軟的全力支持等浊,作為操作系統(tǒng)核心層效率方面不用擔(dān)心腮郊,支持多種開發(fā)框架(含語言):Win SDK、MFC筹燕、Delphi等伴榔。
缺點:基于過程纹蝴,缺乏面向?qū)ο螅褂闷饋聿惶奖阕偕伲恢С址翠忼X塘安,不支持復(fù)雜的繪圖效果(這個相對于GDI+而言)。
【GDI+】
微軟后來推出的二維繪圖引擎援奢。
優(yōu)點:微軟的全力支持兼犯,支持多種開發(fā)框架(含語言):Win SDK、MFC集漾、Delphi等切黔,可以實現(xiàn)復(fù)雜的繪圖效果,如反鋸齒具篇、路徑畫刷等纬霞;面向?qū)ο蟮?a target="_blank" rel="nofollow">架構(gòu),使用起來比較方便驱显。
缺點:繪圖效率較GDI稍低诗芜,繪圖交互性不如GDI(缺少GDI的支持位運算的繪圖模式),開啟反鋸齒后效率不如QT埃疫。
有關(guān)GDI和GDI+的詳細比較伏恐,請看我以前寫的一篇文章:GDI和GDI+的應(yīng)用場合思考。
【DirectDraw】
從GDI栓霜、GDI+到Direct 2D的一個過渡產(chǎn)品翠桦,微軟已明確表示不推薦使用,在MicrosoftDirectX SDK (June 2010)已看不到它的身影胳蛮,在此不作介紹销凑。
【QT】
開源跨平臺(基于LGPL協(xié)議),面向?qū)ο蟮姆绞浇M織仅炊,使用起來較為方便闻鉴。
【Agg】
C++編寫的開源繪圖引擎(基于GPL協(xié)議)
【Cairo】
C編寫的開源繪圖引擎(基于LGPL協(xié)議),大名鼎鼎的FireFox就是用這個繪圖引擎的茂洒。
有關(guān)Agg和Cairo請參考這篇文章:Agg vs. Cairo 二維繪圖引擎之比較和選擇孟岛。該文作者比較推崇Cairo,但據(jù)我公司的一個同事介紹:Cairo的繪圖效率很慢督勺。具體我沒有做過測試渠羞。
【Skia】
Google的Android的繪圖引擎。
【Direct2D】
微軟在Windows Vista及之后的Windows版本推出的意在取代GDI智哀、GDI+的二維繪圖引擎次询,支持硬件加速。
【Direct3D】
微軟開發(fā)的3D繪圖引擎瓷叫。
【OpenGL】
SGI開發(fā)的3D繪圖引擎屯吊。
上面簡單對 Windows下的二維繪圖引擎作了一個簡單介紹送巡。我的推薦是:開發(fā)商業(yè)產(chǎn)品一般情況下在Windows XP及以下Windows版本使用GDI和GDI+,在Windows Vista及其之后的Windows版本(如Win 7)使用Direct2D盒卸。理由是:跨平臺的繪圖引擎如Agg骗爆、Cairo之類的,出于跨平臺封裝的需要蔽介,必然會犧牲一部分性能摘投,就是說它本來就是封裝GDI的,怎么可能超出GDI的繪圖效率呢虹蓄?還有就是諸如Agg還有開源協(xié)議的限制犀呼,這樣就排除了開源二維繪圖引擎。我也不推薦使用Direct3D薇组、OpenGL等三維繪圖引擎進行二維繪圖外臂,理由是三維繪圖可以利用硬件加速,繪圖速度應(yīng)該比GDI律胀、GDI+快宋光,但三維繪圖引擎一般是基于三維的數(shù)據(jù)結(jié)構(gòu)進行組織的,對二維繪圖并不合適累铅,比如以前我們曾利用OpenGL進行二維繪圖,發(fā)現(xiàn)OpenGL在二維一些操作并不合適站叼,如二維中的點娃兽、線捕捉、自定義圖例的添加尽楔、打印的支持等等投储。所以我傾向于使用GDI、GDI+阔馋。GDI的一大缺點是由于不是面向?qū)ο蠼M織的玛荞,使用起來較為繁瑣。這個我覺得可以參考GDI+的面向?qū)ο蠓庋b的方式對GDI進行封裝呕寝。Direct 2D是微軟在后XP時代開發(fā)的開發(fā)二維繪圖引擎勋眯。微軟出于兼容性的考慮還會繼續(xù)對GDI、GDI+進行支持下梢,但毫無疑問微軟的策略是要Direct 2D取代GDI和GDI+的客蹋,因此在WindowsVista及其之后的Windows上進行二維繪圖開發(fā)我建議是直接使用Direct2D。Direct 2D支持硬件加速孽江,在繪圖效率應(yīng)有一定程度的提升讶坯。
三.提高GDI繪圖效率的常用做法
提高GDI繪圖效率的一般原則可以簡單概括為:盡量減少無效繪圖區(qū)域,盡量減少不必要的繪圖操作岗屏。
盡量減少繪圖區(qū)域的通常做法是:
- 設(shè)置裁剪區(qū)辆琅。
裁剪區(qū)的作用就是:只有在這個區(qū)內(nèi)的繪圖過程才會真正有效漱办,在區(qū)外的是無效的,即使在區(qū)外執(zhí)行了繪圖函數(shù)也是不會顯示的婉烟。因為多數(shù)情況下窗口重繪的產(chǎn)生大多是因為窗口部分被遮擋或者窗口有滾動發(fā)生娩井,改變的區(qū)域并不是整個圖形而只有一小部分,這一部分需要改變的就是pDC中的裁剪區(qū)了隅很。因為顯示(往內(nèi)存或者顯存都叫顯示)比繪圖過程的計算要費時得多撞牢,有了裁剪區(qū)后顯示的就只是應(yīng)該顯示的部分,大大提高了顯示效率叔营。但是這個裁剪區(qū)是MFC設(shè)置的屋彪,它已經(jīng)為我們提高了顯示效率,在進行復(fù)雜圖形的繪制時如何進一步提高效率呢绒尊?那就只有去掉在裁剪區(qū)外的繪圖過程了畜挥。可以先用pDC->GetClipBox()得到裁剪區(qū)婴谱,然后在繪圖時判斷你的圖形是否在這個區(qū)內(nèi)蟹但,如果在就畫,不在就不畫谭羔。
- 減少無效區(qū)域华糖。
在GDI繪圖中,被標(biāo)記為無效矩形的區(qū)域直到WM_PAINT消息被處理完之后才會消失瘟裸。因此在繪圖中應(yīng)盡量避免使用Invalidate函數(shù)(該函數(shù)使整個客戶區(qū)設(shè)置為無效區(qū)域)客叉,而應(yīng)在多使用InvalidateRect函數(shù)具體比如你想改變某條線的線型,應(yīng)首先精確計算改線的屏幕范圍话告,然后改變其線型后調(diào)用InvalidateRect函數(shù)進行局部更新兼搏。
盡量減少不必要的繪圖操作。比如二維矢量繪圖中一般有一個滑動鼠標(biāo)滾輪進行全圖縮放的操作沙郭。其實在縮放過程中佛呻,每一次WM_MOUSEWHEEL消息的處理都必須是先把所有的繪圖對象重繪一次。這個其實并沒有必要病线。一個優(yōu)化方案是通過設(shè)置一個標(biāo)記吓著,在繪圖循環(huán)中(一般在復(fù)雜繪圖中都把繪圖對象保存在一個數(shù)組或鏈表中),當(dāng)這個標(biāo)記為TRUE時送挑,就停止繪圖夜矗,當(dāng)這個標(biāo)記為FALSE則不影響繪圖。在處理WM_MOUSEWHEEL消息是让虐,先設(shè)置這個標(biāo)記為TRUE紊撕,然后發(fā)送一個重繪消息,設(shè)置標(biāo)記為FALSE進行重繪赡突。然后在繪圖循環(huán)時先判斷這個標(biāo)記是否TRUE对扶,為TRUE則退出繪圖区赵,然后截取鼠標(biāo)消息,優(yōu)先WM_MOUSEWHEEL消息浪南,大致代碼如下:
MSG msg;
// hView為繪圖窗口句柄
if(PeekMessage(&msg,hView,WM_MOUSEFIRST,WM_MOUSELAST,PM_REMOVE
))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
這樣可以造成這樣的效果:就是假如當(dāng)進行第二次滾動笼才,還在進行第一次滾動時的操作,就立即退出繪圖循環(huán)络凿,這樣就能大大減少不必要的繪圖操作骡送。
參考文獻:
繪圖效率完整解決方案——三種手段提高GDI/GDI+繪圖效率,作者:fyhui
GDI和GDI+的應(yīng)用場合思考絮记,作者:朱金燦
Agg vs. Cairo 二維繪圖引擎之比較和選擇摔踱,作者:張亮
用MFC如何高效地繪圖
GDI使用經(jīng)驗總結(jié),作者:楊濤
DrawCli代碼中雙緩沖怨愤,裁剪區(qū)技術(shù)以及坐標(biāo)變換等技術(shù)分析