HLSL Shader Compiler Error

Started by
8 comments, last by jollyjeffers 16 years, 4 months ago
Hello, I have written a DirectX10 SM4.0 HLSL Shader, but unfortunately if I try to load the .fx file I get this strange error:
Quote: SkyDomeShader.fx(101,45) error X4014: cannot have divergent gradient operations inside loops error: There was an error compiling expression
This is the line where the error occurs:

float sampleAngle = dot(ray, samplePos) / length(samplePos);
The line is in a for loop. ray and samplePos are both float3 vectors:

float3 ray = vertexPosWorld - camPosWorld;
float3 samplePos = camPosInDome + sampleRay * 0.5f;
I have absolutely no idea whats wrong with this code. Just because of this error I installed FX Composer 2 to try my code. And in FX Composer I can compile the code without an error! So can anyone tell me why I get this error if I try to load the fx file with D3DX10CreateEffectFromFile? Thanks!
Advertisement
You can't define a variable more than once. If you had that looped code going 25 times, you would be defining that variable 25 times.

just define it somewhere else and do all your equasions in the loop
---------------------------------------- There's a steering wheel in my pants and it's drivin me nuts
I changed the code and do all defintions before the loop. But I still get the same error. :((
Uh? Divergent gradient? As in the angle gets larger the more you calculate it?

Funky error.

Check that the camPosInDome is not at position 0,0,0 as i dont know what sampleRay is but if is also 0 then this could be a divide by zero error.

It MIGHT be the fact you have samplePos on either side of the divide.
Try:-

vector alsoSamplePos = samplePos;
float sampleAngle = dot(ray, samplePos) / length(alsoSamplePos);

I know shaders can be finiky but its a new one on me if this does fix it. Its the divergent gradient thats wierd. It implies the answer is forever growing instead of coming out as nice juicy float.

Good luck
'I is what I is. Eggegegegegeg' - The wisdom of Popeye
I tried your suggestions, but I still have this strange error. camPosInDome is (0, height, 0) and should never be a null vector.

Since I have no idea what could be the reason for this error and maybe because the real problem is in a different line Im gonna post my vertex shader here:
VS_OUTPUT VS(float3 vertexPos : POSITION) {    VS_OUTPUT output = (VS_OUTPUT)0;    float3 vertexPosWorld = mul( float4(vertexPos, 1.0f), world);  // Position des Vertex im World Space    float3 ray = vertexPosWorld - camPosWorld;    float distance = length(ray);         ray /= distance;  // Eventuell normalize(ray);        // Berechnung der Optical Depth (Integralteil) von der Kamera bis zum Vertex vPos    float camHeight = camPosWorld.y;    float3 camPosInDome = float3(0.0f, camHeight, 0.0f);    float camAngle = dot(camPosInDome, ray) / camHeight;         float2 LUTTexCoords = float2(camHeight * scale, 0.5f - camAngle * 0.5f);    float4 camOpticalDepth = opticalDepthLUT.Sample(opticalDepthLUT_sampler, LUTTexCoords);        float3 rayleighSum = float3(0.0f, 0.0f, 0.0f);    float3 mieSum      = float3(0.0f, 0.0f, 0.0f);         float sampleLength = distance / sampleCount;        float3 sampleRay = ray * sampleLength;    float3 samplePos = camPosInDome + sampleRay * 0.5f;      // All the loop variables (to avoid multiple definitions - dont know if necessary)    float sampleHeight;    float lightAngle;    float2 lightDepthTexCoords;    float4 lightDepth;        float rayleighDensity;    float rayleighDepth;		    float mieDensity;    float mieDepth;	    float sampleAngle;	    float2 sampleDepthTexCoords;    float4 sampleDepth;	    float3 attenuation;    float len;    float3 alsoSamplePos;        for(int i=0; i < sampleCount; i++) {		sampleHeight = samplePos.y;			lightAngle = dot(lightDir, samplePos) / length(samplePos);				lightDepthTexCoords = float2(sampleHeight * scale, 0.5f - lightAngle * 0.5f); 		lightDepth = opticalDepthLUT.Sample(opticalDepthLUT_sampler, lightDepthTexCoords);				rayleighDensity = sampleLength * lightDepth[0];		rayleighDepth = lightDepth[1];				mieDensity = sampleLength * lightDepth[2];		mieDepth = sampleLength * lightDepth[3];		! strange error ! ->: sampleAngle = dot(ray, samplePos) / length(samplePos);					sampleDepthTexCoords = float2(sampleHeight * scale, 0.5f - sampleAngle * 0.5f);		sampleDepth = opticalDepthLUT.Sample(opticalDepthLUT_sampler, sampleDepthTexCoords);				rayleighDepth += camOpticalDepth[1] - sampleDepth[1];		mieDepth += camOpticalDepth[3] - sampleDepth[3];						rayleighDepth *= Kr4PI;		mieDepth *= Km4PI;						attenuation[0] = exp( -rayleighDepth / wavelength4[0] - mieDepth);		attenuation[1] = exp( -rayleighDepth / wavelength4[1] - mieDepth);		attenuation[2] = exp( -rayleighDepth / wavelength4[2] - mieDepth);				rayleighSum[0] += rayleighDensity * attenuation[0];		rayleighSum[1] += rayleighDensity * attenuation[1];		rayleighSum[2] += rayleighDensity * attenuation[2];				mieSum[0] += mieDensity * attenuation[0];		mieSum[1] += mieDensity * attenuation[1];		mieSum[2] += mieDensity * attenuation[2];				samplePos += sampleRay;    }            float angle = dot(-ray, lightDir);    float2 phase;        float angle2 = angle * angle;    float g2 = g*g;    phase[0] = 0.75f * (1.0f + angle2);  // Rayleigh Phase    phase[1] = 1.5f * ((1 - g2) / (2 + g2)) * (1.0f + angle2) /  // Mie Phase		        pow(1 + g2 - 2 *g * angle2, 1.5f);    phase[0] *= 0.0025f * 15.0f;    phase[1] *= 0.0025f * 15.0f;        float4 color = float4(0.0f, 0.0f, 0.0f, 1.0f);    color[0] = rayleighSum[0] * phase[0] / wavelength4[0] + mieSum[0] * phase[1];	color[1] = rayleighSum[1] * phase[0] / wavelength4[1] + mieSum[1] * phase[1];	color[2] = rayleighSum[2] * phase[0] / wavelength4[2] + mieSum[2] * phase[1];	   color[0] = min(color[0], 1.0f);   color[1] = min(color[1], 1.0f);   color[2] = min(color[2], 1.0f);        float3 vPos2 = mul( float4(vertexPosWorld, 1.0f), view);    float4 vPos3 = mul( float4(vPos2, 1.0f), proj);    output.pos = vPos3;    output.color = color;           return output;}


Im thankful for every idea!
On the line

float camAngle = dot(camPosInDome, ray) / camHeight;

change to

float camAngle;
for (inti =0;i <1; i++)
{
camAngle = dot(camPosInDome, ray) / camHeight;
}

I know it is the stupidest for loop ever but does it throw the same error? If not then the error is one of the variables not being as expected. If it does then its probably something to do with the method so try:-

float camAngle;
for (inti =0;i <1; i++)
{
float camAngleA = dot(camPosInDome, ray);
camAngle = camAngleA / camHeight;
}

Does this give your funky error? if not then change the original problem line to be like it.

Secondly after dividing ray by ray's length you have written:-
//Eventuell normalie(ray)
but you never do normalize it - (or is the divide by length the normalize funtion?).

I think it must be the ray variable. This is because you have the line
lightAngle = dot(lightDir, samplePos) / length(samplePos);
earlier in your loop and is not showing the error. Ray is the only difference with the right hand side. This also leads me to think what i wrote before about testing the for loop with a dot()/float to see it that was the problem was a waste of time.

CHECK ray - use debuger to see if values are what you would expect. Its a 3 component vector not 4 so you dont have to set .w part to 0 to ensure its a normal and not a position.

Honestly I am at a loss. I have googled the error code but didnt see anything useful come up.

I did not go through all the shader code as its long and i am lazy but good luck anyway!

Regards
'I is what I is. Eggegegegegeg' - The wisdom of Popeye
Thanks for your help galapogos22!

Unfortunately I cant debug my shader, because I cant compile it ;-)

I played a little bit with the shader code and suddenly the strange error transformed into a new error (still dont know if I should be happy with that;)

Now I get this error message:
Quote:error X4532: cannot map expression to vs_4_0 instruction set

and this error refers to line 2 in the following snippet:
1: float2 LUTTexCoords = float2(camHeight * scale, 0.5f - camAngle * 0.5f);2: float4 camOpticalDepth = opticalDepthLUT.Sample(opticalDepthLUT_sampler, float2(1.0f, 0.0f));

This code is BEFORE the loop. The texture and sampler are defined like this:
Texture2D opticalDepthLUT;SamplerState opticalDepthLUT_sampler {    Filter = MIN_MAG_MIP_POINT;    AddressU = Clamp;    AddressV = Clamp;};

opticalDepthLUT is a 2D Texture of type DXGI_FORMAT_R32G32B32A32_FLOAT, which I fill manually in my application code.
Maybe the old "divergent gradient operation" error has something to do with filtering (in my old code I had Filter = ANISOTROPIC;).
Anyway, does someone have an idea what causes this X4532 error?

Thanks
I have never used samplers and as i use D3D9 it would slightly different anyway.

float4 camOpticalDepth = opticalDepthLUT.Sample(opticalDepthLUT_sampler, float2(1.0f, 0.0f));

You are sampling a texture (using the sampler the showed) and storing this sample in a float4?

As i said i have not done this so i may be very wrong but why a float4? Is it not a float2 kind of thing?

Anyway its all gone over my head so i cant help anymore (not that i did help much) so good luck!

Regards

galapogos
'I is what I is. Eggegegegegeg' - The wisdom of Popeye
I'm not familiar with DX10, but I have seen a very similar error under DX9 to that first one caused by using a tex2D inside a loop. The easiest fix is to make it a tex2Dlod to bypass the gradient calculations.
Quote:Original post by Adam_42
I'm not familiar with DX10, but I have seen a very similar error under DX9 to that first one caused by using a tex2D inside a loop. The easiest fix is to make it a tex2Dlod to bypass the gradient calculations.
This is almost certainly the root cause.

A straight up texture sample uses gradients for sampling mip-maps correctly. These gradients depend on neighbouring pixels - typically a 2x2 grid.

Any sort of loop or branch introduces non-deterministic behaviour and neighbouring pixels may be calculating results in different ways. How do you determine the gradients here? Easy, you wait for all the neighbouring pixels to rasterize and then check, but wait... what if they depend on us and we depend on them - DEADLOCK! ouch. Simplest way, DONT allow this sort of operation at all.

Quote:lightAngle = dot(lightDir, samplePos) / length(samplePos);
lightDepthTexCoords = float2(sampleHeight * scale, 0.5f - lightAngle * 0.5f);
lightDepth = opticalDepthLUT.Sample(opticalDepthLUT_sampler, lightDepthTexCoords);
Sample coordinates depend on the light angle and the light angle depends on ... ... ... follow it all the way back and, by my reckoning, depends on float3 ray = vertexPosWorld - camPosWorld; which will differ slightly for all neighbouring pixels.

The resolution is to use ddx() and ddy() along with SampleGrad.

hth
Jack

<hr align="left" width="25%" />
Jack Hoxley <small>[</small><small> Forum FAQ | Revised FAQ | MVP Profile | Developer Journal ]</small>

This topic is closed to new replies.

Advertisement