軟體渲染有沒有辦法提高紋理採樣速度?

最簡單的情況,就是在片元著色時,根據texcoord算出圖片buffer位置,然後讀出那一個像素來,繼續光照等等其他計算。

稍微複雜一點的也無非就是根據texcoord以及某種過濾方法,比如雙線性等,算出四個或更多buffer位置,讀出像素來混合一下,然後繼續。

可問題是,每次profile都發現讀取像素值特別慢,說白了就是讀內存慢吞吞的。比如,codexl總是報告在一個我寫的沒有幾行的讀取紋理的函數里,一條mov reg,mem指令被採到了很多很多samples。

我的猜測是:

1,如果紋理特別特別大,則高緩一次裝不下多少紋理。如果再加上texcoord跳來跳去的,miss想必挺嚴重。

2,如果用多線程並行處理片元,並且由於啟用了超線程,使得兩個線程跑在同一個物理核上,但它們卻只能分享同一個高緩。如果它們處理的片元幾何距離較遠,也更加加劇了在紋理中跳來跳去的現象,也就更加劇了miss。

我想問問有沒有什麼好的方法提高軟體渲染讀取紋理的速度?

請別告訴我等DDR5啊呵呵~


的確紋理讀取和Filter對的確比吃軟體渲染的性能。對於不同類型的渲染器和在不同硬體平台來說,優化策略也都有有些不一樣。Ray Tracer和Rasterizer的優化策略不同,CPU和GPU程序的優化策略也不同。

首先確保一些最簡單、基本的優化一定得有。這些優化也是與平台無關的。

例如對於Albedo texture來說,儲存的時候不要傻乎乎的存float或者double,不然一個Texel的大小就是16或者32個byte。直接全部存成unsigned char(HDR紋理除外), 這樣一個Texel的大小就只有4個byte,內存訪問的壓力就小了很多。對於Normal map這種單位向量的紋理來說,可以採用一些壓縮的方法。這裡給個這方面的Survey:Journal of Computer Graphics Techniques

再有就是,使用Mipmap Pre-Filter也會在一定程度上減小內存的訪問。因為對於遠處的物體,訪問的紋理大小會比沒有Mipmap的紋理小很多,而且Mipmap也是高質量紋理Filter所必須的。高效的實現Mipmap也有些技巧,因為1/4 Downsample這個過程要求紋理本身的大小是2^n,如果你有一個1023大小的紋理,就必須先Upsample到2048,這樣又會更廢內存。如何更避免這裡的Upscale可以參考這篇2005年NV的technical report:ftp://download.nvidia.com/developer/Papers/2005/NP2_Mipmapping/NP2_Mipmap_Creation.pdf

接下來再簡單說幾個平台相關的優化。

對於CPU上的軟體渲染器來說,紋理在內存中儲存的Layout也會影響性能,因為沒辦法使用GPU中針對Spatial Locality優化的texture cache。由於Linear和Trilinear Filter會一次訪問相鄰的4個Texel,而且不同紋理上(x,y)和(x,y+1)在內存中的線性距離通常比較遠,緩存命中幾率很低。所以將紋理的內存保存成Block Linear的Layout理論上會改善這種情況,訪問上下左右的紋理時,提高緩存的命中率。只不過有些時候,高頻率的紋理地址轉換也會對性能造成一些影響。

如果是在GPU上實現的Rasterizer,則可以利用硬體上的Texture Cache,可以大大減少讀取和Filter的開銷。但由於是軟體實現,Mip LOD的計算無法依賴於硬體。這裡一個可以優化的方法是Shading的時候將GPU上的線程組織成Quad Linear,模擬硬體上Pixel Shader的調度機制。然後直接用Shuffle指令獲取相鄰線程的UV,求差,快速的計算Texture LOD。同樣的方法也可以用在CPU上的實現,最笨的是讓一個CPU線程Shade一個Quad中的四個像素,然後對相鄰UV求差算出LOD。想進一步優化的話可以直接用SIMD一次Shade一個Quad中的四個像素。

對於Ray Tracer來說,紋理的訪問更加隨機。渲染器在同一時刻需要Shade的任務理論上可以觸及場景中所有的紋理,因為不像rasterizer一次渲染一個物體,對於光線追蹤來說,光線打到什麼物體是無法預先確定的。所以針對不同系統,有不同的優化方式。最基本的優化,也許是將畫面分割成若干個小的Tile,然後將Tile分配給不同的線程,這樣對紋理訪問的Spatial Locality有一定的幫助。

