Skip to main content
GameDev.net gamedev.net
🔒 Locked

HLSL: Samplers in pixel shaders

Started by Evil Steve Nov 19, 2010 at 4:02 AM 2 replies 20.4k views
Original Post
Evil Steve
Evil Steve
Hi,

I'm using HLSL for my pixel shader without the effects framework, and I'm new to pixel shaders (Something I really should have used by now, but never mind...).

Here's my very basic shader:
struct PS_INPUT{	float4 pos : POSITION;	float4 diffuse : COLOR0;	float2 uv : TEXCOORD0;};struct PS_OUTPUT{	float4 colour : COLOR0;};sampler textureSampler = sampler_state{	addressU = Clamp;	addressV = Clamp;	mipfilter = NONE;	minfilter = LINEAR;	magfilter = LINEAR;};PS_OUTPUT main(PS_INPUT In){	PS_OUTPUT Out;	Out.colour = tex2D(textureSampler, In.uv) * In.diffuse;	return Out;}

And fxc generates the assembly:
//   Name           Reg   Size//   -------------- ----- ----//   textureSampler s0       1    ps_2_0    dcl v0    dcl t0.xy    dcl_2d s0    texld r0, t0, s0    mul r0, r0, v0    mov oC0, r0


The tex2D instruction takes a sampler as its first parameter, where I pass textureSampler, but looking at the generated assembly, there's nowhere that the sampler is actually set up (bilinear filtering, clamp wrap mode).

Am I supposed to still use SetSamplerState() when doing everything through shaders? If so, what's the point in the sampler_state that I need to pass to tex2D? And if not, why isn't the texture addressing and filtering being applied?

