<p>What's probably happening is that you're doing indirect texture fetches. Are you doing something like this:</p>

<pre><code>vec4 a = texture3D(sampler, coord);
vec4 b = texture3D(sampler, coord + vec4(0, 0, 1));
vec4 c = texture3D(sampler, coord + vec4(0, 1, 0));
vec4 d = texture4D(sampler, coord + vec4(1, 0, 0));
//...etc.
</code></pre>

<p>If so, that can slow you down. What you can do instead is to pass the texture coordinates for each sampler call into your vertex shader from your CPU code. You'd set it up as if you were doing multi-texturing, but all the texture units would point to the same texture, just sampled at different coordinates. </p>

<p>Taking the 2D case, instead of passing in a single texture coordinate like this:</p>

<pre><code>float2 texCoords[] = { 
    { 0, 0 },
    { width, 0 },
    { width, height },
    { 0, height }
};
</code></pre>

<p>You'd pass in 4 of them:</p>

<pre><code>float2 texCoords[] = {
    // texture 0 coords
    { 0, 0 },
    { width, 0 },
    { width, height },
    { 0, height },

    // texture 1 coords
    { 1, 0 },
    { width + 1, 0 },
    { width + 1, height },
    { 1, height },

    // Texture 2 coords
    { 0, 1 },
    { width, 1 },
    { width, height + 1 },
    { 0, height + 1 },

    // Texture 3 coords
    { 1, 1 },
    { width + 1, 1 },
    { width + 1, height + 1 },
    { 1, height + 1 }
};
</code></pre>

<p>In your fragment shader, you'd do something like this:</p>

<pre><code>vec4 pixel0 = texture2D(sampler0, coord0);
vec4 pixel1 = texture2D(sampler1, coord1);
vec4 pixel2 = texture2D(sampler2, coord2);
vec4 pixel3 = texture2D(sampler3, coord3);
</code></pre>

<p>Now you have the 4 pixels needed for interpolation, but there was no fragment shader math done to get the texture coords, so there are no indirect look-ups which are slower than direct look-ups.</p>

CC BY-SA 4.0
2018-05-17T07:03:29.503Z
They are absolutely inderect, yes. Idea to move calculation to vertex shader is interesting. There is a problem though. I don’t simply add or substract 1 from tex coords, I use floor and ceil to find the bounding box of a coordinate in texel space, and because of that, I don’t see how that can be solved in a vertex shader.
Pavlo Muratov
CC BY-SA 4.0
2018-07-16T01:35:39.087Z
This answer is somewhat outdated/wrong. First, doing math on the texture coordinates before sampling is not a big source of performance issues. You might be thinking of _dependent_ texture fetches, where the texture coordinate depends on the output _of an earlier texture sample_ — that will serialize those samples, and because they have a long latency, it can greatly extend the latency of the whole shader. But that's not what we have here; all the sample coords just depend on a single shader input, not on other samples.
Nathan Reed
CC BY-SA 4.0
2018-07-16T01:38:08.693Z
Moreover, vertex interpolation isn't free either; GPUs have limited space for interpolated values (using too many may hurt occupancy), and depending on hardware some pixel shader instructions may be needed to perform the actual interpolation anyway. So it's not necessarily a win to move a bunch of values into interpolators vs using a small amount of math to calculate them directly in the pixel shader.
Nathan Reed
CC BY-SA 4.0
2018-07-16T01:39:36.893Z
It may depend on exact hardware and OS. My experience has been that removing any sort of indirect texture fetch, not just dependent, has generally helped performance, particularly on mobile hardware. But I haven't used every piece of hardware out there, so my suggestion was mainly meant to address what I've experienced in case it was helpful.
user1118321
CC BY-SA 4.0
2018-05-16T22:01:28.303Z
2018-05-16T22:01:28.303Z
user1118321
<p>I'm implementing manual interpolation between texels in a 3D texture to be able to discard some of them when needed. Compared to hardware interpolation, this process takes a lot of time. If I simply leverage hardware interpolation using <code>texture</code> function, rendering takes ~5ms, but with manual fetch using <code>texelFetch</code> it rises to ~13ms (using <code>texture</code> to fetch 8 texels manually increases frame time even further - to ~35ms). The multiplication/summing part of the manual lerp does't matter much - I've tried fetching same texel manually 8 times and the performance is close to hardware interpolation. I thought fetching neighboring texels should give me good cache behavior, but maybe that only applies to 2D textures because neighboring layers of 3D tex are not so cache friendly? Don't know what to think here.. It would be nice if there was some way to use hardware interpolation but discard some texels from the process. The absence of a <code>textureGather</code> function taking a 3D texture also makes me think I'm missing something here.</p>

