小弟疑惑了許久,google未果:

一般z buffer用於merge stage處理不同物體的遮擋,當在同一次draw call中物體存在自遮擋時(例如視線橫穿「凹」型),z buffer會用於光柵化階段嗎?如果會,1.那gpu光柵化階段遍歷三角形應該不是並行的吧(不然對z buffer會有寫衝突)?

2.z test compare function的設置以及z write開關,在光柵化階段也起作用吧?


空明流轉:Salvia雜談(一)——保序的三角形?

zhuanlan.zhihu.com圖標

這都一兩個月了,你還在糾結光柵化會不會收到 z compare func 的影響。

這裡你就應該仔細閱讀一下

Graphics Pipeline?

docs.microsoft.com圖標

固定管線的部分非常簡單明白,就是三角形來了,變換到屏幕空間,按照屏幕的四個邊角一裁,光柵化出x,y和depth,然後算出這個點的顏色,再送到後面和depth buffer上對應x y處的值作比較,通過就寫,不通過就丟掉。

這個時候你就知道原則上 z func 和 rasterizer 並沒有鳥關係。

然後你的第一個問題也很簡單,三角形的發射原理上就是串列的,這個不僅僅是寫衝突,也是為了結果的一致性。

至於並行發射什麼,那都是優化的事情了,但是不管你怎麼並行,結果就應該和串列生成三角形等價。


很久以前,新的三角形如果z test通過了,就會直接把緩衝區里畫好的像素覆蓋掉。現在當然沒這麼簡單了。


蟹腰

首先,光柵化之前的,是由頂點組成的primitive,最典型的就是三角形;

光柵化之後的,是sample。當未開啟multi-sample功能時,基本等同於像素(pixel)。

Z測試發生在什麼時候?當代的GPGPU當中,其實至少包括Hi-Z/Pre-Z/Post-Z這三個階段。Hi-Z和Pre-Z發生在光柵化之後執行fragment shader之前,而Post-Z發生在fragment shader之後。但是無論是哪種Z測試,都是發生在光柵化之後。

也就是說,Z測試發生在光柵化之後,光柵化的時候其實是全量光柵化的,無論primitive之間是否有遮擋的情況。然後通過Hi-Z/Pre-Z減少光柵化生成的sample數量,從而減少fragment shader執行的次數,以及減少最後輸出的sample/pixel的個數。Z測試發生在光柵化之後,從而並不會影響進入光柵化的primitive的個數。

影響進入光柵化的primitive的個數的階段叫裁剪/剔除,最為典型的有視錐裁剪、正面/背面剔除、零面積primitive剔除。被這些演算法剔除的primitive,不會進入光柵化階段。

既然光柵化的輸入為primitive,這個時候已經沒有了所謂的「物體」(Object)的概念。所以也不存在「不同物體之間的遮擋」或者「自遮擋」這些概念。且primitive為平面凸多邊形,不會有自遮擋。

在一個GPGPU當中,光柵化模塊可能會有2組以上(具體視GPGPU架構而不同),這些模塊是並行執行的。因此光柵化操作是並行的。但是,在大多數架構中,它們是按照屏幕不同區域分工的,因此相互之間不容易發生primitive遮擋(大的primitive會在光柵化之前按照分工區域裁剪分割)

Z Write發生在fragment shader當中,在管道位置上是光柵化之後。GPGPU會為光柵化之後首先執行Hi-Z/Pre-Z測試,通過測試的每個sample/fragment/pixel會執行一個fragment shader的實例(線程),這些fragment shader的執行是並行的。如果在fragment shader裡面有Z-Write,那麼這些Z-Write也是並行的。當然,這個並行並不是無限寬度的,而是按照一定的尺寸進行組織的。N卡的基本組織單位叫Wrap,一個Wrap為32個線程(也就是32個sample/fragment/pixel);而A卡稱為Wavefront,一個Wavefront為64個線程。在一個Wrap/Wavefront當中的不同線程,它們在任何一個時刻執行的是同一個命令,這就叫SIMD、或者SIMT架構。也就是說,如果你的fragment shader裡面有z-write命令,那麼對於一個Wrap/Wavefront裡面的線程,它們是同時進行的。當然,具體到很細節的地方,比如內存的寫操作,必然是需要原子操作的地方,其實在某個地方還是會有排隊的。如果有兩個或者兩個以上的線程同時對同一個位置(屏幕/貼圖坐標)進行z-write會怎樣?答案就是GPGPU內部(DB)會有專門的單元根據你設置的z test compare function來裁決,決定最終寫入的值。

對於有z-write的情況,會強制執行post-z,重新進行z測試,因為z-buffer的內容改變了。


可以多個光柵化單元並行執行,每個單元負責不同屏幕空間,可以避免衝突。

單純使用earlyz的情況下,光柵化找到覆蓋的像素點後,插值出深度,然後進行zbuffer進行earlyz test,通過測試的像素點再進行fs/ps處理。

使用HiZ的情況下,光柵化n*n像素塊的時候,計算當前像素塊的的max_z/min_z,讀取zbuffer進行測試。

三角形的光柵化順序按照三角形的api提交順序進行遍歷,也按照這個順序讀取更新zbuffer。


1.首先Blend情況下,一次Drawcall 是根據圖元的提交循序光柵化.可以參考Intel 這個對DirectX12 ROV描述.

Rasterizer Order Views 101: a Primer?

software.intel.com圖標

2.在非Blend情況,三角形片源的順序是並行的.實現的方法可以參考Intel的PixelSyn,同步Pixel Shader裡面的訪問順序可以保證深度不會出現問題,具體實現方式每個都不太一樣吧.但是還是ROV原理保證訪問一致性,但是開了Blend就不能並行啦


zszz z ethe and sss
推薦閱讀:
查看原文 >>
相关文章