Discussion:
[HLSL] How to vectorize a compare against zero
(too old to reply)
Thomas Schulze
2006-02-20 20:53:32 UTC
Permalink
Hello,

I'm using HLSL to do multisampled Depth Shadow Mapping. As you surely
know, depth shadows work by comparing the distance from a light with a
distance stored in a depth texture. If the light distance is greater than
the shadow distance stored in the texture, the pixel is shadowed, else
it's lighted.

To smooth the shadow borders, multiple samples are taken from the depth
texture and independently compared to the light distance. A simplified
HLSL code snippet looks like this:

float4 result;
float distance = input.mLightData.z;
float2 tex1 = input.mLightData.xy + gShadowScattering[0] *
input.mLightData.w;
float2 tex2 = input.mLightData.xy + gShadowScattering[1] *
input.mLightData.w;
float2 tex3 = input.mLightData.xy + gShadowScattering[2] *
input.mLightData.w;
float2 tex4 = input.mLightData.xy + gShadowScattering[3] *
input.mLightData.w;

float4 sdist = float4(
tex2D( TexShadow, tex1).x,
tex2D( TexShadow, tex2).x,
tex2D( TexShadow, tex3).x,
tex2D( TexShadow, tex4).x):

sdist -= float4( distance, distance, distance, distance);

if( sdist.x > 0.0f) result.x = 0.0f; else result.x = 1.0f;
if( sdist.y > 0.0f) result.y = 0.0f; else result.y = 1.0f;
if( sdist.z > 0.0f) result.z = 0.0f; else result.z = 1.0f;
if( sdist.w > 0.0f) result.w = 0.0f; else result.w = 1.0f;

float brightness = dot( result, float4( 0.25f, 0.25f, 0.25f, 0.25f));


The code works fine so far, but the asm code produced by the command line
compiler "fxc" shows separate "cmp instructions for every "if" line.
According to the DX Asm Shader Reference, "cmp" can work simultaneously on
all 4 components of the source vector. How do I get the shader compiler to
collapse all four "cmp" instructions to a single "cmp"?

I tried to write the comparision as a single line, but the shader compiler
flags the line as an error "Float expected". I guess "if" can only work on
scalars. Inline assembler might also be a solution but I didn't find any
docs how to use it and how to access variables from inside the inline asm
statement.

Any hint appreciated. Thanks in advance.

Bye, Thomas
Eyal Teler
2006-02-21 22:50:05 UTC
Permalink
Try using the ? operator:
result = sdist > 0 ? 0 : 1;
Let me know if this worked.

If that doesn't work, you could use saturate(-sign(sdist)) or
something similar to get the same result.

Eyal
Post by Thomas Schulze
Hello,
I'm using HLSL to do multisampled Depth Shadow Mapping. As you surely
know, depth shadows work by comparing the distance from a light with a
distance stored in a depth texture. If the light distance is greater
than the shadow distance stored in the texture, the pixel is shadowed,
else it's lighted.
To smooth the shadow borders, multiple samples are taken from the depth
texture and independently compared to the light distance. A simplified
float4 result;
float distance = input.mLightData.z;
float2 tex1 = input.mLightData.xy + gShadowScattering[0] *
input.mLightData.w;
float2 tex2 = input.mLightData.xy + gShadowScattering[1] *
input.mLightData.w;
float2 tex3 = input.mLightData.xy + gShadowScattering[2] *
input.mLightData.w;
float2 tex4 = input.mLightData.xy + gShadowScattering[3] *
input.mLightData.w;
float4 sdist = float4(
tex2D( TexShadow, tex1).x,
tex2D( TexShadow, tex2).x,
tex2D( TexShadow, tex3).x,
sdist -= float4( distance, distance, distance, distance);
if( sdist.x > 0.0f) result.x = 0.0f; else result.x = 1.0f;
if( sdist.y > 0.0f) result.y = 0.0f; else result.y = 1.0f;
if( sdist.z > 0.0f) result.z = 0.0f; else result.z = 1.0f;
if( sdist.w > 0.0f) result.w = 0.0f; else result.w = 1.0f;
float brightness = dot( result, float4( 0.25f, 0.25f, 0.25f, 0.25f));
The code works fine so far, but the asm code produced by the command
line compiler "fxc" shows separate "cmp instructions for every "if"
line. According to the DX Asm Shader Reference, "cmp" can work
simultaneously on all 4 components of the source vector. How do I get
the shader compiler to collapse all four "cmp" instructions to a single
"cmp"?
I tried to write the comparision as a single line, but the shader
compiler flags the line as an error "Float expected". I guess "if" can
only work on scalars. Inline assembler might also be a solution but I
didn't find any docs how to use it and how to access variables from
inside the inline asm statement.
Any hint appreciated. Thanks in advance.
Bye, Thomas
Thomas Schulze
2006-02-23 16:58:18 UTC
Permalink
Hi Eyal,

thanks for your hints. Using the '?' operator solved the issue.

While scanning the asm output of "fxc" I noticed that for some reasons the
compiler insists in moving one of the constants into a temp register
before doing the actual compare. The code generated for "result = sdist >
0 ? 0 : 1" looks like this:

mov r1.x, c1.w
cmp r0, -r0, r1.x, c3.x

I wonder why? Only a few lines later it has no problems accessing two
constant registers in a single instruction. Well... all I can do is hoping
it has reasons for what it does. A single move won't hurt performance too
much.

Bye, Thomas

Loading...