Reputation: 182
I'm trying to write a pixel shader - I'd like to use Texture.SampleCmpLevelZero as this is usable in loop constructs where Texture.Sample is not.
I've constructed a texture and can sample it fine with Texture.Sample, but switching to SampleCmpLevelZero works for the first few frames, then goes blank, then rarely but intermittently renders correctly.
My scene is static (and the texture data too) - I'm rendering one quad and there is no camera movement of any kind - I can reproduce this reliably by just changing the single line in the PS shader function.
Has anyone seen this?
Thanks
SamplerState sampPointClamp
{
Filter = MIN_MAG_MIP_POINT;
AddressU = Clamp;
AddressV = Clamp;
};
SamplerComparisonState ShadowSampler
{
// sampler state
Filter = MIN_MAG_MIP_POINT;
AddressU = Clamp;
AddressV = Clamp;
// sampler comparison state
ComparisonFunc = LESS;
//ComparisonFilter = COMPARISON_MIN_MAG_MIP_POINT;
};
texture2D tex;
//on the fly full screen quad
PS_IN VS(uint id : SV_VertexID)
{
PS_IN ret;
ret.uv = float2( id & 1, (id & 2) >> 1 );
ret.pos = float4( ret.uv * float2( 2.0f, -2.0f ) + float2( -1.0f, 1.0f), 0.0f, 1.0f );
return ret;
}
float4 PS( PS_IN input ) : SV_Target
{
//return float4(tex.SampleCmpLevelZero(ShadowSampler, input.uv, 0), 0, 0, 1); // Does not work properly
return float4(tex.Sample(sampPointClamp, input.uv).x, 0, 0, 1); // Works fine
}
Upvotes: 0
Views: 5889
Reputation: 4129
Sample should work in loops just fine:
float4 PSColUV(COLUV_PIXEL input) : SV_Target
{
float4 output;
for (int i = 0; i < 4; i++)
{
float f = float(i) / 256.0;
float2 uv = input.UV + float2(i,i);
output += g_txDiffuse.Sample(g_samLinear, uv);
}
return input.Col * output/4.0;
}
produces:
ps_4_0
dcl_sampler s0, mode_default
dcl_resource_texture2d (float,float,float,float) t0
dcl_input_ps linear v1.xyzw
dcl_input_ps linear v2.xy
dcl_output o0.xyzw
dcl_temps 3
0: mov r0.xyzw, l(0,0,0,0)
1: mov r1.x, l(0)
2: loop
3: ige r1.y, r1.x, l(4)
4: breakc_nz r1.y
5: itof r1.y, r1.x
6: add r1.yz, r1.yyyy, v2.xxyx
7: sample r2.xyzw, r1.yzyy, t0.xyzw, s0
8: add r0.xyzw, r0.xyzw, r2.xyzw
9: iadd r1.x, r1.x, l(1)
10: endloop
11: mul r0.xyzw, r0.xyzw, v1.xyzw
12: mul o0.xyzw, r0.xyzw, l(0.250000, 0.250000, 0.250000, 0.250000)
13: ret
Also, you do realise that you're doing a PCF lookup rather than a normal texture sample, and that this won't give you the data in the texture, but rather it's going to compare all the texel subsamples (e.g. 8 in bilinear) with your reference value (0), calculate 0 or 1 depending on if they're LESS or GREATEREQUAL to your reference value, the filter those boolean values into a number between 0 and 1
Reply to comment:
thanks - I think Sample can't be in a loop with a variable length or a length not known at compile time (?). The error I got was " error X4014: cannot have divergent gradient operations inside loops error: There was an error compiling expression". On your other point - I do want an exact sample - I thought that was what I'm getting - I'm just trying to do some procedural texture generation using the texture buffer as a table of values to let me compute the true texel value based on (u,v) etc.. – AnonDev
http://msdn.microsoft.com/en-gb/library/windows/desktop/bb219848%28v=vs.85%29.aspx "Interaction of Per-Pixel Flow Control With Screen Gradients"
Remember that pixels are executed in (at minimum) a 2x2 block. You can't have control flow that would cause some pixels to sample whilst others do not, nor can you have calculations inside control flow that would cause a sample operation to get different gradients.
(Well, you can, but you need to use SampleGrad for that. But! That's not what you want in this instance. )
You say "exact" sample. Do you mean that your resource only has a single mip map and you want to get each texel in the resource without filtering? (i.e. you were doing a point filter?). Given your explanation of the texture being a table of values, then I don't see why you would need the texture to be a mipchain, and only the top level contains useful info. In which case you can use SampleLevel() with a LOD of 0. This means there will be no divergence in the derivatives, as the sample op isn't using derivatives!
This is the same reason SampleCmpLevelZero works but SampleCmp will not :) If you are point sampling, then another good candidate would be Load(), as you give it exact texel positions as you can even use it on buffers. So if your texture look-up positions are based of the pixel (X,Y) for instance, then you can pass these straight into Load (after accounting for the half texel offset..).
Anyway, you really don't want to be using SampleCmp/LevelZero. It does the wrong thing that you're after! It's used for shadow maps and so on. Use SampleLevel with a LOD of 0 instead.
Upvotes: 3
Reputation: 182
The problem was:
SamplerComparisonState ShadowSampler
{
// sampler state
Filter = MIN_MAG_MIP_POINT;
AddressU = Clamp;
AddressV = Clamp;
// sampler comparison state
ComparisonFunc = LESS;
//ComparisonFilter = COMPARISON_MIN_MAG_MIP_POINT;
};
It looks like there was a time when ComparisonFilter existed as an attribute (as it turns up in the docs) e.g. build 3/5/2013 of http://msdn.microsoft.com/en-gb/library/windows/desktop/bb509644(v=vs.85).aspx but will not compile if present.
I fixed the above behaviour by changing the Filter attribute to have the value COMPARISON_MIN_MAG_MIP_POINT - at that point it all worked
Upvotes: 0