vrchat吧 关注:35,075贴子:307,989
  • 27回复贴,共1

幾何過重的情形越來越嚴重

只看楼主收藏回复

感覺最近觀察追蹤,多邊形或著說三角形數量逐漸失控,如果只是單純這些還好,但是這通常反應的了一些事實,製作者可能不清楚負荷究竟有多重和如何測量。
而由於這方面的知識對大多數人不易學習操作,也很難認知甚至真正理解到底有多重和難以解決。
一般而言隨著規模越來越大,GPU幾何管線轉換到像素管線會越來越難也低效率,這受到頂點數據排佈和實際渲染上的複雜來回訪問模式影響,極易受硬件實現上的高延遲影響,從而表現出低利用率。
頂點數據的專用訪問硬件被添加到前端到計算單元周圍,需要經過多個步驟才能成功組織並計算出想要的座標,並最終提供給像素片段,或著也能認為是一個暫時產生的一張張紋理,混合計算輸出最終畫面。
這基本上是目前最優的方法了。
整個流水線你可以簡化成幾何管線(又稱為世界空間管線,NV文件說法)、像素管線(又稱為屏幕空間管線,NV文見說法)
越前面越複雜難以並行,又可以為這些管線細分幾個步驟,幾何管線(圖元分配、頂點屬性獲取(VAF)、頂點著色器)而頂點著色器到像素著色氣或歸納於幾何的後部分,VPC(剔除單元)->RAS(光柵化器),而到像素管線則經由TMU獲取紋理和ROP寫入等最終輸出。
頂點著色器隨著版本改進逐步想達成替換頂點著色器各種限制,幾何著色器(DX10)、細分曲面著色器(DX11)、網格著色器(DX12),想要兼具高效與靈活。
________________
而現在除了VPC累死和RAS轉換不快,其實影響大概也就一些時間,而不管怎麼丟棄當大量頂點數據進入且必須計算的時候,就得至少付出80~90%在幾何管線的時間,是必須經過這些步驟到像素前的設置轉換,才進行一些所謂的硬件剔除的,才同時做所謂的世界空間到攝像機空間、屏幕空間轉換等等云云,所以大量的頂點數據基本上是壓垮現代GPU幾何效率的部分。
而如果你很好正規的製作資產,這些模型做得很好,大概每3個三角形對應2個頂點,做得比較好會接近每2個三角形對應1個頂點,你可以知道大概以三角形數量而言,約50~66%比例算出大致的頂點數量。
如果你完全不懂整個流程,不懂分割UV島這些,細碎亂分毫無規則感,甚至會導致頂點重複計算,從而導致頂點數量翻倍,從而嚴重加重渲染負荷。
______________
影響有多大?非常大!
因為你多個渲染步驟,本質上都是重複走上述的管線N次,也就是說你想算出一些效果就會走頂點到像素,下個步驟也是頂點到像素,N個步驟後結合成功輸出最終畫面。
而畫面中人物數量越高,呈現線性增長幾何負荷,但是不線性增長像素負荷,這是因為會取決於渲染面積,遠處的avatar佔據面積小,近處佔據面積大,甚至結合剔除機制省下一些不必要渲染的像素開銷,增長十幾倍幾何開銷也僅只會增長數倍像素開銷。
像素與分辨率呈正比,且大量相對同質好走訪數據,利用率普遍相對高利用率。
幾何如果是簡單的靜態mesh還好,如果你是蒙皮mesh需要變形,並行度就會受到限制難上升,盡管一些渲染步驟仍然能大幅提高利用率,但通常負荷非常沉重,提高利用率遠不如增加的負荷,會顯著降低幀數。
______________
大概怎麼估算負荷?
以大量蒙皮為例,大概約20%RAS利用率,30%多頂點VAF利用率瓶頸,同時也可能導致L2瓶頸,通常是VAF,但VAF極受單元數量甚至緩存系統,非常難以計算且動態,還受到許多導入模型設置等影響。
(利用率受前端數量影響也挺多,前端越多通常利用率越低甚至會崩跌(本質上是無法並行導致可以通過的數量有限,數量越多導致分得越多,從而呈現利用率過低))
大概估算方式是先算RAS,假設頂點負荷重-20~30%的幀數。
先取得GPU的前端數量,例如一張顯卡擁有5個前端(是個3060ti/4070ti),頻率在1.8Ghz/2.6Ghz,則計算如下...
可以得到理論值為9、13,利用率計算出約1.8GTri、2.6Gtri,而受到頂點數據很好-5%,但普遍20~30%,這裡取20%計算。
1.8*(1-0.2)=1.44Gtri
2.6*(1-0.2)=2.08Gtri
因為普遍使用toon shader,這裡使用輪廓。
假設150K tri 是活動且在攝像機內,計算完輪廓為300k tri。
直射光或稱主光燈時,僅計算一次,而大多數為了能在場景中表現動態的亮暗,和有效在法線產生二值化的toon shader上產生顯著效果,打上了像素燈光,導致通道(pass)增加。
而必須重複計算的結果,當使用一盞光源,導致重複計算完到600k tri,如果為兩盞燈(每盞燈範圍越大容易重複覆蓋,只要覆蓋到的模型部分就會導致重計算,這裡簡化成剛好模型所有網格被全部都照到)都照到計算到900k tri。
這裡設下標準,不開鏡子下直接看到這些所有avatar一共10個。
10*600k tri=6M
10*900k tri=9M
分別轉換單位計算,從上面1.44、2.08轉換到1440M、2080M。
可以得到大約240、347fps,在6M tri下。
或160、231fps,在9M tri下。
接下來假設幾何非常沉重,導致整體時間佔比剛好頂到一個極限左右,75%時間佔比(不詳細解釋原因,因為太長),其他部分被像素佔據,並且像素不更沉重的情況下。
分別得到180fps、260fps (6M)和120fps、173fps。
不考慮場景及其他更重負荷情況下的fps。如果你的顯卡僅是3060、6600XT之類等級,可能更低,例如以3060來說大概3個,雖然利用率更高些。
簡易估算大概*0.7(對於3060ti)->108fps(6M 1燈)、84fps (9M 2燈),你可以理解為什麼GPU負荷這麼高。
如果你開啟鏡子,利用率會稍微上升,並假設全部看見,負荷會增至原有1.8~1.9倍。
對於3060你會得到以下結果
57~60fps (6M tri 1燈),44~47fps (9M tri 2燈)
對於3060ti你會得到以下結果
95~100fps( 6M tri 1燈),63~67fps(9M tri 2燈)
對於4070ti你會得到以下結果
137~144fps(6M tri 1燈),91~96fps(9M tri 2燈)
如果你一次看到更多avatar,或燈光設計不合理密集或單燈過大範圍,負荷會更大,請將更多avatar盡可能優化,部分活動avatar超過25萬三角形不少算少有點離譜。
以上是大致的典型值,可供參考估算。
請勿使用在超過3060ti、4070ti以上規格前端的GPU,會導致計算不準確,結果會近似以上,等未來計算著色器替換頂點著色器以計算著色器蒙皮合批利用可以『近似』估算,雖然近似估算誤差大。


