浮点数小数部分修复了Shader卡顿
When the fractional part of a float fixes your shader

我为音乐视频制作Voronoi噪声Shader时,发现它在RTX 4070显卡上出现诡异卡顿,而其他设备运行正常。排查一周后,LLM建议将fract函数替换为x - floor(x),问题竟奇迹般消失。但进一步复现测试发现,这并非简单的驱动Bug,而是编译器在特定上下文中对fract指令的误编译。这次调试经历揭示了GPU驱动中隐藏的计算陷阱,也提醒我们:看似等价的数学表达,在底层实现中可能大相径庭。
一个编译器如果根据发出的指令不同而计算同一方程得出不同结果,那它本质上就是误编译。
HN 评论区
10- earth-tattoo
好文章,读起来真是一种享受。这让我想起了几年前 Hacker News 的样子!
我有一段时间没碰 OpenGL/Shader 了,但昨天在洗澡时想到几年前写的一个算法,勾起了我对初次理解 Shader 整个概念时有多困难的回忆。基本上没有 main 函数,没有 for 循环之类的。你的 Shader 是为每一帧的每个像素调用的。我不禁好奇,在当今的世界这变得有多容易了。我花了两个月完成的东西,现在可能只需要一个提示词。
- Sharlin
需要指出的是,`fract(x)` 只有在 x >= 0 时才真正等价于 `x - floor(x)`。虽然本例中正是这种情况,但在很多情况下负值也是可能出现或预期的,此时应该使用后者。这是一个很容易犯的错误。
- flohofwoe
结果发现是另一个问题,但另一个更常见的导致 Shader 输出差异的原因是:当浮点值被截断为整数(且该值非常接近最近的整数),然后用这个截断后的值作为索引(或未过滤采样器的纹理坐标)时。这可能导致在某些 GPU/驱动组合上出现差一错误(off-by-one error),而在其他组合上则不会。发生这种情况完全可以理解,但除非在广泛的 GPU 和驱动上进行测试,否则很难捕捉到。
TL;DR:不要指望 GPU 上的浮点运算严格兼容 IEEE-754 标准。