Sté*_*ard 10 iphone shader opengl-es glsl
已知分支在OpenGL ES着色器中特别具有计算成本.在这样的着色器中,我在除以之前检查值是否为null,例如:
if(value == 0.0)
other_value = 0.0;
else
other_value = 1.0 / value;
Run Code Online (Sandbox Code Playgroud)
为了加快速度,我想if通过直接做到这一点来避免这种情况:
other_value = 1.0 / value;
Run Code Online (Sandbox Code Playgroud)
我想知道如果value碰巧等于0会发生什么,这在我的治疗中有点罕见,这就是为什么测试它并不容易.着色器是否会崩溃?应用程序崩溃了吗?
bob*_*obo 18
确实未定义.
在iPad模拟器上,将红色分量除以0.0得到0(所有红色都从此图片中消失).

在iPad硬件上,将r分量除以0.0会使其饱和为全红色(即+无限制钳位).

所以不,你根本不能依赖未定义的行为来产生一致的结果,但是通过除以0和它本身就没有什么不好的事情发生.
在我的着色器中,我将rgb值除以alpha.碰巧的是,如果alpha值为0,则无论如何都不会显示像素,所以我对分区的任何一个方向都没有问题(给0或+ inf).
这样的分支通常并不昂贵。它们通常使用谓词实现。也就是说,GPU计算两个分支,但仅在条件为真的情况下才实际存储指令的结果。因此,不使用跳转指令。汇编代码如下所示:
cmp_eq p0, r0, 0.0 // predicate = (value == 0.0)
(p0) mov r1, 0.0 // other_value = 0.0, if predicate true
(!p0) rcp r1, r0 // other_value = 1.0 / value, if predicate false
Run Code Online (Sandbox Code Playgroud)
请注意,在这种情况下,实际上不必确定第二条指令。无论如何,如其他指出的那样,当分母为零时,除法(倒数)的结果不确定。但是正如您所看到的,您应该能够以很少的廉价指令为代价获得明确的行为(划分通常很慢)。据我所知,所有支持真实分支(跳转指令)的GPU也都支持谓词。着色器编译器将评估是使用谓词还是跳转,并且通常会做正确的事情。
当然,如果您真的不关心除以零的结果,那么可以节省所有的谓词成本。
代替
float invert_value(in float value)
{
if(value == 0.0)
return 0.0;
else
return 1.0 / value;
}
Run Code Online (Sandbox Code Playgroud)
你可以写
float invert_value_ifless(in float value)
{
float sign_value = sign(value);
float sign_value_squared = sign_value*sign_value;
return sign_value_squared / ( value + sign_value_squared - 1.0);
}
Run Code Online (Sandbox Code Playgroud)
这将准确返回您想要的内容
不过,我不确定这在最新的硬件上是否真的更快。
| 归档时间: |
|
| 查看次数: |
5749 次 |
| 最近记录: |