gpt4 book ai didi

performance - 为什么这个 GLSL 着色器这么慢?

转载 作者:行者123 更新时间:2023-12-01 23:00:29 24 4
gpt4 key购买 nike

我正在尝试在片段着色器中的网格上进行光线跟踪。我已经编写了下面的着色器来做到这一点(顶点着色器只是绘制一个屏幕四边形)。

#version 150

uniform mat4 mInvProj, mInvRot;
uniform vec4 vCamPos;

varying vec4 vPosition;

int test(vec3 p)
{
if (p.x > -4.0 && p.x < 4.0
&& p.y > -4.0 && p.y < 4.0
&& ((p.z < -4.0 && p.z > -8.0) || (p.z > 4.0 && p.z < 8.0)))
return 1;
return 0;
}

void main(void) {
vec4 cOut = vec4(0, 0, 0, 0);

vec4 vWorldSpace = mInvRot * mInvProj * vPosition;
vec3 vRayOrg = vCamPos.xyz;
vec3 vRayDir = normalize(vWorldSpace.xyz);

// http://en.wikipedia.org/wiki/Xiaolin_Wu%27s_line_algorithm
vec3 adelta = abs(vRayDir);
int increaser;
vec3 gradient, sgradient;
if (adelta.x > adelta.y && adelta.x > adelta.z)
{
increaser = 0;
gradient = vec3(vRayDir.x > 0.0? 1.0: -1.0, vRayDir.y / vRayDir.x, vRayDir.z / vRayDir.x);
sgradient = vec3(0.0, gradient.y > 0.0? 1.0: -1.0, gradient.z > 0.0? 1.0: -1.0);
}
else if (adelta.y > adelta.x && adelta.y > adelta.z)
{
increaser = 1;
gradient = vec3(vRayDir.x / vRayDir.y, vRayDir.y > 0.0? 1.0: -1.0, vRayDir.z / vRayDir.y);
sgradient = vec3(gradient.x > 0.0? 1.0: -1.0, 0.0, gradient.z > 0.0? 1.0: -1.0);
}
else
{
increaser = 2;
gradient = vec3(vRayDir.x / vRayDir.z, vRayDir.y / vRayDir.z, vRayDir.z > 0.0? 1.0: -1.0);
sgradient = vec3(gradient.x > 0.0? 1.0: -1.0, gradient.y > 0.0? 1.0: -1.0, 0.0);
}
vec3 walk = vRayOrg;
for (int i = 0; i < 64; ++i)
{
vec3 fwalk = floor(walk);
if (test(fwalk) > 0)
{
vec3 c = abs(fwalk) / 4.0;
cOut = vec4(c, 1.0);
break;
}
vec3 nextwalk = walk + gradient;
vec3 fnextwalk = floor(nextwalk);

bool xChanged = fnextwalk.x != fwalk.x;
bool yChanged = fnextwalk.y != fwalk.y;
bool zChanged = fnextwalk.z != fwalk.z;

if (increaser == 0)
{
if ((yChanged && test(fwalk + vec3(0.0, sgradient.y, 0.0)) > 0)
|| (zChanged && test(fwalk + vec3(0.0, 0.0, sgradient.z)) > 0)
|| (yChanged && zChanged && test(fwalk + vec3(0.0, sgradient.y, sgradient.z)) > 0))
{
vec3 c = abs(fwalk) / 4.0;
cOut = vec4(c, 1.0);
break;
}
}
else if (increaser == 1)
{
if ((xChanged && test(fwalk + vec3(sgradient.x, 0.0, 0.0)) > 0)
|| (zChanged && test(fwalk + vec3(0.0, 0.0, sgradient.z)) > 0)
|| (xChanged && zChanged && test(fwalk + vec3(sgradient.x, 0.0, sgradient.z)) > 0))
{
vec3 c = abs(fwalk) / 4.0;
cOut = vec4(c, 1.0);
break;
}
}
else
{
if ((xChanged && test(fwalk + vec3(sgradient.x, 0.0, 0.0)) > 0)
|| (yChanged && test(fwalk + vec3(0.0, sgradient.y, 0.0)) > 0)
|| (xChanged && yChanged && test(fwalk + vec3(sgradient.x, sgradient.y, 0.0)) > 0))
{
vec3 c = abs(fwalk) / 4.0;
cOut = vec4(c, 1.0);
break;
}
}

walk = nextwalk;
}

gl_FragColor = cOut;
}

只要我查看紧密的网格项,即硬编码项,帧率看起来可以接受(Geforce 680M 上为 400+fps)(尽管与我目前编写的其他着色器相比低于我的预期),但是当我查看时在空时(所以循环一直到 64),帧率很糟糕(40fps)。当靠近网格时,我得到大约 1200 fps,每个像素最终都在同一个关闭的网格项中。

虽然我知道为每个像素做这个循环是一些工作,但它仍然是一些简单的基本数学,特别是现在我已经删除了纹理查找并只使用了一个简单的测试,所以我不明白为什么必须这样做如此努力地减慢一切。我的 GPU 有 16 个内核,运行频率为 700+Mhz。我以 960x540、518400 像素渲染。它应该能够处理的比我想象的要多得多。

如果我删除上面的抗锯齿部分(我将根据增量值测试一些额外相邻点的代码部分),它会好一点(100fps),但是来吧,通过这些计算,它不应该有很大的不同!
如果我拆分代码以便不使用增加器但为每个不同部分完成以下代码,则帧率保持不变。
如果我将一些整数更改为浮点数,则没有任何变化。

我以前做过更密集和/或复杂的着色器,那么为什么这个着色器如此之慢?谁能告诉我我做的什么计算使它变得如此缓慢?

我没有设置不使用的制服或类似的东西,C 代码也只是渲染。这是我之前成功使用过 100 次的代码。

任何人?

最佳答案

简短的回答是:着色器中的分支和循环是(可能)邪恶的。
但它远不止于此:阅读此主题以获取更多信息:Efficiency of branching in shaders

它是这样的:

图形适配器有一个或多个 GPU,一个 GPU 有多个内核。每个内核都设计为运行多个线程,但这些线程只能运行完全相同的代码(取决于实现)。

因此,如果 10 个线程必须执行不同的循环,那么只要最大的循环需要运行,这 10 个线程都必须运行(取决于实现,循环可能会比必要的更进一步,或者线程可能会停止) .

与分支相同:如果线程有一个 if,则可能(取决于实现)两个分支都被执行并使用其中一个的结果。

因此,总而言之,如果您希望根据某些条件删除一些计算,那么做更多的数学运算并使用 0 因子可能(并且可能主要是)比编写条件本身和分支更好。

例如:

(using useLighting = 0.0f or 1.0f)
return useLighting * cLightColor * cMaterialColor + (1.0 - useLighting) * cMaterialColor;

可能比:
if (useLighting < 0.5)
return cMaterialColor;
else
return cLightColor * cMaterialColor;

但有时它可能不会......性能测试是关键......

关于performance - 为什么这个 GLSL 着色器这么慢?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16337723/

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