Jump to content

  • Log In with Google      Sign In   
  • Create Account


Dynamic branching in shader not working. Keeps jumping out.


Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.

  • You cannot reply to this topic
10 replies to this topic

#1 lipsryme   Members   -  Reputation: 883

Like
0Likes
Like

Posted 01 July 2012 - 11:51 AM

I'm trying to implement a branching inside my uber shader to achieve different material types using deferred shading but keep getting problems with the branching.

Now this is where it seems to cause the problem:

float4 PS_Directional(VSO input) : SV_TARGET
{
	float4 output = float4(0.0f, 0.0f, 0.0f, 1.0f);

	// Get Material ID
	float materialID = tex2D(AlbedoBuffer, input.UV).a;

	// Get Normals
	half4 encodedNormal = tex2D(NormalBuffer, input.UV);
	half3 Normal = mul(normalize(decode(encodedNormal)), inverseView);


	if(materialID == 0.02f)
	{
          output = 1.0f;
	}


	return output;
}


As you can see I'm doing an if on the materialID to set a pixel color specifically for each objects material.
Now when I run this I just get a black screen, as it's (output) initialized at the beginning.
Running this in PIX I can see him going inside the if statement, setting output to the correct color and then going back to the if statement and returning 0.0f again.
What is going on here ? Why does it set the correct color and jump back afterwards to undo it ??

Edited by lipsryme, 01 July 2012 - 11:56 AM.


Sponsor:

#2 Radikalizm   Crossbones+   -  Reputation: 2683

Like
1Likes
Like

Posted 01 July 2012 - 12:14 PM

First of all try to avoid doing dynamic branching like this, and look into less naive approaches for rendering multiple materials in a deferred setup. This thread has some good ideas for such approaches: http://www.gamedev.n...erred-renderer/
Have a look at hodgman's post about using a material mask to reduce branching to an absolute minimum (I've built a variant of this technique which does deferred rendering with 3 different BRDFs myself)

Second, I believe your issue here has to do with floating point error. Due to the way floating point values are stored in memory you can never assume a statement like 'materialId == 0.02f' to return true, because the actual value of your floating point number would probably be something lower than 0.02f
Always use a small delta range for checking equality between floating point numbers

Edited by Radikalizm, 01 July 2012 - 12:26 PM.

Software Engineer - Skybox Labs


#3 mark ds   Members   -  Reputation: 758

Like
2Likes
Like

Posted 01 July 2012 - 12:29 PM

Radikalzm is most likely correct.

An easy way to find out would be:
float materialID = tex2D(AlbedoBuffer, input.UV).a;
double d = materialID;

Check the value of 'd'. It'll be something like 0.019999999552965164

#4 mhagain   Crossbones+   -  Reputation: 6359

Like
2Likes
Like

Posted 01 July 2012 - 12:29 PM

I'm not so sure about the advice to avoid dynamic branching at all costs here. Not so long ago I would have been, and would have given much the same advice, but times change and more info comes in.

The key thing is that the HLSL code you write does not necessarily need to bear any relationship to the code generated by the shader compiler. It's incredibly instructive to look at the generated asm code in PIX or another shader debugging tool - you may find that the HLSL code with branching has been converted into code that has no branching whatsoever. The D3D shader compiler is extremely good at doing this, and the whole experience can be quite an eye-opener (not to mention changing your attitude towards shader branching).

It appears that the gentleman thought C++ was extremely difficult and he was overjoyed that the machine was absorbing it; he understood that good C++ is difficult but the best C++ is well-nigh unintelligible.


#5 lipsryme   Members   -  Reputation: 883

Like
0Likes
Like

Posted 01 July 2012 - 12:59 PM

I see that is quite an interesting solution there @Radikalizm.
On topic: You are right I just tried dividing the materialID by 10 and multiplying it by 10 again after reading it back and it suddenly works.

#6 Radikalizm   Crossbones+   -  Reputation: 2683

Like
0Likes
Like

Posted 01 July 2012 - 01:03 PM

