Performance Question: Alpha Texture vs Frag Shader discard

Started by
5 comments, last by pcmaster 5 years, 3 months ago

Good Afternoon,

I have a quick question regarding the performance of rendering a texture(sprite) say Super Mario where some pixels have an alpha value = 0.

Is it quicker performance wise to render such a texture with the original alpha value = 0 or to use color keying in the fragment shader and discarding say color vec4(0,1,1,1) to arrive at the same transperancy effect.

Thanks again for your time,

Mike

Advertisement

If I can get away by just using a blend state, I'll stick with it; discarding somehow messing up my depth testing and for sure it will bypass whatever current raster state you may have for every pixel that should be discarded and it does not render translucent or semi-transparent; it's either draw it or discard it, but that's just my experience ^_^y

The only possible answer is: implement both and measure.

From my experience, discarding big groups of transparent pixels usually helps on the GCN architecture, but it "depends". Measure :)

Full expected Hodgman / MJP etc to provide definitive answer on this :), but afaik, it may depend on the hardware.

See this thread:

https://www.gamedev.net/forums/topic/655602-why-discard-pixel-take-a-noticeable-performance-hit/

And this linked page on the graphics pipeline:

https://fgiesen.wordpress.com/2011/07/08/a-trip-through-the-graphics-pipeline-2011-part-7/

There are 2 basic options when considering transparency and those are:

Alpha Testing

For cases, where transparency is a binary decision (either opaque, or fully transparent), alpha testing is an option. For such scenarios alpha testing is an option, where you can keep z-testing on, and draw in any order. In legacy OpenGL this was used as (example):


glAlphaFunc(GL_GREATER, cutoutValue);
glEnable(GL_ALPHA_TEST);

In GLSL/HLSL it looks like:


if (alphaValue < cutoutValue)
  discard;

A discarded fragment will never affect - atomic counters, SSBO/RWBuffer, image load store operations and any bound color buffers. Unless specified that depth/stencil tests happen before shader - they also won't affect depth/stencil buffer values - this can be done in GLSL with:


layout(early_fragment_tests) in;

And this is why so many people point out that performing discard is slow.

Why?

Generally with opaque geometry there is always early-z optimization. This prevents unnecessary executions in fragment shader whenever we already know that the fragment is not going to be drawn. Which is why it is most efficient to render opaque geometry front-to-back.

By doing discard in fragment shader (or any writes to depth buffer), we effectively require pixel shader to run for each pixel (therefore no early-z optimization is possible).

Also, as GPU often executes group of pixels at once (F.e. 4x4 block) the execution time per block will differ based on - whether all fragments are discarded (especially early in the shader - which is best scenario), or some/none pixels are discarded (at which point you will need to wait for all the pixels to finish the pixel shader).

Conclusion

This doesn't necessarily means that using alpha test is bad, it just means that it has some performance hit for majority of renderers (Immediate Mode Rendering, Tile Based Rendering, etc.), and the performance hit can be especially seen on mobile hardware.

The ideal order of rendering is - opaque geometry (front-to-back), alpha tested geometry (order doesn't matter) and then alpha blended geometry (back-to-front).

Also the overall performance will be based on whether you can perform occlusion culling efficiently (using any methods available - BSP, Hi-Z, etc.), therefore reducing number of objects drawn that will actually be invisible in final image.

Alpha Blending

If alpha testing isn't enough for you (and you need non-binary transparency) - then the most straight forward solution is alpha blending. Blending is done by combining previous value in frame buffer with new value calculated from fragment shader. This leads to major problem - that all your transparent objects need to be drawn after all opaque objects in back to front order (sorting may not be enough though - and you may need to split the geometry to achieve correct ordering).

With alpha blending early-z works (although note - you're drawing in back-to-front order - so it will have impact only for transparent geometry hidden behind opaque), therefore on some architectures it can outperform alpha testing (PowerVR is well known for this).

 

In the end - it is hard to tell what is better for you, because it will depend on few major factors:

  • How does your scene look like?
  • How complex are your shaders?
  • Target hardware?

So the correct answer is what @pcmaster gave you.

 

There are also other options that allow you for correct order-independent-transparency, but generally tend to be a lot heavier to implement (for example alpha-to-coverage, depth-peeling)

My current blog on programming, linux and stuff - http://gameprogrammerdiary.blogspot.com

@Vilem Otte He says, he's going to render a 2D Mario-like sprite :) So I think that's about how the scene looks like.

This topic is closed to new replies.

Advertisement