+1 what mhagain said. The key being when it’s cheap/free or gains you perf (which sometimes happens).
Not necessarily. A runtime-evaluated GPU-side branch is not a-priori bad, whether conditional or unconditional. And in some cases, adding one can greatly performance. But you have to look at each one and think like the shader compiler would. That is, consider “what’s actually going to happen on the GPU when I do this”. (Related: See this fun and educational Twitter thread.)
Sadly, there’s no great middle ground that solves these issues yet (AFAIK). You just have to look at each on a case-by-case basis. This IMO is one of the areas GPU and GPU driver technology has really fallen behind. In any non-trivial real-time GPU rendering system, the amount of dev time this single issue consumes is absolutely ridiculous.
Rather than re-invent the wheel here, let me point you to some good “food-for-thought” reading on this issue:
- The Shader Permutation Problem - Part 1: How Did We Get Here?
- The Shader Permutation Problem - Part 2: How Do We Fix It?
- Ubershaders: A Ridiculous Solution to an Impossible Problem - Dolphin Emulator
- Uniform branching vs preprocessor ifdefs?
- Removed all branching from my code after reading how bad it is for the GPU. Made no performance difference at all. Went back to cultivating my potatoes.
Since you obviously care about maximizing performance, one aspect of this “shader permutation” issue to be very wary of is when the driver forceably injects separate shader permutations on-the-fly behind-the-scenes into your nice, neat, carefully-thought-out shader permutation graph, to the detriment of your application’s performance. If you don’t know about “state-based recompiles” you should read up on them.
Beyond the above, here are a few “State-based Recompile Links”:
- A little clarification on modern shader compile times
- The Missing Guide to Modern Graphics APIs – 2. PSOs
- Effects of driver-sided program re-linking
- Stuttering in Game Graphics: Detection and Solutions (NVIDIA)
- How to make OpenGL usage Vulkan like (NVIDIA)
- NV_command_list (NVIDIA)
- Solution to Shader Recompiles in Radeons (AMD)
- On TechReport’s frame latency measurement and why gamers should care
- What causes GLSL recompilation of vertex shader based on state?
- Bringing AAA Graphics to Mobile Platforms (Mobile GPUs)
With OpenGL, you have to suffer with this kind of thing happening at draw-time, … if you don’t foresee it and predesign a fork in your shader permutation tree to avoid it.
Vulkan initially didn’t solve this problem; it just forced it all to happen on startup, with the full “recompile all the shader permutations” perf hit being taking whenever you update the graphics driver. That is, unless there was some already-populated net DB being queried to bulk-download precompiled shaders directly into your driver’s shader cache. However, recently Vulkan has made some great strides toward providing real software solutions to this “GPU shader permutation problem”:
- Vulkan 1.3.210 Released With Two Notable Extensions
- VK_EXT_graphics_pipeline_library
- Reducing Draw Time Hitching with VK_EXT_graphics_pipeline_library
Unfortunately, this is Vulkan only. But it does provide one more compelling reason to switch to Vulkan.