聊了个聊
由于Unity的兴起,让更多的人开始走向游戏开发,进而深入渲染的性能优化的人也越来越多,但并不是所有人都知道constant buffer,作者本人就是其中一个。不得否认,它的诞生已是十几年前的事了。。。
Constant Buffer概念及其特点:
用于cpu向gpu中的shader程序提供单帧的常量数据。
常量缓冲区是GPU资源。
每帧更新,且每次更新提交的数据都是整个constant buffer。基于此需要合理安排什么变量纳入其中。
同时,常量的概念只是在单帧内保持不变,整个游戏运行过程中是允许修改这些buffer的。
directX对它的支持:
0.cbuffer和tbuffer属于Shader Model 4支持的新特性。在DirectX中在DX10版本被引入。
1.cb中的数据结构应该直接对应着HLSL中的数据结构,这样更新cb时,只需要直接复制数据即可。
2.cb是128bit对齐,及其大小须是16byte的n倍(n个float4大小)。
3.cb的bind flag只能是D3D11_BIND_CONSTANT_BUFFER,不能与其他位标记组合使用。使用cb时,不需要resource view,可以直接绑定到管线。
4.每个管线中只有16个constant buffer插槽。(不推荐用满。)
constant buffer的作用、意义:
DX10允许通过一块大小可变的buffer向shader提供常量数据,而不是DX9前只有数量受限的n个寄存器(常量数组。)
DX10的constant buffer是每帧整体提交数,DX9前则是每次调用Draw有可能会变更buffer数据,批量将变更的buffer集做提交。
cb中的数据总是作为一个整体被提交给GPU,即cb中只是一个变量改变了,也须重新提交整个cb。
官方推荐,不要任何变量都放到cb中。
也不要把插槽都占满。
应该按照变量变更频率,变化快的可能每帧内要求多次变化就不要放cb里,单帧内不变的,更新频率大于一帧的就可以cb中,非必要不要使用大的buffer,以尽量减少带宽消耗。比如,把viewMatrix,viewProjMatrix,eyePosition,sunVector等per-frame数据放到cb0中,只要每帧渲染前更新一次即可;把worldMatrix,localLight,objectColor等作为per-object参数放到另外一块cb1中,每次渲染物体时更新。
(
下面这篇ppt讲得挺详细,推荐大家可以看看:
https://www.slideshare.net/cagetu/windows-to-reality-getting-the-most-out-of-direct3-d-10-graphics-in-your-games
)
如何用好constant buffer:
方案1:(directx的skinning和unity SRP Batching都是采用该方案)
根据用途划分哪些是给全局、某些mesh、某些材质、某些pass用的CBs。
非必要不每帧变更。
方案2:
根据变更内容的大小来,建立生产者-消费者系统。每次匹配足够且最小的buffer做填充。
参考:
https://haiyang.blog.csdn.net/article/details/82667358?spm=1001.2101.3001.6650.10&utm_medium=distribute.pc_relevant.none-task-blog-2defaultCTRLISTRate-10-82667358-blog-78778217.pc_relevant_3mothn_strategy_recovery&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2defaultCTRLISTRate-10-82667358-blog-78778217.pc_relevant_3mothn_strategy_recovery&utm_relevant_index=11
https://www.cnblogs.com/clayman/archive/2011/10/18/2216889.html
https://www.slideshare.net/cagetu/windows-to-reality-getting-the-most-out-of-direct3-d-10-graphics-in-your-games (推荐看看,对constant buffer概念的了解有帮助)
https://stackoverflow.com/questions/51196001/what-exactly-is-a-constant-buffer-cbuffer-used-for-in-hlsl