• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            麒麟子

            ~~

            導航

            <2025年6月>
            25262728293031
            1234567
            891011121314
            15161718192021
            22232425262728
            293012345

            統計

            常用鏈接

            留言簿(12)

            隨筆分類

            隨筆檔案

            Friends

            WebSites

            積分與排名

            最新隨筆

            最新評論

            閱讀排行榜

            評論排行榜

            #

            關于圖象的拉伸問題


            <如果窗口的視圖區大小和SwapChain的大小不一,那么DirectX將通過Stretch Blit來自動處理圖像的伸縮變化。盡管這可能并不令人期待,因為這在視圖區變大的時候將導致圖像的模糊。> 你說的這個問題 要怎么才能解決?


            有位博友這樣問過,因為最近少有上博客,于是沒有回答及時,請見諒,我這里只能說說我們現在的解決辦法。

            當后臺緩沖區的分辨率和視圖區不統一的時候,會導致拉伸現象,使畫面變得模糊。

            首先說個題外話:
            正因為變得模糊,因此有人故意將后臺緩沖區做得比視區稍大一點,這樣來抗鋸齒,至于效果如何,沒有真正見過,有興趣的可以試試。

            下面說說解決辦法。
            我們的解決辦法也很簡單,就分三步
            1,窗口改變的時候,告訴設備窗口大小改變。
            2,按改變后的窗口重建緩沖區。
            3。強制設備丟失,并重新加載需要的資源。

            由于在做這個之前,設備丟失已經做好了,于是就偷了個懶,窗口改變的時候就傳入窗口大小,并reset
            這樣設備就強制處于丟失狀態。


            不知道有沒有說清楚,反正主要的就是要重建緩沖區,并處理設備丟失問題。。。

            posted @ 2009-10-10 21:25 麒麟子 閱讀(1480) | 評論 (0)編輯 收藏

            近期在研究Skeletal Animation(骨骼動畫)

             骨骼動畫一直是我感興趣的內容.雖然采用現成的CSkinMesh能夠使用XFile的骨骼動畫.但對自己來說總感覺缺少了點什么.于是,還是深入理解理解為好!!!

            ZDNet軟件頻道時間2008-03-24作者:Skyman | CSDN
            本文關鍵詞:骨骼動畫) Animation Skeletal 游戲 Linux

            骨骼動畫(Skeletal Animation)又叫Bone Animation,它與關鍵幀動畫(Key-frame Animation)相比,占用空間小,因為它不需要象關鍵幀動畫那樣要存儲每一幀的各個頂點的數據,而是只需要存儲每一幀的骨骼,骨骼與頂點相比,當然要少得多。所以骨骼動畫有很多優勢,當然其技術難度也很高。我個人覺得動畫在計算機圖形學中是一個十分重要的內容,不管是在游戲、電影動畫還是虛擬現實中,生動逼真的動畫(人、動物等)會使之增色不少。所以我決定今后的研究方向就是計算機動畫。目前在研究Skeletal Animation,這是目前動畫技術中的主流。歡迎同好與我交流,共同提高!

                骨骼動畫的實現思路是從我們人的身體的運動方式而來的(所以VR就是對現實世界的虛擬嘛 :-))。動畫人物的身體(肉、皮膚)是一個網格(Mesh)模型,網格的內部是一個骨架結構。當人物的骨架運動時,身體就會跟著骨架一起運動。骨架是由一定數目的骨骼組成的層次結構,每一個骨骼的排列和連接關系對整個骨架的運動有很重要的影響。每一個骨骼數據都包含其自身的動畫數據。和每個骨架相關聯的是一個“蒙皮”(Skin)模型,它提供動畫繪制所需要的幾何模型(Vertex,Normal,etc)和紋理材質信息。每個頂點都有相應的權值(Weight),這些權值定義了骨骼的運動對有關頂點的影響因子。當把動畫人物的姿勢和全局運動信息作用到骨架上時,這個“蒙皮”模型就會跟隨骨架一起運動。如下圖所示:

                所以關鍵是對骨架進行動畫生成,生成的方法也是用關鍵幀。關鍵幀動畫是對人物的網格(Mesh)模型采用關鍵幀生成動畫;而骨骼動畫則是對人物的骨架采用關鍵幀生成動畫,然后再讓網格(Mesh)模型跟隨骨架運動。關鍵幀動畫實現的2個關鍵點是:關鍵幀的選取和中間幀的插補。

                關鍵幀的指定有2種基本的方法:前向動力學(FK)和逆向動力學(IK)。前向動力學用一組節點的角度來找到末端受動器的位置;而逆向動力學則是找到將末端受動器置于所要位置所需的一組節點角度。前向動力學的優點是:計算簡單,運算速度快,缺點是:需指定每個關節的角度和位置,而由于骨架的各個節點之間有內在的關聯性,直接指定各關節的值很容易產生不自然協調的動作;逆向動力學的優點是:只需指定主要關節點的位置,負擔輕,缺點是:計算模型比較復雜,開發者需要機械運動和動力學、幾何學以及向量數學等方面的相關知識。

                中間幀的插值分2步:(1) 根據當前時間,通過插值計算出每個骨骼的旋轉、平移等值,形成中間幀的骨架。插值算法一般采用四元數(Quternion)的球面線性插值(Spherical linear interpolation)SLERP,SLERP特別適合在兩個方位之間進行插值,不會出現像對歐拉角插值那樣出現萬象鎖的現象,而且這種插值能產生更平滑和連續的旋轉,表達方式也很簡潔;(2) 根據骨架的變化情況,插值計算出骨架的“蒙皮”模型的各個頂點的位置變化。對于某個特定骨骼,“蒙皮”模型的頂點變換矩陣=初始姿勢的變換矩陣的逆×姿勢變換后的矩陣。另外還要考慮頂點可能受多個骨骼運動的影響。這時我們對每個與當前頂點相關聯的骨骼,將其運動姿勢變換矩陣×當前頂點相對于該骨骼的偏移向量×該骨骼對當前頂點的影響因子(即權重Weight),對所有與當前頂點相關聯的骨骼都這么處理,然后相加,就得到當前頂點的新位置。

                由此看出,如何設置各關鍵幀的骨架的各節點的位置和骨骼的轉向(也就是骨架的POSE)是其中的關鍵,有2種方法:一種是由動畫師手工放置,這個對動畫師的技術要求就比較高,要求動畫師對現實生活中的人和動物等的動作有細心的觀察。否則設置的骨架動作就會不自然、不協調;另外一種是基于運動捕捉(Motion Capture)的方法,就是在人的各個關節處安置運動捕捉傳感器,當人做各種動作時,捕捉儀器就將各節點的位置數據記錄下來,這樣我們就可以根據這些節點數據進行骨架建模。由于這是捕捉的真實的人的動作,所以這種方式得到的動畫就很自然、很真實,但捕捉儀器造價昂貴,國內估計只有很少幾家有財力的游戲公司才購置了這些設備吧。

                目前有好多3D模型格式支持Skeletal Animation,像Microsoft的.X格式、MilkShape的MS3D格式、Half Life的MDL格式、ID Software的MD5格式等。我準備首先研究一下MS3D格式,因為它有公開的格式說明文檔,閱讀起來比較容易,而且應用很廣。當然,首先要深入學習Skeletal Animation的底層技術,打好堅實的基礎,呵呵!


            posted @ 2009-10-10 21:17 麒麟子 閱讀(1700) | 評論 (0)編輯 收藏

            GPU中的ps 1.x 寄存器

            將就看吧,有些單詞我實在不知道怎么翻譯,只可意會!

            像素著色器需要依靠寄存器來取得頂點數據,輸出像素數據,取得計算時的臨時結果和關聯紋理采樣通道(stage)。有幾種類型的寄存器,每一種都有特殊的功能和用途。

            像素著色器需要的用到的數據由寄存器保管,下面是寄器存的所有介紹
            寄存器類型:描述了四種可用的寄存器和他們各自的用途
            讀取端口限制:單指針使用多個寄存器時的限制
            R/RW: 描述了哪些寄存器可以用來讀,寫或是讀寫。
            范圍:各個分量的范圍的詳細說明

            Register Types  
                                                 Versions   
            Name  Type                   1_1        1_2        1_3        1_4
            c#  Constant register       8             8             8           8
            r#  Temporary register    2             2             2           6
            t#  Texture register          4             4             4           6
            v#  Color register            2             2             2           2 in phase 2

            1,常量寄存器:常量寄存器容納了常量數據。數據可以用IDirect3DDevice9::SetPixelShaderConstantF函數將一個常量裝入常量寄存器中。也可以用def-ps來定義一個常量。 常量寄存器對紋理尋址指令來說是不可用的,唯一例外的是texm3x3spec-ps指令,這個指令使用一個常量寄存器來提供一個視線向量(eye-ray vector)

            2,臨時寄存器:臨時寄存器用來存立即結果。r0用來作為PS的最終輸出。shader的最后時刻r0中存放的是最后的像素顏色值
            如果任何的著色器試圖從一個沒有被寫入數據的臨時寄存器中讀取數據時,著色器激IDirect3DDevice9::CreatePixelShader將會失敗(shader validation will fail)。假設激活(validation)是可用狀態D3DXAssembleShader函數調用也會因為相同的原因而失敗。(不要使用D3DXSHADER_SKIPVALIDATION)

            紋理寄存器:
            在ps 1_1 到1_3中,紋理寄存器容納紋理數據或是紋理坐標。當一個紋理被采樣時,紋理數據便被裝載到一個紋理寄存器中。
            當紋理通道狀態屬性被登記的時候紋理采樣使用紋理坐標來查詢(look up)或采樣(sample)一個紋理坐標(u,v,w,q)標記的顏色值。紋理坐標數據會根據頂點紋理坐標數據進行插值,并關聯到相關的紋理通道。紋理通道號與紋理坐標聲明序列有一個一一對應關系。默認情況下,頂點格式中定義的第一個紋理坐標與紋理通道0關聯。
             在這些版本的像素著色器中,當紋理寄存器用來做算術運算的時候就和臨時寄存器的效果一樣了。
            在ps_1_4中,紋理寄存器(t#)容納的是只讀紋理坐標信息。這意味著紋理坐標集和紋理通道編號是獨立的。紋理通道編號由目的寄存器(r0 to r5)決定。對于texld指令來說,紋理坐標集由源寄存器t0 to t5決定。因此紋理坐標集可以映射到任何的紋理通道上。另外,對于texld的源寄存器(指定紋理坐標信息)也可以是臨時寄存器(r#)。在這樣的情況下,臨時寄存器記錄紋理坐標。
            顏色寄存器容納了每個像素的顏色值,這個值通過頂點數據中的漫反射和鏡面光顏色值迭代而來。對于ps_1_4。顏色寄存器只有在phase2中可用。如果著色模式設置為D3DSHADE_FLAT,那么頂點顏色中的顏色迭代將不可用。如果霧化開啟的話,那么渲染管線還是會忽略著色模式,對霧進行顏色迭代。記住霧化比像素著色器后應用。
            通常我們會從v0加載頂點漫反射顏色數據。從v1加載頂點鏡面光顏色數據。
            輸入顏色數據值將會被規范到0和1,因為這是像素著色器中的顏色寄存器的有效范圍

            像素著色器對顏色寄存器進行只讀操作。顏色寄存器中存放的是迭代值,但是迭代可能會造成比紋理坐標低很多精度

             

             

            posted @ 2009-09-12 13:36 麒麟子 閱讀(2479) | 評論 (5)編輯 收藏

            如何避免VS2005下的d3d9types.h(1385) warning C4819

            用VS2005+DirectX9 SDK(手頭測試過的是2004年10月的DirectX SDK和2006年4月的DirectX SDK)編譯游戲會出現以下warning:

             


            --------------------------------------------------------------------------------


            d:\microsoft directx 9.0 sdk (october 2004)\include\d3d9types.h(1385) : warning C4819: The file contains a character that cannot be represented in the current code page (936). Save the file in Unicode format to prevent data loss

             

            --------------------------------------------------------------------------------
            要修正這個問題,不必要存為UTF8的文件,而是搜索_D3DDEVINFO_VCACHE,然后會看到:

            typedef struct _D3DDEVINFO_VCACHE ...{
                DWORD   Pattern;                    /**//* bit pattern, return value must be FOUR_CC(慍? 慉? 慍? 慔? */
                DWORD   OptMethod;                  /**//* optimization method 0 means longest strips, 1 means vertex cache based */
                DWORD   CacheSize;                  /**//* cache size to optimize for  (only required if type is 1) */
                DWORD   MagicNumber;                /**//* used to determine when to restart strips (only required if type is 1)*/
            } D3DDEVINFO_VCACHE, *LPD3DDEVINFO_VCACHE;
            那四個亂碼的去掉就可以了

            參考了http://gamep.mmoh.jp/e39255.html


            本文來自CSDN博客,轉載請標明出處:http://blog.csdn.net/SONIC3D/archive/2007/11/01/1861794.aspx

            posted @ 2009-08-24 20:51 麒麟子 閱讀(2723) | 評論 (1)編輯 收藏

            轉 深入理解D3D9

            文章來源:http://www.cnblogs.com/effulgent/archive/2009/02/10/1387438.html
            深入理解D3D9對圖形程序員來說意義重大,我把以前的一些學習筆記都匯總起來,希望對朋友們有些所幫助,因為是零散筆記,思路很雜,還請包涵。

            其實只要你能完美理解D3DLOCK、D3DUSAGE、D3DPOOL、LOST DEVICE、QUERY、Present()、BeginScene()、EndScene()等概念,就算是理解D3D9了, 不知道大家有沒有同感。有如下幾個問題,如果你能圓滿回答就算過關:)。
            1、       D3DPOOL_DEFAULTD3DPOOL_MANAGEDD3DPOOL_SYSTEMMEMD3DPOOL_SCRATCH到底有何本質區別?
            2、       D3DUSAGE的具體怎么使用?
            3、       什么是Adapter?什么是D3D DeviceHAL DeviceRef Device有何區別?Device的類型又和Vertex Processing類型有什么關系?
            4、       APP(CPU)、RUNTIMEDRIVERGPU是如何協同工作的?D3D API是同步函數還是異步函數?
            5、       Lost Device到底發生了什么?為什么在設備丟失后D3DPOOL_DEFAULT類型資源需要重新創建?

            D3D中有三大對象,他們是D3D OBJECTD3D ADAPTERD3D DEVICED3D OBJECT很簡單,就是一個使用D3D功能的COM對象,其提供了創建DEVICE和枚舉ADAPTER的功能。ADAPTER是對計算機圖形硬件和軟件性能的一個抽象,其包含了DEVICEDEVICE則是D3D的核心,它包裝了整個圖形流水管線,包括變換、光照和光柵化(著色),根據D3D版本不同,流水線也有區別,比如最新的D3D10就包含了新的GS幾何處理。圖形管線的所有功能由DRIVER提供,而DIRVER分兩類,一種是GPU硬件DRIVER,另一種是軟件DRIVER,這就是為什么在D3D中主要有兩類DEVICEREF和HAL,使用REF DEVICE時,圖形管線的光柵化功能由軟件DRIVERCPU上模擬的,REF DEVICE從名字就可以看出這個給硬件廠商做功能參考用的,所以按常理它應該是全軟件實現,具備全部DX標準功能。而使用HAL DEVICE時,RUNTIME則將使用HAL硬件層控制GPU來完成變換、光照和光柵化,而且只有HAL DEVICE中同時實現了硬件頂點處理和軟件頂點處理(REF DEVICE一般不能使用硬件頂點處理,除非自己在驅動上做手腳,比如PERFHUD)。另外還有個一個不常用的SOFTWARE DEVICE,用戶可以使用DDI編寫自己的軟件圖形驅動,然后注冊進系統,之后便可在程序中使用。

            檢查系統軟件硬件性能。
            在程序的開始我們就要判斷目標機的性能,其主要流程是:
            確定要用的緩沖格式
            GetAdapterCount()
            GetAdapterDisplayMode

            GetAdapterIdentifier //得到適配器描述
            CheckDeviceType //判斷指定適配器上的設備是否支持硬件加速
            GetDeviceCaps //指定設備的性能,主要判斷是否支持硬件頂點處理(T&L)
            GetAdapterModeCount //得到適配器上指定緩沖格式所有可用的顯示模式
            EnumAdapterModes //枚舉所有顯示模式
            CheckDeviceFormat
            CheckDeviceMultiSampleType
            詳細使用請參考DX文檔。

            WINDOWS圖形系統的主要分為四層:圖形應用程序、D3D RUNTIME、SOFTWARE DRIVER和GPU。此四層是按功能來分的,實際上他們之間界限并不如此明確,比如RUNTIME中其實也包含有USER MODE的SOFTWARE DRIVER,詳細結構這里不再多說。而在RUNTIME里有一個很重要的結構,叫做command buffer,當應用程序調用一個D3D API時,RUNTIME將調用轉換成設備無關的命令,然后將命令緩沖到這個COMMAND BUFFER中,這個BUFFER的大小是根據任務負載動態改變的,當這個BUFFER滿員之后,RUNTIME會讓所有命令FLUSHKERNEL模式下的驅動中,而驅動中也是有一個BUFFER的,用來存儲已被轉換成的硬件相關的命令,D3D一般只允許其緩沖最多3個幀的圖形指令,而且RUNTIMEDRIVER都會被BUFFER中的命令做適當優化,比如我們在程序中連續設置同一個RENDER STATE,我們就會在調試信息中看到如下信息“Ignoring redundant SetRenderState - X”,這便是RUNTIME自動丟棄無用的狀態設置命令。在D3D9中可以使用QUERY機制來與GPU進行異步工作,所謂QUERY就是查詢命令,用來查詢RUNTIMEDRIVER或者GPU的狀態,D3D9中的QUERY對象有三種狀態,SIGNALEDBUILDINGISSUED,當他們處于空閑狀態后會將查詢狀態置于SIGNALED STATE,查詢分開始和結束,查詢開始表示對象開始記錄應用程序所需數據,當應用程序指定查詢結束后,如果被查詢的對象處于空閑狀態,則被查詢對象會將查詢對象置于SIGNALED狀態。GetData則是用來取得查詢結果,如果返回的是D3D_OK則結果可用,如果使用D3DGETDATA_FLUSH標志,表示將COMMAND BUFFER中的所有命令都發送到DRIVER。現在我們知道D3D API絕大部分都是同步函數,應用程序調用后,RUNTIME只是簡單的將其加入到COMMAND BUFFER,可能有人會疑惑我們如何測定幀率?又如何分析GPU時間呢?對于第一個問題我們要看當一幀完畢,也就是PRESENT()函數調用是否被阻塞,答案是可能被阻塞也可能不被阻塞,要看RUNTIME允許緩沖中存在的指令數量,如果超過額度,則PRESENT函數會被阻塞下來,如何PRESENT完全不被阻塞,當GPU執行繁重的繪制任務時,CPU工作進度會大大超過GPU,導致游戲邏輯快于圖形顯示,這顯然是不行的。測定GPU工作時間是件很麻煩的事,首先我們要解決同步問題,要測量GPU時間,首先我們必須讓CPUGPU異步工作,在D3D9中可以使用QUERY機制做到這點,讓我們看看Accurately Profiling Driect3D API Calls中的例子:
            IDirect3DQuery9* pQueryEvent;

            //1.創建事件類型的查詢事件
            m_pD3DDevice->CreateQuery( D3DQUERYTYPE_EVENT, &pQueryEvent);
            //2.COMMAND BUFFER中加入一個查詢結束的標記,此查詢默認開始于CreateDevice
            pQueryEvent->Issue(D3DISSUE_END);
            //3.COMMAND BUFFER中的所有命令清空到DRIVER中去,并循環查詢事件對象轉換到SIGNALED狀態,當GPU完成CB中所有命令后會將查詢事件狀態進行轉換。
            while(S_FALSE == pQueryEvent->GetData( NULL, 0, D3DGETDATA_FLUSH) )
                 ;
            LARGE_INTEGER start, stop;
            QueryPerformanceCounter(&start); 
            SetTexture();
            DrawPrimitive(); 
            pQueryEvent->Issue(D3DISSUE_END);
            while(S_FALSE == pQueryEvent->GetData( NULL, 0, D3DGETDATA_FLUSH) )
                   ;
            QueryPerformanceCounter(&stop); 

            1.第一個GetData調用使用了D3DGETDATA_FLUSH標志,表示要將COMMAND BUFFER中的繪制命令都清空到DRIVER中去,當GPU處理完所有命令后會將這個查詢對象狀態置SIGNALED。
            2.將設備無關的SETTEXTURE命令加入到RUNTIME的COMMAND BUFFER中。
            3.將設備無關的DrawPrimitive命令加入到RUNTIME的COMMAND BUFFER中。
            4.將設備無關的ISSUE命令加入到RUNTIME的COMMAND BUFFER中。
            5.GetData會將BUFFER中的所有命令清空到DRIVER中去,注意這是GETDATA不會等待GPU完成所有命令的執行才返回。這里會有一個從用戶模式到核心模式的切換。
            6.等待DRIVER將所有命令都轉換為硬件相關指令,并填充到DRIVER BUFFER中后,調用從核心模式返回到用戶模式。
            7.GetData循環查詢 查詢對象 狀態。當GPU完成所有DRIVER BUFFER中的指令后會改變查詢對象的狀態。

            如下情況可能清空RUNTIME COMMAND BUFFER,并引起一個模式切換:
            1.Lock method(某些條件下和某些LOCK標志)

            2.創建設備、頂點緩沖、索引緩沖和紋理
            3.完全釋放設備、頂點緩沖、索引緩沖和紋理資源
            4.調用ValidateDevice
            5.調用Present
            6.COMMAND BUFFER已滿
            7.用D3DGETDATA_FLUSH調用GetData函數

            對于D3DQUERYTYPE_EVENT的解釋我不能完全理解(Query for any and all asynchronous events that have been issued from API calls)明白的朋友一定告訴我,只知道當GPU處理完D3DQUERYTYPE_EVENT類型查詢在CB中加入的D3DISSUE_END標記后,會將查詢對象狀態置SIGNALED狀態,所以CPU等待查詢一定是異步的。為了效率所以盡量少在PRESENT之前使用BEGINSCENE ENDSCENE對,為什么會影響效率?原因只能猜測,可能EndScene會引發Command buffer flush這樣會有一個執行的模式切換,也可能會引發D3D RUNTIME對MANAGED資源的一些操作。而且ENDSCENE不是一個同步方法,它不會等待DRIVER把所有命令執行完才返回。 

            D3D RUTIME的內存類型,分為3種,VIDEO MEMORY(VM)、AGP MEMORYAM)和SYSTEM MEMORYSM),所有D3D資源都創建在這3種內存之中,在創建資源時,我們可以指定如下存儲標志,D3DPOOL_DEFAULTD3DPOOL_MANAGEDD3DPOOL_SYSTEMMEMD3DPOOL_SCRATCHVM就是位于顯卡上的顯存,CPU只能通過AGPPCI-E總線訪問到,讀寫速度都是非常慢的,CPU連續寫VM稍微快于讀,因為CPUVM時會在CACHE中分配32或64個字節(取決于CACHE LINE長度)的寫緩沖,當緩沖滿后會一次性寫入VMSM就是系統內存,CPU讀寫都非常快,因為SM是被CACHE2級緩沖的,但GPU卻不能直接訪問到系統緩沖,所以創建在SM中的資源,GPU是不能直接使用的;AM是最麻煩的一個類型,AM實際也存在于系統內存中,但這部分MEM不會被CPU CACHE,意味著CPU讀寫AM都會寫來個CACHE MISSING然后才通過內存總線訪問AM,所以CPU讀寫AM相比SM會比較慢,但連續的寫會稍微快于讀,原因就是CPUAM使用了“write combining”,而且GPU可以直接通過AGPPCI-E總線訪問AM。 

            如果我們使用D3DPOOL_DEFAULT來創建資源,則表示讓D3D RUNTIME根據我們指定的資源使用方法來自動使用存儲類型,一般是VM或AM,系統不會在其他地方進行額外備份,當設備丟失后,這些資源內容也會被丟失掉。但系統并不會在創建的時候使用D3DPOOL_SYSTEMMEM或D3DPOOL_MANAGED來替換它,注意他們是完全不同的POOL類型,創建到D3DPOOL_DEFAULT中的紋理是不能被CPU LOCK的,除非是動態紋理。但創建在D3DPOOL_DEFAULT中的VB IB RENDERTARGET BACK BUFFERS可以被LOCK。當你用D3DPOOL_DEFAULT創建資源時,如果顯存已經使用完畢,則托管資源會被換出顯存來釋放足夠的空間。 D3DPOOL_SYSTEMMEM和D3DPOOL_SCRATCH都是位于SM中的,其差別是使用D3DPOOL_SYSTEMMEM時,資源格式受限于Device性能,因為資源很可能會被更新到AMVM中去供圖形系統使用,但SCRATCH只受RUNTIME限制,所以這種資源無法被圖形系統使用。 D3DRUNTIME會優化D3DUSAGE_DYNAMIC 資源,一般將其放置于AM中,但不敢完全保證。另外為什么靜態紋理不能被LOCK,動態紋理卻可以,都關系到D3D RUNTIME的設計,在后面D3DLOCK說明中會敘述。

            D3DPOOL_MANAGED表示讓D3D RUNTIME來管理資源,被創建的資源會有2份拷貝,一份在SM中,一份在VM/AM中,創建的時候被放置LSM,在GPU需要使用資源時D3D RUNTIME自動將數據拷貝到VM中去,當資源被GPU修改后,RUNTIME在必要時自動將其更新到SM中來,而在SM中修改后也會被UPDATEVM去中。所以被CPU或者GPU頻發修改的數據,一定不要使用托管類型,這樣會產生非常昂貴的同步負擔。當LOST DEVICE發生后,RESETRUNTIME會自動利用SM中的COPY來恢復VM中的數據,因為備份在SM中的數據并不是全部都會提交到VM中,所以實際備份數據可以遠多于VM容量,隨著資源的不斷增多,備份數據很可能被交換到硬盤上,這是RESET的過程可能變得異常緩慢,RUNTIME給每個MANAGED資源都保留了一個時間戳,當RUNTIME需要把備份數據拷貝到VM中時,RUNTIME會在VM中分配顯存空間,如果分配失敗,表示VM已經沒有可用空間,這樣RUNTIME會使用LRU算法根據時間戳釋放相關資源,SetPriority通過時間戳來設置資源的優先級,最近常用的資源將擁有高的優先級,這樣RUNTIME通過優先級就能合理的釋放資源,發生釋放后馬上又要使用這種情況的幾率會比較小,應用程序還可以調用EvictManagedResources強制清空VM中的所有MANAGED資源,這樣如果下一幀有用到MANAGED資源,RUNTIME需要重新載入,這樣對性能有很大影響,平時一般不要使用,但在關卡轉換的時候,這個函數是非常有用的,可以消除VM中的內存碎片。LRU算法在某些情況下有性能缺陷,比如繪制一幀所需資源量無法被VM裝下的時候(MANAGED),使用LRU算法會帶來嚴重的性能波動,如下例子:

            BeginScene();
            Draw(Box0);
            Draw(Box1);
            Draw(Box2);
            Draw(Box3);
            Draw(Circle0);
            Draw(Circle1);
            EndScene();
            Present();

            假設VM只能裝下其中5個幾何體的數據,那么根據LRU算法,在繪制Box3之前必須清空部分數據,那清空的必然是Circle0……,很顯然清空Box2是最合理的,所以這是RUNTIME使用MRU算法處理后續Draw Call能很好的解決性能波動問題,但資源是否被使用是按FRAME為單位來檢測的,并不是每個DRAW CALL都被記錄,每個FRAME的標志就是BEGINSCENE/ENDSCENE對,所以在這種情況下合理使用BEGINSCENE/ENDSCENE對可以很好的提高VM不夠情況下的性能。根據DX文檔的提示我們還可以使用QUERY機制來獲得更多關于RUNTIME MANAGED RESOURCE信息,但好像只在RUNTIME DEBUG模式下有用,理解RUNTIME如何MANAGE RESOURCE很重要,但編寫程序的時候不要將這些細節暴露出來,因為這些東西都是經常會變的。最后還要提醒的是,不光RUNTEIMEMANAGE RESOURCEDRIVER也很可能也實現了這些功能,我們可以通過D3DCAPS2_CANMANAGERESOURCE標志取得DRIVER是否實現資源管理功能的信息,而且也可以在CreateDevice的時候指定D3DCREATE_DISABLE_DRIVER_MANAGEMENT來關閉DRIVER資源管理功能。  

            D3DLOCK探索D3D RUNTIME工作

            如果LOCK DEFAULT資源會發生什么情況呢?DEFAULT資源可能在VMAM中,如果在VM中,必須在系統內容中開辟一個臨時緩沖返回給數據,當應用程序將數據填充到臨時緩沖后,UNLOCK的時候,RUNTIME會將臨時緩沖的數據傳回到VM中去,如果資源D3DUSAGE屬性不是WRITEONLY的,則系統還需要先從VM里拷貝一份原始數據到臨時緩沖區,這就是為什么不指定WRITEONLY會降低程序性能的原因。CPUAM也有需要注意的地方,因為CPUAM一般是WRITE COMBINING,也就是說將寫緩沖到一個CACHE LINE上,當CACHE LINE滿了之后才FLUSHAM中去,第一個要注意的就是寫數據必須是WEAK ORDER的(圖形數據一般都滿足這個要求),據說D3DRUNTIMENV DIRVER有點小BUG,就是在CPU沒有FLUSHAM時,GPU就開始繪制相關資源產生的錯誤,這時請使用SFENCE等指令FLUSH CACHE LINE。第二請盡量一次寫滿一個CACHE LINE,否則會有額外延遲,因為CPU每次必須FLUSH整個CACHE LINE到目標,但如果我們只寫了LINE中部分字節,CPU必須先從AM中讀取整個LINE長數據COMBINE后重新FLUSH。第三盡可能順序寫,隨機寫會讓WRITE COMBINING反而變成累贅,如果是隨機寫資源,不要使用D3DUSAGE_DYNAMIC創建,請使用D3DPOOL_MANAGED,這樣寫會完全在SM中完成。

            普通紋理(D3DPOOL_DEFAULT)是不能被鎖定的,因為其位于VM中,只能通過UPDATESURFACEUPDATETEXTURE來訪問,為什么D3D不讓我們鎖定靜態紋理,卻讓我們鎖定靜態VB IB呢?我猜測可能有2個方面的原因,第一就是紋理矩陣一般十分龐大,且紋理在GPU內部已二維方式存儲;第二是紋理在GPU內部是以NATIVE FORMAT方式存儲的,并不是明文RGBA格式。動態紋理因為表明這個紋理需要經常修改,所以D3D會特別存儲對待,高頻率修改的動態紋理不適合用動態屬性創建,在此分兩種情況說明,一種是GPU寫入的RENDERTARGET,一種是CPU寫入的TEXTURE VIDEO,我們知道動態資源一般是放置在AM中的,GPU訪問AM需要經過AGP/PCI-E總線,速度較VM慢許多,而CPU訪問AM又較SM慢很多,如果資源為動態屬性,意味著GPUCPU訪問資源會持續的延遲,所以此類資源最好以D3DPOOL_DEFAULTD3DPOOL_SYSTEMMEM各創建一份,自己手動進行雙向更新更好。千萬別 RENDERTARGETD3DPOOL_MANAGED 屬性創建,這樣效率極低,原因自己分析。而對于改動不太頻繁的資源則推薦使用DEFAULT創建,自己手動更新,因為一次更新的效率損失遠比GPU持續訪問AM帶來的損失要小。 

            不合理的LOCK會嚴重影響程序性能,因為一般LOCK需要等待COMMAND BUFFER前面的繪制指令全部執行完畢才能返回,否則很可能修改正在使用的資源,從LOCK返回到修改完畢UNLOCK這段時間GPU全部處于空閑狀態,沒有合理使用GPUCPU的并行性,DX8.0引進了一個新的LOCK標志D3DLOCK_DISCARD,表示不會讀取資源,只會全寫資源,這樣驅動和RUNTIME配合來了個瞞天過海,立即返回給應用程序另外塊VM地址指針,而原指針在本次UNLOCK之后被丟棄不再使用,這樣CPU LOCK無需等待GPU使用資源完畢,能繼續操作圖形資源(頂點緩沖和索引緩沖),這技術叫VB IB換名(renaming)。 

            很多困惑來源于底層資料的不足,相信要是MS開放D3D源碼,開放驅動接口規范,NV / ATI顯示開放驅動和硬件架構信息,這些東西就很容易弄明白了。

            順便做個書的廣告 《人工智能:一種現代方法》中文版 卓越網已經有貨,AI巨作,不過閱讀需要相當的基礎,對思維非常有啟迪,想買的朋友不要錯過。后面我會將學習重點從圖形轉到AI上來,對AI有興趣的朋友一起交流。

            posted @ 2009-08-13 00:29 麒麟子 閱讀(2177) | 評論 (0)編輯 收藏

            僅列出標題
            共38頁: First 18 19 20 21 22 23 24 25 26 Last 
            国产色综合久久无码有码| 久久免费视频网站| 要久久爱在线免费观看| 香蕉久久夜色精品国产尤物| 亚洲AV日韩精品久久久久久| 久久香蕉综合色一综合色88| 午夜精品久久久久成人| 国内精品九九久久久精品| 91久久精品国产91性色也| 国产精品久久久香蕉| 狠狠88综合久久久久综合网| 很黄很污的网站久久mimi色| 无码人妻精品一区二区三区久久| 精品久久一区二区三区| 亚洲国产成人精品无码久久久久久综合 | 久久久黄色大片| 成人国内精品久久久久影院| 久久综合久久性久99毛片| 日韩AV无码久久一区二区| 久久99精品国产麻豆蜜芽| 久久久久亚洲精品无码蜜桃| 久久强奷乱码老熟女网站| 久久久久无码精品国产| 久久九九久精品国产| 国产V亚洲V天堂无码久久久| 久久中文字幕视频、最近更新| 久久精品国产亚洲AV无码娇色| 日日狠狠久久偷偷色综合96蜜桃| 久久精品人人做人人爽电影| 午夜精品久久久久久毛片| 亚洲精品无码久久毛片| 久久久WWW成人| 久久久精品波多野结衣| 国产精品99久久久久久猫咪 | 粉嫩小泬无遮挡久久久久久| 亚洲国产精品无码久久九九| 久久中文字幕视频、最近更新| 久久久久噜噜噜亚洲熟女综合| 国产成人精品久久亚洲高清不卡 | 久久福利青草精品资源站| 国产美女久久久|