这是签名。

glUniform4f(GLint location, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
glUniform4fv(GLint location, GLsizei count, const GLfloat *v);


以我的拙见,前者应该更快,因为可以直接从寄存器传递值而无需从内存中获取值。但是,我想听听很多意见。

最佳答案

虽然*v变体主要用于设置数组类型的制服,但OpenGL规范明确允许您将数组变体也用于通过计数1来设置标量值。

让我引用OpenGL Spec(强调自己):


命令glUniform {1 | 2 | 3 | 4} {f | i} v可用于修改单个统一变量
或统一变量数组。这些命令传递一个计数和一个指向要
加载到统一变量或统一变量数组中。计数为1
如果修改单个统一变量的值,且计数为1或更大
可用于修改整个数组或数组的一部分。


这是来自OpenGL 2.1 Spec的内容,但是对于OpenGL 4.2 Spec来说却是相同的。

实际上,也允许采用另一种方式。假设您有一个vec3 v[2]类型的制服,并使用glGetUniformLocation()查询其位置,则它可能会返回6。这意味着6实际上是v[0]的位置。



现在回到最初的问题:哪个变体更快?

这是不可能的。它们可能相等地快,或者一个可能比另一个快,这在很大程度上取决于实现。实际上,我希望大多数实现在另一种实现的基础上实现两者之一。

例如。考虑以下代码:

void glUniform1f ( GLint location, GLfloat v0 ) {
    glUniform1fv(location, 1, &v0);
}


在这种情况下,数组变体会更快。但是,以下变体也是可能的:

void glUniform1fv ( GLint location, GLsizei count, GLfloat * value ) {
    int i;

    for (i = 0; i < count; i++) {
        glUniform1f(location, *value);
        value++;
        location++;
    }
}


在这种情况下,非数组变量会更快。

我个人会说(这完全是我个人的看法),早期的OpenGL实现可能使用非数组变体实现了数组变体,因为这是较简单的实现,在整个OpenGL库的其余部分几乎没有其他修改。另一方面,它的实现也慢得多,因为它涉及到一个循环,对于现代图形适配器而言,这很可能是不必要的,因此,现代实现很可能在数组变量的顶部实现非数组变量。

数组变体还有其他优点。考虑以下功能:

struct v3 {
     GLfloat x;
     GLfloat y;
     GLfloat z;
};

void setUniform ( GLint location, struct v3 * vPtr ) {
    glUniform3f(location, vPtr->x, vPtr->y, vPtr->z);
}


仅对vPtr进行三次解引用以调用非数组函数是相当愚蠢的,并且几乎比以下实现更快:

void setUniform ( GLint location, struct v3 * vPtr ) {
    glUniform3fv(location, 1, (const GLfloat *)vPtr);
}


同样,所有数组变体始终具有恰好三个参数,而其他变体最多可以具有五个参数。当需要传递给函数的参数越多,则通过堆栈而不是通过寄存器传递这些参数时,函数调用本身将越慢。而且,函数调用具有的参数越多,则对于具有混合调用方案的体系结构而言,所有这些参数在寄存器中传递的可能性就越小。因此,通过在普通CPU上可以预期的纯函数调用开销,对具有很少参数的函数的调用通常比对具有多个参数的函数的调用要快,尽管这种差异仅在您执行数千次调用时才重要。第二,对于统一值通常不是这种情况。

关于optimization - 考虑到各种优化,更快的glUniform4f/glUniform4fv是什么?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/3642468/

10-12 00:30
查看更多