Sign in to follow this  
OuncleJulien

Is this not possible? (The shader from hell)

Recommended Posts

Using HLSL vs_1_1 is it not possible to compare the x component of a float4 vertex to any arbitrary number? Because this seems to be the case for me. And I can't find any documentation to verify this. For example, this expression will equate to false as expected. (1 > 2) // Works as it should, returns false However, if I compare any vertex data to an arbitrary number it'll *always* return true. (position.x > 1.0f) && (poisition.x < 1.0f) // returns true The above is impossible because a number will always be greater *or* less then that same number, never both at once. In my shader this will evaluate true, and I can't figure out why it would be doing this. If I set the value of position.x before I do the comepare then the statement works as it should. position.x = 5.0f; (position.x > 1.0f) && (poisition.x < 1.0f) // Works normally, returns false Applying transformations to the vertex in the shader as such: output.position = mul(mat,position); ..Work exactly as it should all the time. I just don't understand why I can't compare any of my vertex data with if statements?! I've setup the shader debugger and put watches on the variables and the data comes in as it should. This is driving me crazy and has pushed be a few notches closer to the brink of insanity as I've bashed my head on this for the last 4 days. If someone has any insight into this please let me know. Here's the shader: const uniform float4x4 mat; const uniform float index; struct Output { float4 position : POSITION; float2 uv : TEXCOORD0; }; Output main(float4 position : POSITION, float3 n : NORMAL0, float2 uv : TEXCOORD0) { Output output = (Output)0; if (position.x > 10.0f && position.x < 10.0f) { // Inside here *always* gets executed on each vertex, and it shouldn't because of the above line. Anyone know why? uv.x = cos(index*0.2f); uv.y = sin(index*0.2f); } output.position = mul(mat,position); output.uv = uv; return output; }

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
I don't have access to the fx compiler right now, but I suspect inspecting the assembly output would clarify the issue.

Share this post


Link to post
Share on other sites
Quote:
Original post by Anonymous Poster
I don't have access to the fx compiler right now, but I suspect inspecting the assembly output would clarify the issue.

That would be a good idea. The HLSL compiler for 1.1 seems to have a lot of quirks in it. Most people just write it in ASM, instead of having to deal with compiler issues (for 1.1 shaders).

Share this post


Link to post
Share on other sites
In vs_1_1, both code paths are executed, and the compiler tries to make so that the result is what you expect through some trickery. For example, take a look at this shader:

const uniform float4x4 mat;
const uniform float index;

struct Output
{
float4 position : POSITION;
float2 uv : TEXCOORD0;
};

Output main(float4 position : POSITION, float3 n : NORMAL0, float2 uv : TEXCOORD0)
{
Output output = (Output)0;
float someVal = 1.0f;

if (position.x > 10.0f && position.x <10.0f)
{
position.y = 5.0f;
}


output.position = position;
output.uv = uv;

return output;
}


Compile this with Fxc and you get:

//
// Generated by Microsoft (R) D3DX9 Shader Compiler 4.09.00.1126
//
// fxc /T vs_1_1 /Fc boo.txt test.txt
//
vs_1_1
def c0, 10, 5, 0, 0
dcl_position v0
dcl_texcoord v1
slt r0.w, c0.x, v0.x
slt r1.w, v0.x, c0.x
mul r0.w, r0.w, r1.w
add r1.w, -v0.y, c0.y
mad oPos.y, r0.w, r1.w, v0.y
mov oPos.xzw, v0
mov oT0.xy, v1

// approximately 7 instruction slots used



The key instruction here is the slt:
slt dst, src0, src1

Does this:

dest.x = (src0.x < src1.x) ? 1.0f : 0.0f;
dest.y = (src0.y < src1.y) ? 1.0f : 0.0f;
dest.z = (src0.z < src1.z) ? 1.0f : 0.0f;
dest.w = (src0.w < src1.w) ? 1.0f : 0.0f;


So what the 2 slt's up there do is simple. Each one represents one of the conditional expressions in the 'if'. So the first slt will evaluate r0.w to 1 if position.x > 10.0f, and the second will evaluate r1.w to 1 if position.x < 10.0f

The conditional composed of the 2 sub-conditionals "anded" together is true only if both are true (1), and thus the 'w's are multiplied together into r0.w

Now the problem is both paths will be executed. i.e. position.y will be set to 5.0f, no matter what you do (for vs1.1). So the compiler works around it like this. It stores (5 - y) in r1.w

Next, it does:
mad oPos.y, r0.w, r1.w, v0.y

which is:
position.y = conditional_result * (5 - y ) + y


If the conditional evaluated to true, you'd get:
position.y = 5 - y + y = 5


Else, you'd get:
position.y = y


If you try more complex examples, you'll find that the compiler does similar trickery. In general, it'll try to find a way to execute both paths, but make the result what you expect. Sometimes, it might fail.

Share this post


Link to post
Share on other sites
Quote:
Original post by circlesoft
Quote:
Original post by Anonymous Poster
I don't have access to the fx compiler right now, but I suspect inspecting the assembly output would clarify the issue.

That would be a good idea. The HLSL compiler for 1.1 seems to have a lot of quirks in it. Most people just write it in ASM, instead of having to deal with compiler issues (for 1.1 shaders).

The problems people face with the 1.1 model isn't much due to the compilter, as much as it is attributed to the limitations of the model itself. One has to understand the model well in order to be able to - sometimes - walk the compiler by hand.

Share this post


Link to post
Share on other sites
Quote:
Original post by Coder
The problems people face with the 1.1 model isn't much due to the compilter, as much as it is attributed to the limitations of the model itself. One has to understand the model well in order to be able to - sometimes - walk the compiler by hand.
It seems that most people who are experienced with 1.1 (and actually use it) know ASM anyways, so it's not that big of a deal.

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
Quote:

If you try more complex examples, you'll find that the compiler does similar trickery. In general, it'll try to find a way to execute both paths, but make the result what you expect. Sometimes, it might fail.


For targets without branching, (most of them), the compiler emits both sides of the branch and patches the output based on the conditional.

The only case where this DOESN'T sometimes work is for NAN Propogation - for instance:


if(x > 0)
{
y = y/x;
}
else
y = 0;

then the code would look something like:

rcp r0.w, v0.x
mul r1.w, r0.w, v1.x
slt r0.w, c0.x, v0.x
mul r0.w, r1.w, r0.w

However, if x == 0, y will == NAN no matter what you do - algebraic fixups don't work. Since there are no conditional movs or dynamic branches for most of vs targets, there isn't really a way to avoid this.

Share this post


Link to post
Share on other sites
Quote:
Original post by Anonymous Poster
Quote:

If you try more complex examples, you'll find that the compiler does similar trickery. In general, it'll try to find a way to execute both paths, but make the result what you expect. Sometimes, it might fail.


For targets without branching, (most of them), the compiler emits both sides of the branch and patches the output based on the conditional.

The only case where this DOESN'T sometimes work is for NAN Propogation - for instance:


if(x > 0)
{
y = y/x;
}
else
y = 0;

then the code would look something like:

rcp r0.w, v0.x
mul r1.w, r0.w, v1.x
slt r0.w, c0.x, v0.x
mul r0.w, r1.w, r0.w

However, if x == 0, y will == NAN no matter what you do - algebraic fixups don't work. Since there are no conditional movs or dynamic branches for most of vs targets, there isn't really a way to avoid this.


Didn't mean to be anonymous...

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this