對於紋理訪問是很大瓶頸的系統,例如Disney的Hyperion,又或者在GPU上極度需要避免Execute Divergence的SIMT的程序,可以考慮wavefront的做法。在做光線求交的時候只保存交點的信息,但並不做任何著色。接著對所有交點按照所訪問的紋理排序,最後對訪問同樣紋理的交點批量著色。

再有就是,對於Diffuse反射的光線來說,Texture Lod無法定義,這時候選取Coarse的Mip Level對性能也會有一定的幫助。同樣的情況也適用於任何Bidirectional Tracing的演算法中由光線追蹤出的光線。雖然說了那麼多點,但是渲染系統的優化也遠不止針對紋理而已。幾何處理,著色,採樣等等一堆問題可以提高渲染的質量/性能比。我的建議是只有在確保自己沒有做一些非常明顯的會降低性能的事情時再考慮系統底層的優化。


可以考慮用 Pre-Z Pass 減少紋理讀取的數量。

其次多線程的時候把Tile而不是Primitive分配到線程上 —— 分配Primitive到不同線程而不顧執行順序,在邏輯上就是錯誤的。

參見這篇文章:

Salvia雜談(一)——保序的三角形 - 藍色小藥丸 - 知乎專欄

然後讀取Texture時候的Cache Missing Ratio,在L2和LLC上都不是很高,你可以Profiling一下。

有一個地方要注意,Texture fetching本來調用的次數就是非常多的。只有它所佔的時間和其他著色環節比例異常的情況下,才需要去優化它。這裡有很多回答都提到了硬體的Texture Unit。Texture Unit單元的價值,Cache僅僅是一部分。更有用是硬體的整個Data Path帶來的Latency Hiding的能力。

Cache的優化不以Line為單位來做,而是應該以Cache Set Size來做。Cache Set Size內的訪問順序並不重要 —— 當然考慮Cache Size和下一個部分的鄰接性是另外一回事。而且,Temporary Locality也是與Cache Set相關,並不是嚴格要求Neighborhood, 所以 @文刀秋二 提到的 (x ,y) 的線性距離問題在做了Tiling,分配了合適的Tile Size後,就不太重要了。

更複雜的定址,在CPU上還要浪費時間算Hamilton或Morton Code。在沒有Structural Latency Hiding的支持下一般是划不來的。

@Milo Yip 提到Mip Map是有優化作用,但這個主要是Functionality上的需求,默認software rendering就應該有,該開的時候就應該開,所以不能算是優化了。對於一些真正有稀疏採樣行為的方法 —— 比如Bilateral Filtering,PCF,還就不能用Mipmap。

@叛逆者 提到的grouped texture fetching —— 在HW上,只要把 Cache Line 加寬就行了,Cache本身就是天然的memory access group。

Tile Swizzling是個不錯的主意。如果有編譯器配合,可以生成很漂亮的SIMD指令 —— 但是取值本身可能比較糟糕,因為本來一個color一個32bit就擼回來了,剩下都是寄存間的操作。但是如果Swizzling之後,明面上就需要4個訪問指令才能擼回來,好壞就看CPU自己的優化了 —— 比如CPU把L1擼成Register File之類的。

Sampling based profiling,在指令這個級別有非常多的False Alarm,用的時候要當心。


如果內存是瓶頸,演算法上可以試一下:

  1. mip-map
  2. texture swizzling
  3. block compression


其實對軟體渲染器來說,texture fetch和filtering都是非常嚴重的問題。所以Larrabee的結構是,幾乎所有的組件都是軟體的,連blending都是軟體的,但texture fetch和filtering堅持用硬體做。也是因為這部分如果用軟體的話,性能和功耗都受不了(然而即便如此,功耗還是受不了,才取消了)。

在GPU上,有GDDR5甚至HBM這種帶寬超大的貨,可以把需要fetch的坐標攢一批,一次讀取,硬體filtering。但軟體做的話,DDR3並沒法用這種方法帶來同樣大的性能提升。而且硬體的紋理不是線性排布的,一般是分tile,tile內zigzag。你也可以嘗試用同樣的方法降低cache missing。


1.做 texture compress

2.做tile 的sample,提高cache命中


推薦閱讀:

在遊戲引擎中常用的光照模型有哪些?
3D 渲染中使用 Accumulation Buffer 實現景深(Depth of Field)效果?
如何評價國產3D動畫《墓王之王》?
如何在WPF程序中調試C++ dll?
keyshot渲染燈具怎麼才能做到光線自然發出?

TAG:計算機圖形學 | 計算機圖形學和可視化 | 3D渲染 |