Jhe*_*ico 7 opengl performance oculus
我正在研究oculus Rift失真着色器的OpenGL实现.着色器通过获取输入纹理坐标(包含先前渲染的场景的纹理)并使用失真系数对其进行变换,然后使用变换的纹理来确定片段颜色来工作.
我希望通过预先计算失真并将其存储在第二个纹理中来提高性能,但结果实际上比直接计算慢.
直接计算版看起来基本上是这样的:
float distortionFactor(vec2 point) {
float rSq = lengthSquared(point);
float factor = (K[0] + K[1] * rSq + K[2] * rSq * rSq + K[3] * rSq * rSq * rSq);
return factor;
}
void main()
{
vec2 distorted = vRiftTexCoord * distortionFactor(vRiftTexCoord);
vec2 screenCentered = lensToScreen(distorted);
vec2 texCoord = screenToTexture(screenCentered);
vec2 clamped = clamp(texCoord, ZERO, ONE);
if (!all(equal(texCoord, clamped))) {
vFragColor = vec4(0.5, 0.0, 0.0, 1.0);
return;
}
vFragColor = texture(Scene, texCoord);
}
Run Code Online (Sandbox Code Playgroud)
其中K是作为制服传入的vec4.
另一方面,置换贴图查找如下所示:
void main() {
vec2 texCoord = vTexCoord;
if (Mirror) {
texCoord.x = 1.0 - texCoord.x;
}
texCoord = texture(OffsetMap, texCoord).rg;
vec2 clamped = clamp(texCoord, ZERO, ONE);
if (!all(equal(texCoord, clamped))) {
discard;
}
if (Mirror) {
texCoord.x = 1.0 - texCoord.x;
}
FragColor = texture(Scene, texCoord);
}
Run Code Online (Sandbox Code Playgroud)
还有一些其他操作可用于校正纵横比和计算镜头偏移,但它们非常简单.期望它优于简单的纹理查找是否真的合理?
And*_*man 12
GDDR内存具有相当高的延迟性,现代GPU架构具有大量的数字运算功能.它曾经是另一种方式,GPU无法进行计算,通过从立方体贴图中获取,规范化更便宜.
抛出这样一个事实,你不是在这里进行常规的纹理查找,而是依赖查找,这并不奇怪.由于您从中获取的位置取决于另一次获取的结果,因此无法预先获取/有效缓存(有效的延迟隐藏策略)着色器所需的内存.这不是"简单的纹理查找".
更重要的是,除了执行从属纹理查找之外,您的第二个着色器还包括discard关键字.这将有效地消除在许多硬件上进行早期深度测试的可能性.
老实说,我不明白你为什么要将distortionFactor (...)函数"优化" 到查找中.它使用平方长度,所以你甚至不处理a sqrt,只是一堆乘法和加法.
Andon M. Coleman已经解释了发生了什么.基本上内存带宽和更重要的内存延迟是现代GPU的主要瓶颈,因此在大约2007年到今天之间构建的外观简单计算通常比纹理查找快得多.
实际上,存储器访问模式对效率具有如此大的影响,稍微重新排列访问模式并确保正确对齐可以容易地提供1000倍的性能提升(BT;然而这是CUDA编程).然而,依赖查找不一定是性能杀手:如果依赖纹理坐标查找与控制器纹理是单调的,那么它通常不会那么糟糕.
话虽这么说,你有没有听说过霍纳的方法?你可以重写
float factor = (K[0] + K[1] * rSq + K[2] * rSq * rSq + K[3] * rSq * rSq * rSq);
Run Code Online (Sandbox Code Playgroud)
平凡的
float factor = K[0] + rSq * (K[1] + rSq * (K[2] + rSq * K[3]) );
Run Code Online (Sandbox Code Playgroud)
为您节省一些操作.