gpt4 book ai didi

glsl - 由单个 for 循环引起的奇怪的性能下降

转载 作者:行者123 更新时间:2023-12-02 09:30:25 47 4
gpt4 key购买 nike

我目前正在 Linux(NVIDIA 360M 卡,带有 313.0 nv 驱动程序)上编写一个 OpenGL 3.1(带有 GLSL 版本 330)应用程序,大约有 15k 行。我的问题是,在我的一个顶点着色器中,通过对实际上应该是无操作的代码进行最小的更改,我可能会遇到性能急剧下降的情况。

例如:

// With this solution my program runs with 3-5 fps
for(int i = 0; i < 4; ++i) {
vout.shadowCoord[i] = uShadowCP[i] * w_pos;
}

// But with this it runs with 30+ fps
vout.shadowCoord[0] = uShadowCP[0] * w_pos;
vout.shadowCoord[1] = uShadowCP[1] * w_pos;
vout.shadowCoord[2] = uShadowCP[2] * w_pos;
vout.shadowCoord[3] = uShadowCP[3] * w_pos;

// This works with 30+ fps too
vec4 shadowCoords[4];
for(int i = 0; i < 4; ++i) {
shadowCoords[i] = uShadowCP[i] * w_pos;
}
for(int i = 0; i < 4; ++i) {
vout.shadowCoord[i] = shadowCoords[i];
}

或者考虑一下:

uniform int uNumUsedShadowMaps = 4; // edit: I called this "random_uniform" in the original question

// 8 fps
for(int i = 0; i < min(uNumUsedShadowMaps, 4); ++i) {
vout.shadowCoord[i] = vec4(1.0);
}

// 30+ fps
for(int i = 0; i < 4; ++i) {
if(i < uNumUsedShadowMaps) {
vout.shadowCoord[i] = vec4(1.0);
} else {
vout.shadowCoord[i] = vec4(0.0);
}
}

在此处查看完整的着色器代码,其中出现了此问题: http://pastebin.com/LK5CNJPD

任何关于可能导致这些问题的想法都会受到赞赏。

最佳答案

我终于找到了问题的根源,也找到了解决办法。

但在直接找到解决方案之前,请让我粘贴最少的着色器代码,这样我就可以重现这个“错误”。

顶点着色器:

#version 330 

vec3 CountPosition(); // Irrelevant how it is implemented.

uniform mat4 uProjectionMatrix, uCameraMatrix;

out VertexData {
vec3 c_pos, w_pos;
vec4 shadowCoord[4];
} vout;

void main() {
vout.w_pos = CountPosition();
vout.c_pos = (uCameraMatrix * vec4(vout.w_pos, 1.0)).xyz;
vec4 w_pos = vec4(vout.w_pos, 1.0);

// 20 fps
for(int i = 0; i < 4; ++i) {
vout.shadowCoord[i] = uShadowCP[i] * w_pos;
}

// 50 fps
vout.shadowCoord[0] = uShadowCP[0] * w_pos;
vout.shadowCoord[1] = uShadowCP[1] * w_pos;
vout.shadowCoord[2] = uShadowCP[2] * w_pos;
vout.shadowCoord[3] = uShadowCP[3] * w_pos;

gl_Position = uProjectionMatrix * vec4(vout.c_pos, 1.0);
}
<小时/>

片段着色器:

#version 330

in VertexData {
vec3 c_pos, w_pos;
vec4 shadowCoord[4];
} vin;

out vec4 frag_color;

void main() {
frag_color = vec4(1.0);
}
<小时/>

有趣的是,只需对顶点着色器进行最小的修改即可使这两种解决方案都以 50 fps 的速度运行。 main函数应该修改为这样:

void main() {
vec4 w_pos = vec4(CountPosition(), 1.0);
vec4 c_pos = uCameraMatrix * w_pos;

vout.w_pos = vec3(w_pos);
vout.c_pos = vec3(c_pos);

// 50 fps
for(int i = 0; i < 4; ++i) {
vout.shadowCoord[i] = uShadowCP[i] * w_pos;
}

// 50 fps
vout.shadowCoord[0] = uShadowCP[0] * w_pos;
vout.shadowCoord[1] = uShadowCP[1] * w_pos;
vout.shadowCoord[2] = uShadowCP[2] * w_pos;
vout.shadowCoord[3] = uShadowCP[3] * w_pos;

gl_Position = uProjectionMatrix * c_pos;
}

区别在于上面的代码从着色器中读取变量,而底部的代码将这些值保存在临时变量中,并且只写入到变量中。

结论:

读取着色器的输出变化通常被视为一种优化,可以减少一个临时变量,或者至少我在互联网上的很多地方都看到过它。尽管存在上述事实,读取变化实际上可能是无效的 OpenGL 操作,并且可能使 GL 进入未定义状态,在这种状态下,代码中的随机更改可能会触发事情。

最好的一点是 GLSL 330 specification没有说任何关于从之前写入的输出变化中读取的内容。可能是因为这不是我应该做的事情。

<小时/>

附注

另请注意,原始代码中的第二个示例可能看起来完全不同,但在这个小代码片段中它的工作原理完全相同,如果读取输出变化,则 i < min(uNumUsedShadowMaps, 4) 会变得相当慢。作为 for 循环中的条件,但是如果仅写入输出变化,则不会对性能造成任何变化,并且 i < min(uNumUsedShadowMaps, 4)其中一个也能以 50 fps 运行。

关于glsl - 由单个 for 循环引起的奇怪的性能下降,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19433469/

47 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com