I'm not so sure about the advice to avoid dynamic branching at all costs here. Not so long ago I would have been, and would have given much the same advice, but times change and more info comes in.

The key thing is that the HLSL code you write does not necessarily need to bear any relationship to the code generated by the shader compiler. It's incredibly instructive to look at the generated asm code in PIX or another shader debugging tool - you may find that the HLSL code with branching has been converted into code that has no branching whatsoever. The D3D shader compiler is extremely good at doing this, and the whole experience can be quite an eye-opener (not to mention changing your attitude towards shader branching).


In this simple case with just a really small amount of branches I agree with you that it won't really have an impact (on more modern GPUs that is), however when it comes to a setup which can support a lot of materials it will become a problem. I believe pixel shaders get executed in some sort of thread groups (terminology?), and as long as all the pixels in such a group take the same path of the branch there won't be much of a problem. This does become a problem however when multiple paths are executed, since the pixel shader will run through all the options and pick the right result afterwards for all pixels in said group (please do correct me if I'm wrong here, my knowledge of the matter isn't completely solid).

IMO it's still best to avoid use of branching, some small branches here and there won't hurt, but for things like lighting calculations I believe it'd be best to find an alternative when it comes to a greater amount of branch options.

Edited by Radikalizm, 01 July 2012 - 01:06 PM.

Software Engineer - Skybox Labs


#7 lipsryme   Members   -  Reputation: 883

Like
0Likes
Like

Posted 01 July 2012 - 01:07 PM

Ugh now I'm having a new problem.

Using code like this:
if(materialID < 2.1f &amp;&amp; materialID > 1.9f)
{
  return float4(1.0f, 0.0f, 0.0f, 1.0f);
}
else if(materialID < 1.1f &amp;&amp; materialID > 0.9f)
{
  return 1.0f;
}

gives me the object in the right color (red) but with a white border...

I guess it comes back to the same problem with precision, right ?
What value range would I use to define this more clearly for the pixel shader ?
PIX tells me the pixel of the white border uses a materialID of 1.0

Edited by lipsryme, 01 July 2012 - 01:12 PM.


#8 Radikalizm   Crossbones+   -  Reputation: 2683

Like
0Likes
Like

Posted 01 July 2012 - 01:17 PM

Could you maybe provide a screenshot of the problem? Could be a problem with texture filtering when sampling your texture for a material ID, or maybe your material ID isn't being written to your g-buffer correctly

Software Engineer - Skybox Labs


#9 lipsryme   Members   -  Reputation: 883

Like
1Likes
Like

Posted 01 July 2012 - 01:23 PM

Looks like this: http://cl.ly/082u1i2O3s3X43391x0W

I think it's the overlapping materialID values that cause this.
Using a greater distance between one and another e.g. 0-1 (ID 1) and 2-3 (ID 2) seems to work.

edit: You might be right, haven't thought of the idea that the linear filtering might interpolate those materialID values quite a bit.

Update: It was indeed the texture filtering that was causing this precision issue. Using point clamp works perfectly.

Edited by lipsryme, 01 July 2012 - 02:04 PM.


#10 FGBartlett   Members   -  Reputation: 132

Like
2Likes
Like

Posted 01 July 2012 - 08:25 PM

I think conditional branching in shaders only provides a performance hit if each SIMD instance might take a unique branch. If so, you will get a SIMD 'stall'. The shared branch instances will execute in the current active working set, then the other branch set will execute, and then eventually they will 'sync' up afer all branch sets and once again grinf away efficiently as SIMD across the entire working set.

But just because you take a hit doesn't mean you can't do it. Just be aware there is a hit. Instrument and measure the hit, compare normal cases with extremes. It might not be so bad, that totally depends on the logic.

This issue becomes more front and center with openCL but it also applies to shaders.

#11 Zoner   Members   -  Reputation: 232

Like
0Likes
Like

Posted 12 July 2012 - 06:47 PM

I'm dying to really see how well modern hardware handles true branches when you can disregard old hardware, because we work extra hard to flatten our shaders and build custom permutations for all of them in order to minimuze shader ALU processing.




Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.



PARTNERS