IP属地:中国台湾1楼2024-09-08 16:36回复
    實際上需要考慮場景其他的模型和基本上著色器可能會過度繪製幾次與屏幕像素的量,基本上很難在avatar數量較低(數個到十個多左右算低)達到75%時間佔比,考慮各種情況實際上可能僅50~60%。
    所以上述fps 不*0.75而是*0.5~0.6,數值會更低。如果是大量花草看紙片做法還是紙片混合建模、純建模都有很大不同的差異,更別提密集的樹。(盡管靜態mesh可能會比蒙皮速度快至兩倍)
    3060、3060ti、4070ti 於6M下參考值->168、240、347
    3060、3060ti、4070ti 於9M下參考值->112、160、231
    84~100 、 120~144、173~208
    56~67 、80~96、115~139
    通常分辨率可能都足夠高,或是一些因素導致像素負荷更重,所以會比上述更差一些,而且目前還沒包含動態陰影甚至軟陰影,會導致增長很多負荷,硬陰影比軟陰影在效率上更高(利用率更高),雖然兩者計算量相等,硬陰影如果增加一倍所以大概1.8~1.9,軟陰影就2.2~2.5。
    _______
    有趣的問題,似乎不管怎樣增長硬件規模,每個週期在圖元分配到獲取頂點屬性上似乎不容易超過或趨向每週期1個頂點?即使透過計算著色器合批、網格著色器等先進特性只是逼近該數值或稍微解放點?(離VRchat有點太遠的議題,目前最多利用細分著色器(DX11))
    或許就是為什麼GPU要一直提高頻率的原因...
    我不是NV/AMD的GPU設計師,不懂為什麼會有這樣的趨勢,或著只是剛好而已,這是個猜想...分享部分可計算可取得的數據....
    _______________________


    IP属地:中国台湾2楼2024-09-08 18:05
    收起回复
      青月我喜欢你


      IP属地:山东来自Android客户端3楼2024-09-08 18:54
      收起回复
        难怪感觉开镜子好像比以前更卡了?好吧也许是我模型没优化好()但是我自己大概加载出来40MB的模型有时候vr上一个人开镜子都有点小卡


        IP属地:广东来自Android客户端4楼2024-09-08 20:45
        收起回复
          上述的每週期1個頂點其實還是可以有辦法突破的,會重複利用同樣頂點索引做許多事情,減少最前端的工作。
          不過仍然還是相當沉重的,如果自製資產太爛需要花非常多時間學習,除了好看高效整個流程可能要數年甚至非常多年...
          現在Shader基本上也會結合Unity引擎從而達成重複利用頂點索引,盡管仍然無法節省大量重複的頂點數據訪問和拼裝成本,但是至少提高了並行度。
          不過意外發現,Unity BIRP的設計存在一些問題,在擁有龐大頂點的情況下請禁用垂直同步一類,與CPU開銷同步或PCIE等等均無關,而是會導致限制並行效率,且同時反應出無CPU瓶頸下卻無法使GPU利用率滿載的特性。
          極端情況下會導致-30%fps,禁用後可以提高利用率到100%,同等利用率下減損5~10%fps。
          SRP以上沒有這個問題,不過一些實作會導致VPC過於沉重(以URP為例)。(對於靜態Mesh 相對沒頂點瓶頸,VPC剔除上更精密,但開銷也更大,如果能有效確認來大片刪除還行,但通常大量輸入都過於細小剔除)
          (URP還有個奇葩問題,開了垂直同步會比沒開還快,約能快10%+...跟BiRP剛好相反(-30%...),所以還是別逆天搞超多頂點,會牽涉複雜的緩衝區和同步問題)
          依據profile和nv文件,VPC/RAS雖成綑綁定,但VPC算做幾何管道最後一級,會算進幾何負載中,而RAS則會納入像素負載中。
          根據前端數量*利用率*頻率 = 可以處理的圖元輸入量
          RAS則取決於圖元輸出量

          Clip Primitives in 也等同於Unity中的 Tris

          Clip Primitives Out則決定RAS(RAS覆蓋面積也會決定,最小轉換2x2 最大轉換16x16,超過面積會複製到大屏幕上,由內部插值完成,統計無法看到,普遍對應1RAS=16像素,AMD RDNA2後為32像素。)

          靜態網格
          222fps

          使用計算著色器加速(當前VRchat 使用Unity2022但使用頂點著色器替換,效率約降低三四成利用率,這是因為索引效率影響,估計等Unity6 動態批合後減少CPU開銷和提高線程組調用效率才行)
          186fps(預測頂點著色器約120~122fps)
          蒙皮時(Unity後續實作計算著色器 為了簡化,所以不允許無權重頂點可以直接定義蒙皮,會強制在編輯器檢查和執行期加載檢查不通過導致消失。)
          雖然同樣約8.4M左右頂點,但是由於頂點屬性更多負荷更重。
          使用簡單結構細分,原始比例是2三角形比1頂點,由於UV展開重複頂點定義會膨脹些,所以比例達約1個三角形比0.58個頂點。
          透過點開FBX可以看到頂點數據和三角形組裝所需的索引共佔據的網格內存體積(並非相對壓縮的FBX大小)

          FBX約27.7MB 實際顯存占用約34.7MB 每個頂點約32byte 每個三角形12byte

          FBX約32.2MB 實際顯存占用約45.3MB 每個頂點約48byte 每個三角形12byte
          一般單網格沒那麼大,會使得『頂點』總數低於65536(2的16次方)從而使用16bit索引組裝三角形,這樣每個三角形只要2byte*3=6byte。
          這是一般人使用booth上資產的情況

          每個頂點在蒙皮上使用了92byte
          實際上拼裝索引過程複雜難算,會消耗大量的帶寬,而無法單純看體積大小計算,也許一個10MB的網格,實際上反複索引頂點拼裝形成外觀消耗了大概10GB+的緩存帶寬,一些miss產生了數GB的VRAM帶寬開銷。
          頂點屬性越多,同樣單個頂點就越沉重,一定程度上也阻礙了每週期是否能穩定存取單個頂點的能力,一些benchmark中極端的測試因此嚴格限死每週期的上限,導致幾乎幾何順序化,從而讓頂點著色器性能相當差勁。
          幾何著色器就擁有這種特性,雖然靈活能塑造外型,但是嚴重單線程化的訪問甚至因為其允許靈活高複雜度更多操作更低效率,導致除非很必要很必要的場景才考慮這個DX10活了一下就被淘汰的東西,或許你只能在某些自製遊戲引擎中有機會看到較高幾何著色器負荷的時候,因為是老舊的Shader。
          細分曲面著色器很好解決了頂點數據問題,甚至能大量利用紋理位移鑲嵌細分,省下一大筆頂點和組裝三角形帶寬成本,僅只需要考慮密集三角形造就的VPC、RAS問題。
          然而因為無法在細分時靈活切分各種細分形狀,無法準確複現任何外形,還有與頂點著色器使用的Shader在座標計算上不合,從而錯誤接收陰影和投射陰影,甚至會導致投射類著色器等等功能失誤產生畫面bug。
          計算著色器和網格著色器就不解釋了,VRchat用不了。
          理想上而言,我們忽視任何頂點數據瓶頸和頂點索引在每幀硬件重複生成、組裝等並行性問題一大堆,僅只考慮光柵化器前的座標轉換與剔除的單元也就是VPC。
          三角形數量100萬,增加輪廓後200萬,渲染100個,然後忽視nvidia、AMD硬件剔除實作和偷偷搞的緩衝區設計。
          2M*100=200M
          你是一個3Ghz的GPU,你一共有十二個前端,現在效率是理想利用滿100%無延遲問題,你不需要輸出任何像素。
          12*3=36G tri ->36000M tri
          36000/200=180fps
          ________
          同等情況下的三角形/頂點效率也有所不同,這取決於Shader需要訪問的數據、計算延遲等,通常實作下
          輪廓>陰影>複製>燈光,雖然差距可能不是很大...


          IP属地:中国台湾5楼2024-09-09 22:12
          收起回复
            拿得来这些内容的


            IP属地:浙江来自Android客户端6楼2024-09-10 13:28
            收起回复
              上面可能已經有一些人計算了,但是發現消耗的帶寬很大甚至可能超過profile的數值,這是怎麼回事?
              其實有這樣的一個特性,也就是『steam』。

              這種特性可以讓mesh上的頂點按需使用,也就是只有Shader需要的時候才取用,規避進入L2甚至節省VRAM上的帶寬(看引擎實現,可能L2、VRAM中改變點結構存取,可能浪費VRAM也可能不浪費VRAM的帶寬)
              不過如果沒有這些機制去產生交錯緩衝區等,仍然可能沒能有效利用偏移值等引擎內部實作的技巧,最終可能會浪費帶寬。
              _______________
              對於一些avatar你去獲取數據時,可以發現一個頂點上消耗掉80~90byte甚至有更多的,實際渲染消耗上可能48~60byte每個頂點。
              可以認知到其實每一步都是很精心設計,如果沒有這些機制和索引等,最終一個三角形需要數以百計的byte壓垮了顯存容量,一個網格輕易數十上百MB,甚至在帶寬消耗上非常誇張,尤其是顯存帶寬輕易就浪費完了。
              透過這些機制從顯存上獲取數據重新組裝回三角形,充分利用與節省帶寬在緩存上,不過仍然對於大量的三角形而言很能難長期保存在緩存上,因為GPU緩存並不大且按照普遍使用方式,幾乎難以重複使用命中,相對於CPU來說GPU僅只能簡化設計為FIFO。
              而往往跑完這一步到下一步就被擠壓推出去,所以幾何難以保持在緩存上面,相對於紋理幾乎輕易能夠被L1和L2保存反覆命中而言,只能夠利用硬件機制在L2和VRAM上工作,最終給一些數據在L1光柵化到像素片處理。
              而紋理有mipmap,根據不同分辨率按面積等給予適當的,容易遍歷走訪,也代表紋理採樣率與像素填充這類能與屏幕分辨率呈比例增長,減少浪費帶寬和提高命中率。
              盡管仍然有延遲著色這些情況導致同樣命中率不佳和數據龐大等。
              而由於頂點數據屬性複雜和需要按一定前後順序才能還原外形,不具備紋理的高同質性,使得數據訪問一直嚴重阻礙了效率,盡管UE5的微幾何體技術,一定程度上實現了可控三角形採樣率。
              你需要讀這些數據並組裝,是一個讀+寫入數據組成順序的過程(設置有用需要用到的數據等,所以盡可能簡化不包含各種實際情況),然後還可能索引兩次做去重頂點...
              _______________
              以sio(汐)來說大概有以下這些數據

              有32.58MB的網格內存
              但...

              以每個頂點平均88byte,三角形6byte,也大概才6.5MB沒到7MB啊,那奇怪了上面怎麼這麼大?

              造成這個原因是因為形態鍵,本質上就是一種頂點做加法而已,但是並不直接影響渲染過程的帶寬,如果其值沒有大於0的話,就不會活動,形同steam。
              啟用形態鍵後,通常頂點數量並不多,但須要走一遍流程,不過不產生而外的任何圖元(三角形),但是最終會導致相當大的延遲,每個形態鍵都要走一個相當大的延遲而不是直接累加上去,這導致大量使用形態鍵激活不僅會產生大量的pass浪費CPU,同時也會造成利用率嚴重下降,如果每個avatar都使用數十個形態鍵活動,所有avatar都這樣,最終會導致利用率僅剩原有幾分之一,而幀數自然也只有幾分之一。
              原始的body僅1MB在這些上面,而形態鍵產生了整整19MB,這些頂點數據並不會納入統計數量內。
              _______________________

              最終如果sio的數量足夠多,大量的頂點數據會導致L2瓶頸。

              而大概消耗了70%的帶寬(23%/33.3%)
              不過並不一定適用於所有顯卡的瓶頸狀況,這主要以微架構設計等差異產生,例如位寬,還有每位寬對應的緩存芬片部分。
              你可以理解成384bit每32/64bit形成一個通道,分成12/6片,每片對應L2甚至L3(AMD RDNA2後),所以位寬增加除了增加顯存帶寬,也同樣會增加末級緩存帶寬等。
              (上面是安培,然後40系列L2寬度沒講但拓寬50%,頻率上升33%,最終約兩倍L2帶寬撐住...而RDNA2相比RDNA拓寬半倍,L2帶寬更多(盡管L3相對弱得多),而RDNA3再次拓寬,不過大容量多級容易提高緩存訪問延遲,這會導致利用率下降就是了...
              所以現代遊戲3A類型通常L2瓶頸,而AMD可能是有效的運算量或利用率上不去,盡管原因可能跟幾何沒太大關係,因為一般遊戲不可能像VRchat這樣嚴重誇張浪費幾何,而是盡可能利用LOD或各種技術優化,只是帶寬花費由G-buffer造成的...(行動端GPU會側重該面優化提高紋理的效率,但過多頂點和三角形會導致沖刷列表,所以這些設計不能吃太多頂點、三角形,相比桌面基本上IMR來說承受能力弱很多,NV會TBR切換,AMD是接近純粹IMR...)
              所以不要問為什麼移動端的模型只有一萬到兩萬面或著說三角形,甚至都不敢出現太多,怕把效率給搞崩了...盡管能省下一大筆帶寬功耗成本,而現代手機中按ARM/高通統計,常駐遊戲5w持續功耗中有接近1w是內存功耗,而這還是應用許多優化後的。
              NV有個問題是不適合『一次』超過分辨率/4的三角形數量,會阻礙剔除(VPC單元)效率,抵達峰值甚至會跌落。(可能會切換...大概)(因為光柵化器2x2所以是1:4,100萬三角形對應400萬屏幕分辨率。)
              你可以理解手機上遊戲不能真給你計算總共顯示50~100萬三角形的原因了...
              (單幀中會多次)


              IP属地:中国台湾7楼2024-09-10 22:12
              回复