Vulkan-docs: Request for clarification on shader interfaces

Created on 22 Feb 2018  路  7Comments  路  Source: KhronosGroup/Vulkan-Docs

I'd like to raise an issue on an ambiguity in the spec wrt shader interface matching. I'm honestly not sure what the spec means to say in this area, and this seems crucial for tool, driver and shader development.

In a sentence (TL;DR):
Is it valid for vertex shader to have user-defined outputs with locations 0, 1 and 2, but for fragment shader to only have user-defined input with location 1 (assuming output/input for location 1 matches in size/component)?

On one hand, the spec says

At an interface between two shader stages, the user-defined variable interface must match exactly, as described above.

Which can be interpreted as "no" and I can imagine that this simplifies driver code if a driver wants to compile shaders separately. However I'm not sure how to interpet this sentence precisely.

On another hand, no other API has the same strict requirement (HLSL, GLSL and MSL all have rules that allow omitting some outputs from subsequent shader stages, although the rules tend to vary a bit), existing Vulkan drivers seem to handle missing outputs fine, and validation layers don't issue an error for this (they do issue a performance warning).

I would like to get a clarification on this issue in the form of either an explicit statement that allows this, or an explicit statement that prohibits this, as part of the spec. Additionally, a few other points I'm not clear on (what follows is quotes from 14. Shader Interfaces):

14.1.1. Built-in Interface Block
... be declared in a block whose top-level members are the built-ins.

What does "block" mean in this context? Basic block from SPIRV?

Built-ins only participate in interface matching if they are declared in such a block. They must not have any Location or Component decorations.

Is it even valid to have builtins in a different block? I'm assuming "no" because then you'd have two blocks with builtins?
Is it valid to have a BuiltIn that is listed in the block with other builtins but isn't referred to by the OpEntryPoint?
It it valid to have a BuiltIn outside a block with Location/Component decoration?

14.1.3. Interface Matching
At an interface between two non-fragment shader stages, the built-in interface block must match exactly, as described above.

Does this mean for any output you must have an input? How does this work for, say, vertex shader Layer output if you also have a geometry shader present? Similarly to TL;DR, this should clarify what "exactly matching" means even if it seems redundant.

At an interface involving the fragment shader inputs, the presence or absence of any built-in output does not affect the interface matching.

Does this mean the built-in input to the fragment shader stage (and built-in output to the stage that precedes it)?

At an interface between two shader stages, the user-defined variable interface must match exactly, as described above.

As stated in the TL;DR, this should clarify what "exactly matching" means, even if it seems redundant.

14.2. Vertex Input Interface
All vertex shader inputs declared as above must have a corresponding attribute and binding in the pipeline.

This seems less ambiguous, and I'm assuming this does mean that pipeline can have attribute/binding entries that aren't listed in the vertex shader inputs; it would be nice to spell this out explicitly.

Most helpful comment

Thanks. We've taken your last update above for internal discussion and hopefully will be doing corresponding spec updates soon.

All 7 comments

After reading the shader validation source code, my renewed understanding of builtin rules is as follows:

  • You can declare builtin inputs/outputs either as standalone variables, or as a Block - that is, a variable of type Struct with a Block decoration
  • You can have at most one input and one output Block with built-ins per entrypoint; in addition to that, you can have an arbitrary number of free-standing builtin variables of scalar/vector type.
  • Input and output Block must match exactly between shader stages - that is, they have to contain the same fields with the same builtin decorations - with the exception of fragment shader inputs where you can omit... something... (still not sure what).

Please let me know if this is accurate, and the original question about user-defined variables still stands. Also it would be great if the spec said Block instead of block everywhere where it means SPIRV Struct with Block decoration...

How does this work for, say, vertex shader Layer output if you also have a geometry shader present?

It doesn't; the BuiltIn Layer is not legal to be used in a VS:

Layer output by a Geometry Execution Model, input to a Fragment Execution Model, for multi-layer framebuffer. See Vulkan or OpenGL API specifications for more detail.

Vulkan doesn't have ARB_shader_viewport_layer_array.


with the exception of fragment shader inputs where you can omit... something... (still not sure what).

"Something"? The spec gives a blank-check to the built-in interface between the FS and the prior stage. That's what "the presence or absence of any built-in output does not affect the interface matching," means. An FS is not required to take the Position built-in input, nor is the previous stage required to write the FrontFacing built-in output if the FS reads that input.

The FS has its own built-in variable interface, whose values are not (necessarily) supplied by the prior stage.

the BuiltIn Layer is not legal to be used in a VS:

I believe this is incorrect, see VK_EXT_shader_viewport_index_layer.

Feel free to replace it with PointSize or any other vertex shader output, it really doesn't matter if it's Layer or not - for example, can I output PointSize from VS and not have PointSize as an input to GS?

The spec gives a blank-check to the built-in interface between the FS and the prior stage

Right, the "output" part initially confused me slightly but I now realize that it's phrased the way it is because depending on pipeline configuration, different stages can immediately precede FS. This specific part now makes more sense, thanks.

@zeux it seems like some of your initially posted questions are getting resolved in the course of the discussion. Could you perhaps post a stripped-down version of the OP with what remaining issues/questions are open?

@oddhack the main questions/requests are still open. Here's a new version (lmk if you'd prefer me updating the top post):

I'd like to raise an issue on an ambiguity in the spec wrt shader interface matching. I'm honestly not sure what the spec means to say in this area, and this seems crucial for tool, driver and shader development.

In a sentence (TL;DR):
Is it valid for vertex shader to have user-defined outputs with locations 0, 1 and 2, but for fragment shader to only have user-defined input with location 1 (assuming output/input for location 1 matches in size/component)?

On one hand, the spec says

At an interface between two shader stages, the user-defined variable interface must match exactly, as described above.

Which can be interpreted as "no" and I can imagine that this simplifies driver code if a driver wants to compile shaders separately. However I'm not sure how to interpet this sentence precisely.

On another hand, no other API has the same strict requirement (HLSL, GLSL and MSL all have rules that allow omitting some outputs from subsequent shader stages, although the rules tend to vary a bit), existing Vulkan drivers seem to handle missing outputs fine, and validation layers don't issue an error for this (they do issue a performance warning).

I would like to get a clarification on this issue in the form of either an explicit statement that allows this, or an explicit statement that prohibits this, as part of the spec. Additionally, a few other points I'm not clear on (what follows is quotes from 14. Shader Interfaces):

At an interface between two shader stages, the user-defined variable interface must match exactly, as described above.

As stated in the TL;DR, this should clarify what "exactly matching" means, even if it seems redundant.

14.2. Vertex Input Interface
All vertex shader inputs declared as above must have a corresponding attribute and binding in the pipeline.

This seems less ambiguous, and I'm assuming this does mean that pipeline can have attribute/binding entries that aren't listed in the vertex shader inputs; it would be nice to spell this out explicitly.

Thanks. We've taken your last update above for internal discussion and hopefully will be doing corresponding spec updates soon.

Was this page helpful?
0 / 5 - 0 ratings