HLSL structs

Started by
4 comments, last by matt77hias 5 years, 12 months ago

HLSL packs data so that it does not cross a 16-byte boundary. How does this translate to all the pre-defined types such as Texture2D, SamplerState? What is the size of these by default? Since, HLSL just inlines all code involved in a shader, I wonder if it is a good practice (with regard to performance) to pass structs around with a bunch of related parameters instead of having to pass a giant list of primitive types around (for cases with and without extra padding)? (My goals is to partition all my code into two layers: one layer that uses user-bound data and one layer that doesn't depend on these variable globals).

🧙

Advertisement

Packing only really matters when the structures are exposed to the oustide world, such as in a buffer/etc. Structures that are just passed between functions are just syntactic sugar (AFAIK) and the compiler can inline everything however it likes.

You can't put Texture2D, SamplerState, etc, into a buffer (right?), so they fall into the latter category, and the layout gets optimized away by the compiler anyway :)

2 minutes ago, Hodgman said:

You can't put Texture2D, SamplerState, etc, into a buffer (right?)

Yes, was just referring to HLSL function to HLSL function data transfer (The inside world :D )

3 minutes ago, Hodgman said:

so they fall into the latter category, and the layout gets optimized away by the compiler anyway

Nice! (I was worrying as well that somehow I would create a separate temporary for every global variable. But now I can and will go structs the whole way. :P )

🧙

FYI: our shader codebase very frequently passes around structs containing textures/samplers/etc. in order to keep things clean, and I haven't seen any compilers generate sub-optimal code for this. The only time things can get a bit funky is if you put structs into buffers or cbuffers like Hodgman mentioned, in which case you will deal with packing rules. Also, it's legal to do this in HLSL:
 


struct MyBindingStruct
{
    Texture2D Tex0;
    Texture2D Tex1;
    Texture2D Tex2;
};

MyBindingStruct MyBindings;

float4 PSMain(in float4 ScreenPos : SV_Position) : SV_Target0
{
    return MyBindings.Tex1[uint2(ScreenPos.xy)];
}


If you do this, the compiler will assign SRV slots to every texture in every struct that your shader code references, even if you only use a single texture from that struct. So far example in the shader code I posted, you'll see "MyBindings.Tex1" get assigned to register t1, which corresponds to SRV slot 1. This is different behavior from when you don't put textures in a struct, in which case Tex1 would get assigned to register t0.

5 hours ago, MJP said:

If you do this, the compiler will assign SRV slots to every texture in every struct that your shader code references, even if you only use a single texture from that struct. So far example in the shader code I posted, you'll see "MyBindings.Tex1" get assigned to register t1, which corresponds to SRV slot 1. This is different behavior from when you don't put textures in a struct, in which case Tex1 would get assigned to register t0.

Didn't know this syntactic sugar. Though, I am not really a fan, since implicitly registers will be assigned which is what I want to avoid. At my highest level, I will (and need to) add the registers myself making use of a header file that is included in both C++ and HLSL.

🧙

This topic is closed to new replies.

Advertisement