Generating Shader Permutations - keeping the balance

Started by
3 comments, last by Ashkan 16 years, 8 months ago
I'm currently in the process of generating shader permutations using preprocessor directives but found myself in trouble while trying to balance the load between vertex and pixel shaders. Based on some recent discussions, some other samples I checked and some time spent playing around with the idea, I found it rather easy to set up the shaders for scenarios in which all or most of the lighting calculations is done exclusively in vertex or pixel shaders. The general idea is to feed the non-varying parameters such as light properties via uniform parameters and iterate over it in vertex or pixel shader to calculate its contribution. What has bugged me though is the process of distributing the workload. Here is a sample to clear my point:

//------------------------------------
// Uniform Parameters
//------------------------------------

// some uniform parameters such as light properties (type, color, falloff and such)


//------------------------------------
// Varying Parameters
//------------------------------------
struct vertexInput_textured {
    float3 position                     : POSITION;
    float3 normal                       : NORMAL;
    float2 texcoord                     : TEXCOORD0;
};

struct vertexOutput {
    float4 position                     : POSITION;
    float3 normal                       : TEXCOORD0;
    float2 texcoord                     : TEXCOORD1;
    float3 lightDirection               : TEXCOORD2;
    float3 viewDirection                : TEXCOORD3;
};

vertexOutput VS_TransformDiffuse( vertexInput_textured IN ) {
    // calculate the lightDirection and viewDirection in the vertex-shader
}

float4 PS_DiffuseSpecular( vertexOutput IN  ) : COLOR0 {
    // do the calculations in the pixel shaders
}



If we were to calculate lightDirection in the pixel shader (or had done all the calculations in the vertex shader on the other hand) things were just hunk dory. The problem here is that lightDirection is passed to the fragment shader inside vertexOutput structure so every other light adds a member to this vertexOutput structure, so I need a way to procedurally generate all these vertexOuput structures and their corresponding pixel shaders or else I would end up manually writing them in the effect file; something which was to be avoided in the first place. Add texcoords (for multi-texturing purposes) to this mix and it would become a living hell. I think I'm missing something here since FarCry or HL2 (that I think used this approach) had a lot of per-pixel effects. Should all the calculations be done either on vertex or pixel shader? Isn't there any way of balancing the load? Any ideas? Thanks
Advertisement
How about this:

struct vertexOutput {    float4 position                     : POSITION;    float3 normal                       : TEXCOORD0;    float2 texcoord                     : TEXCOORD1;    float3 viewDirection                : TEXCOORD2;#if LIGHTS >= 0    float3 light0Direction               : TEXCOORD3;#endif#if LIGHTS >= 1    float3 light1Direction               : TEXCOORD4;#endif#if LIGHTS >= 2    float3 light2Direction               : TEXCOORD5;#endif};
deathkrushPS3/Xbox360 Graphics Programmer, Mass Media.Completed Projects: Stuntman Ignition (PS3), Saints Row 2 (PS3), Darksiders(PS3, 360)
Thanks deathkrush. That was interesting, but HOLY COW I just came up with a better solution more pleasant to our instincts: arrays! I just realized that one can actually use arrays in those structures (big discovery, huh?) [grin]. The size of this array can be set using a #define. Here's a revised version:

struct vertexOutput {    float4 position                     : POSITION;    float3 normal                       : TEXCOORD0;    float2 texcoord                     : TEXCOORD1;    float3 viewDirection                : TEXCOORD2;    float3 lightDirection[MAX_LIGHT]    : TEXCOORD3;};
Those vertex structures are much too big and any NVIDIA card (probably also ATI cards) will get a hiccup with those. Performance of the vertex shader is dependend on the number of attributes you feed it. With a vertex structure like this your vertex shader performance is pretty much dead.
Quote:Performance of the vertex shader is dependend on the number of attributes you feed it.

If you're concerned about the bus traffic caused by fat streams sent to the video card or the vertex processor been brought down to it's knees, I think you've probably mistaken that structure for a structure representing the incoming vertex's layout. That structure is actually what's get passed down to the fragment shader. Anyway, I'm still very open to suggestions. Have you got any better ideas?

This topic is closed to new replies.

Advertisement