Nice article. What a joy to read. Reminds me of what hacker news was until a few years ago!
I haven't worked with opengl/shaders in a while, but was thinking about some algorithm I wrote a few years ago, while in shower yesterday. It brought back the memories of how difficult it was for me to first understand the whole concept of shaders. There's basically no main function, no for loops etc. Your shader is called for each pixel, for every frame. I was wondering how easy it would have been in today's world. I spent like 2 months on something that is just a prompt now.
I'm in game dev but I also have very poor abilities for mentally operating on visual or geometrical data. I'm normally far away from the graphics parts but sometimes I take a look and shaders are by far the least intuitive type of code to me. I've learned enough about what shaders do to sort of parse the simple ones, but anything with shaders definitely feels like working against my brain's natural tendencies.
If you prompted a shader today, you still wouldn't understand shaders. The LLM also has absolutely no understanding of whether a graphical effect looks good.
Should be noted that `fract(x)` is importantly only equivalent to `x - floor(x)` when x >= 0. Which it was in this case, but often negative values are also possible/expected and the latter should be used instead. This is an easy mistake to make.
It turned out to be something different, but another much more common source of shader output differences is when a float value is clamped to integer (with the value being very close to the closest integer), and then use the clamped value as index (or tex coord with an unfiltered sampler). This may result in an off-by-one error on some gpu/driver combos but not others. Completely understandable why it happens, but hard to catch unless testing on a wide range of GPUs and drivers.
TL;DR: don't expect that floating point operations on GPUs are strictly IEEE-754 compatible
The classic HLSL compiler is infamous for being full of bugs (and slow, for that matter) so I wasn't surprised to see it come up here...
Fantastic seeing the author lay out all the steps involved in getting a renderdoc capture of a browser and what's involved in debugging shader issues in a webpage.
It's interesting that the issue only manifested on the geforce 40xx if it was an fxc issue though... wonder if it's fxc combined with a driver issue and not just one or the other?
hey! author here. I think I missed the opportunity to mention that, it wasn't only reproducible on the 40xx. it was my first hypothesis, but after I figured out it was a DirectX11 issue, i was able to reproduce on another windows machine with a different configuration. I just didn't have enough windows machines available to begin with. :)
> Root cause: Nvidia driver 595.79 (RTX 4070) miscompiles GLSL fract() usage in this shader’s context for large-magnitude operands (~100–1000): the returned fractional part is temporally discontinuous (moves smoothly, then jumps).
It looks like the LLM hallucinated a diagnosis of a miscompilation based on which fix worked. I would not treat its claim as accurate without further investigation.
Edit: Read the rest of the article and it looks like further investigation was performed, and it had nothing to do with the GPU driver after all. Good stuff.
Nice article. What a joy to read. Reminds me of what hacker news was until a few years ago!
I haven't worked with opengl/shaders in a while, but was thinking about some algorithm I wrote a few years ago, while in shower yesterday. It brought back the memories of how difficult it was for me to first understand the whole concept of shaders. There's basically no main function, no for loops etc. Your shader is called for each pixel, for every frame. I was wondering how easy it would have been in today's world. I spent like 2 months on something that is just a prompt now.
I'm in game dev but I also have very poor abilities for mentally operating on visual or geometrical data. I'm normally far away from the graphics parts but sometimes I take a look and shaders are by far the least intuitive type of code to me. I've learned enough about what shaders do to sort of parse the simple ones, but anything with shaders definitely feels like working against my brain's natural tendencies.
If you prompted a shader today, you still wouldn't understand shaders. The LLM also has absolutely no understanding of whether a graphical effect looks good.
Claude is good[1] at writing shaders. It can take a description and turn it into working GLSL code for relatively complex effects.
[1] Better than me anyway.
Should be noted that `fract(x)` is importantly only equivalent to `x - floor(x)` when x >= 0. Which it was in this case, but often negative values are also possible/expected and the latter should be used instead. This is an easy mistake to make.
It turned out to be something different, but another much more common source of shader output differences is when a float value is clamped to integer (with the value being very close to the closest integer), and then use the clamped value as index (or tex coord with an unfiltered sampler). This may result in an off-by-one error on some gpu/driver combos but not others. Completely understandable why it happens, but hard to catch unless testing on a wide range of GPUs and drivers.
TL;DR: don't expect that floating point operations on GPUs are strictly IEEE-754 compatible
The classic HLSL compiler is infamous for being full of bugs (and slow, for that matter) so I wasn't surprised to see it come up here...
Fantastic seeing the author lay out all the steps involved in getting a renderdoc capture of a browser and what's involved in debugging shader issues in a webpage.
It's interesting that the issue only manifested on the geforce 40xx if it was an fxc issue though... wonder if it's fxc combined with a driver issue and not just one or the other?
hey! author here. I think I missed the opportunity to mention that, it wasn't only reproducible on the 40xx. it was my first hypothesis, but after I figured out it was a DirectX11 issue, i was able to reproduce on another windows machine with a different configuration. I just didn't have enough windows machines available to begin with. :)
> Root cause: Nvidia driver 595.79 (RTX 4070) miscompiles GLSL fract() usage in this shader’s context for large-magnitude operands (~100–1000): the returned fractional part is temporally discontinuous (moves smoothly, then jumps).
It looks like the LLM hallucinated a diagnosis of a miscompilation based on which fix worked. I would not treat its claim as accurate without further investigation.
Edit: Read the rest of the article and it looks like further investigation was performed, and it had nothing to do with the GPU driver after all. Good stuff.
Good investigation! The whole webgl stack is such a piece of shit huh