Direct3D的一些小贴士收藏(转载)
GPU性能調(diào)試:
通常來說,使用CPU時(shí)間事件來調(diào)試GPU是低效并且是不準(zhǔn)確的。D3D API在多數(shù)命令下會(huì)阻塞,甚至是Draw函數(shù)。它會(huì)在一些時(shí)間片上做一些真正的工作,而這往往是不可預(yù)知的。因此,GPU的性能調(diào)試只能用PIX或者是其他專用產(chǎn)品,例如NVIDIA’s NVPerfHUD來進(jìn)行。
顯卡所用的內(nèi)存:
顯卡所用的內(nèi)存可以分為兩大類:本地的和非本地的(相對(duì)于顯卡來說)。在顯卡處理的某些數(shù)據(jù)類型的時(shí)候,需要本地內(nèi)存,例如 幀緩沖。 非本地內(nèi)存,有時(shí)也成為AGP卡槽內(nèi)存(AGP aperture),可以被顯卡訪問的某些數(shù)據(jù)類型所在的系統(tǒng)內(nèi)存,例如頂點(diǎn)緩沖。本地內(nèi)存要比非本地內(nèi)存快。
本地內(nèi)存通常是在顯卡內(nèi)的,但是有些顯卡可以共享系統(tǒng)內(nèi)存,這通常是平衡速度和價(jià)格之間的選擇。在這種情況下,幀緩存可以存在于系統(tǒng)內(nèi)存中,而不是在本地內(nèi)存中。這種技術(shù)下,顯卡處理某些數(shù)據(jù)的速度比不使用共享內(nèi)存的要慢,因?yàn)閿?shù)據(jù)必須從I/O Bus(例如PCI-Express)上傳輸過來。但是這可以使顯卡成本大大降低。在NVIDIA,這種技術(shù)被稱為TurboCache,而ATI稱之為HyperMemory。
著色器和著色模型:
Shader是運(yùn)行在GPU上的,處理一些D3D流水管線上一些任務(wù)的程序。有三種類型的shader,他們分別對(duì)應(yīng)三種可編程的stage:
Vertex shader (頂點(diǎn)著色器VS) stage, geometry shader (幾何著色器GS) stage, 還有pixel shader(像素著色器PS) stage。其中幾何著色器只能在DX10平臺(tái)上使用。
著色模型(shader model)是在GPU上運(yùn)行的虛擬機(jī)。每個(gè)虛擬機(jī)定義被稱為一種shader profile。并且包含了特定的匯編語言。
著色器的職責(zé):
著色器通常是流水管線中描述物體表面的部分。例如,一種看起來像木頭的材質(zhì)被稱為木頭著色器(wood shader)。而在D3D中,這些著色語言指令集可以做的事情遠(yuǎn)不止描述物體表面。他們可以用來計(jì)算光照,矩陣轉(zhuǎn)換,頂點(diǎn)動(dòng)畫,進(jìn)行裁切,動(dòng)態(tài)生成新的幾何物體,等等。在Mental ray中,shader按照職責(zé)可以劃分為surface shader, light shader, shader shader, output shader等等。
在D3D中,這三種著色器的職責(zé)劃分并不是很明確。例如,光照計(jì)算過可以在頂點(diǎn)著色器,或者是像素著色器中完成,這取決于應(yīng)用程序的需求。因此,包含各種著色器的著色器集合應(yīng)運(yùn)而生。他們鏈接起來定義了一個(gè)工作流水線。
關(guān)于Direct3D 9 資源和內(nèi)存類型:
D3D支持下列類型的資源:紋理(包括常規(guī)的和渲染目標(biāo)render target),頂點(diǎn)緩沖,索引緩沖,字體,交換鏈(swap chain),狀態(tài)組,深度模板緩沖,特效等等。
有四種內(nèi)存類型(池),資源可以在這里分配:
·???????? 默認(rèn)Default:在顯卡內(nèi)存中,包括AGP卡槽內(nèi)存和本地顯存。在設(shè)備丟失之后,必須被釋放,重構(gòu)。
·???????? 托管Managed:存在于系統(tǒng)內(nèi)存中,按需拷貝到顯存。
·???????? 系統(tǒng)SystemMem:永遠(yuǎn)存在于系統(tǒng)內(nèi)存中,并且不能直接用于渲染??梢援?dāng)作源或者目標(biāo)拷貝。例如UpdateSurface和UpdateTexture。
·???????? Scrach: 永遠(yuǎn)存在于系統(tǒng)內(nèi)存中,并且不會(huì)被設(shè)備大小或格式限制,例如紋理的2的冪限制。不能把它放到顯存中。
查找資源泄露:
在關(guān)閉一個(gè)基于D3D的應(yīng)用程序時(shí),D3D調(diào)試運(yùn)行庫會(huì)報(bào)告內(nèi)存泄露。按照以下步驟定位泄漏點(diǎn)。
1.?????? 在DirectX Control Panel中(通常在DXSDK安裝目錄中可以找到),啟用“Use Debug Version of Direct3D 9”并且將Debug Output Level設(shè)置為”More”。確保Break on Memory Leaks被禁用。點(diǎn)擊Apply。
2.?????? 在VS中調(diào)試運(yùn)行應(yīng)用程序。在關(guān)閉應(yīng)用程序之后,查看VS的輸出窗口Direct 3D9: (WARN) : Memory Address:? 00xxxxxx,? IAllocID= xx dwSize = xxxxxxxx;(pid = xxxxx)
3.?????? 每條記錄對(duì)應(yīng)了一個(gè)資源泄漏,查看并記住ID,然后在DirectX Control Panel中輸入ID并且點(diǎn)擊Apply。
4.?????? 再次運(yùn)行程序,重復(fù)以上步驟。程序會(huì)在分配點(diǎn)中斷,你可以檢查哪里遺忘釋放。
5.?????? 當(dāng)你調(diào)試完成之后,別忘了將Break On AllocID設(shè)置為0。
處理設(shè)備丟失(Device Lost)
一個(gè)D3D設(shè)備可以在很多情況下丟失,例如從全屏向窗口轉(zhuǎn)換,一個(gè)電源管理事件,按CTRL+DEL+ALT返回Windows Security Dialog。
必須采取措施去檢查一個(gè)設(shè)備是否丟失,丟失了之后如何恢復(fù)。
方法:在某些地方調(diào)用IDirect3DDevice9::TestCooperativeLevel,例如在每幀開始渲染之前調(diào)用。當(dāng)發(fā)現(xiàn)設(shè)備丟失之后,采取下列措施:
1.?????? 釋放所有在Default內(nèi)存中的資源
2.?????? 釋放其他沒有和Default, Managed, SystemMem綁定的資源
3.?????? 調(diào)用IDirect3DDevice9::TestCooperativeLevel去確認(rèn)設(shè)備是否可以被重置如果能,那么調(diào)用IDirect3DDevice9::Reset 如果不能,繼續(xù)等待,然后再嘗試
4.?????? 重新創(chuàng)建需要的資源
渲染目標(biāo)和交換鏈(Render Targets and Swap Chains)
一個(gè)渲染目標(biāo)是一個(gè)用于保存在圖形流水線輸出像素的表面。也就是說,它是一個(gè)顏色數(shù)組。一個(gè)設(shè)備可以有一個(gè)或者多個(gè)活動(dòng)的渲染目標(biāo),可以通過SetRenderTarget來啟用。一個(gè)用于渲染目標(biāo)的表面只能放在Default池中,有三種渲染目標(biāo):
·???????? 渲染目標(biāo)表面Render target surfaces(通過CreateRenderTarget創(chuàng)建)
·???????? 渲染目標(biāo)紋理Render target textures(tongguo D3DUSAGE_RENDERTARGET標(biāo)識(shí)來創(chuàng)建)
·???????? 交換鏈Swap chains 交換鏈就是后備緩沖的集合,它們能夠相繼渲染到前緩沖,也就是屏幕上。一個(gè)在交換鏈中的后備緩沖可以當(dāng)作一個(gè)渲染目標(biāo)賦給一個(gè)設(shè)備。但是,不像其他的渲染目標(biāo),交換鏈可以渲染到屏幕上,因?yàn)榻粨Q鏈?zhǔn)呛痛翱?全屏大小綁定的??梢詣?chuàng)建多個(gè)交換鏈,注意更改默認(rèn)交換鏈大小會(huì)造成設(shè)備丟失,所以窗口程序會(huì)忽略默認(rèn)的交換鏈,而使用一個(gè)附加的交換鏈來避免這個(gè)問題。渲染目標(biāo)可以被鎖定(用來讀取),但是當(dāng)這個(gè)渲染目標(biāo)是活動(dòng)的話,會(huì)影響系統(tǒng)性能。我們可以根據(jù)需要用IDirect3DDevice9::GetRenderTargetData來將一個(gè)在Default池中的渲染目標(biāo)拷貝出來??梢允褂肐Direct3DDevice9::StrechRectangle在兩個(gè)在顯卡內(nèi)存中的渲染目標(biāo)中進(jìn)行高效拷貝。
批處理(Batching)
D3D的效率在很大程度上受制于傳給API的幾何模型數(shù)據(jù)的批次上。一個(gè)批處理就是調(diào)用一次DrawPrimitive或者DrawIndexPrimitive。在GPU可以處理數(shù)據(jù)前,CPU花相當(dāng)長(zhǎng)時(shí)間來處理每批數(shù)據(jù)。現(xiàn)在常見的CPU和GPU,可以參考以下數(shù)據(jù):
·???????? 使用DX9,CPU每秒可以處理50000批次;使用DX10,這個(gè)數(shù)據(jù)是200000。
·???????? 在DX9中,處理2000個(gè)三角形在CPU和GPU所花的時(shí)間大致相等。在DX10中,這個(gè)數(shù)據(jù)是500。簡(jiǎn)單的著色程序使這個(gè)數(shù)字增加,復(fù)雜的著色程序使這個(gè)數(shù)字減少。在CPU和GPU在同一個(gè)批次上花相同時(shí)間的情況下,實(shí)例化(Instancing)可以提高三角形的輸出能力。因?yàn)橐陨显?#xff0c;每個(gè)批次中處理數(shù)據(jù)的數(shù)量越大越好,這樣能夠?qū)⑷切蔚耐掏铝孔畲蠡?/p>
在實(shí)踐中,具體有兩種方式:
·???????? Consolidation合并:將相同性質(zhì)的幾何元素合并起來,通常是將一些屬性進(jìn)行排序的結(jié)果
·???????? Instancing實(shí)例化:將相同的幾何物體,經(jīng)過一些細(xì)微的,不同的變換后畫出多個(gè)實(shí)例來。例如世界坐標(biāo)系的轉(zhuǎn)換和顏色轉(zhuǎn)換。
頂點(diǎn),索引緩沖Vertex / Index Buffer
頂點(diǎn)和索引緩沖有兩種類型:靜態(tài)和動(dòng)態(tài)的。
一旦創(chuàng)建之后,靜態(tài)的緩沖使用起來比動(dòng)態(tài)的快一倍。但是,動(dòng)態(tài)緩沖的加鎖和解鎖要比靜態(tài)的快,它們是為更改的每一幀設(shè)計(jì)的,通常被存儲(chǔ)在AGP卡槽內(nèi)存中。經(jīng)常對(duì)靜態(tài)緩沖加解鎖是不明智的,因?yàn)橹挥械闰?qū)動(dòng)完成了所有掛起的命令之后才能返回該緩沖的指針。如果經(jīng)常這樣做,這會(huì)導(dǎo)致CPU和GPU很多不必要的同步,這樣性能將會(huì)變得很差。
為了得到最好的性能,必須采用動(dòng)態(tài)緩存。這樣驅(qū)動(dòng)可以繼續(xù)進(jìn)行并行渲染。使用DISCARD或者是NOOVERWRITING標(biāo)志可以實(shí)現(xiàn)這一點(diǎn),這樣驅(qū)動(dòng)可以在更新數(shù)據(jù)的同時(shí)繼續(xù)處理老的數(shù)據(jù)。
DISCARD:這個(gè)標(biāo)志說明應(yīng)用程序不關(guān)心當(dāng)前緩沖的內(nèi)容。所以在緩沖被渲染的同時(shí),驅(qū)動(dòng)可以給應(yīng)用程序一個(gè)全新的緩沖。這個(gè)處理稱之為“buffer renaming”。注意,在實(shí)踐中,驅(qū)動(dòng)傾向于不去釋放“緩沖重命名”中所用的內(nèi)存,因此這個(gè)標(biāo)志必須盡量少用。
NOOVERWRITE:這表示,對(duì)于之前添加的,不帶這個(gè)標(biāo)志的數(shù)據(jù),應(yīng)用程序不會(huì)更改它。例如應(yīng)用程序只會(huì)在現(xiàn)有緩沖之后添加數(shù)據(jù)。所以驅(qū)動(dòng)可以繼續(xù)使用現(xiàn)有數(shù)據(jù)進(jìn)行渲染。
CPU和GPU的并行處理
D3D runtime會(huì)將一堆命令做成命令串傳給GPU,這就允許GPU和CPU進(jìn)行并行處理。這樣也是硬件加速渲染這么高效的原因之一。但是,在很多情況下,CPU和GPU必須進(jìn)行同步之后才能做進(jìn)一步的處理。通常來說,應(yīng)該盡量避免這種情況,因?yàn)檫@會(huì)導(dǎo)致整個(gè)流水管線的刷新,大幅降低性能。例如,對(duì)靜態(tài)緩沖加鎖,這要求GPU先處理完所有的命令之后,才能返回被鎖緩沖的指針。如果用動(dòng)態(tài)緩沖,就可以避免,就像前面講過的一樣。
有一些同步是不可避免的,例如,CPU可能會(huì)需要一些GPU還來不及處理的命令結(jié)果。在這種情況下,用戶會(huì)感到畫面延遲Lag。要避免這種情況,可以在GPU落后兩三幀的情況下調(diào)用Present來強(qiáng)迫CPU等待GPU。因此,調(diào)用Present可能比較慢,但是正式它處理了必要的同步。
狀態(tài)的更換State Changes
不管冗余還是不冗余,狀態(tài)的轉(zhuǎn)換在到達(dá)驅(qū)動(dòng)層的時(shí)候,開銷總是很大。所以在某些層面,狀態(tài)轉(zhuǎn)換必須被過濾。一個(gè)對(duì)狀態(tài)進(jìn)行更換的函數(shù)調(diào)用并不一定會(huì)開銷很大,因?yàn)镈3D Runtime很有可能緩沖這些轉(zhuǎn)換請(qǐng)求,在真正調(diào)用DrawPrimitive函數(shù)之前不會(huì)去執(zhí)行它。多次的狀態(tài)轉(zhuǎn)換也不會(huì)加大開銷,因?yàn)橹皇褂米詈笠粋€(gè)狀態(tài)值。盡管如此,狀態(tài)轉(zhuǎn)換還是應(yīng)該盡量避免。某些狀態(tài)轉(zhuǎn)換會(huì)比其他的轉(zhuǎn)換的開銷更大。例如,對(duì)于更改處于活動(dòng)狀態(tài)的頂點(diǎn)緩沖和像素緩沖會(huì)導(dǎo)致整個(gè)流水管線的刷新。因?yàn)樵谀承╋@卡上,同一時(shí)間每個(gè)類型只有一個(gè)著色器可以處于活動(dòng)狀態(tài)。一個(gè)圖形流水線可以很長(zhǎng),花一段時(shí)間才能完成一個(gè)像素的渲染。因此,整個(gè)流水線的刷新需要盡量避免。在不同的顯卡上,某個(gè)狀態(tài)的更新的花費(fèi)差別可能會(huì)很大。另外,D3D的函數(shù)調(diào)用個(gè)數(shù)也必須盡量的少,雖然它的開銷不如達(dá)到驅(qū)動(dòng)層的狀態(tài)更改那么大??梢允褂脿顟B(tài)塊來減少D3D API的調(diào)用,狀態(tài)塊可以將狀態(tài)的更改集中在一起,并且可以重用。
轉(zhuǎn)載于:https://www.cnblogs.com/ComputerG/archive/2011/03/10/1979608.html
創(chuàng)作挑戰(zhàn)賽新人創(chuàng)作獎(jiǎng)勵(lì)來咯,堅(jiān)持創(chuàng)作打卡瓜分現(xiàn)金大獎(jiǎng)總結(jié)
以上是生活随笔為你收集整理的Direct3D的一些小贴士收藏(转载)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 大摩维持浩大游戏“增持”评级
- 下一篇: 绿色vmware 安装后看不到虚拟的网卡