Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

OpEntryPoint should list _all_ variable IDs referenced by the corresponding function. #35

Open
warp-10 opened this issue Jun 8, 2017 · 6 comments

Comments

@warp-10
Copy link

warp-10 commented Jun 8, 2017

The specification requires listing only inputs and outputs for OpEntryPoint. It should require listing all global variable IDs (including uniforms) that are referenced within the function's static call graph.

In order to verify that two SPIR-V modules can be linked, and report meaningful errors, an application cannot rely on the ID list provided by OpEntryPoint.

Listing only inputs and outputs is not sufficient to determine if linkage between stages from different modules (that share one or more uniforms by name or location) is valid. The locations, bindings, and types of shared uniforms must match between stages.

Unless the application assumes that all entry points in a module reference all uniforms declared therein, static analysis is still necessary to perform this very basic kind of validation.

Determining whether a referenced variable ID is an input or an output is easy, determining if a function actually uses a variable is time-consuming.

I am unable to find rationale for this limitation. If it is documented somewhere, I would appreciate a link.

@warp-10 warp-10 closed this as completed Jun 9, 2017
@warp-10 warp-10 reopened this Jun 9, 2017
@warp-10
Copy link
Author

warp-10 commented Jun 9, 2017

Originally closed because I thought I made a mistake.

If this is ever addressed, great!

Otherwise, it looks like assumptions pursuant to this limitation might already have been baked into every driver in existence.

Still, a discussion about the rationale - why uniforms aren't considered "input" - would be appreciated.

@dneto0
Copy link
Contributor

dneto0 commented Jun 28, 2017

I recall this was a deliberate choice but I can't remember why. I've asked the working group to review this.

@johnkslang
Copy link
Member

The interfaces are classified as:

  • "input/output" for what is passed approximately "per invocation" between shaders, and by extension the analogous input into the first shader stage in the pipeline and the output of the last shader stage
  • "uniform" for reading/writing buffers set up through binding points in the API

It is understandable to view something in the uniform interface as an "input" (and sometimes also an "output"), but, the above terms are used to be clear which interface is being discussed.

Using this terminology...

  • the input/output interface must match from the output of one stage to the input of the next stage
    • (this is not true of the uniform interface)
  • to achieve this matching, the input/output interface has to be based on something like the OpEntryPoint list, and not based what's actually used, so that the shader writer can achieve the match without requiring artificial static access of something just to get it in the interface
    • (this is not true of the uniform interface, where it is somewhat pointless/harmless to discuss whether a buffer that is not accessed is still part of an interface)
  • the uniform interface can be captured from per-stage reflectors, or later static analysis, or simply driven by what is bound from the API side
    • (this is not true of the input/output interface)

So, there are real differences between these interfaces. Having said that, Khronos is considering requiring future generators of SPIR-V to somehow also include the uniform interface more explicitly, if reflection tools etc. are not sufficient.

Do you have a situation where a consumer of SPIR-V has to deduce an approximation to a uniform interface? Knowing use cases might help.

@warp-10
Copy link
Author

warp-10 commented Jul 5, 2017

In the case of simple stage-to-stage interface matching, my concerns can be boiled down to special-case handling of subpassInput that crops up absolutely everywhere. The fact that it is a uniform is a problem, since this introduces coupling between creating renderpasses and handling of individual stages within a subpass. Although it appears only in the fragment stage, it is a uniform that is essentially owned by the system responsible for advancing to the next subpass. Moreover, we have to know about subpassInput when building subpass dependency graphs (the renderer I'm building deduces renderpass structure from an ordered list of shader linkage descriptions).

It would make the language (GLSL) easier to use if there was no such distinction between "in" streams within a fragment shader (they're all ultimately vec4 from the programmer's perspective), though I'm not certain of other implications of this at the moment.

Note: This is all off the top of my head. I may come back to update this comment if it hasn't gone stale with too many references pointing into it.

EDIT:

It would not be a loss of generality to extend OpEntryPoint to list absolutely every externally-visible symbol it touches. A robust implementation must completely parse all shader bytecode anyway; detecting an "in" versus a "uniform" is a negligible amount of work by comparison.

@johnkslang
Copy link
Member

This functionality was added in version 1.4 of SPIR-V.

@AlexeySotkin
Copy link

It looks like listing global variables as interface of an OpEntryPoint is required for shaders only, isn't it? If yes, does it make sense to allow empty list of interface ids for OpEntryPoint if the Execution Model operand is Kernel?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants