提高二維矢量繪圖效率之一般做法

作者:朱金燦
來源: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ù)分析

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末派敷,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子撰洗,更是在濱河造成了極大的恐慌篮愉,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,378評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件差导,死亡現(xiàn)場離奇詭異试躏,居然都是意外死亡,警方通過查閱死者的電腦和手機设褐,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,356評論 2 382
  • 文/潘曉璐 我一進店門颠蕴,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人络断,你說我怎么就攤上這事裁替∠盥辏” “怎么了貌笨?”我有些...
    開封第一講書人閱讀 152,702評論 0 342
  • 文/不壞的土叔 我叫張陵,是天一觀的道長襟沮。 經(jīng)常有香客問我锥惋,道長,這世上最難降的妖魔是什么开伏? 我笑而不...
    開封第一講書人閱讀 55,259評論 1 279
  • 正文 為了忘掉前任膀跌,我火速辦了婚禮,結(jié)果婚禮上固灵,老公的妹妹穿的比我還像新娘捅伤。我一直安慰自己,他們只是感情好巫玻,可當(dāng)我...
    茶點故事閱讀 64,263評論 5 371
  • 文/花漫 我一把揭開白布丛忆。 她就那樣靜靜地躺著祠汇,像睡著了一般。 火紅的嫁衣襯著肌膚如雪熄诡。 梳的紋絲不亂的頭發(fā)上可很,一...
    開封第一講書人閱讀 49,036評論 1 285
  • 那天,我揣著相機與錄音凰浮,去河邊找鬼我抠。 笑死,一個胖子當(dāng)著我的面吹牛袜茧,可吹牛的內(nèi)容都是我干的菜拓。 我是一名探鬼主播,決...
    沈念sama閱讀 38,349評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼惫周,長吁一口氣:“原來是場噩夢啊……” “哼尘惧!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起递递,我...
    開封第一講書人閱讀 36,979評論 0 259
  • 序言:老撾萬榮一對情侶失蹤喷橙,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后登舞,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體贰逾,經(jīng)...
    沈念sama閱讀 43,469評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,938評論 2 323
  • 正文 我和宋清朗相戀三年菠秒,在試婚紗的時候發(fā)現(xiàn)自己被綠了疙剑。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,059評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡践叠,死狀恐怖言缤,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情禁灼,我是刑警寧澤管挟,帶...
    沈念sama閱讀 33,703評論 4 323
  • 正文 年R本政府宣布,位于F島的核電站弄捕,受9級特大地震影響僻孝,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜守谓,卻給世界環(huán)境...
    茶點故事閱讀 39,257評論 3 307
  • 文/蒙蒙 一穿铆、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧斋荞,春花似錦荞雏、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,262評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽羡疗。三九已至,卻和暖如春别洪,著一層夾襖步出監(jiān)牢的瞬間叨恨,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評論 1 262
  • 我被黑心中介騙來泰國打工挖垛, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留痒钝,地道東北人。 一個月前我還...
    沈念sama閱讀 45,501評論 2 354
  • 正文 我出身青樓痢毒,卻偏偏與公主長得像送矩,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子哪替,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,792評論 2 345

推薦閱讀更多精彩內(nèi)容

  • 發(fā)現(xiàn) 關(guān)注 消息 iOS 第三方庫栋荸、插件、知名博客總結(jié) 作者大灰狼的小綿羊哥哥關(guān)注 2017.06.26 09:4...
    肇東周閱讀 12,024評論 4 62
  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 171,509評論 25 707
  • 學(xué)習(xí)到了兩句話 < 因小失大 > <貪多嚼不爛> 看了范冰冰演得潘金蓮的電影瞬間顏范轉(zhuǎn)忠實粉絲凭舶,因此記住了不能因小...
    大溪的清晨島嶼閱讀 131評論 0 1
  • “一旦走出了那些與“習(xí)慣”之間的糾纏和掙扎晌块,自然也就明白,有時我們只是有太多遲疑帅霜,有時我們只是臆想出了太多的恐懼匆背,...
    樂小檬閱讀 187評論 0 0
  • 風(fēng)云際會,萬事興身冀。
    10086好閱讀 166評論 0 0