GLSL中统一缓冲区对象(UBO)使用限制相关技术咨询
UBO相关限制规则解答
以下结论均对应OpenGL 3.3核心规范,匹配你给出的硬件参数示例:
你的猜测正确:单独声明的uniform变量不会占用
GL_MAX_VERTEX_UNIFORM_BLOCKS配额,所有散写的非块uniform都会被编译器归到隐式的默认uniform块中,存储由驱动内部管理。GL_MAX_VERTEX_UNIFORM_BLOCKS只统计着色器里显式定义的命名uniform块(也就是layout(xxx) uniform 块名{}这种形式的块)数量。GL_MAX_UNIFORM_BLOCK_SIZE是单个命名uniform块的独立大小上限,你给出的16384代表单个UBO块最多存储16KB数据。注意:你计算的1416384=229376字节总容量是错误的,根本不存在“单阶段UBO总容量=块数上限单块大小”的规则,有两个额外约束:
- 单个顶点着色器阶段里,所有被实际使用的uniform(包括默认块里的散写uniform、所有绑定的命名UBO块里的活动uniform)的总分量数不能超过
GL_MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS的限制,GL3.3对这个值的最低要求仅为960个float分量(合3840字节),远小于你算出的224KB; - UBO是全局缓冲区对象,可以跨多个着色器程序复用,没有全局层面的UBO总容量上限,只要单次绑定到某个着色器阶段的块符合该阶段的约束即可。
- 单个顶点着色器阶段里,所有被实际使用的uniform(包括默认块里的散写uniform、所有绑定的命名UBO块里的活动uniform)的总分量数不能超过
先纠正一个认知:默认uniform块不是UBO,不需要你手动创建、绑定缓冲区对象,完全由驱动内部管理,所以两个子问题答案都是否定的:
- A:默认块不受
GL_MAX_UNIFORM_BLOCK_SIZE的16384字节限制,它的大小上限由独立参数GL_MAX_VERTEX_UNIFORM_COMPONENTS规定,GL3.3下这个参数最小值是1024个float分量(合4096字节),不同硬件实际值有差异,部分显卡碰巧也是16384字节,但和UBO单块限制是完全独立的两套规则。 - B:默认块不占用
GL_MAX_VERTEX_UNIFORM_BLOCKS配额。就算你一个自定义UBO都不写,顶点阶段还是有完整14个命名块的可用额度,不会扣成13。
- A:默认块不受
散写的uniform变量完全不占用
GL_MAX_UNIFORM_BUFFER_BINDINGS配额。这个参数是OpenGL上下文全局的UBO绑定点总数,只有你调用glBindBufferBase/glBindBufferRange把缓冲区对象绑到上下文的UBO绑定点上时,才会占用对应位置。默认块根本不需要绑定缓冲区,和这些绑定点没有关系。
你的示例代码里只把Matrices块显式绑定到了0号绑定点,所以剩余可用绑定点是84-1=83个,不会剩余81个。
内容的提问来源于stack exchange,提问作者whitwhoa

