真沒想到(constinction)contingent,干貨|關(guān)于Constant Buffer你需要知道的一些事兒,同聲歌,
目錄:
1.constant conflicts
2.constant conflict
3.constandt
4.constant threat
5.constant constant
6.constituented
7.constantable
8.constant invasions
9.constant concentration
10.constantterm
1.constant conflicts
作者:李星前言之前寫過一篇文章《Unity|使用GPU Instance提升游戲性能》,留言問有沒有考慮內(nèi)存大小的使用,SV_InstanceID這個索引其實是保存在Constant Buffer中的,其中人設(shè)性格大全會有大量的transform等信息,所以不如使用細(xì)分來的好。
2.constant conflict
由于不能直接回復(fù),就沒有回復(fù)了,然后整理了一些之前了解到與Constant Buffer相關(guān)的內(nèi)容打算把它貼出來(本人對OpenGL 或者OpenGL ES不是很熟,DirectX的話相對熟悉點,這里就從DirectX方面來說吧!同時這里所說的可能和Unity關(guān)系不大,但有些原理應(yīng)該是相通的,如有錯誤還望各位指正。
3.constandt
)Unity中的實現(xiàn)在Unity2017上,Unity的工程師給出了一份可下載的PPT,根據(jù)PPT中的代碼片段,可以看出Unity的GPU Instance的實現(xiàn)方人設(shè)性格大全式,用到了Constant Buffer,而且Constant Buffer的大小也有限制,即64KB(這個64kb的限制應(yīng)該是受GPU中Constant Memory的限制或者是寄存器的限制,這里有點模糊)。
4.constant threat
PPT下載地址:http://pan.baidu.com/s/1jI3IYxg當(dāng)然這里說的Constant Buffer的大小有限制是說單個Buffer的限制,而不是所有Constant Buffer的限制,這意味著你可以創(chuàng)建很多個Constant Buffer ,微軟官網(wǎng)關(guān)于Shader Constants有這塊的說明,同一個著色器階段可以最多綁定14人設(shè)性格大全個Constant Buffer(DirectX支持16個輸入插槽)。
5.constant constant
微軟官網(wǎng)關(guān)于Shader Constants說明:https://msdn.microsoft.com/en-us/library/windows/desktop/bb509581(v=vs.85).aspx
6.constituented
而Structure Buffer的話應(yīng)該不受這個空間限制,我猜想可能存儲在Local Memory內(nèi)或者Shared Memory(這個只是我個人的臆測理解,歡迎拍磚校正)Constant Buffer。
7.constantable
Constant B人設(shè)性格大全uffer引入緣由Constant Buffer其實是在DirectX 10引入的,DirectX 9并不存在這個概念,在DirectX 9中發(fā)送到GPU命令緩沖區(qū)80%的數(shù)據(jù)是提交著色器常量數(shù)據(jù)(Constant Data),而很多引擎則是發(fā)送所有的繪制調(diào)用更新,這顯然是比較浪費的。
8.constant invasions
在DirectX 9中,不同著色器階段訪問的相同數(shù)據(jù)是不能保存的,只能在相應(yīng)階段進(jìn)行設(shè)置,例如頂點著色器階段與像素著色器階段分別訪問相同的常量,你不得不設(shè)置兩次常量即在常量緩沖區(qū)出現(xiàn)之前,切換著色器,沒有任何辦法來保存之間存在的常量。
9.constant concentra人設(shè)性格大全tion
常量緩沖區(qū)改變了這一現(xiàn)狀,它存儲著色器常量的值對象,在需要改變時才更改常量緩沖區(qū)可以綁定到不同的著色器階段,所以沒必要存儲多次但是不幸的是將相同常量緩沖區(qū)綁定到不同著色器階段后,更新常量緩沖區(qū)將變得更加昂貴,因此在實際使用過程中我們應(yīng)該盡可能避免這情況。
10.constantterm
應(yīng)當(dāng)注意的情況1.避免更新大常量緩沖區(qū)中的小部分?jǐn)?shù)據(jù)DirectX 10的文檔中對于Constant Buffer這一塊有說明根據(jù)更新的頻率將其更新對象放置在不同的緩沖區(qū)中,如每幀只更新一個的wvp矩陣,又如每個對象都需要設(shè)置的transform信息,我們可以如此定義:。
cbuffer cbPerObjec人設(shè)性格大全t { float4x4 gWVP;};cbuffer cbPerFrame { float3 gLightDirection; float3 gLightPosition
; float4 gLightColor;};2.注意合理輸入布局類似于C/C++中的內(nèi)存對齊一般,Constant Buffer的對齊是16個字節(jié),即128位進(jìn)行對齊因此,如果我們既想節(jié)省帶寬,又想達(dá)到高速傳輸效率,就需要合理的對齊進(jìn)行布局了。
(我查了一下,OpenGL類似也有這么個規(guī)則,叫std140的人設(shè)性格大全準(zhǔn)則,不過OpenGL ES中目前沒發(fā)現(xiàn),而DX12已經(jīng)是256位對齊了)下面我列舉一個不合理示例:cbuffer cbPerObj { float2 uv0。
; float3 normal; float2 uv1;};上面的Constant Buffer中,將會占用16 * 3 = 48 byte的空間由于padding原則,我們可以通過調(diào)整uv1和normal的位置,將其減少為16 * 2 = 32 byte的空間。
cbuffer cbPerObj { float2 uv人設(shè)性格大全0; float2 uv1; float3 normal;};這里額外的說一下Structure Buffer方面的布局,Structure Buffer似乎沒有自動的padding,但128位這個訪問偏移還是存在的,所以如果不合理的布局也會造成訪問性能受損。
如下:Struct obj { float4 position; float r;};上面的結(jié)構(gòu)剛好也就是占用20個字節(jié),一個結(jié)構(gòu)定義在連續(xù)的內(nèi)存上存在跨塊訪問,因此我們可以稍微犧牲點帶寬,填幾個占位坑,避免這種跨塊訪問。
Struct人設(shè)性格大全 obj { float4 position; float r; float pad0; float pad1; float pad2;};然后就是避免一些操作,因為更新常量緩沖區(qū)的代價是極其昂貴的,上面提到合理的輸入布局即16字節(jié)對其能夠提高內(nèi)存拷貝的速度,即dx11中Map操作時的內(nèi)存拷貝速度。
同時我們需要注意一些事項,如避免在合并寫入時進(jìn)行讀操作,為什么呢?因為CPU向圖形設(shè)備接口合并寫入的時候,會對寫入緩存一段時間,將多個相鄰的寫入合并成為一個更大的總線人設(shè)性格大全事務(wù),這比單個寫入要快很多然而當(dāng)你在合并寫入的內(nèi)存上進(jìn)行讀取時,將會被視為未緩存的操作,意味著所有待合并的寫入緩存區(qū)都將被刷新。
執(zhí)行讀取而不需要進(jìn)行任何的緩存,刷新合并寫入緩存區(qū)花費時間,導(dǎo)致部分高速緩存進(jìn)行存儲效率低下,同時未緩存的讀取也是一樣這里舉個例子,我們在填充緩沖區(qū)時進(jìn)行以下操作:pCb = (CPUTModelConstantBuffer*)mapInfo.pData; 。
pCb->World = world; pCb->ViewProjection = view * projection; pCb->WorldViewProjection
= 人設(shè)性格大全world * pCb->ViewProjection;//這里注意上面這段代碼,在給WorldViewProjection設(shè)置值的時候,我們?nèi)×似銿iewProjection的內(nèi)容,這將導(dǎo)致整個緩存區(qū)刷新并且不緩存。
我們可以改變的方法是,在事先給ViewProjection賦值的那個矩陣操作緩存起來XMMATRIX viewProj = view * projection; pCb = (CPUTModelConstantBuffer*)mapInfo.pData
; pCb->World = world; pCb->ViewProjection = vi人設(shè)性格大全ewProj; pCb->WorldViewProjection = world * viewProj
;僅僅是這么一個臨時變量保存的操作,就可以節(jié)省一半的時鐘周期再一個就是盡可能的避免切換兩個不同的常量緩沖區(qū),或者一個常量緩沖區(qū)只綁定一個著色器階段,提防常量緩沖區(qū)no hit的開銷3.避免避免在每一幀進(jìn)行大量的繪制調(diào)用。
以免圖形驅(qū)動程序耗盡重命名空間,進(jìn)而導(dǎo)致游戲卡頓為何有此一說?因為應(yīng)用程序想要改變常量緩沖區(qū)的內(nèi)容,通常需要當(dāng)前舊的內(nèi)容(GPU仍然在訪問或者即將需要訪問它們)圖形驅(qū)動程序為了避免停頓,圖形驅(qū)動程序會對Map()/ Unmap()調(diào)用對或UpdateSubresource()的人設(shè)性格大全調(diào)用,其中每一次調(diào)用會返回一個指向不同的內(nèi)存塊的指針。
驅(qū)動程序使用一定量的額外內(nèi)存來進(jìn)行常量緩沖區(qū)重命名,而重命名的操作累計內(nèi)存可能會增大,從而超出其重命名空間限制而導(dǎo)致卡頓題外話使用常量緩沖區(qū)的性能對于大小小于64kb的緩沖區(qū)而言,使用常量緩沖區(qū)比結(jié)構(gòu)化緩沖區(qū)性能較好,Unity的GPU Instance使用的是常量緩沖區(qū)來實現(xiàn)的(這也是我猜想Unity為何使用Constant Buffer的原因)。
而且目前它有一個宏的限制,UNITY_MAX_INSTANCE_COUNT 是500,也就是一次繪制調(diào)用最多是500個實例,可以猜測其在C++中的結(jié)構(gòu)定義應(yīng)該是130字節(jié)左右130個字節(jié)的長度,人設(shè)性格大全足以放置一些矩陣、位置、縮放以及uv之類的屬性了。
同時就我上篇所說,其實大可不必要擔(dān)心這些會導(dǎo)致內(nèi)存占用過大,因為往往你一張1024*1024的貼圖就比它大了n倍再則,細(xì)分目前來說對桌面端都不提倡,更何況移動端(保守的說,未來五年應(yīng)該都不會使用),而且虛幻在他的官方文檔就性能這一塊都是建議關(guān)閉曲面細(xì)分的。
虛幻的官方文檔:http://docs.unrealengine.com/latest/CHN/Engine/Performance/Guidelines/index.html有趣的論壇話題這里有一個比較有意思的話題(Fastest way to update a constant buffe人設(shè)性格大全r per draw call 這是我在一個論壇看到的),大體是這么回事,有個人想渲染一些相同的東西,進(jìn)行多次繪制,而著色器使用同一個常量緩沖區(qū),如何更新這個常量緩沖區(qū)能夠達(dá)到更好的性能。
話題鏈接:https://www.gamedev.net/forums/topic/616350-dx11-fastest-way-to-update-a-constant-buffer-per-draw-call/
其實這個有點類似于GPU Instance,我們根據(jù)當(dāng)前位置,動態(tài)地渲染一些周圍的植被系統(tǒng)目前所知的,調(diào)用Graphics.DrawMeshInstanced這個API幾次應(yīng)該是毫無壓力的具體Un人設(shè)性格大全ity工程師對于這種情況用的是一個大的常量緩沖區(qū)呢?還是每個調(diào)用一個常量緩沖區(qū)就不知了。
對于一個對象被繪制多次,其相對應(yīng)的Constant Buffer應(yīng)該就有多個,例如:cbuffer obj { float4 position; float r;};當(dāng)繪制n個時,應(yīng)該就存在n個這樣的Constant Buffer。
當(dāng)然這個也有64kb的限制,也就是說,你一次繪制只能繪制64kb/sizeof(obj),這里的計算必須是padding,也就是128位對齊(貌似DirectX 12已經(jīng)是256位對齊了)如果一次常量緩沖區(qū)填滿了還有未人設(shè)性格大全完成的繪制,那么其將繼續(xù)進(jìn)行Map()/UnMap()和Draw call()之類的工作,直到其全部繪制完成。
往期沙龍精彩回顧:① 第一期:劉宇,演講就是講好故事② 第二期:顧露和劉馬良,Lua性能優(yōu)化方案③ 第三期:李翔威,Unity資源配置,項目中的資源管理④ 第四期:李翔威,運行時資源管理—Unity⑤ 第五期:李翔威,C#內(nèi)存與性能優(yōu)化
⑥ 第六期:王勇智,光學(xué)動作捕捉應(yīng)用分享⑦ 第七期:肖星,Unity Girls |《Flappy Bird》小游戲快速制作⑧第八期:王海銀,游戲體驗設(shè)計,創(chuàng)造情感的魅力獎勵升級!一篇稿拿200元,還有積分換小米6!點擊【
閱讀原文】立即查看活動!
長按二維人設(shè)性格大全碼關(guān)注西山居技術(shù)