3
\$\begingroup\$

I have a texture that's from the color attachment of an FBO in OpenGL ES 2.0, so I have limited control over the number of channels in the image.

Suppose I only need the color from the R channel of this texture. If I immediately swizzle out the R in the fragment shader like this:

float brightness = texture2D(u_texture, v_texCoord).r;

can I expect the GPU to know not to bother looking up G, B, and A?

I figure this is something that might vary from device to device, depending on the optimizations of the shader compiler, but to me this looks like a very obvious and easy optimization.

I'd like to know if I can be reasonably confident that almost all GPUs will make the optimization. This shader is a multiple-texture shader, and I'd hate to get surprised by some percentage of devices running it much slower than what I've tested on. If I cannot, then I may want to take pains to use a different method of generating my image so I can ensure a texture with fewer channels.

\$\endgroup\$
  • \$\begingroup\$ But even regardless of the optimization, how can you ever be sure that other devices run it as fast as your own device? I mean, unless your device is the slowest one, there is bound to be another device slower? \$\endgroup\$ – Felsir Sep 8 '15 at 13:51
  • \$\begingroup\$ That's Android development for you. You can't be totally sure, but you can test on a reasonably low end device, set a minimum Android version number to filter out most devices that are weaker than that, and try to make some reasonable assumptions such as the above to minimize the number of devices that will have performance issues. \$\endgroup\$ – TenFour04 Sep 8 '15 at 13:55
  • 1
    \$\begingroup\$ GPUs don't usually read a single or multiple bytes, it's expected to read a cache line or so. So don't expect it to do the optimization I have touched on the subject here \$\endgroup\$ – concept3d Sep 8 '15 at 15:16
  • \$\begingroup\$ I also recommend you ask the question here computergraphics.stackexchange.com \$\endgroup\$ – concept3d Sep 8 '15 at 15:20
  • \$\begingroup\$ @concept3d, I hadn't really thought about that, but that's an excellent point. With Nearest texture filtering, it seems there would be no difference in performance unless the source texture itself was <4-bytes per pixel. But with linear filtering, wouldn't a lerp have to be done on each individual byte (not the combined group of four), which is extra operations? I guess it depends if the word has to be broken up into four separate bytes for four separate lerps, or if there's some kind of GPU operation that can lerp a word in a byte-independent sort of way. \$\endgroup\$ – TenFour04 Sep 8 '15 at 15:25
3
\$\begingroup\$

You are not going to see any difference from fetching one channel over many. There is no optimization to make.

Longer explanation:

Texure is stored, you can guess without any doubt, by pixel in memory. Which means, r,g,b,a are packed together on the same place. (i.e. channels are interleaved). Fetching stuff from memory happens in batches of whatever the DDR format banksize is, which is probably quite large, more than one pixel for sure. Luckily, because shaders fetch usually only one pixel, transferring more is not lost in overhead, it is used to fill the texture unit cache. Which works well usually because of correlation between shader unit core locality, and texture space locality.
This is ensured using Z-order curve storage in main memory. (aka Morton code).
for the trivia this is actually also called swizzling, but has nothing to do with shader swizzled accessors.

The swizzle operation takes no supplementary time thanks to the pipelined instruction architecture, but it does not permit optimization either.

One could think nvidia card (scalar shader units) would be advantaged over ATI cards (vector shader units) in the case where ALU works with scalars like here. But this is not related to compilation, or optimization.

Some optimizations that the compiler WILL perform:

move texture fetches as high as possible in the shader, above any computation even sometimes. This is possible if tex2d instructions are not dependent on variable uvs (purely varying passing verbatim). Note that this will be true even if the tex2d instruction is inside a condition !

The goal of this, is to try to act as a prefetcher. To hide bus latencies over ALU speed.

| improve this answer | |
\$\endgroup\$
  • \$\begingroup\$ Do you know how linear interpolation for texture filtering is done if the channels are interleaved? And does a single or double channel texture still get fetched with 4 bytes per pixel? \$\endgroup\$ – TenFour04 Sep 9 '15 at 11:59
  • \$\begingroup\$ from eecg.toronto.edu/~myrto/gpuarch-ispass2010.pdf apparently a typical cache line is 32 bytes, so if you have a single channel texture, one fetch will burst read 32 pixels at once. these pixels will be cached so neighbors can profit. It is very advantageous to diminish your texture depth/channels/dimensions as much as you can to reduce bandwidth requirements. So if you can make your textures single channel-ed, it is much better. \$\endgroup\$ – v.oddou Sep 10 '15 at 1:02
  • \$\begingroup\$ for the first question, the filtering is not impacted by memory layout. check this statement vec3 clr(ram[x], ram[x+1], ram[x+1]) versus vec3 clr(ram[x], ram[x+w], ram[x+w+w]) with w=total texture mem size / numchannels. These 2 statements symbolizes channels fetching to compose one vector color with 2 different memory layouts, 1=interleaved, 2=separated. The computations on the filtering happens on clr style variables, and therefore not impacted by where its components comes from. \$\endgroup\$ – v.oddou Sep 10 '15 at 1:10

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.