20

In HLSL I must use semantics to pass info from a vertex shader to a fragment shader. In GLSL no semantics are needed. What is an objective benefit of semantics?

Example: GLSL

vertex shader

varying vec4 foo
varying vec4 bar;

void main() {
  ...
  foo = ...
  bar = ...
}

fragment shader

varying vec4 foo
varying vec4 bar;

void main() {
  gl_FragColor = foo * bar;
}

Example: HLSL

vertex shader

struct VS_OUTPUT
{
   float4  foo : TEXCOORD3;
   float4  bar : COLOR2;
}

VS_OUTPUT whatever()
{
  VS_OUTPUT out;

  out.foo = ...
  out.bar = ...

  return out;
}

pixel shader

void main(float4 foo : TEXCOORD3,
          float4 bar : COLOR2) : COLOR
{
    return foo * bar;
}

I see how foo and bar in the VS_OUTPUT get connected to foo and bar in main in the fragment shader. What I don't get is why I have the manually choose semantics to carry the data. Why, like GLSL, can't DirectX just figure out where to put the data and connect it when linking the shaders?

Is there some more concrete advantage to manually specifying semantics or is it just left over from assembly language shader days? Is there some speed advantage to choosing say TEXCOORD4 over COLOR2 or BINORMAL1?

I get that semantics can imply meaning, there's no meaning to foo or bar but they can also obscure meaning just was well if foo is not a TEXCOORD and bar is not a COLOR. We don't put semantics on C# or C++ or JavaScript variables so why are they needed for HLSL?

Andon M. Coleman
  • 42,359
  • 2
  • 81
  • 106
gman
  • 100,619
  • 31
  • 269
  • 393

3 Answers3

20

Simply, (old) glsl used this varying for variables naming (please note that varying is now deprecated).

An obvious benefit of semantic, you don't need the same variable names between stages, so the DirectX pipeline does matching via semantics instead of variable name, and rearranges data as long as you have a compatible layout.

If you rename foo by foo2, you need to replace this names in potentially all your shader (and eventually subsequent ones). With semantics you don't need this.

Also since you don't need an exact match, it allows easier separation between shader stages.

For example:

you can have a vertex shader like this:

struct vsInput
{
float4 PosO : POSITION;
float3 Norm: NORMAL;
float4 TexCd : TEXCOORD0;
};

struct vsOut
{
float4 PosWVP : SV_POSITION;
float4 TexCd : TEXCOORD0;
float3 NormView : NORMAL;
};

vsOut VS(vsInput input)
{ 
     //Do you processing here
}

And a pixel shader like this:

struct psInput
{
    float4 PosWVP: SV_POSITION;
    float4 TexCd: TEXCOORD0;
};

Since vertex shader output provides all the inputs that pixel shader needs, this is perfectly valid. Normals will be ignored and not provided to your pixel shader.

But then you can swap to a new pixel shader that might need normals, without the need to have another Vertex Shader implementation. You can also swap the PixelShader only, hence saving some API calls (Separate Shader Objects extension is the OpenGL equivalent).

So in some ways semantics provide you a way to encapsulate In/Out between your stages, and since you reference other languages, that would be an equivalent of using properties/setters/pointer addresses...

Speed wise there's no difference depending on naming (you can name semantics pretty much any way you want, except for system ones of course). Different layout position will do imply a hit tho (pipeline will reorganize for you but will also issue a warning, at least in DirectX).

OpenGL also provides Layout Qualifier which is roughly equivalent (it's technically a bit different, but follows more or less the same concept).

Hope that helps.

mrvux
  • 8,523
  • 1
  • 27
  • 61
  • 1
    this acutally makes no sense. If you use TEXCOORD2 in some shaders and TEXCOORD0 in other they won't match either so you're still forced to match by name whether it's your own variable name or choosing a semantic name. – gman Sep 25 '18 at 08:06
  • @gman Agree, but I'm guessing shader programs so often use the constructs labeled by standard semantics (e.g. NORMAL) in exactly the same way that this is fine. Maybe what graphics programmers really wanted were standardized variable names that all programs are required to use the same way? That would be a difficult thing to roll out, given how many shader programs already exist, so perhaps semantics was the next-best thing that could practically be provided? – Manningham Aug 22 '21 at 02:52
  • Interestingly those semantics are gone in all modern GPU apis (vulkan, metal, ...) and it's just matching by location so there are no more standardized names. – gman Dec 20 '21 at 20:19
  • @gman It was never about modern apis or not, it's just a d3d thing and is still there in d3d12/shader model 6+ compiler features. Internally it maps semantic to location but you need semantic in d3d land modern or not. – mrvux Dec 23 '21 at 20:32
4

As Catflier has mentioned above, using semantics can help decoupling the shaders.

However, there are some downsides of semantics which I can think of:

  1. The number of semantics are limited by the DirectX version you are using, so it might run out.

  2. The semantics name are a little misleading. You will see these kind of variables a lot (look at posWorld variable):

    struct v2f { float4 position : POSITION; float4 posWorld : TEXCOORD0; }

You will see that the posWorld variable and the TEXCOORD0 semantic are not relevant at all. But it is fine because we do not need to pass texture coordinate to TEXCOORD0. However, this is likely to cause some confusions between those who just pick up shader language.

0

I much prefer writing : NAME after a variable than writing layout(location = N) in before. Also you don't need to update the HLSL shader if you change the order of the vertex inputs unlike in Vulkan.

  • 2
    GLSL does not require `layout(location = N)`. That is only there for people who want to hard code things. Without it the driver will chose the locations and you look them up at runtime. Further, any modern engine will be generating the shaders so choosing locations will be left up to the engine and it's trivial for it to do so with names or numbers but arguably computers are better at numbers than names so the names buy you nothing except more overhead. – gman Sep 20 '20 at 12:20