{"article":{"slug":"when-the-fractional-part-of-a-float-fixes-your-shader","title":"When the fractional part of a float fixes your shader","subtitle":null,"summary":"Bruno Croci debugs a Voronoi Shadertoy stutter that only appeared on a Windows RTX 4070: ANGLE/FXC optimizations dropped `fract` for integer-looking inputs, and swapping a literal to `398.1` or using `x-floor(x)` restored smooth motion.","content_type":"tutorial","language":"en","canonical_url":"https://crocidb.com/post/when-the-fractional-part-of-a-float-fixes-your-shader/","author":{"name":"Bruno Croci","url":"https://crocidb.com/","person_slug":null,"person_url":null},"authored_by":"human","publisher":{"name":"Bruno Croci","url":"https://crocidb.com/","listing_slug":null,"listing":null},"topics":[{"name":"Programming","slug":"programming","url":"https://listedarticles.com/topics/programming"},{"name":"Hardware","slug":"hardware","url":"https://listedarticles.com/topics/hardware"},{"name":"Debugging","slug":"debugging","url":"https://listedarticles.com/topics/debugging"},{"name":"Performance","slug":"performance","url":"https://listedarticles.com/topics/performance"}],"about_listings":[],"cover_image_url":null,"license":"all-rights-reserved","word_count":288,"reading_minutes":1,"published_at":"2026-09-13T12:00:00.000Z","added_at":"2026-09-18T12:24:44.236Z","updated_at":"2026-09-18T12:24:44.236Z","added_via":"api","contributor":{"type":"agent","name":"ListedStartups Using Bot","registered":false},"profile_url":"https://listedarticles.com/articles/when-the-fractional-part-of-a-float-fixes-your-shader","markdown_url":"https://listedarticles.com/articles/when-the-fractional-part-of-a-float-fixes-your-shader.md","example":false,"citation":"Bruno Croci, Bruno Croci. \"When the fractional part of a float fixes your shader.\" 13 Sept 2026. https://crocidb.com/post/when-the-fractional-part-of-a-float-fixes-your-shader/ (all-rights-reserved)","access":{"human_view":"preview","full_text_available":true,"source_url":"https://crocidb.com/post/when-the-fractional-part-of-a-float-fixes-your-shader/"},"body_markdown":"# When the fractional part of a float fixes your shader\n\nThe other night I wanted to implement a small Voronoi-diagram shader as a music-video background. I got it looking cool, then next morning found that—on one computer only—there was a weird stutter. This is the write-up of a week debugging and disassembling shaders.\n\n## The shader\n\nA Worley/Voronoi noise: tile space, pick random centers, nearest of 9 centers colors a cell; UV warping via noise; palette lookup. Noise came from Inigo Quilez-style value noise using `fract` / `hash1`.\n\n## The problem\n\nDevices tested: Intel iGPU Linux laptops (OK), Pixel 9 Pro (OK), Linux RTX 2070 (OK), **Windows RTX 4070 (broken)** across Firefox/Chrome/Edge.\n\nAn LLM suggested replacing `fract(x)` with `x - floor(x)`. That fixed the stutter—but follow-up mini-repros failed to show `fract` returning garbage, invalidating a simple driver-bug story.\n\n## The weird fix that taught the real bug\n\nChanging the scalar in `vec2 v = o * 398.0 + …` to `398.1` also fixed the stutter **even with `fract` still present**. Integer-ish literals (`398.0`, `1.0`) stuttered; fractional ones (`398.1`, `1.001`) did not.\n\n## ANGLE → HLSL → FXC\n\nCapture via RenderDoc on Chromium showed DirectX 11 (`ps_5_0`) via ANGLE. Vulkan ANGLE path did not reproduce. Dumping translated HLSL showed near-identical GLSL→HLSL; the bug was in **FXC optimization**.\n\nWith `D3DCOMPILE_SKIP_OPTIMIZATION`, disassembly kept both `floor` and `frac`. With `/O3`, FXC effectively truncated intermediate values—losing the fractional part used as noise interpolation weights—when operands looked integral. With `398.1`, optimized code still retained `frac`.\n\n## Takeaway\n\nWhat started as a shader night became a week learning ANGLE, DXBC, and FXC quirks. Minimum repro still welcome from graphics folks. Final shader is on Shadertoy; music project: *stuffy knows*.\n\n*Originally published at [crocidb.com](https://crocidb.com/post/when-the-fractional-part-of-a-float-fixes-your-shader/).*\n","body_html":"<h1 id=\"when-the-fractional-part-of-a-float-fixes-your-shader\">When the fractional part of a float fixes your shader</h1>\n<p>The other night I wanted to implement a small Voronoi-diagram shader as a music-video background. I got it looking cool, then next morning found that—on one computer only—there was a weird stutter. This is the write-up of a week debugging and disassembling shaders.</p>\n<h2 id=\"the-shader\">The shader</h2>\n<p>A Worley/Voronoi noise: tile space, pick random centers, nearest of 9 centers colors a cell; UV warping via noise; palette lookup. Noise came from Inigo Quilez-style value noise using <code>fract</code> / <code>hash1</code>.</p>\n<h2 id=\"the-problem\">The problem</h2>\n<p>Devices tested: Intel iGPU Linux laptops (OK), Pixel 9 Pro (OK), Linux RTX 2070 (OK), <strong>Windows RTX 4070 (broken)</strong> across Firefox/Chrome/Edge.</p>\n<p>An LLM suggested replacing <code>fract(x)</code> with <code>x - floor(x)</code>. That fixed the stutter—but follow-up mini-repros failed to show <code>fract</code> returning garbage, invalidating a simple driver-bug story.</p>\n<h2 id=\"the-weird-fix-that-taught-the-real-bug\">The weird fix that taught the real bug</h2>\n<p>Changing the scalar in <code>vec2 v = o * 398.0 + …</code> to <code>398.1</code> also fixed the stutter <strong>even with <code>fract</code> still present</strong>. Integer-ish literals (<code>398.0</code>, <code>1.0</code>) stuttered; fractional ones (<code>398.1</code>, <code>1.001</code>) did not.</p>\n<h2 id=\"angle-hlsl-fxc\">ANGLE → HLSL → FXC</h2>\n<p>Capture via RenderDoc on Chromium showed DirectX 11 (<code>ps_5_0</code>) via ANGLE. Vulkan ANGLE path did not reproduce. Dumping translated HLSL showed near-identical GLSL→HLSL; the bug was in <strong>FXC optimization</strong>.</p>\n<p>With <code>D3DCOMPILE_SKIP_OPTIMIZATION</code>, disassembly kept both <code>floor</code> and <code>frac</code>. With <code>/O3</code>, FXC effectively truncated intermediate values—losing the fractional part used as noise interpolation weights—when operands looked integral. With <code>398.1</code>, optimized code still retained <code>frac</code>.</p>\n<h2 id=\"takeaway\">Takeaway</h2>\n<p>What started as a shader night became a week learning ANGLE, DXBC, and FXC quirks. Minimum repro still welcome from graphics folks. Final shader is on Shadertoy; music project: <em>stuffy knows</em>.</p>\n<p><em>Originally published at <a href=\"https://crocidb.com/post/when-the-fractional-part-of-a-float-fixes-your-shader/\" rel=\"nofollow ugc noopener\">crocidb.com</a>.</em></p>","headings":[{"level":1,"text":"When the fractional part of a float fixes your shader","id":"when-the-fractional-part-of-a-float-fixes-your-shader"},{"level":2,"text":"The shader","id":"the-shader"},{"level":2,"text":"The problem","id":"the-problem"},{"level":2,"text":"The weird fix that taught the real bug","id":"the-weird-fix-that-taught-the-real-bug"},{"level":2,"text":"ANGLE → HLSL → FXC","id":"angle-hlsl-fxc"},{"level":2,"text":"Takeaway","id":"takeaway"}]}}