CC BY-SA 4.0
2018-05-13T21:33:04.617Z
Well, `textureGather` is already a slight bit hacky in that it forces you to just a single channel for the apparently sole reason that it can't return 4 `vec4`s API-wise. So I'd guess the lack of a `textureGather` for 3D textures might be simply due to the interface problems of returning 8 values instead of 4 from a function.
Christian Rau
<opengl><glsl><fragment-shader><3dtexture>
Manually fetching 8 neighboring texels from 3D texture greatly decreases performance
Pavlo Muratov
# Manually fetching 8 neighboring texels from 3D texture greatly decreases performance

(Asked by: username_0 on 2018-05-13)

I'm implementing manual interpolation between texels in a 3D texture to be able to discard some of them when needed. Compared to hardware interpolation, this process takes a lot of time. If I simply leverage hardware interpolation using `texture` function, rendering takes ~5ms, but with manual fetch using `texelFetch` it rises to ~13ms (using `texture` to fetch 8 texels manually increases frame time even further - to ~35ms). The multiplication/summing part of the manual lerp does't matter much - I've tried fetching same texel manually 8 times and the performance is close to hardware interpolation. I thought fetching neighboring texels should give me good cache behavior, but maybe that only applies to 2D textures because neighboring layers of 3D tex are not so cache friendly? Don't know what to think here.. It would be nice if there was some way to use hardware interpolation but discard some texels from the process. The absence of a `textureGather` function taking a 3D texture also makes me think I'm missing something here.

**Tags:** opengl, glsl, fragment-shader, 3dtexture
> **Comments:**
> **username_1**: Well, `textureGather` is already a slight bit hacky in that it forces you to just a single channel for the apparently sole reason that it can't return 4 `vec4`s API-wise. So I'd guess the lack of a `textureGather` for 3D textures might be simply due to the interface problems of returning 8 values instead of 4 from a function.  

---

## 1 answers

### Answer by username_2 on 2018-05-16. Score: -1

What's probably happening is that you're doing indirect texture fetches. Are you doing something like this:
vec4 a = texture3D(sampler, coord);
vec4 b = texture3D(sampler, coord + vec4(0, 0, 1));
vec4 c = texture3D(sampler, coord + vec4(0, 1, 0));
vec4 d = texture4D(sampler, coord + vec4(1, 0, 0));
//...etc.

If so, that can slow you down. What you can do instead is to pass the texture coordinates for each sampler call into your vertex shader from your CPU code. You'd set it up as if you were doing multi-texturing, but all the texture units would point to the same texture, just sampled at different coordinates. 
Taking the 2D case, instead of passing in a single texture coordinate like this:
float2 texCoords[] = { 
    { 0, 0 },
    { width, 0 },
    { width, height },
    { 0, height }
};

You'd pass in 4 of them:
float2 texCoords[] = {
    // texture 0 coords
    { 0, 0 },
    { width, 0 },
    { width, height },
    { 0, height },

    // texture 1 coords
    { 1, 0 },
    { width + 1, 0 },
    { width + 1, height },
    { 1, height },

    // Texture 2 coords
    { 0, 1 },
    { width, 1 },
    { width, height + 1 },
    { 0, height + 1 },

    // Texture 3 coords
    { 1, 1 },
    { width + 1, 1 },
    { width + 1, height + 1 },
    { 1, height + 1 }
};

In your fragment shader, you'd do something like this:
vec4 pixel0 = texture2D(sampler0, coord0);
vec4 pixel1 = texture2D(sampler1, coord1);
vec4 pixel2 = texture2D(sampler2, coord2);
vec4 pixel3 = texture2D(sampler3, coord3);

Now you have the 4 pixels needed for interpolation, but there was no fragment shader math done to get the texture coords, so there are no indirect look-ups which are slower than direct look-ups.

> **Comments:**
> **username_0**: They are absolutely inderect, yes. Idea to move calculation to vertex shader is interesting. There is a problem though. I don’t simply add or substract 1 from tex coords, I use floor and ceil to find the bounding box of a coordinate in texel space, and because of that, I don’t see how that can be solved in a vertex shader.  
> **username_3**: This answer is somewhat outdated/wrong. First, doing math on the texture coordinates before sampling is not a big source of performance issues. You might be thinking of _dependent_ texture fetches, where the texture coordinate depends on the output _of an earlier texture sample_ — that will serialize those samples, and because they have a long latency, it can greatly extend the latency of the whole shader. But that's not what we have here; all the sample coords just depend on a single shader input, not on other samples.  
> **username_3**: Moreover, vertex interpolation isn't free either; GPUs have limited space for interpolated values (using too many may hurt occupancy), and depending on hardware some pixel shader instructions may be needed to perform the actual interpolation anyway. So it's not necessarily a win to move a bunch of values into interpolators vs using a small amount of math to calculate them directly in the pixel shader.  
> **username_2**: It may depend on exact hardware and OS. My experience has been that removing any sort of indirect texture fetch, not just dependent, has generally helped performance, particularly on mobile hardware. But I haven't used every piece of hardware out there, so my suggestion was mainly meant to address what I've experienced in case it was helpful.  

---

