Sign in to follow this  

Splitting up shaders

This topic is 2837 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Im wondering about the whole shader explosion thing. I hear this is the case due to the amount of shader combinations avaliable. But what exactly do they mean by a shader combinations? I guess the main case would be for different shader versions.And another could be compiling a shader for both non-skinned and skinned vertices, something like
#ifdef skinned
#define VS SkinnedVertex
#else
#define VS NonSkinnedVertex

VertexShader(VS in)
{
  // do normal vertex stuff
  #ifdef skinned
  // do skinning
  #endif
}

But I also hear they use the same method for compiling shaders for other things, such as whether to use a specular power value or a specular map. And then also for enviroment relection mapping.
#ifdef useSpecularmap
   Texture and Sampler for spec map
#endif

#ifdef useEnviromentmap
   Texture and Sampler for enviroment map
#endif

PixelShader(VS in)
{
  // do normal pixel stuff

  #ifdef useSpecularmap
    // specular lighting use specmap
    #else
    // specular lighting using material float
  #endif  

  #ifdef useEnviromentmap
    // add lighting using useEnviromentmap
  #endif  
}

So the above stuff alone produces a bunch of combinations (shader version, vertex type, specular mapping and enviroment mapping switches). So do they just compile them all, and then simply pick one that matches the shader version and the objects material? The reason I ask, is becuase Im wondering why they dont just do some sort of if test in code rather than pre-processor stuff. This way you need to compile less shaders. I know this wont work with the vertex type and shader version example, but it could with the other stuff.

cbuffer PerInstance
{
  float useSpecularmap;
  float useEnviromentmap;
}

PixelShader(VS in)
{
  // do normal pixel stuff

  if(useSpecularmap)
  {
    // specular lighting use specmap
   }else{
    // specular lighting using material float
  }

  if(useEnviromentmap)
  {
    // add lighting using useEnviromentmap
  }  
}

I gather this is lots of checks for each pixel, but isnt having a shader switch more expensive? Whats the best approach?

Share this post


Link to post
Share on other sites
Quote:

The reason I ask, is becuase Im wondering why they dont just do some sort of if test in code rather than pre-processor stuff.


I think typically GPU's have not had good conditional performance due to their architecture, they are streamlined to crunch as much floating point math as possible. I don't know if this is improved in newer cards, but in the past there was no branch prediction, and the GPU would actually execute both branches simultaneously before choosing the output.


If you have to run a vertex or pixel shader one million times per frame, then you really don't want anything extra that is going to slow it down, and the one time hit for switching shaders and the extra however many KB of memory it takes is often worth generating a family of similar shaders. Especially if you can sort your rendered objects to minimize shader switches.

Obviously there is a tradeoff involved in choosing shader granularity, but you'll have to test different combinations to find the most efficient combination in your engine.

Share this post


Link to post
Share on other sites
Quote:
Original post by maya18222
I gather this is lots of checks for each pixel, but isnt having a shader switch more expensive? Whats the best approach?


It depends a lot on the platform and the GPU. Some handle static branching a lot better than others, some handle shader switching better.

There are definitely people that don't precompile a million permutations of their shaders. I know of at least one big-budget AAA game that took the approach of just having 20 or so shaders with no #defines or anything like that. I would imagine that this is difficult for artists to work, but it probably also let them hand-optimize their shaders.

Also keep in mind that in D3D11 you have yet another option, with dynamic shader linkage.

Share this post


Link to post
Share on other sites

This topic is 2837 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this