Late response to this, but all I can suggest is leveraging the per-component math of HLSL better in your shaders...
float xCoordMultiplication : register (c13);
float yCoordMultiplication : register (c14);
Make that a float2
float2 xyCoordMultiplier : register (c13) : register (c14);
I think that's how you tie two different registers to one global. Might want to double check MSDN HLSL reference to be sure, though.
With your xy multiplier now a float 2, you can change this...
OUT.texCoord = float2(IN.texCoord.x * xCoordMultiplication,
IN.texCoord.y * yCoordMultiplication);
... to this ...
OUT.texCoord = IN.texCoord.xy * xyCoordMultiplier.xy;
You save yourself having to cast another float2 (for the x & y math operations), and you leverage .xy per-component math which is faster then doing it each separately.
In your pixel shader...
float3 processedSpecular = pow(saturate(dot(normal, halfway)), materialPower) * specular;
... HLSL has an intrinsic function called "lit" that you can read more about here... http://developer.download.nvidia.com/cg/lit.html
Basically you hand it a sun luminence dot (NDotL ... dot ( normal, light)), a specular reflection dot (NDotH ... dot ( normal, halfway)) and a specular pow value (your materialPower) it does all the pow, saturate, etc.. basically creates your float specular luminence to * by your float3 specularLightIntensity.
While you still have to calculate the dots in the shader, you'd use the lit function, b/c it replaces the pow,saturate,etc you have with a built-in function doing it more efficiently then you coding it in the shader yourself.
I would also change this stuff around...
float alphaChannel = texColor.a + filterColor.a;
float4 color = 1.2f * (texColor + filterColor.a * filterColor + float4(processedSpecular, 0.0f));
return float4(color.r, color.g, color.b, filterColor.a + texColor.a);
... you're not using alphaChannel; you're adding filterColor.a + texColor.a in the return again.. so just make your return be...
color.rgb = 1.2f * (texColor.rgb + filterColor.a * filterColor.rgb + processedSpecular);
color.a = texColor.a + filterColor.a;
... that way you declare 1 float4 return value, and do the math for .rgb and .a separately. B/c as you're doing it in your initial way, you're wasting calculations a) generating a float alphaChannel var that never gets used, b) calculating color.rgba when you just replace color.a in the return anyways (by re-calculating alphaChannel), c) you're casting another float4 in your return, and inefficiently comma-delim'ing your color.r, color.g, color.b values when you can just color.rgb them together.
The idea is to reduce the number of variables casts you make... so while you can "float4 ( somevalue.r, somevalue.g, somevalue.b, somevalue.a )"... if you're already creating a return value, then just use it as the return value instead of recasting it.
Sometimes your return value you're dealing with may just be a float3, eg: if you're only pulling the rgb of a texture, working with it, and the alpha .a will always be 1. Even then.. just cast a float4 from the start, do all your work with the .rgb float3 parts of it, and then set the .a part of it to 1 and return it...
color.a = 1;
color.rgb = tex2d (sample, uv).rgb;
color.rgb = (complex code that alters it)
... ... ...
You create a single float4, and then just work with it's .rgb through the shader, but return the float4 whole at the end.
You can do this in other places, too... often people will pack HLSL vars full.. eg: they'll take 2 float4's and use the .rgb parts for colors and then pack a float2 in the .a alphas of them...
float4 sunU; // .rgb = sun vec * light matrix // .a = UV.x
float4 skyV; // .rgb = sky vec * light matrix // .a = UV.y
void vertex_shader ( in blah i, out someObject o)
o.sunU.rgb = suncolor.rgb;
o.sunU.a = uv.x;
o.skyV.rgb = skycolor.rgb;
o.skyV.a = uv.y;
I prefer casting a variable once, and then loading it like I did above. But, I see folks double-casting vars all the time, like so...
o.sunU = float4 ( suncolor.rgb, uv.x );
o.skyV = float4 ( skycolor.rgb, uv.y );
.. I mean... it does the same thing: loads the float4's with their values. But, it casts a second float4 on the right-side of the equation to do so. We're casting 4 float4's there.. the sunU and skyV, and then the right-side equations to piece together what we're packing in them. The way I wrote it eariler, you only cast 2 float4's in the struct, then use swizzling to tell them what goes in what parts without having to cast more vars to do so en-masse.
It seems like such a minor thing, and overall it probably is, but when you have something like that in a pixel shader firing off for every pixel... it's just unnecessary overhead ... X many pixels times Y number of frames per second... it adds up.