Is it possible for a shader to conditionally use different stage kernels depending on which keywords are defined, by wrapping the #pragma directives within an #if statement?
For example, could you do something like this and expect Unity’s shader compiler to handle it?
Is it straight up just not possible to toggle kernels with shader features like this? The use case here is that we want the game to use different shader configurations depending on the desired platform/feature set.
Tried making a minimal repro test case. Getting the following compiler complaints that I don’t really get, given the shader code.
Error: Did not find shader kernel ‘my_domain’ to compile [my confusion - it can’t find my_domain since it’s defined within an #if (USE_MY_TESSELLATION) block, but the my_domain kernel is only requested within an #if (USE_MY_TESSELLATION) block as well…]
Error: Did not find shader kernel ‘my_hull’ to compile
Error: Did not find shader kernel ‘my_vert_tess’ to compile
Warning: Duplicate #pragma vertex found, ignoring: #pragma vertex my_vert (line 24) [my confusion - how can there be a duplicate #pragma vertex when they’re declared within mutually exclusive #if blocks?]
Warning: Duplicate #pragma fragment found, ignoring: #pragma fragment my_frag (line 25)
In Unity’s shader compiling system, #pragma lines are processed before #if lines, so you can’t create variants with different shader stages. This makes sense a bit since they use some #pragma lines to determine what variants to compile.
Thanks for the response. So is it just not possible to conditionally enable tessellation on a shader? It seems like the compiler should be able to support something along those lines, since some platforms support the feature and some don’t.
I see. What about the use case where a platform supports the feature but our app doesn’t have available performance cycles to enable the feature for that platform (ie, we manually want to disable/enable the feature and not rely on hardware support level).
The LOD levels are arbitrary, and mostly unused by Unity at this point, so the documentation only represents how it was used for legacy shaders. The Standard shader has two SubShaders, one using LOD 300 w/ #pragma target 3.0, the other using LOD 150 w/ #pragma target 2.0. That doesn’t mesh with that documentation at all, but again it doesn’t really matter. Just set your LOD to >300 for tesellation and set the max LOD to less than that when you want to skip that subshader.
This sounds like a way to effectively workaround the wanted-for-many-years feature of conditionally compiling shader Pass’s - create two subshaders, one with the pass, one without, move all their code into a separate cginc file to avoid maintaining two copies, and use Shader.maximumLOD to choose between variants at runtime?