SRP如何提升了性能
渲染的原理
渲染過程,一般都是先設(shè)置各類狀態(tài)(設(shè)置如何清除各種顯卡中的幀緩沖,設(shè)置使用的Shader程序,設(shè)置要繪制的頂點(diǎn)數(shù)據(jù)(以及Shader中的頂點(diǎn)數(shù)據(jù)如何對(duì)應(yīng)到這些頂點(diǎn)數(shù)據(jù)),設(shè)置要使用的Uniform變量,設(shè)置面剔除,設(shè)置深度緩沖、模板緩沖,Blend混合等等),然后調(diào)用DrawCall命令來繪制。
其中設(shè)置這些狀態(tài)的過程Unity中就叫SetPassCall,而設(shè)置這些狀態(tài)的命令的性能消耗是非常高的,特別是其中從內(nèi)存?zhèn)鬏敂?shù)據(jù)到顯卡內(nèi)存中這些。
一、如何減少SetPassCall
既然SetPassCall這么耗性能,那么如何減少呢?在老版的Unity渲染流程中,可以發(fā)現(xiàn)有兩大塊可以節(jié)省很多性能:
1.在Shader使用中的很多Uniform變量,其實(shí)都是不變的(大部分時(shí)間),比如燈光那些(位置,方向,亮度之類的),相機(jī)的View矩陣、投影矩陣,以及自定義的一些也是很少變化的。這里的很少變化指的是,每一幀變化這種情況。
2.很多Uniform變量的數(shù)據(jù)只發(fā)生很小的改變,也要對(duì)這個(gè)整個(gè)Uniform進(jìn)行重新設(shè)置數(shù)據(jù)。同時(shí),Uniform變量本身也是有數(shù)量限制的。
鑒于以上原因,以O(shè)penGL為例子,他提供了一種方法來優(yōu)化上面的情況,即UBO(Uniform Buffer Object)對(duì)象與Uniform Block(Uniform塊),在DX中或者Unity中叫常量緩沖區(qū)。
即可以上傳一個(gè)全局的Uniform組合塊,他們可以在各種Shader中通用,不用每渲染一個(gè)物體,就要設(shè)置一次這些Uniform的值,同時(shí)還提供了接口來修改這個(gè)塊中的一部分值。
這樣當(dāng)渲染相同Shader的時(shí)候,將那些相同的Uniform變量組合到一起,就可以節(jié)省多次設(shè)置這些狀態(tài)值的開銷。
同時(shí)如果有部分值變化了,也可以通過只修改部分的接口,來提升整體的性能。
二、OpenGL中的UBO使用
1.設(shè)置塊布局
由于硬件不同所以在構(gòu)造uniform組合時(shí),要明確規(guī)定這個(gè)組合的數(shù)據(jù)要如何分布,所以在Shader中要明確設(shè)置布局(這里是std140布局,默認(rèn)的共享布局方式會(huì)導(dǎo)致不同的內(nèi)存分布)。
layout (std140) uniform ExampleBlock
{
float value;
vec3 vector;
mat4 matrix;
float values[3];
bool boolean;
int integer;
};
這樣在內(nèi)存設(shè)置好對(duì)應(yīng)的內(nèi)存布局后,就可以映射到對(duì)應(yīng)的顯卡內(nèi)存中。
2.創(chuàng)建并使用Uniform Buffer Object
代碼如下(示例):
unsigned int uboExampleBlock;
glGenBuffers(1, &uboExampleBlock);
glBindBuffer(GL_UNIFORM_BUFFER, uboExampleBlock);
glBufferData(GL_UNIFORM_BUFFER, 152, NULL, GL_STATIC_DRAW); // 分配152字節(jié)的內(nèi)存
glBindBuffer(GL_UNIFORM_BUFFER, 0);
這樣就可以申請(qǐng)并設(shè)置對(duì)應(yīng)的緩沖對(duì)象數(shù)據(jù),然后去填充這個(gè)數(shù)據(jù):
glBindBuffer(GL_UNIFORM_BUFFER, uboExampleBlock);
int b = true; // GLSL中的bool是4字節(jié)的,所以我們將它存為一個(gè)integer
glBufferSubData(GL_UNIFORM_BUFFER, 144, 4, &b);
glBindBuffer(GL_UNIFORM_BUFFER, 0);
3.Shader與Uniform Buffer Object綁定
由于UBO可能有多個(gè),Shader中的Uniform Buffer Block也可能有多個(gè),所以需要一種方式來映射他們。OpenGL中使用綁定點(diǎn)的方式來映射。
UBO的綁定:
glBindBufferBase(GL_UNIFORM_BUFFER, 2, uboExampleBlock);
// 或
glBindBufferRange(GL_UNIFORM_BUFFER, 2, uboExampleBlock, 0, 152);
對(duì)應(yīng)Shader中的綁定
unsigned int lights_index = glGetUniformBlockIndex(shaderA.ID, "Lights");
glUniformBlockBinding(shaderA.ID, lights_index, 2);
這樣Shader中的Uniform Buffer Block就知道去哪一個(gè)UBO去取數(shù)據(jù)了,且已經(jīng)分配好布局,能搞正常拿到對(duì)應(yīng)的數(shù)據(jù)。
4.修改部分?jǐn)?shù)據(jù)
如果我們想只修改其中的一部分?jǐn)?shù)據(jù),我們可以
glBufferSubData(GL_UNIFORM_BUFFER, 144, 4, &b);
來修改一個(gè)UBO中的一部分?jǐn)?shù)據(jù)。文章來源:http://www.zghlxwxcb.cn/news/detail-533371.html
總結(jié)
Unity使用SRP時(shí),對(duì)我們封裝了上面類似OpenGL的一大串功能設(shè)置及相關(guān)功能,且做到各個(gè)平臺(tái)兼容。SRP Batch就是利用全局的數(shù)據(jù)緩沖的方式,以及局部修改的方式,來幫助提高渲染性能。文章來源地址http://www.zghlxwxcb.cn/news/detail-533371.html
到了這里,關(guān)于【Unity URP 小知識(shí)】SRP如何提升了性能的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!