Advertisement

Problem with pixel shader compilation

Started by March 08, 2018 03:21 PM
6 comments, last by _void_ 6 years, 10 months ago

Hi guys!

 

I am using tile based shading in my project.  I am adding shadows contribution to the shading pass and I am getting strange errors when compiling the pixel shader.

Below is a code snippet of the pixel shader.


float3 pointLightsContrib = float3(0.0f, 0.0f, 0.0f);
for (uint lightIndexPerTile = pointLightIndexPerTileStart; lightIndexPerTile < pointLightIndexPerTileEnd; ++lightIndexPerTile)
{
	uint lightIndex = g_PointLightIndexPerTileBuffer[lightIndexPerTile];
  
  	float3 lightWorldSpacePos = g_PointLightWorldBoundsBuffer[lightIndex].center;
  	// Plus rest of the code

	float3 lightContrib = CalcPointLightContribution(lightWorldSpacePos, lightColor, lightRange,
		worldSpaceDirToViewer, worldSpacePos, worldSpaceNormal, diffuseAlbedo, specularAlbedo, shininess);
  
  	// Plus rest of the code		
	float lightVisibility = CalcPointLightVisibility(g_VarianceShadowMapSampler, g_PointLightTiledVarianceShadowMap,
		lightViewProjMatrix, lightViewNearPlane, lightRcpViewClipRange, worldSpacePos);
		
	pointLightsContrib += lightVisibility * lightContrib;
}

And there are helper functions used from the pixel shader above.


float VSM(SamplerState shadowSampler, Texture2D<float2> varianceShadowMap, float2 shadowMapCoords, float receiverDepth)
{
	float2 moments = varianceShadowMap.Sample(shadowSampler, shadowMapCoords).xy;
	return ChebyshevUpperBound(moments, receiverDepth);
}

float CalcPointLightVisibility(SamplerState shadowSampler, Texture2D<float2> varianceShadowMap,
	float4x4 lightViewProjMatrix, float lightViewNearPlane, float lightRcpViewClipRange, float3 worldSpacePos)
{
	float4 lightClipSpacePos = mul(lightViewProjMatrix, float4(worldSpacePos, 1.0f));
	
	float3 lightPostWDivideProjSpacePos = lightClipSpacePos.xyz / lightClipSpacePos.w;
	float2 shadowMapCoords = float2(0.5f * (lightPostWDivideProjSpacePos.x + 1.0f), 0.5f * (1.0f - lightPostWDivideProjSpacePos.y));
		
	float lightSpaceDepth = lightClipSpacePos.w;
	float normalizedLightSpaceDepth = (lightSpaceDepth - lightViewNearPlane) * lightRcpViewClipRange;

	return VSM(shadowSampler, varianceShadowMap, shadowMapCoords, normalizedLightSpaceDepth);
}

When I compile the shader, I get the following warning and error.

Warning:  warning X3570: gradient instruction used in a loop with varying iteration, attempting to unroll the loop

Error: error X3511: unable to unroll loop, loop does not appear to terminate in a timely manner (210 iterations) or unrolled loop is too large, use the [unroll(n)] attribute to force an exact higher number

The warning points to the line "float2 moments = varianceShadowMap.Sample(shadowSampler, shadowMapCoords).xy;" of VSM function

and the error points to the line "for (uint lightIndexPerTile = pointLightIndexPerTileStart; lightIndexPerTile < pointLightIndexPerTileEnd; ++lightIndexPerTile)".

If I change implementation of VSM function to simply { return 1.0f } it compiles fine.

 

What is going on? 

If the compiler can't determine if pointLightindex start and end are uniform. It means that some pixels may loop more or less. And then you get to your sampling instruction with neighbor pixels threads masked.

 

To sample, the GPU use a 2x2 quad to compute derivative of your uvs, but in your case some values won't be here, it is undefined behavior. You can use SampleLevel or SampleGrad to solve that. Or just know that you will have the proper conditions and ignore the warning

Advertisement

@galop1nYou are absolutely correct. SampleLevel fixes the problem.

Thanks a bunch!

32 minutes ago, _void_ said:

@galop1nYou are absolutely correct. SampleLevel fixes the problem.

Thanks a bunch!

I don't think so, are you not using mipmaps to do VSM pre filtering ? If you do so, SampleLevel loose that.

My VSM memories are fading, but i am pretty sure they involve mips :)

@galop1n At the moment, I am not doing VSM pre-filtering yet but planning to add this.

I did not understand. Why wouldn't SampleLevel work with VSM mip-maps? 

Because SampleLevel force the mip, and computing level or full gradient ( for aniso ) is not trivial, while normally, the gpu can just the neighbors values to figure it all for free.

Right now, you just you give 0 to the call that disable mips even if they were here

Advertisement

OK. I see what you mean now

This topic is closed to new replies.

Advertisement