D3D10移植感想

    折騰了許久,今天終於完成到D3D10的移植了。總體感覺不錯,性能提高了不少。基本上,有一種再也不想回到混亂的D3D9時代的感覺。新的API很精簡,沒有冗餘,操作和性能的關係很明瞭,完全貼合硬件。

    當然,這也意味着,它和D3D8、9的設計方向完全不同,而是一套偏向底層的API。早年,D3D API一直飽受爭議,PC開發者大多認爲它太底層太難用,而少數來自遊戲主機開發背景的人則反而認爲它抽象層次太高阻礙優化(遊戲主機的API要更加底層)。當然,PC開發者的意見形成壓倒性的優勢,所以D3D不斷向易用性方向前進,在版本8、9達到頂峯,甚至一時間贏得了超過OpenGL的口碑。但出乎意料的是,可編程管線的迅速發展改寫了前進的方向,尤其是頂級的遊戲廠商,他們對性能和靈活性的追求遠遠超過易用性。一套API難以同時滿足不同需求的用戶。此時的OpenGL也遇到了相同的問題,遊戲開發者認爲GL API已經嚴重脫離當今的硬件加速模型,需要調整精簡,而CAD開發者則認爲完全不需要,兼容性才最重要。爭論n年之後的結果,就是分成兩個profile。

    這種情況下,D3D10被設計成一套全新的底層API,面向高端用戶。一般商務3D需求則有高層的WPF來滿足,兩者間的空白由XNA來填補。WPF和XNA都是基於.NET的,而對D3D10,微軟甚至沒有官方的.NET包裝。這個定位,也導致D3D10的使用難度很高,如果不是追求頂級性能和靈活性,沒必要爲此浪費青春,退半步就有微軟在易用性上下了苦功的XNA,而且XNA本身也爲未來過渡到D3D10架構做了充足的鋪墊(XNA還是跨平臺的,支持Windows、XBox、Windows Phone 7、Zune)。

    作爲底層的API,D3D10是不太適合直接用來寫應用的——尻,D3D就沒有一個版本適合直接用來寫應用的,每隔幾年API就變得面目全非了,總得包裝一層。但因爲這次變動太大,包裝層都不得不改。同時,D3DX的擴展庫大幅縮水,大量的設計時預處理功能不復存在,而D3D11的擴展庫幾乎就不剩什麼東西了。因爲高端開發者是看不上D3DX的,他們都有自己的更優秀的實現。既然D3D10已經定位爲面向高端開發的底層API,也就沒必要費時間去維護龐大的D3DX了。這些功能呢要是自己重頭寫起,也是要花費不少功夫的。

    新架構下,渲染API核心只有三樣東西:輸入流(頂點數據)、配置管線中不可編程部分的狀態對象、shader。Shader的作用被大幅放大,alpha test、clipping、fog等全由shader實現。所以熟練使用shader是升級到10的前提,最好在升級前就儘可能把這些都轉換爲shader實現。

    但話說現在D3D11都出了很久了,10的文檔卻還是那麼的單薄。很多東西都要自己試出來。比如現在InputLayout必須和vertex shader的輸入參數匹配,但其實只是要位置和semantic匹配,vertex shader的輸入參數是可以比InputLayout少的。再比如,當前版本的effect pool含有非shared的cbuffer的話,編譯正確,加載依賴於此pool的effect時則出錯。再比如,D3DX10FilterTexture()是處理staging的紋理還是顯存中的紋理呢,是CPU處理還是GPU處理?API裏只有SamplerState,shader裏卻有一個沒有文檔只有樣例的SamplerComparisonState,而且對於SampleCmp族函數,還必須使用SamplerComparisonState,其中一個文檔樣例中出現的屬性,編譯時會報錯說該屬性不存在……

    最頭痛的是Device Removed。雖然沒有了Device Lost,但這回不僅僅是暫時丟失控制權,而是設備直接沒了。要調試一下也不容易,得卸載顯卡驅動,再重新安裝;或者帶獨立顯卡的筆記本電腦擴展塢,接駁和斷開。而且設備移除發生時,程序又能怎麼辦呢?等待重新出現一個可用設備。一個可能是可用設備不會再出現了,另一個可能是出現一個不同的設備,設備能力有所不同。以前設備丟失只要Reset就好了,managed資源會自動恢復,現在可得重新創建設備,什麼都得重新初始化。當然,設備移除算是小概率事件,誰會在遊戲過程中更新顯卡驅動呢?當然接駁擴展塢還是可能的,驅動內部錯誤復位導致設備移除事件也是可能的……

    另一個較大的設計方向變化是,分離設計時與運行時。大量的操作,如狀態對象的創建、管線各個stage間傳遞參數結構的映射鏈接、shader參數的按修改頻率分組等,都要在設計時明確,初始化時執行,而運行時不再校驗處理。D3D9的靈活、自由、朦朧的組合匹配不復存在。這對引擎架構有不小的影響,意味着vertex buffer的格式和shader相關,比如一個shadow map的shader不能再和不同格式的vertex buffer組合使用。

    一個有趣的發現是,D3D10 API不僅繼承了D3D9的左右手系都支持的特性,而且更加的貼近右手系。D3D10_BOX等體描述都是按右手系的軸方向,D3D10_RASTERIZER_DESC也提供了OpenGL式的基於正反面而非纏繞方向的CullMode和獨立的FrontCounterClockwise參數定義面正向的纏繞方向。在WPF、XNA都使用右手系的情況下,D3D轉向右手系也是理所當然的。當然,紋理座標系仍然是top-down而非GL的bottom-up。其實這個和左右手系無關,3DSMAX就是top-down的紋理座標,2D紋理座標使用top-down模式還是很符合2D處理習慣的(不如說是GL的bottom-up紋理座標更另類一點)。3D紋理座標就是在x向右y向下的2D座標系基礎上,加上向前的深度方向的z,正好是右手系。

    10的debug信息比以前有了大幅的進步,其詳細程度超過文檔。不過,比較不容易發現的是,要開啓debug信息輸出,不止要創建debug layer,而且要在DX Control Panel里加入程序的路徑纔行。debug信息會輸出到IDE的Output Window,但是,對於managed project,需要在工程屬性裏debug頁勾選unmanaged code debugging纔行。對於免費的Visual Studio Express版,C#、VB無此選項,需要用其它工具,比如DebugViewNT。

    最後,相信大家會有這個疑問,爲何不直接升級到D3D11呢。這個確實想過,但考慮到難度,步子邁得太大,會扯着蛋。從10到11會相對容易,9到10則問題重重,在調試很困難的情況下,循序漸進,一個一個地解決問題要容易些。另一方面,11剛出不算久,支持的顯卡不多,用的人少,遇到問題時解決方案都難找。而且,微軟對11的API的態度都有點實驗性質的,還是“不敢爲天下先”好了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章