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