Also, a different question - what's the usual way to output depth in the pixel shader? My Google-fu is weak and I couldn't find any references on what the depth output should be (And I presume that if I don't output a depth value, some default value is used)?

I feel like I'm missing something obvious here [smile]. Does anyone have any good references for HLSL without the effects framework?

Cheers,
Steve
MJP
MJP
Quote:
Original post by Evil Steve
Hi,

I'm using HLSL for my pixel shader without the effects framework, and I'm new to pixel shaders (Something I really should have used by now, but never mind...).


Are you sure you're not a Visual Basic MVP or something? :P

Quote:
Original post by Evil Steve
Here's my very basic shader:
*** Source Snippet Removed ***
And fxc generates the assembly:
//   Name           Reg   Size//   -------------- ----- ----//   textureSampler s0       1    ps_2_0    dcl v0    dcl t0.xy    dcl_2d s0    texld r0, t0, s0    mul r0, r0, v0    mov oC0, r0


The tex2D instruction takes a sampler as its first parameter, where I pass textureSampler, but looking at the generated assembly, there's nowhere that the sampler is actually set up (bilinear filtering, clamp wrap mode).


Quote:
Original post by Evil Steve
Am I supposed to still use SetSamplerState() when doing everything through shaders? If so, what's the point in the sampler_state that I need to pass to tex2D? And if not, why isn't the texture addressing and filtering being applied?



Okay so at the lowest level (no effects), shaders don't have any concept of sampler states. You set those states on the device using SetSamplerState, for a specified sampler index. Then in the pixel shader profile you're compiling to, there are sampler registers that map directly to the sampler/texture index you use for SetSamplerState/SetTexture. Looking at your assembly, you're doing a texture load on s0 which means index 0. So if wanted to bind a texture to sampler you would call SetTexture and pass 0, and for any sampler states you would call SetSamplerState and also pass 0.

When you declare some HLSL type that's mapped to a register (samplers, constants, etc.), the HLSL compiler will automatically assign that variable to a register for you. Usually it's just done in ascending order. Your C++ code can obtain reflection data for a shader via ID3DXConstantTable that includes all constants and samplers used in a shader, as well as which register they were mapped to. You could then use that data to set appropriate states on the device. As an alternative to that, you can also explicitly map a constant or a sampler to a register. The syntax is like this:
sampler2D someSampler : register(s0);float4 someConstant : register(c0);


If you're not using effects, you can remove all of that sampler_state stuff. That information is parsed by the effect framework, so that at runtime it can call SetSamplerState with the appropriate values when you use the effect. Without effects it's useless.

Quote:
Original post by Evil Steve
Also, a different question - what's the usual way to output depth in the pixel shader? My Google-fu is weak and I couldn't find any references on what the depth output should be (And I presume that if I don't output a depth value, some default value is used)?


You output depth with the "DEPTH" semantic. Basically whatever value you output gets used directly in the depth test and written to the depth buffer, which means you want post-projection z/w in the range [0.0, 1.0]. If you don't output a depth value, the interpolated z/w from the position output by your vertex shader is used.

Be careful though with depth output...it will totally break early z-cull optimizations used on GPU's to prevent occluded pixels from being shaded, which can seriously degrade performance if you're running heavy pixel shaders. But regardless the cases where you actually need depth output should be pretty rare.

[Edited by - MJP on November 19, 2010 12:52:42 PM]
Evil Steve
Evil Steve
Quote:
Original post by MJP
Okay so at the lowest level (no effects), shaders don't have any concept of sampler states. You set those states on the device using SetSamplerState, for a specified sampler index. Then in the pixel shader profile you're compiling to, there are sampler registers that map directly to the sampler/texture index you use for SetSamplerState/SetTexture. Looking at your assembly, you're doing a texture load on s0 which means index 0. So if wanted to bind a texture to sampler you would call SetTexture and pass 0, and for any sampler states you would call SetSamplerState and also pass 0.
Ah, the reference to the sampler in tex2D was throwing me off and making me wonder if the SetSamplerState stuff was fixed-function only...

Quote:
Original post by MJP
When you declare some HLSL type that's mapped to a register (samplers, constants, etc.), the HLSL compiler will automatically assign that variable to a register for you. Usually it's just done in ascending order. Your C++ code can obtain reflection data for a shader via http://msdn.microsoft.com/en-us/library/bb205762%28VS.85%29.aspx that includes all constants and samplers used in a shader, as well as which register they were mapped to. You could then use that data to set appropriate states on the device. As an alternative to that, you can also explicitly map a constant or a sampler to a register. The syntax is like this:
sampler2D someSampler : register(s0);float4 someConstant : register(c0);


If you're not using effects, you can remove all of that sampler_state stuff. That information is parsed by the effect framework, so that at runtime it can call SetSamplerState with the appropriate values when you use the effect. Without effects it's useless.
I see. So if I know what texture stages my textures are in already, I should just explicitly map a sampler to a register?

Basically, I was hoping just to be able to specify the texture stage as a parameter to tex2D() (Which explicitly assigning registers like in your example seems to do).

Quote:
Original post by MJP
You output depth with the "DEPTH" semantic. Basically whatever value you output gets used directly in the depth test and written to the depth buffer, which means you want post-projection z/w in the range [0.0, 1.0]. If you don't output a depth value, the interpolated z/w from the position output by your vertex shader is used.

Be careful though with depth output...it will totally break early z-cull optimizations used on GPU's to prevent occluded pixels from being shaded, which can seriously degrade performance if you're running heavy pixel shaders. But regardless the cases where you actually need depth output should be pretty rare.
I see - that would explain why the examples I saw tended not to output depth in the pixel shader then.

Thanks!
MJP
MJP
Quote:
Original post by Evil Steve
If you're not using effects, you can remove all of that sampler_state stuff. That information is parsed by the effect framework, so that at runtime it can call SetSamplerState with the appropriate values when you use the effect. Without effects it's useless.
I see. So if I know what texture stages my textures are in already, I should just explicitly map a sampler to a register?

Basically, I was hoping just to be able to specify the texture stage as a parameter to tex2D() (Which explicitly assigning registers like in your example seems to do).
[/quote]

Yeah, you can just map the sampler to the index you want and then just use that sampler with tex2D.

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.