~~
先前研究渲染系統(tǒng)線程化的時(shí)候翻到了這篇文章,于是一邊看一邊寫出了漢語(yǔ)。 文中寫多地方翻譯得很不通順,見(jiàn)諒。
譯者序:偶然在網(wǎng)上看到這篇文章,自己很想仔細(xì)研究一下。但搜尋半天不見(jiàn)中文版。于是自己斗膽翻譯了一下。文中不免有漏洞百出,甚至可以說(shuō)有些地方不及Google翻譯得好。但這樣總的來(lái)說(shuō)是出了一個(gè)中文版,而我自己在翻譯過(guò)程中也會(huì)停下來(lái)仔細(xì)思考。
OGRE這個(gè)線程化的文章很老了。因?yàn)镺GRE目前已經(jīng)支持多線程渲染。 這篇文章貌似是某些人研究出來(lái)的三個(gè)線程化方案,并給出了測(cè)試結(jié)果。以向OGRE社區(qū)證明線程化方案的可行性。 對(duì)于許多想研究渲染線程化的人來(lái)說(shuō),是一篇值得參考的文章。文中提出了許多在不同情況下線程化時(shí)遇到的問(wèn)題,以及需要注意的問(wèn)題。值得一讀/
介紹
OGRE3D(a.k.a. Ogre)是目前最常用的開(kāi)放源代碼 3D 引擎之一。它是一款功能完善的通用 3D 引擎,可應(yīng)用于從游戲到科學(xué)模擬等多種商用產(chǎn)品。該引擎由來(lái)自開(kāi)放源代碼社區(qū)的數(shù)百名技術(shù)人員歷經(jīng)五年時(shí)間而開(kāi)發(fā)成功。如欲了解 Ogre 的詳細(xì)信息,請(qǐng)?jiān)L問(wèn)網(wǎng)站 www.ogre3d.org 。
然而,盡管 Ogre 功能強(qiáng)大,但是它卻在技術(shù)上存在一個(gè)重要缺憾,那就是它無(wú)法在系統(tǒng)中充分利用多個(gè)處理器的優(yōu)勢(shì)。目前,英特爾已經(jīng)有多款雙核產(chǎn)品上市,而超線程(HT)技術(shù)更是在多年前就已應(yīng)用在英特爾® 奔騰® 4 處理器中。將 Ogre 線程化所實(shí)現(xiàn)的性能增益將絲毫不遜色于添加第二枚處理器所實(shí)現(xiàn)的性能增益。
本文將向您介紹將 Ogre 渲染系統(tǒng)線程化的三種不同處理方法,并且我們將根據(jù)下文所描述的線程化目的,選擇一種方法進(jìn)行完整實(shí)施。
線程化目標(biāo)
當(dāng)我們?cè)趯?duì)OGRE線程化時(shí),需要實(shí)現(xiàn)以下幾個(gè)目標(biāo):
·通過(guò)改動(dòng)最少的OGRE源碼以使OGRE社區(qū)接受。
·在雙核處理器上,相對(duì)于非線程化渲染的OGRE系統(tǒng)來(lái)說(shuō),提升25%的FPS,以平衡應(yīng)用程序的CPU和GPU使用率
·在用戶不知道的情況下對(duì)SDK包中的DEMO進(jìn)行必要的變動(dòng),而不讓用戶在畫(huà)面上有任何察覺(jué)。
假設(shè)
本文提及了OGRE中的許多類,以及使用了OGRE中的許多程序片段。所以,這里假設(shè)讀者都是對(duì)OGRE的源碼非常了解或者已經(jīng)對(duì)源碼進(jìn)行過(guò)快速的查閱,否則將很難理解這些OGRE的特性。同樣,讀者也應(yīng)該對(duì)線程的概念有所了解。這里就不再介紹更多關(guān)于線程的內(nèi)容。
限制
這里所討論的所有實(shí)現(xiàn),都沒(méi)有在超過(guò)兩個(gè)處理器的機(jī)器上實(shí)驗(yàn)過(guò)。因此,這些技術(shù)對(duì)于雙核處理器或雙核心系統(tǒng)最適合不過(guò)。以后的文章中將會(huì)討論如何在OGRE中創(chuàng)建一個(gè)線程隊(duì)列,使OGRE以及使用OGRE的應(yīng)用程序都能夠在雙核處理器以及多核上得到性能的提升。
線程化OGRE渲染系統(tǒng)使用到的技術(shù)
OGRE中有很多地方都可以被線程化,但線程化最能在多核上提升性能的是渲染系統(tǒng)。渲染系統(tǒng)在OGRE占據(jù)了巨大的一塊,并且從某種意義上講,它能單獨(dú)地被外部程序訪問(wèn)。下面介紹三種將OGRE渲染系統(tǒng)線程化的例子。
1、 在OGRE中對(duì)于渲染的調(diào)用可以被放在他自己的線程中。
2、 一個(gè)線程化層可以被放在OgreMain和渲染系統(tǒng)插件之間。
3、 渲染系統(tǒng)插件可以單開(kāi)一個(gè)線程來(lái)調(diào)用圖形API。
上面這三種方案都有各自的優(yōu)缺點(diǎn),本文將會(huì)一一討論。
線程化并不會(huì)對(duì)每個(gè)應(yīng)用程序有利
注意,線程化只對(duì)那種花費(fèi)在圖形調(diào)用API和邏輯處理上的時(shí)間很接近的應(yīng)用程序有好處。若其中一個(gè)較另一個(gè)差別很大,則看不到明顯的效果。
技術(shù)方案1:線程化OgreMain(高級(jí)線程化手段)
在OgreMain中進(jìn)行線程化是一種最高級(jí)的線程化手段,也表示能獲得最高級(jí)的潛在性能。這是因?yàn)镺gre在做一次渲染的時(shí)候,需要做很多事情,并且不僅僅是提交某些命令或數(shù)據(jù)到顯卡。比如,決定哪個(gè)攝相機(jī)是活動(dòng)攝相機(jī),遍歷場(chǎng)景中所有可見(jiàn)物體,標(biāo)志所有可見(jiàn)物體去渲染,等等。 下面的插圖展示了一個(gè)Ogre渲染過(guò)程(為了簡(jiǎn)化起見(jiàn),一些東西被忽略)。高級(jí)線程化將導(dǎo)致這里所有的過(guò)程被放置在他自己的線程里。
線程化問(wèn)題
采用這種方案有一個(gè)主要的問(wèn)題就是,兩個(gè)線程中將會(huì)發(fā)生代碼重疊。打個(gè)比方,主線程和渲染線程都需要訪問(wèn)場(chǎng)景中某個(gè)場(chǎng)景對(duì)象的相同數(shù)據(jù)。主線程要更新它的位置和方向,然而此時(shí)渲染線程要讀這些信息或者在渲染線程渲染前主線程修改了這些內(nèi)容。從而導(dǎo)致渲染幀的內(nèi)容與實(shí)際不符,會(huì)相差一幀。特別地,當(dāng)渲染在渲染一個(gè)對(duì)象時(shí)主線程卻要把它刪除,就會(huì)出問(wèn)題。如下圖所示:
除了剛剛提到的線程自身的問(wèn)題外,同樣也存在處理器共享失敗的問(wèn)題。當(dāng)一個(gè)變量被一個(gè)線程更新的時(shí)候,這個(gè)變量是處于這個(gè)線程所在的CPU緩存行中的,而另外一個(gè)線程也會(huì)訪問(wèn)這個(gè)緩存行中的內(nèi)容的相同數(shù)據(jù)。由于它們共享緩存行,一個(gè)處理器需要清空整個(gè)緩存行,不管其它處理器是否做了修改。這就是這個(gè)高級(jí)線程方方案的問(wèn)題所在。因?yàn)橹骶€程和渲染線程使用同樣的類的實(shí)例。 由于類體變量被相繼地放置在內(nèi)存中,因此他們要共享同樣的緩存行。關(guān)于更多緩存行共享失敗的問(wèn)題。可以查看相關(guān)文章。
避免問(wèn)題
為了避免上面提到的線程問(wèn)題,這里提供了兩個(gè)可以安全訪問(wèn)和更新對(duì)象的解決方案。
1、 使用一個(gè)更新隊(duì)列。
2、 復(fù)制對(duì)象
更新隊(duì)列的方案通過(guò)維持一個(gè)對(duì)象的更新隊(duì)列來(lái)防止訪問(wèn)重疊。見(jiàn)下圖。 更新將只發(fā)生一次,即當(dāng)主線程準(zhǔn)備讓渲染線程開(kāi)始渲染的時(shí)候。當(dāng)然,你需要等待渲染線程完成后才能進(jìn)行第二次啟用。這個(gè)方案有一個(gè)缺點(diǎn),就是單處理系統(tǒng)上的CPU反而會(huì)承受這個(gè)更新隊(duì)列的額外負(fù)擔(dān),而享受不到這個(gè)更新隊(duì)列的好處。另一個(gè)缺點(diǎn)就是,當(dāng)對(duì)硬件資源(如索引,頂點(diǎn)緩沖等)改變時(shí)。排隊(duì)改變這些資源將會(huì)很困難,因?yàn)檫@些數(shù)據(jù)都非常大。
復(fù)制對(duì)象的方案從本質(zhì)上講,就是為一個(gè)經(jīng)常變動(dòng)的對(duì)象復(fù)制副本。在這種方案下,使用OGRE的應(yīng)用程序?qū)⒈灰髲?fù)制一個(gè)經(jīng)常需要更新的對(duì)象,因?yàn)橹挥兴滥男?duì)象是需要經(jīng)常更新的。應(yīng)用程序也不得不按照一定的方式來(lái)寫:對(duì)象的處理是在對(duì)象被顯示后的下一幀。(這點(diǎn)沒(méi)有太明白,貌似意思是說(shuō),對(duì)象的處理和渲染為兩個(gè)幀,一個(gè)幀拿來(lái)渲染,一個(gè)幀拿來(lái)處理,看到下面那圖應(yīng)該是這個(gè)意思)。當(dāng)然,如果你的應(yīng)用程序并不每幀更新對(duì)象,這也是一個(gè)問(wèn)題,在這種情況下,你的對(duì)象有可能是在幾幀后才被訪問(wèn),這樣就會(huì)導(dǎo)致沖突。也可以對(duì)其做一些優(yōu)化,如只有對(duì)象中主線程和渲染線程要共享的數(shù)據(jù)才被復(fù)制,以此來(lái)減少負(fù)擔(dān)。在這樣的情況下對(duì)象將不再是一個(gè)復(fù)制品,但是將會(huì)有一個(gè)雙緩沖用于存放你復(fù)制的這些東西。
在下圖中,注意那個(gè)object X 將保持一致性(假設(shè)更新速度大于30FPS)。但是object Y將不會(huì),因?yàn)樵谇耙粠M(jìn)行了縮放,但是這個(gè)數(shù)據(jù)并沒(méi)有被體現(xiàn)在復(fù)制對(duì)象中。
圖里有許多關(guān)于同步的東西被我刪掉了,但是上面著實(shí)能夠反應(yīng)這個(gè)技術(shù)的實(shí)現(xiàn)形式。
上面說(shuō)到的兩個(gè)技術(shù)中,并沒(méi)有任何一個(gè)技術(shù)被OGRE社區(qū)接受,它們都需要大量修改OGRE代碼,因此并未繼續(xù)。一個(gè)需要復(fù)制對(duì)象數(shù)據(jù)來(lái)控制數(shù)據(jù)修改的例子便是Frustum::updataView函數(shù)和_update函數(shù),對(duì)于實(shí)現(xiàn)這個(gè)函數(shù)的所有類,都需要在渲染中被調(diào)用,以及OGRE的其它地方(渲染以外的地方)。
在哪里進(jìn)行線程化
在OgreMain中進(jìn)行線程化的一個(gè)理想的地方便是在Root::renderOneFrame中。這個(gè)函數(shù)調(diào)用了主渲染_Root::_updateAllRenderTargets,這個(gè)函數(shù)可以輕易地被封裝一次。
下面是一些實(shí)現(xiàn)上面想法的示例代碼。
_wait 和_set函數(shù)演示了操作系統(tǒng)依賴的同步函數(shù)調(diào)用,例如,WINDOWS版本的_waitForRenderingComplete將會(huì)包含一個(gè)WaitForSingleObject調(diào)用。注意當(dāng)多線程開(kāi)啟的時(shí)候,應(yīng)該在真正渲染完成之前調(diào)用_fireFrameEnded函數(shù)。
技術(shù)方案2:創(chuàng)建一個(gè)線程渲染系統(tǒng)層(中級(jí)線程化手段)
創(chuàng)建一個(gè)線程化的渲染系統(tǒng)層對(duì)OGRE渲染系統(tǒng)來(lái)說(shuō)是一個(gè)很不顯眼的方案。但是由于OGRE渲染系統(tǒng)的復(fù)雜性,它也是最困難的方案。渲染層從本質(zhì)上講是對(duì)渲染系統(tǒng)插件(如D3D,OPENGL)的一個(gè)封裝。想要在OGRE中創(chuàng)建和集成一個(gè)這樣的附加渲染系統(tǒng),只需要對(duì)OGRE進(jìn)行較少的改動(dòng)。但是創(chuàng)建創(chuàng)建一個(gè)線程化的渲染系統(tǒng)層,又是另一回事了。
為了創(chuàng)建一個(gè)線程化的渲染系統(tǒng)層,你至少需要在OgreMain中實(shí)現(xiàn)Ogre::RenderSystem 類和Ogre:RenderWindow類。這兩個(gè)類僅僅是界于Ogre和實(shí)際的渲染器插件之間的一個(gè)層。這個(gè)層的工作并不是簡(jiǎn)單的將對(duì)插件的函數(shù)調(diào)用進(jìn)行封裝。需要決定要做哪些什么,以便調(diào)用渲染器插件,因?yàn)檫@個(gè)方案的目標(biāo)是將渲染的工作分離到另一個(gè)線程中。在實(shí)面這些類的函數(shù)時(shí),有幾事情需要思考。
·習(xí)慣性地(如,所有函數(shù)調(diào)用僅僅是在開(kāi)始渲染之前調(diào)用。)可以僅是對(duì)渲染器插件的直接調(diào)用,(相當(dāng)于函數(shù)轉(zhuǎn)發(fā))。也可以在包裝的同時(shí)進(jìn)行一些必要的初始化。
·在調(diào)用渲染器插件進(jìn)行創(chuàng)建操作時(shí),將需要等待前一幀渲染完成。并且需要一個(gè)包裝類來(lái)包裝那個(gè)渲染器返回(提供一個(gè)已經(jīng)存在的實(shí)例)的與創(chuàng)建相當(dāng)?shù)念悺R粋€(gè)需要包裝類的好例子便是渲染器插件返回的RenderWindow類。這個(gè)類的實(shí)例通過(guò)RenderWindow:createRenderWindow創(chuàng)建并返回。
·某些函數(shù)需要訪問(wèn)基類。RenderSystem和RenderWindow類需要調(diào)用一些基類方法來(lái)完成一些內(nèi)部事情。在OGRE中不這樣做,會(huì)導(dǎo)致不正確的行為。
·渲染用的函數(shù)需要被排隊(duì),以便享受到多線程的好處。渲染線程將會(huì)遍歷那個(gè)隊(duì)列,并按順序調(diào)用那些函數(shù)。 RenderWindow中的swapBuffers函數(shù)是一個(gè)例外。它的包裝函數(shù)既要加入渲染隊(duì)列管理,但它又是向渲染線程發(fā)出信號(hào),執(zhí)行渲染隊(duì)列中的函數(shù)的地方。
上面提到的幾點(diǎn)描述了實(shí)現(xiàn)這個(gè)方案需要做的事情,也還有其它一些小問(wèn)題需要考慮,并且一些問(wèn)題需要在實(shí)現(xiàn)的時(shí)候處理。
線程化的問(wèn)題
這個(gè)實(shí)現(xiàn)和“方案1:高級(jí)線程化方案”一樣,存在同樣的問(wèn)題。除開(kāi)這種情況,最好的解決方案就是復(fù)制需要共享的數(shù)據(jù)。因?yàn)檫@個(gè)中間層不擁有Ogre中的類。也有其它一些從“低級(jí)線程化方案”中借鑒而來(lái)的解決辦法來(lái)完成這個(gè)實(shí)現(xiàn),從而對(duì)顯卡資源提供一個(gè)線程安全訪問(wèn)手段。
在哪里線程化
正如先前提到的,這將是線程化Ogre渲染系統(tǒng)的一個(gè)最不顯眼的方案。所需要對(duì)Ogre做的輕微改變僅是對(duì)Ogre現(xiàn)有的渲染系統(tǒng)增加一個(gè)線程化的渲染系統(tǒng)層。像這樣
技術(shù)方案3:線程化渲染插件(低級(jí)線程化手段)
線程化一個(gè)特定的渲染插件帶來(lái)了最低級(jí)的適應(yīng)性,因?yàn)樗吞囟ǖ募夹g(shù)(如D3D,OPENGL)綁定起來(lái)。但是它也使你能夠最大限度地操縱硬件資源。
實(shí)現(xiàn)這個(gè)方案最干凈利落的辦法就是創(chuàng)建一個(gè)介于API和渲染插件之間的層,用來(lái)處理線程化。(如下圖)
在這種方法下,它僅僅是用你的層來(lái)替換API接口。并且每個(gè)一調(diào)用從渲染插件的調(diào)用都是線程安全的,因?yàn)槟愕倪@個(gè)層處理了所有的調(diào)用。為D3D做這個(gè),僅僅是用你自己的包裝類和方法替換了IDirect3D的接口。對(duì)于OPENGL,你將移除所有的OPENGL頭文件,并用你自己包裝好后的頭文件替換掉它們。有可能你需要用一個(gè)命名空間來(lái)包裝OPENGL函數(shù),以免出現(xiàn)名詞沖突。
這個(gè)方案依然和“中級(jí)線程化手段”一樣需要考慮些線程化相關(guān)的東西。
·初始化不需要多線程
·創(chuàng)建函數(shù)以及一些get函數(shù)需要在渲染完一幀前等待。
·渲染命令,和伴隨參數(shù)將需要加入隊(duì)列中。
關(guān)于索引和頂點(diǎn)緩沖的加鎖
對(duì)于所有的方案,都存在一個(gè)使用硬件資源時(shí)的潛在線程問(wèn)題。對(duì)索引頂點(diǎn)緩沖區(qū)的加鎖就是一個(gè)很大的挑戰(zhàn),因?yàn)槟承?yīng)用程序在執(zhí)行的時(shí)候總是會(huì)反復(fù)對(duì)這些緩沖區(qū)進(jìn)行加鎖和解鎖。比如對(duì)于動(dòng)態(tài)緩沖區(qū),總是會(huì)每幀都改變它的內(nèi)容來(lái)實(shí)現(xiàn)畫(huà)面的變化。一些應(yīng)用程序也會(huì)重用緩沖區(qū)以使多個(gè)對(duì)象每幀都能夠共享同樣的頂點(diǎn)和索引緩沖區(qū)。為了解決這個(gè)問(wèn)題,我們需要緩沖這些緩沖區(qū)。然而,可以通過(guò)很多方法來(lái)實(shí)現(xiàn),下面有兩種緩沖辦法:
1、 部分緩沖區(qū)加鎖,這是一個(gè)類似于雙緩沖的緩沖技術(shù)。我們將在顯卡中創(chuàng)建兩個(gè)緩沖區(qū),而不是一個(gè)。在這種情況下,當(dāng)應(yīng)用程序在寫一個(gè)緩沖區(qū)的時(shí)候,渲染線程將使用另一個(gè)緩沖區(qū)中的數(shù)據(jù)進(jìn)行渲染。這個(gè)方案可以提升渲染速度但是有一個(gè)缺點(diǎn),就是會(huì)消耗更多的顯存。并且不能處理應(yīng)用程序在每一幀對(duì)同一緩沖區(qū)連續(xù)寫兩次的情況。
2、 完全緩沖區(qū)加鎖,這個(gè)技術(shù)保持一個(gè)對(duì)于緩沖區(qū)的所有鎖的副本。保留一個(gè)本地緩沖區(qū)并在上面進(jìn)行所有的修改。當(dāng)解鎖它的時(shí)候,那些數(shù)據(jù)就會(huì)被放入一個(gè)參數(shù)隊(duì)列,這樣就可以對(duì)每次加鎖/解鎖維護(hù)一個(gè)唯一的副本。雖然這樣可以對(duì)緩沖區(qū)數(shù)據(jù)進(jìn)行精確的維護(hù),但當(dāng)某些應(yīng)用程序在鎖較大的數(shù)據(jù)的時(shí)候效果會(huì)大打折扣。
為什么鎖表面的時(shí)候不用緩沖
表面(如前臺(tái)緩沖,后臺(tái)緩沖,紋理等)通常消耗大量的存儲(chǔ)空間。 所以,在對(duì)表面加鎖時(shí)緩沖是無(wú)用的,也是不必要的。為什么沒(méi)有用呢,因?yàn)樵谏厦娴募渔i緩沖技術(shù)中,一個(gè)顯卡會(huì)瞬間消耗掉大量的存儲(chǔ)空間,因?yàn)檫@個(gè)時(shí)候我們需要?jiǎng)?chuàng)建兩個(gè)表面。 例如:一個(gè)1024X1024 32bpp的紋理通常會(huì)消耗掉4MB的顯存,但是如果采用了上面的緩沖鎖技術(shù),那么將會(huì)占用8MB的顯存。這個(gè)技術(shù)將會(huì)導(dǎo)致紋理可用的顯存資源直接減半。而對(duì)于完全緩沖區(qū)鎖技術(shù)。則會(huì)消耗了大量的系統(tǒng)內(nèi)存并且花費(fèi)較多時(shí)間來(lái)拷貝數(shù)據(jù)。因?yàn)檫@個(gè)技術(shù)在系統(tǒng)內(nèi)存中維護(hù)了一個(gè)數(shù)據(jù)的副本。所以它將會(huì)一次性地為這個(gè)表面分配大量的空間。當(dāng)解鎖的時(shí)候,又會(huì)將數(shù)據(jù)拷貝到參數(shù)隊(duì)列里,并且參數(shù)隊(duì)列在必要的時(shí)候,也會(huì)分配較大的空間。在渲染時(shí),渲染線程同樣需要將數(shù)據(jù)從參數(shù)隊(duì)列中取出,并拷貝到真正的表面上。所有的這些拷貝操作,都會(huì)導(dǎo)致加鎖和解鎖的速度大大降低。
表面加鎖時(shí)緩沖不必要是因?yàn)閼?yīng)用程序不需要直接對(duì)表面(紋理除外)進(jìn)行讀寫,為了取得更好的性能,可以使用顯卡直接對(duì)表面進(jìn)行操作。紋理,從另一方面講,僅會(huì)被加鎖一次,然后從文件中加載信息到它的表面。所以,對(duì)于紋理的加鎖,可以讓主線程等待渲染線程返回,然后再進(jìn)行加鎖,而不用對(duì)其進(jìn)行緩沖。注意,等待渲染線程返回并加鎖有可能導(dǎo)致錯(cuò)誤。因?yàn)橛锌赡茱@卡正在填充這個(gè)表面資源。記住,頻繁的對(duì)表面進(jìn)行加鎖將會(huì)導(dǎo)致因?yàn)橹骶€程的強(qiáng)制等待而使效率降低。
這個(gè)方案的實(shí)現(xiàn)只能是在包裝圖形API的那個(gè)包裝類中。每一個(gè)函數(shù)都會(huì)有不同的實(shí)現(xiàn),因?yàn)樗鼈冇锌赡苁侵苯诱{(diào)用圖形API,而有可能是要在調(diào)用圖形API前等待前一幀繪制完成。或者是將數(shù)據(jù)放入渲染線程的隊(duì)列,讓渲染線程去調(diào)用API。也可以對(duì)其進(jìn)行一些優(yōu)化,采用在包裝類中做一些緩存來(lái)緩存那些需要等待的調(diào)用(譯注:個(gè)人理解是因?yàn)槊恳粠枰却恼{(diào)用可能不止一個(gè),將他們緩存起來(lái)。這樣當(dāng)渲染線程返回時(shí),一并調(diào)用這些函數(shù),就能少了許多等待)。你還需要的就是修改渲染系統(tǒng)插件的代碼,用你的包裝類函數(shù)替換掉所有的圖形API調(diào)用。
下面的代碼演示了如何進(jìn)行IUnknown接口的包裝。
這個(gè)技術(shù)達(dá)到了本文介紹中的所有目標(biāo),并且也是最終的選擇方案。D3D9渲染系統(tǒng)被選擇來(lái)實(shí)現(xiàn)這個(gè)方案,伴隨本文的代碼可以從Intel Developer website上下載。
OGRE分析以及結(jié)果
這個(gè)部分我們將討論采用“低級(jí)線程化手段”時(shí),運(yùn)行OGRE的例子程序的情況。下面的數(shù)據(jù)是在2.4GHz Core 2 雙核處理器,NVIDIA 7800顯卡上測(cè)試的結(jié)果。這些數(shù)據(jù)顯示了兩個(gè)不同的緩沖加鎖方案,以及在沒(méi)有開(kāi)啟多線程時(shí)DirectX包裝類的負(fù)載。綠色背景指明了使用這個(gè)方案時(shí)提升到了1.1倍,甚至更多。 黃色部分指明了運(yùn)用該方案時(shí),降低到了1.0倍以下,但是并無(wú)太大損耗。而紅色部分指明了動(dòng)用此方案時(shí),出現(xiàn)了沖突情況。
注意,這里有太多的1。0左右的元素,當(dāng)然也有一些稍微低于1。0的。但是不會(huì)太多。可以看到,這里也有許多綠色的元素,表明運(yùn)行良好。但要注意,這些測(cè)試?yán)佣际荗GRE的DEMO,DEMO并不使用CPU處理太多的東西。只有兩個(gè)元素是紅的。都是處于“完全緩沖加鎖”方案中。因?yàn)檫@些DEMO經(jīng)常更新很大的頂點(diǎn)緩沖。導(dǎo)致很多時(shí)間花費(fèi)在等待復(fù)制完成,從而出現(xiàn)問(wèn)題。
需要特別說(shuō)明的是“Shadow Demo”。有兩種陰影方案,模版和紋理。只有模版陰影在“部分緩沖加鎖”方案時(shí)會(huì)出現(xiàn)問(wèn)題,而紋理陰影則工作良好。
同時(shí)也要注意的時(shí),一些例子在“完全緩沖加鎖”方案中運(yùn)行的效果比“部分緩沖加鎖”方案要好。在這種情況下,應(yīng)用程序取得一個(gè)可以讀寫的緩沖區(qū)。在這種情況下,主要是負(fù)載在于應(yīng)用程序會(huì)將顯存中的數(shù)據(jù)復(fù)制到系統(tǒng)內(nèi)存中。而“完全緩沖加鎖”方案通過(guò)將加鎖和解鎖放到渲染線程中,而將這個(gè)負(fù)擔(dān)消除了。
結(jié)論:
將一個(gè)3D渲染引擎線程化是一項(xiàng)具有挑戰(zhàn)性的工作,但事實(shí)證明,它是可行的。正如先前所展示的一樣,將OGRE渲染引擎線程化是很成功的,并且在某些DEMO上運(yùn)行出了良好的效果。有三種線程化方案,但最終只選擇了“低級(jí)優(yōu)化方案“來(lái)實(shí)現(xiàn)。因?yàn)槠錆M足了本文最初提出的目標(biāo)。在OGRE社區(qū)的共同努力下,OGRE可以在CPU和GPU資源都密集型的應(yīng)用程序中,運(yùn)行出更多幀數(shù)和更平滑的顯示效果。
posted on 2010-12-20 23:14 麒麟子 閱讀(2380) 評(píng)論(0) 編輯 收藏 引用 所屬分類: Game and Engine
Powered by: C++博客 Copyright © 麒麟子