OpenGL统一函数 - 为什么这么多?

时间:2016-07-19 11:01:58

标签: c++ opengl glsl shader uniform

为什么有这么多功能来设置制服?

glUniform1f    glUniform2f    glUniform3f    glUniform4f
glUniform1fv   glUniform2fv   glUniform3fv   glUniform4fv
glUniform1i    glUniform2i    glUniform3i    glUniform4i
glUniform1iv   glUniform2iv   glUniform3iv   glUniform4iv
glUniform1ui   glUniform2ui   glUniform3ui   glUniform4ui
glUniform1uiv  glUniform2uiv  glUniform3uiv  glUniform4uiv

glUniformMatrix2fv  glUniformMatrix2x3fv  glUniformMatrix2x4fv
glUniformMatrix3fv  glUniformMatrix3x2fv  glUniformMatrix3x4fv
glUniformMatrix4fv  glUniformMatrix4x2fv  glUniformMatrix4x3fv

我认为数据上传到顶点和元素缓冲区的方式更好,因为我不必为不同的类型调用不同的函数。 为什么这是制服的情况?是否有可能只使用一个函数,我只能传递一个指针?

4 个答案:

答案 0 :(得分:3)

Hindsight始终是20/20,并且选择与其他以各种类型和维度采用矢量数据的函数一致。我指的是glVertex ......当然。现在,传递值的最初原因是,在某些体系结构上有足够的寄存器,这在寄存器中传递值更有效。编译器也可以优化前面的操作,以便在正确的寄存器中找到正确的值。

OpenGL是SGI为其图形工作站和Irix OS开发的IrixGL的后代。这些工作站使用MIPS架构。 MIPS的调用约定是(https://en.wikipedia.org/wiki/Calling_convention#MIPS

  

32位MIPS最常用的[5]调用约定是O32 [6] ABI,它将前四个参数传递给寄存器$ a0- $ a3中的函数; ...

     

...

     

N32和N64 ABI将前8个参数传递给寄存器$ a0- $ a7中的函数; ...

所以你有它:在MIPS上,每个值传递vec4元素实际上是一个非常明智的选择。特别是在IrixGL和OpenGL-1.0中,没有顶点数组,你必须进行大量的glVertex调用。

答案 1 :(得分:1)

如果您使用的是现代OpenGL,则可以使用自OpenGL 3.1以来一直可用的Uniform Buffer Objects

然而,还有一点涉及"设置"需要。具体来说,它们要求您以特定方式创建着色器(定义统一块)。您还需要为块定义内存布局(std140是一种流行的布局布局),或者查询布局,以确定如何格式化统一缓冲区数据,以便绑定与格式匹配由GPU预期。

完成所有设置后,绑定完成后调用:glBindBuffer(GL_UNIFORM_BUFFER, <name>),就像顶点和索引流一样。

答案 2 :(得分:1)

GL_ARB_shader_objects

的讨论中注意到了这一点
  

15)有可能发生巨大的负载爆炸       命令,该怎么办?

     

讨论:我们需要能够加载vec1,vec2,vec3或vec4,或者   vec1的数组,vec2的数组,vec3的数组或vec4的数组。   此外,还需要加载2x2,3x3和4x4矩阵,   和2x2的数组,3x3的数组和4x4矩阵的数组。输入   加载制服命令的值可以(传统的OpenGL)进来   字节,短路,整数,浮点数,双精度和无符号字节,无符号短路   和无符号的整数。

     

解决方案:建议的子集位于新过程和函数中   以下部分。

有问题的子集是获得批准的子集:

void Uniform1fARB(int location, float v0)
void Uniform2fARB(int location, float v0, float v1)
void Uniform3fARB(int location, float v0, float v1, float v2)
void Uniform4fARB(int location, float v0, float v1, float v2, float v3)

void Uniform1iARB(int location, int v0)
void Uniform2iARB(int location, int v0, int v1)
void Uniform3iARB(int location, int v0, int v1, int v2)
void Uniform4iARB(int location, int v0, int v1, int v2, int v3)

void Uniform1fvARB(int location, sizei count, const float *value)
void Uniform2fvARB(int location, sizei count, const float *value)
void Uniform3fvARB(int location, sizei count, const float *value)
void Uniform4fvARB(int location, sizei count, const float *value)

void Uniform1ivARB(int location, sizei count, const int *value)
void Uniform2ivARB(int location, sizei count, const int *value)
void Uniform3ivARB(int location, sizei count, const int *value)
void Uniform4ivARB(int location, sizei count, const int *value)

void UniformMatrix2fvARB(int location, sizei count, boolean transpose, const float *value)
void UniformMatrix3fvARB(int location, sizei count, boolean transpose, const float *value)
void UniformMatrix4fvARB(int location, sizei count, boolean transpose, const float *value)

后来添加了对无符号整数和非平方矩阵的调用。

我认为@datenwolf的观点是glVertex系列调用具有许多功能以便优化寄存器中的值传递,另一方面设置制服应该发生不同的顺序比传递顶点更少的频率,所以我不认为这里的性能是一个真正的问题。

“遵循已经建立的API”听起来像是一个更明智的解释。

此外,您真的喜欢通过void *接口传递数据类型吗?您要问的是像

这样的API
glUniform(GLint location, GLenum datatype, GLsizei count, const GLvoid *data)

GL已经充满了这样的破坏和类型不安全的水平(你好,无类型GLenum!),我更喜欢那些不会增加更多内容的API。

答案 3 :(得分:0)

根据统一数据格式,硬件需要做什么可能会有所不同。

您要问的是,在GL驱动程序中实现了潜在的开关/ if系列。然后,您必须为每次使用API​​支付费用,即使应用程序已经确切地知道它将要设置的制服类型。这不是一个有效的API设计(不管现在实际传递制服缓冲区的效率更高的事实。在设计API时并非如此)。

这就是glVertex3f等人的原因。也有API设计。但至少那些没有产生glErrors。它对于Uniforms来说有点脆弱,因为它们肯定会产生错误,所以代码实际上并不是完全最小化。