diff options
| author | Tim Foley <tfoleyNV@users.noreply.github.com> | 2019-02-28 07:59:17 -0800 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2019-02-28 07:59:17 -0800 |
| commit | 852c88cc9d7e720af66275bf7fdf58341f5f6e7c (patch) | |
| tree | 2ffc048a68060bde53ccf5f9fcd5363869f65acf /docs/layout.md | |
| parent | 15bab62e69286a835b68e3c3aab6ba6c946f3715 (diff) | |
Eliminate the specializeProgramLayout() function (#869)
The `specializeProgramLayout()` primarily existed to support global generic parameters.
The guiding idea of the design had been that plugging in concrete types for global generic parameters should only affect the layout/binding of shader parameters that depend on the global generic type parameters.
All other shader parameters should keep the same layout/location across all specializations.
This idea was implemented by conceptually having two phases of layout:
* A generic-argument-independent phase would do layout on all the shader parameters that *don't* depend on global generic type parameters.
* A second phase would then pick up where the other one left off (re-using existing parameter layouts to guarantee a match), and just layout out the shader parameters that *do* depend on global generic type parameters. Because the other parameters were already laid out, these new parameters would only ever fill in the gaps in layout (or come after all the other parameters, if explicit bindings aren't used).
This implementation strategy proved to be a bit of a mess, since we had to duplicate most of the code between the two passes anyway.
This commit eliminates `specializeProgramLayout()` entirely, and instead threads through global generic type arguments as part of the main layout pass. It is almost strictly a cleanup pass, now that the refactored logic for `Program` means the same layout algorithm can apply to specialized and unspecialized programs.
This change has one important semantic consequence (which is technically a break in backwards compatiblity for anybody using global generic parameters). Parameters that depend on global generic type parameters now get laid out in declaration order, just like all other shader parameters. This simplifies the rules, and in my experience actually makes application code *easier* to write in a systematic way (whereas the original design was motivated by the idea that giving more things stable locations would be beneficial).
A future improvement could be made so that we don't thread through the global generic substitution as part of layout. Instead, we could just attach a list of the global generic type arguments directly to the `TypeLayoutContext` and look those up on-demand when we encounter a global generic parameter type during layout. This would actually eliminate the need for global generics to appear as a `Substitution` entirely.
Diffstat (limited to 'docs/layout.md')
| -rw-r--r-- | docs/layout.md | 26 |
1 files changed, 13 insertions, 13 deletions
diff --git a/docs/layout.md b/docs/layout.md index aecb22d70..12144c155 100644 --- a/docs/layout.md +++ b/docs/layout.md @@ -210,19 +210,19 @@ Generics Generic type parameters complicate these layout rules. For example, we cannot compute the exact resource requirements for a `vector<T,3>` without knowing what the type `T` is. -When generic parameters are used in a program, the layout rules are ammended as follows: +When computing layouts for fully specialized types or programs, no special considerations are needed: the rules as described in this document still apply. +One important consequence to understand is that given a type like: -* Identify those parameters with types that *depend on* a generic parameter - * A generic type parameter depends on itself - * An instantiation of a generic type `F<A>` depends on a generic parameter if `A` does - * An aggregate (`struct`) type depends on a generic type if the type of any of its fields does - -* Split the global parameter order into two lists: one for parameters that do not depend on generic parameters, and one for parameters that do - -* When enumerating shader parameters, always enumerate the non-generic-dependent parameter first +```hlsl +struct MyStuff<T> +{ + int a; + T b; + int c; +} +``` -This choie ensures that plugging in different types for the generic type parameters of an entry point will not change the layout that was computed for any "ordinary" parameters that did not depend on the generics. +the offset computed for the `c` field depends on the concrete type that gets plugged in for `T`. +We think this is the least surprising behavior for programmers who might be familiar with things like C++ template specialization. -Note that we do *not* currently apply this same logic to `struct` types (e.g., lay out all the non-generic-dependent fields before the generic-dependent ones). -At present, we think it is valuable for a specialization of a generic type to lay out like an "equivalent" non-generic type, but we may consider changing that decision. -To avoid problems, users are encourage to declare types so that all non-generic-dependent fields come before generic-dependent ones. +In cases where confusion about a field like `c` getting different offsets in different specializations is a concern, users are encouraged to declare types so that all non-generic-dependent fields come before generic-dependent ones. |
