<h2>Background</h2>
<p>In order to support <a href="https://en.wikipedia.org/wiki/Mipmap" rel="nofollow noreferrer">mipmapping</a>, the texture sampling system needs to know what scale the texture is being displayed at. In order to determine that scale automatically, the <em>derivatives</em> (or “gradient”) of the texture coordinates are used. The way GPUs calculate derivatives is by comparing the results of the calculations performed in one fragment to adjacent fragments.</p>
<p>The reason you can't put <code>textureSample</code> inside of <code>if</code> is because it is possible that the <code>if</code> takes different branches on different pixels, and so the derivative won't exist. “Uniform control flow” means “all fragments are guaranteed to execute this code”.</p>
<h2>Possible solutions</h2>
<ul>
<li><p>If <code>r_texture</code> has no mipmaps, or if <code>r_sampler</code> is configured to prevent using them, then you don't need to select a mipmap level. Use <code>textureSampleLevel(r_texture, r_sampler, in.tex_coords, 0.0)</code> — the additional argument is the mipmap level, and 0 means the full-resolution texture, which is all you want in this case.</p>
</li>
<li><p>If you do wish to use mipmaps, then you can compute the relevant derivatives outside of the <code>if</code>, and use them inside:</p>
<pre><code>let ddx = dpdx(in.tex_coords);
let ddy = dpdy(in.tex_coords);
if in.use_texture {
    let sample = textureSampleGrad(r_texture, r_sampler, in.tex_coords, ddx, ddy);
    return sample * in.color;
} else {
    return in.color;
}
</code></pre>
<p>This is basically doing what <code>textureSample</code> would do implicitly, but moving just the parts that can't be in the <code>if</code> outside.</p>
</li>
</ul>
<h2>Language notes</h2>
<p>The code in this answer is <a href="https://www.w3.org/TR/WGSL/" rel="nofollow noreferrer">WGSL</a>. Equivalent functions in GLSL:</p>
<div class="s-table-container">
<table class="s-table">
<thead>
<tr>
<th>WGSL</th>
<th>GLSL</th>
</tr>
</thead>
<tbody>
<tr>
<td>textureSample()</td>
<td>texture()</td>
</tr>
<tr>
<td>textureSampleGrad()</td>
<td>textureGrad()</td>
</tr>
<tr>
<td>dpdx()</td>
<td>dFdx()</td>
</tr>
<tr>
<td>dpdy()</td>
<td>dFdy()</td>
</tr>
</tbody>
</table>
</div>
<p>Also, <a href="https://www.khronos.org/opengl/wiki/Sampler_(GLSL)#Non-uniform_flow_control" rel="nofollow noreferrer">here's another introduction to the same concepts from the Khronos OpenGL wiki (which uses GLSL)</a>.</p>

CC BY-SA 4.0
2023-09-26T18:21:16.997Z
Thanks, that was very insightful. FWIW, I found that the mipmap level in `textureSampleLevel()` needs to be specified as a float.
junglie85
CC BY-SA 4.0
2023-09-23T22:27:22.807Z
2023-09-26T20:19:27.710Z
2023-09-26T20:19:27.710Z
Kevin Reid
<p>How can I avoid having to declare the sampler outside of the if statement in this shader code sample?</p>
<pre><code>let sample = textureSample(r_texture, r_sampler, in.tex_coords);
if in.use_texture {
    return sample * in.color;
} else {
    return in.color;
}
</code></pre>
<p>This came up as an answer to another of my <a href="https://computergraphics.stackexchange.com/questions/13682/conditionally-sample-from-texture-in-shader/13683#13683">questions</a>, and it was suggested that the sampler needed to be declared here due to uniform control flow, but that it could be avoided.</p>
<p>How to avoid it?</p>

CC BY-SA 4.0
2023-09-25T20:10:27.807Z
This more of avoiding calling the textureSample function outside an if statement then declaring it.
pmw1234
<shader><fragment-shader>
How to avoid declaring sampler outside of statement?
junglie85
# How to avoid declaring sampler outside of statement?

(Asked by: username_0 on 2023-09-23)

How can I avoid having to declare the sampler outside of the if statement in this shader code sample?
let sample = textureSample(r_texture, r_sampler, in.tex_coords);
if in.use_texture {
    return sample * in.color;
} else {
    return in.color;
}

This came up as an answer to another of my questions, and it was suggested that the sampler needed to be declared here due to uniform control flow, but that it could be avoided.
How to avoid it?

**Tags:** shader, fragment-shader
> **Comments:**
> **username_1**: This more of avoiding calling the textureSample function outside an if statement then declaring it.  

---

## 1 answers

### Answer by username_2 on 2023-09-23. Score: 4 | Accepted answer

Background
In order to support mipmapping, the texture sampling system needs to know what scale the texture is being displayed at. In order to determine that scale automatically, the derivatives (or “gradient”) of the texture coordinates are used. The way GPUs calculate derivatives is by comparing the results of the calculations performed in one fragment to adjacent fragments.
The reason you can't put textureSample inside of if is because it is possible that the if takes different branches on different pixels, and so the derivative won't exist. “Uniform control flow” means “all fragments are guaranteed to execute this code”.
Possible solutions

If r_texture has no mipmaps, or if r_sampler is configured to prevent using them, then you don't need to select a mipmap level. Use textureSampleLevel(r_texture, r_sampler, in.tex_coords, 0.0) — the additional argument is the mipmap level, and 0 means the full-resolution texture, which is all you want in this case.

If you do wish to use mipmaps, then you can compute the relevant derivatives outside of the if, and use them inside:
let ddx = dpdx(in.tex_coords);
let ddy = dpdy(in.tex_coords);
if in.use_texture {
    let sample = textureSampleGrad(r_texture, r_sampler, in.tex_coords, ddx, ddy);
    return sample * in.color;
} else {
    return in.color;
}

This is basically doing what textureSample would do implicitly, but moving just the parts that can't be in the if outside.


Language notes
The code in this answer is WGSL. Equivalent functions in GLSL:




WGSL
GLSL




textureSample()
texture()


textureSampleGrad()
textureGrad()


dpdx()
dFdx()


dpdy()
dFdy()




Also, here's another introduction to the same concepts from the Khronos OpenGL wiki (which uses GLSL).

> **Comments:**
> **username_0**: Thanks, that was very insightful. FWIW, I found that the mipmap level in `textureSampleLevel()` needs to be specified as a float.  

---

