劉敏娜 李延香 魏浩



摘要:針對OpenGL渲染圖形要多次訪問緩存區(qū)的問題,提出一種OpenGL和CUDA混合編程的圖形渲染算法來加速PerlinKernel生成虛擬地形圖。首先,通過OpenGL將緩存映射到CUDA內(nèi)存空間,利用CUDA完成加速計算任務(wù);然后,為幾何圖形設(shè)置開始和結(jié)束的位置標(biāo)志,使用基元重啟對圖形進(jìn)行組合;最后,對緩沖區(qū)對象進(jìn)行渲染。實驗結(jié)果表明,改進(jìn)后的基于基元重啟的混合算法在GTX650GPU上的平均幀速率為960fps,幀速率提高6%,算法改進(jìn)后渲染方法的執(zhí)行效率提高了63倍。實驗證實基元重啟可以提高3D處理性能。
關(guān)鍵詞:圖形渲染;OpenGL;CUDA;基元重啟;Perlin
中圖分類號:TP393文獻(xiàn)標(biāo)識碼:A
1引言
圖形渲染在核試驗、DNA分子分布、天氣預(yù)報等大規(guī)模科學(xué)計算任務(wù)中扮演著重要的角色[1,2]。在OpenGL中圖形渲染是由CPU進(jìn)行單獨完成的,CPU從RAM中獲得數(shù)據(jù)并且處理數(shù)據(jù),然后寫入RAM中[3]。這樣做性能并不高,原因如下:①CPU的負(fù)載重而導(dǎo)致響應(yīng)速度慢,影響渲染速度和質(zhì)量;②圖形渲染中使用了multiDraw()方法,繪圖開銷過大。multiDraw()用一條命令代替了多條glDraw*()方法,但是使用這個方法,導(dǎo)致頂點數(shù)組擴大了1/2,大量的冗余數(shù)據(jù)傳輸?shù)紺PU中,造成極大的開銷[4-7]。
本文提出了一種CUDA和OpenGL混合圖形渲染的方法。CUDA(ComputeUnifiedDeviceArchitecture),是NVIDIA顯卡廠商推出的通用并行計算架構(gòu),該架構(gòu)使GPU能夠解決復(fù)雜的計算問題[8-10]。在本文中,為了進(jìn)一步提高數(shù)據(jù)傳輸效率,圖形渲染中引入了基元重啟,使用基元重啟可以對幾何圖形進(jìn)行組合,組合之后,需要處理的集合圖形數(shù)據(jù)更少,系統(tǒng)運行速度更快。
2.1傳統(tǒng)的OpenGL圖形渲染
OpenGL中的頂點,顏色,法線和其它頂點屬性數(shù)據(jù)都是由GLTools庫管理的。每次調(diào)用glDrawArrays、glDrawElements等一些需要頂點數(shù)據(jù)的函數(shù)時,信息是從一個帶有本地GPU的高性能系統(tǒng)中的應(yīng)用程序內(nèi)存中獲取的,數(shù)據(jù)將從應(yīng)用程序的內(nèi)存中通過PCI-Express接口總線傳遞到GPU本地內(nèi)存[11],將會耗費大量時間,降低應(yīng)用程序的運行速度。
如果將對象的所有頂點數(shù)據(jù)打包到單個緩沖區(qū)中,程序中必定包含循環(huán),會產(chǎn)生很多OpenGL調(diào)用,每次調(diào)用都會有一定的系統(tǒng)開銷。如果場景中存在大量對象,每個對象都有相關(guān)的三角形,那么對glDrawArrays的調(diào)用中的開銷將會積累,從而對應(yīng)用程序性能產(chǎn)生負(fù)面影響。
為了提高系統(tǒng)的處理效率,可以將大批非連接的三角形組合成三角形帶,如圖1所示。本來獨立的三角型需要3個頂點才能進(jìn)行表示,經(jīng)過組合之后每個三角形所需的頂點數(shù)減少到1個(不包含三角形帶中的第一個三角形)。這樣需要處理的集合數(shù)據(jù)更少了,系統(tǒng)運行速度會更快。
但是問題是,一個三角形可以通過單次調(diào)用glDrawArrays或者glDrawElements進(jìn)行渲染,一組三角形帶的渲染就要單獨對OpenGL進(jìn)行多次調(diào)用,這意味著在一個使用條帶化集合圖形的程序中有更多的函數(shù),這可能會抵消使用條帶化所獲得的性能提升。所以針對條帶化處理應(yīng)該有更好的方法來提高系統(tǒng)的性能,文中提出了基元重啟算法。
2.2基元重啟
基元重啟是設(shè)定一個可以被OpenGL狀態(tài)機識別的數(shù)據(jù)值,該數(shù)據(jù)值用于標(biāo)識當(dāng)前圖形圖元已經(jīng)繪制完成。下一個數(shù)據(jù)項表示同樣類型的另一個圖形圖元開始。基元重啟應(yīng)用在GL_TRIANGLE_TRIP、GL_TRIANGLE_FAN、GL_LINE_STRIP和GL_LINE_LOOP幾何圖形類型中。方法在一個條帶(或者扇,環(huán))結(jié)束和另一個開始時通知OpenGL。在幾何圖形中指示出一個條帶結(jié)束,下一個條帶的開始位置,實現(xiàn)時需要在元素數(shù)組中放置一個作為保留值的特殊標(biāo)志。由于OpenGL是從元素數(shù)組中獲取頂點索引(或者在內(nèi)部生成它們),在glDrawArrays非索引繪制命令情況下,會檢查這個特殊索引值,并且在遇到它時結(jié)束當(dāng)前條帶并在下一個頂點開始一個新的條帶。在基元重啟模式開啟時,OpenGL會在遇到它時停止當(dāng)前的條帶并開始一個新的條帶。
如圖2所示,三角形帶由9個頂點組成,在單個連接的三角形帶中一共產(chǎn)生了8個三角形。通過開啟基元重啟模式并將基元重啟索引設(shè)置為5,三角形帶會在頂點4處結(jié)束,如圖3所示。頂點5的實際位置將被忽略,下一個進(jìn)行處理的頂點6將稱為新的三角形帶的起始位置。所以,在向OpenGL傳遞9個頂點的情況下,得到兩個獨立的三角形帶,一個繪制3個三角形,另一個繪制2個三角形。這樣一次數(shù)據(jù)傳輸?shù)臄?shù)據(jù)量就增加了。
基元重啟的好處:
1)基元重啟的標(biāo)記值和繪圖的數(shù)據(jù)可同時生成并存放于GPU上。
2)不同基元重啟標(biāo)記值可以指定不同數(shù)量的繪圖元素,可通過給glDrawElements()指定不同的繪圖模式,繪制任意數(shù)量的線段、三角條帶、三角扇面等圖形,所以可以繪制不規(guī)則的網(wǎng)格或表面。
3)通過安排索引可以優(yōu)化渲染性能,達(dá)到在紋理單元中最大限度重用數(shù)據(jù)高速緩存。
2.3基于基元重啟的OpenGL和CUDA圖形渲染的實現(xiàn)
采用Perlin噪聲生成器創(chuàng)建虛擬地形的立體地圖[12],通過按鍵命令改變地形特征。框架分成4個獨立的文件,分別如下:
1)kernelVBO.cpp,CUDA數(shù)據(jù)生成器;
2)simpleGLmain.cpp,定義OpenGL和GLUT的主體框架;
3)simpleVBO.cpp,是通用的OpenGL與CUDA設(shè)置以及內(nèi)存管理;
4)callbackVBO.cpp,用于定義鍵盤,鼠標(biāo),顯示的回調(diào)函數(shù)。
kernelVBO
kernelVBO的處理流程如下:
1)指定Perlin噪聲計算中使用的頭文件、變量和方法;
2)colorElevation()方法根據(jù)地形各點的海拔返回像素的顏色,選用不同顏色可以為用戶呈現(xiàn)一種觀看地圖的感覺;
3)錯誤檢查函數(shù);
4)k_perlin()函數(shù)利用Perlin噪聲生成地形圖,將低于海平面的區(qū)域的高度設(shè)為0。調(diào)用cudaThreadSynchronize(),主機刷新OpenGL緩沖區(qū)需要等待Kernel執(zhí)行完畢。
simpleGLmain
simpleGLmain用來在屏幕上打開一個窗口,并設(shè)置一些基本的視角變換參數(shù)。調(diào)用gluPerspective(),在三維空間中設(shè)置一個攝像機,從該攝像機的位置觀察CUDA生成的數(shù)據(jù)。當(dāng)數(shù)據(jù)或視角位置發(fā)生變化時,OpenGL會識別和刷新顯示像素。
渲染需要進(jìn)行如下3D變換:
[1]視角變換,場景中攝像機的安放與定點;
[2]模型變換,安排場景構(gòu)成;
[3]投影變換,調(diào)整攝像機的變焦;
[4]可視區(qū)變換選擇最終的尺寸。
OpenGL的視角、模型、投影、可視區(qū)變換,以及坐標(biāo)系統(tǒng)的設(shè)定都要慎重。
simpleGLmain處理流程:
1)main函數(shù)初始化用于計算幀速率的定時器,然后調(diào)用用戶自定義的方法初始化CUDAKernel,然后注冊用戶的回調(diào)函數(shù),最后調(diào)用GLUT主循環(huán);
2)計算幀速率,并將其顯示在窗口的標(biāo)題欄中;
3)GLUT和OpenGL初始化函數(shù)創(chuàng)建一個窗口,并在3D空間中指定一個視角位置。
simpleVBO
simpleVBO的算法如下:
1)定義創(chuàng)建和映射色彩信息PBO和頂點VBO的邏輯。
2)creatVBO()調(diào)用glBufferData(),在GPU上分配圖形緩存區(qū)。GL_DYNAMIC_DRAW標(biāo)志位告知OpenGL該數(shù)據(jù)存儲會被重復(fù)修改與使用。cudaGraphicsGLRegisterBuffer()將緩沖對象注冊為CUDA可訪問數(shù)據(jù)。deleteVBO()方法將OpenGL緩沖對象解除注冊并釋放對應(yīng)的存儲空間。
3)runCUDA()完成所有色彩PBO的與頂點VBO的映射和檢索指針。地址傳給lauch_kernel()方法,并被用戶自定義的Kernel使用。Lanuch_kernel()在返回之前會等待所有的Kernel執(zhí)行完畢,因此該方法返回時可以安全交回OpenGL資源。
使用基元重啟渲染三角形時,通過glPrimituveRestartIndexNV()方法告知OpenGL狀態(tài)機重啟的標(biāo)記值,然后在OpenGL客戶狀態(tài)機上啟動基元重啟功能。調(diào)用glDrawElement()渲染數(shù)據(jù)。當(dāng)渲染結(jié)束,在OpenGL狀態(tài)機上關(guān)閉基元重啟。
3實驗結(jié)果及性能分析
實驗平臺為Intel2.3GHzCore2雙核處理器,圖形加速器為NVIDIA公司的GTX650,核心頻率為1000MHz,顯存頻率為4500MHz,顯存位寬為128b,顯存為1024MB,操作系統(tǒng)為Linux,運行的是PerlinKernel生成虛擬地形圖的示例。驅(qū)動程序的版本號是9.18.13.2057,總線采用PCIExpress3.0x16接口。應(yīng)用程序在VS2010環(huán)境編譯及執(zhí)行,采用CUDA平臺GPU設(shè)備編寫kernel程序,程序使用擴展的C語言編寫。
表1中的數(shù)據(jù)代表在最差情況幀速率方案中,程序混合使用CUDA和OpenGL所展示的能力和速度。實際的應(yīng)用程序僅會重新計算渲染場景所必需的最小數(shù)據(jù)量,顯然會獲得更高的性能。幀速率包含了重新計算每個頂點3D坐標(biāo)和顏色的時間,以及圖像中每個像素顏色所需要的時間。
在ParallelNsight中查看程序執(zhí)行時間,PerlinKernel只消耗了很短的(幾乎可以忽略不計的)執(zhí)行時間,執(zhí)行的時間主要耗費在OpenGL的緩沖交換,需要多次進(jìn)行緩沖數(shù)據(jù)交換。
在ParallelNsight中查看OpenGLAPI函數(shù)調(diào)用的情況,得到各種渲染方法的執(zhí)行時間:基元重啟,大約30μs,multidraw大約1900μs,逐一繪制各扇形:大約1000000μs。執(zhí)行時間雷達(dá)圖如下圖5所示。因為基元重啟減少了PCIe總線上的數(shù)據(jù)傳輸,避免了數(shù)據(jù)傳輸對性能的影響,因此使用基元重啟比使用優(yōu)化的OpenGL的multiDraw()方法性能要高出1900/30=63倍。
4結(jié)語
本文研究了基于基元重啟的OpenGL和CUDA圖形渲染算法,在OpenGL和CUDA之間實現(xiàn)互操作的原理,OpenGL將內(nèi)存映射入CUDA內(nèi)存之后,利用CUDA進(jìn)行并行處理。但是如果兩者之間的數(shù)據(jù)需要頻繁交換,一定程度上會降低執(zhí)行效率。通過在傳輸數(shù)據(jù)上設(shè)置基元重啟標(biāo)志,一次傳輸?shù)臄?shù)據(jù)信息量大了,這樣降低了數(shù)據(jù)的交換次數(shù),提高了處理的速度。從實驗結(jié)果上分析,采用OpenGL和CUDA混合編程改寫Perlin噪聲生成的人工地形程序比使用優(yōu)化的OpenGLMultiDraw()方法性能有了大幅度的提高。接下來需要解決的問題是OpenGL和CUDA混合編程實現(xiàn)網(wǎng)絡(luò)攝像頭的現(xiàn)場視頻流處理。
參考文獻(xiàn)
[1]張權(quán).渲染技術(shù)在虛擬仿真中的應(yīng)用[J].電子制作,2015,(09):62-63.
[2]QIAOShaojie,WANGYouwei,NIShengqiao.HighspeedimagerenderingmethodbasedonOpenGL[J].ComputerEngineeringandDesign,2011,47(21):47-49.(喬少杰,王有為,倪勝巧.基于OpenGL的快速圖像渲染方法[J].計算機應(yīng)用研究,2008,25(5):1589-1595.)
[3]孫曉潔,葉樺,費樹岷.基于OpenGL的混凝土泵車智能臂架系統(tǒng)仿真[J].科技通報,2014(05):22-25.
[4]吳恩華.輻射度技術(shù)用于隨機分維幾何面的全局光照計算[J].計算機學(xué)報,2000,(05):321-323.
[5]ZHAOJianbin,LILingqiao,YANGHuihua.Researchongraphicrenderingenginewiththreadlevelparallelismmethod[J].ComputerEngineeringandDesign,2011,47(21):47-49.(趙建斌,李靈巧,楊輝華.線程級并行計算在圖形渲染引擎中的研究[J].計算機工程與設(shè)計,2011,32(12):4143-4147.
[6]RICHARDS.WRIGHT,JR.NicholasHaemel.OpenGlSuperBibleFifthEdition[M].北京:人民郵電出版社,2012:380-420.
[7]李妮,陳錚,龔光紅.多核并行計算技術(shù)在景象匹配仿真中的應(yīng)用[J].系統(tǒng)工程與電子技術(shù),2010,32(2):428-432.
[8]張林波,遲學(xué)斌,莫則堯,等.并行計算導(dǎo)論[M].北京:清華大學(xué)出版社,2006:1-59.
[9]RobFarber.CUDAApplicationDesignandDevelopment[M].北京:機械工業(yè)出版社,2012:178-185.
[10]GORDERPF.Multicoreprocessorsforscienceandengineering[J].ComputinginScience&Engineering,2007,9(2):3-7.
[11]NVIDIACUDAProgrammingGuide,version2.1[S].NVIDIA,2008.
[12]項予,許森.基于Perlin噪聲的動態(tài)水面實時渲染[J].計算機工程與設(shè)計,2013,34(11):3966-3969.
第35卷第1期2016年3月計算技術(shù)與自動化ComputingTechnologyandAutomationVol35,No1Mar.2016第35卷第1期2016年3月計算技術(shù)與自動化ComputingTechnologyandAutomationVol35,No1Mar.2016