<feed xmlns='http://www.w3.org/2005/Atom'>
<title>slang.git/source/slang/type-layout.cpp, branch master</title>
<subtitle>Making it easier to work with shaders</subtitle>
<id>https://git.yummers.dev/slang.git/atom?h=master</id>
<link rel='self' href='https://git.yummers.dev/slang.git/atom?h=master'/>
<link rel='alternate' type='text/html' href='https://git.yummers.dev/slang.git/'/>
<updated>2019-05-31T21:20:37+00:00</updated>
<entry>
<title>Use slang- prefix on slang compiler and core source (#973)</title>
<updated>2019-05-31T21:20:37+00:00</updated>
<author>
<name>jsmall-nvidia</name>
<email>jsmall@nvidia.com</email>
</author>
<published>2019-05-31T21:20:37+00:00</published>
<link rel='alternate' type='text/html' href='https://git.yummers.dev/slang.git/commit/?id=6cbc3929a54d37bd23cb5efa8e3320ba02f78b2f'/>
<id>urn:sha1:6cbc3929a54d37bd23cb5efa8e3320ba02f78b2f</id>
<content type='text'>
* Prefixing source files in source/slang with slang-

* Prefix source in source/slang with slang- prefix.

* Rename core source files with slang- prefix.

* Update project files.

* Fix problems from automatic merge.
</content>
</entry>
<entry>
<title>WIP: Support for other source target language (#971)</title>
<updated>2019-05-31T17:17:34+00:00</updated>
<author>
<name>jsmall-nvidia</name>
<email>jsmall@nvidia.com</email>
</author>
<published>2019-05-31T17:17:34+00:00</published>
<link rel='alternate' type='text/html' href='https://git.yummers.dev/slang.git/commit/?id=b81ff3ef968d1cc4e954b31a1812b3c391d17b02'/>
<id>urn:sha1:b81ff3ef968d1cc4e954b31a1812b3c391d17b02</id>
<content type='text'>
* WIP: Setting up C/Cpp source compilation targets.

* WIP: Emitting C/CPP.

* WIP: Split out SourceSink, and use it for source output on emit.

* SourceSink -&gt; SourceStream

* * Made SourceStream use m_ prefixing of members.
* Make all methods use lower camel
* Removed methods from SourceStream interface that are not used externally (use _ prefixing)
* Improvements to documentation

* EmitContext is now effectively empty, so just use SharedEmitContext as EmitContext.

* SharedEmitContext -&gt; EmitContext

* Methods to LowerCamel in emit.cpp

* Split out EmitContext and ExtensionUsageTracker into separate files.

* Split out EmitVisitor into slang-c-like-source-emitter files.

* EmitVisitor -&gt; CLikeSourceEmitter

* Tidy up around CLikeSourceEmitter - simplify header.

* Small tidy up - removing repeated comments that are in header.

* Remove EmitContext paramter threading.

* Small tidy up.
Use prefixed macros for slang-c-like-source-emitter.h

* Small tidy up in slang-c-like-source-emitter.cpp

* First pass at splitting out UnmangleContext.

* MangledNameParser -&gt; MangledLexer.

* WIP making EmitOp (EOp) enum available outside of cpp

* Generating EmitOpInfo from macro.

* Split out emit precedence handling.
Don't use kOp_ style anymore, just use an array indexed by EmitOp.

* Disable C simple test for now.

* Keep g++/clang happy with token pasting.

* Fix win32 narrowing warning.
</content>
</entry>
<entry>
<title>Basic layout and reflection for specialized types (#970)</title>
<updated>2019-05-22T22:01:13+00:00</updated>
<author>
<name>Tim Foley</name>
<email>tfoleyNV@users.noreply.github.com</email>
</author>
<published>2019-05-22T22:01:13+00:00</published>
<link rel='alternate' type='text/html' href='https://git.yummers.dev/slang.git/commit/?id=d4924f5fc67f56b60d11381bf77d21bc01eb8763'/>
<id>urn:sha1:d4924f5fc67f56b60d11381bf77d21bc01eb8763</id>
<content type='text'>
* Basic layout and reflection for specialized types

Suppose I have an interface, and a simple implementation of it:

```hlsl
interface IModifier
{
    float modify(float value);
}

struct Doubler : IModifier
{
    float modify(float value) { return 2 * value; }
}
```

SAnd now suppose I want to define an implementation that recursively uses the same interface:

```hlsl
struct MultiModifier : IModifier
{
    IModifier first;
    IModifier second;

    float modify(float value)
    {
        value = first.modify(value);
        value = second.modify(value);
        return value;
    }
}
```

And now consider that I might have a generic entry point that uses the interface:

```hlsl
void myShader&lt;M : IModifier&gt;( uniform M modifier, ... )
{ ... }
```

I can easily specialize `myShader` for `M = Doubler`, but in order to specialze it for `M = MultiModifier` I need a way to specify what the types of `MultiModifier.first` and `.second` should be.

That is what the `spReflection_specializeType` function is used to do: take a type like `MultiModifier` and specialize it for, say, `first : Doubler` and `second : Doubler`. That function creates an `ExistentialSpecializedType` that records the base type (`MultiModifier`) and the specialization arguments (the concrete types plus the witness tables that prove they implement the required interfaces).

The change that introduced that logic neglected to include an implementation of type layout for `ExistentialSpecializedType`, and also didn't add any support for the new kind of type through the reflection API. That is what this change seeks to rectify.

When it comes to layout, a specialized type neeeds to apply layout to its base type (e.g., `MultiModifier`) with the appropriate existential type "slot" arguments bound, which luckily is stuff that type layout already supporst (to handle specialization of interface-type shader parameters).

Unlike the case for interface-type shader parameters where the "primary" and "pending" data for a type get propagated up the chain and allocated to different places, a specialized type should be allocated contiguously (e.g., `myShader&lt;M&gt;` is going to assume that the type `M` occupies a contiguous range in memory). The type layout for a specialized type thus computes a layout that is more-or-less a structure type consisting of the "primary" data followed by the "pending" data. This gets wrapped up in a new `ExistentialSpecializedTypeLayout` class.

The reflection API then needs to expose an `ExistentialSpecializedTypeLayout` as a new kind of type, and then also provide access to the relevant pieces. For the "base" type, I went ahead and re-used the `getElementType` entry point, just for simplicity (we can debate whether that or a new entry point is more appropriate/convenient). For the actual layout, all that was needed was a way to query the offset for where the "pending" data gets placed, and that is already conveniently encoded as a `VarLayout` field in the `ExistentialSpecializedTypeLayout`.

With this change, specialized types are closer to being truly usable, although there is still missing logic in IR lowering because we need to make sure that explicitly specialized types are represented differently from types that are specialized based on global shader parameters.

* fixup: review feedback
</content>
</entry>
<entry>
<title>String/List closer to conventions, and use Index type (#959)</title>
<updated>2019-04-29T21:03:46+00:00</updated>
<author>
<name>jsmall-nvidia</name>
<email>jsmall@nvidia.com</email>
</author>
<published>2019-04-29T21:03:46+00:00</published>
<link rel='alternate' type='text/html' href='https://git.yummers.dev/slang.git/commit/?id=4880789e3003441732cca4471091563f36531635'/>
<id>urn:sha1:4880789e3003441732cca4471091563f36531635</id>
<content type='text'>
* List made members m_
Tweaked types to closer match conventions.

* Use asserts for checking conditions on List.
Other small improvements.

* List&lt;T&gt;.Count() -&gt; getSize()

* List&lt;T&gt;
Add -&gt; add
First -&gt; getFirst
Last -&gt; getLast
RemoveLast -&gt; removeLast
ReleaseBuffer -&gt; detachBuffer
GetArrayView -&gt; getArrayView

* List&lt;T&gt;::
AddRange -&gt; addRange
Capacity -&gt; getCapacity
Insert -&gt; insert
InsertRange -&gt; insertRange
AddRange -&gt; addRange
RemoveRange -&gt; removeRange
RemoveAt -&gt; removeAt
Remove -&gt; remove
Reverse -&gt; reverse
FastRemove -&gt; fastRemove
FastRemoveAt -&gt; fastRemoveAt
Clear -&gt; clear

* List&lt;T&gt;
FreeBuffer -&gt; _deallocateBuffer
Free -&gt; clearAndDeallocate
SwapWith -&gt; swapWith

* List&lt;T&gt;
SetSize -&gt; setSize
Reserve -&gt; reserve
GrowToSize growToSize

* UnsafeShrinkToSize -&gt; unsafeShrinkToSize
Compress -&gt; compress
FindLast -&gt; findLastIndex
FindLast -&gt; findLastIndex
Simplify Contains

* List&lt;T&gt;
Removed m_allocator (wasn't used)
Swap -&gt; swapElements
Sort -&gt; sort
Contains -&gt; contains
ForEach -&gt; forEach
QuickSort -&gt; quickSort
InsertionSort -&gt; insertionSort
BinarySearch -&gt; binarySearch

Max -&gt; calcMax
Min -&gt; calcMin

* Initializer::Initialize -&gt; initialize
List&lt;T&gt;::
Allocate -&gt; _allocate
Init -&gt; _init
IndexOf -&gt; indexOf

* * Put #include &lt;assert.h&gt; in common.h, and remove unneeded inclusions
* Small refactor of ArrayView - remove stride as not used

* getSize -&gt; getCount
setSize -&gt; setCount
unsafeShrinkToSize-&gt;unsafeShrinkToCount
growToSize -&gt; growToCount
m_size -&gt; m_count

* Some tidy up around Allocator.

* Use Index type on List.

* Refactor of IntSet.
First tentative look at using Index.

* Made Index an Int
Did preliminary fixes.
Made String use Index.

* Partial refactor of String.

* String::Buffer -&gt; getBuffer
ToWString -&gt; toWString

* Small improvements to String.
String::
Buffer() -&gt; getBuffer()
Equals() -&gt; equals

* Try to use Index where appropriate.

* Fix warnings on windows x86 builds.
</content>
</entry>
<entry>
<title>Add the missing case for `AssocTypeDecl` in varying parameters' layout generation. (#947)</title>
<updated>2019-04-16T14:46:02+00:00</updated>
<author>
<name>Yong He</name>
<email>yonghe@outlook.com</email>
</author>
<published>2019-04-16T14:46:02+00:00</published>
<link rel='alternate' type='text/html' href='https://git.yummers.dev/slang.git/commit/?id=a81efa750f093fdbfcf28c5d9bd619fca119bcde'/>
<id>urn:sha1:a81efa750f093fdbfcf28c5d9bd619fca119bcde</id>
<content type='text'>
</content>
</entry>
<entry>
<title>Allow plugging in types with resources for interface parameters (#913)</title>
<updated>2019-03-26T19:49:02+00:00</updated>
<author>
<name>Tim Foley</name>
<email>tfoleyNV@users.noreply.github.com</email>
</author>
<published>2019-03-26T19:49:02+00:00</published>
<link rel='alternate' type='text/html' href='https://git.yummers.dev/slang.git/commit/?id=88859d413e53e4228ae3b832d8bbd2711ccce84a'/>
<id>urn:sha1:88859d413e53e4228ae3b832d8bbd2711ccce84a</id>
<content type='text'>
* Allow plugging in types with resources for interface parameters

The key feature enabled by this change is that you can take a shader declared with interface-type parameters:

```hlsl
ConstantBuffer&lt;ILight&gt; gLight;
float4 myShader(IMaterial material, ...)
{ ... }
```

and specialize its interface-type parameters to concrete type that can contain resources like textures, samplers, etc.

The hard part of doing this layout is that we need to support signatures that include a mix of interface and non-interface types. Imagine this contrived example:

```hlsl
float4 myShader(
    Texture2D diffuseMap,
    ILight        light,
    Texture2D specularMap)
{ ... }
```

We end up wanting `diffuseMap` to get `register(t0)` and `specularMap` to get `register(t1)`, so that they have the same location no matter what we plug in for `light`.
But if we plug in a concrete type for `light` that needs a texture register, we need to allocate it *somewhere*.
We handle this by having the `TypeLayout` for `light` come back with a "primary" type layout that doesn't have any texture registers, but with a "pending" type layout that includes the texture register requirements of whatever concrete type we plug in.

This split between "primary" and "pending" layout then needs to work its way up the hierarchy, so that an aggregate `struct` type with a mix of interface and non-interface fields (recursively), needs to compute an aggregate "primary type layout" and an aggregate "pending type layout," and then each field needs to be able to compute its offset in the primary/pending layout of the aggregate.

A large chunk of the work in this PR is then just implementing the split between primary and pending data, and ensuring that layouts are computed appropriately.

The next catch is that when a "parameter group" (either a parameter block or constant buffer) contains one or more values of interface type, then we can allow the parameter group to "mask" some of the resource usage of the concrete types we plug in, but others "bleed through."

For example, if we have:

```hlsl
struct MyStuff { float3 color; ILight light; }
ConstantBuffer&lt;MyStuff&gt; myStuff;

struct SpotLight { float3 position; Texture2D shadowMap; }
``

If we plug in the `SpotLight` type for `myStuff.light`, then the `float3` data for the light can be "masked" by the fact that we have a constant buffer (we can just allocate the `float3` `position` right after `color`), but the `Texture2D` needed for `shadowMap` needs to "bleed through" and become "pending" data for the `myStuff` shader parameter.

Adding support for that detail more or less required a full rewrite of the logic for allocating parameter group type layouts.

The next detail is that when we go to legalize a declaration like the `myStuff` buffer, we will end up with something like:

```hlsl
struct MyStuff_stripped { float3 color; }
struct Wrapped
{
    MyStuff_stripped primary;
    SpotLight pending;
}
ConstantBuffer&lt;Wrapped&gt; myStuff;
```

This "wrapped" version of the buffer type more accurately reflects the layout we need/want for the uniform/ordinary data, but in order to further legalize it and pull out the resource-type fields like `shadowMap` we need to have accurate layout information, and the problem is that layout information for the original buffer can't apply to this new "wrapped" buffer.

The last major piece of this change is logic that runs during existential type legalization to compute new layouts for "wrapped" buffers like these that embeds correct offset/binding/register information for any resources nested inside them. A key challenge in that code is that existential legalization needs to erase any "pending" data from the program entirely, so that offset information that used to be relatie to the "pending" part of a surrounding type now needs to be relative to the primary part.

The work here may not be 100% complete for all scenarios, but it does well enough on the new and existing tests that I want to checkpoint it. Note that a few other tests have had their output changed, but in all cases I've reviewed the diffs and determined that the change in observable behavior is consistent with what we intened Slang's behavior to be.

Note that there is still one major piece of support for interface-type parameters that is missing here, and which might force us to revisit some of the decisions in this code: we don't properly support user-defined `struct` types with interface-type fields.

* fixup: typos
</content>
</entry>
<entry>
<title>Improve support for interfaces as shader parameters (#886)</title>
<updated>2019-03-09T00:24:02+00:00</updated>
<author>
<name>Tim Foley</name>
<email>tfoleyNV@users.noreply.github.com</email>
</author>
<published>2019-03-09T00:24:02+00:00</published>
<link rel='alternate' type='text/html' href='https://git.yummers.dev/slang.git/commit/?id=4f94dd46a2d885e570814dd14a5e46f8e0814802'/>
<id>urn:sha1:4f94dd46a2d885e570814dd14a5e46f8e0814802</id>
<content type='text'>
* Improve support for interfaces as shader parameters

This change adds two main things over the existing support:

1. It is now possible to plug in concrete types that actually contain (uniform/ordinary) fields for the existential type parameters introduced by interface-type shader parameters. The `interface-shader-param2.slang` test shows that this works.

2. There is a limited amount of support for doing correct layout computation and generating output code that matches that layout, so that interface and ordinary-type fields can be interleaved to a limited extent. The `interface-shader-param3.slang` test confirms this behavior.

There are several moving pieces in the change.

* When it comes to terminology, we try to draw a more clear distinction between existial type parameters/arguments and existential/object value parametes/arguments. A simple way to look at it is that an `IFoo[3]` shader parameter introduces a single existential type parameter (so that a concrete type argument like `SomeThing` can be plugged in for the `IFoo`) but introduces three existential object/value parameters (to represent the concrete values for the array elements).

* At the IR level, we support a few new operations. A `BindExistentialsType` can take a type that is not itself an interface/existential type but which depends on interfaces/existentials (e.g., `ConstantBuffer&lt;IFoo&gt;`) and plug in the concrete types to be used for its existential type slots.

* Then a `wrapExistentials` instruction can take a type with all the existentials plugged in (possibly by `BindExistentialsType`) and wrap it into a value of the existential-using type (e.g., turn `ConstantBuffer&lt;SomeThing&gt;` into a `ConstantBuffer&lt;IFoo&gt;`).

* The IR passes for doing generic/existential specialization have been updated to be able to desugar uses of these new operations just enough so that a `ConstantBuffer&lt;IFoo&gt;` can be used.

* When we specialize an IR parameter of an interface type like `IFoo` based on a concrete type `SomeThing`, we turn the parameter into an `ExistentialBox&lt;SomeThing&gt;` to reflect the fact that we are conceptually referring to `SomeThing` indirectly (it shouldn't be factored into the layout of its surrounding type).

* Parameter binding was updated so that it passes along the bound existential type arguments in a `Program` or `EntryPoint` to type layout, so that we can take them into account. The type layout code needs to do a little work to pass the appropriate range of arguments along to sub-fields when computing layout for aggregate types.

* Type layout was updated to have a notion of "pending" items, which represent the concrete types of data that are logically being referenced by existential value slots. The basic idea is that these values aren't included in the layout of a type by default, but then they get "flushed" to come after all the non-existential-related data in a constant buffer, parameter block, etc.

* The logic for computing a parameter group (`ConstantBuffer` or `ParameterBlock`) layout was updated to always "flush" the pending items on the element type of the group, so that the resource usage of specialized existential slots would be taken into account.

* The type legalization pass has been adapted so that we can derive two different passes from it. One does resource-type legalization (which is all that the original pass did). The new pass uses the same basic machinery to legalize `ExistentialBox&lt;T&gt;` types by moving them out of their containing type(s), and then turning them into ordinary variables/parameters of type `T`.

Big things missing from this change include:

- Nothing is making sure that "pending" items at the global or entry-point level will get proper registers/bindings allocated to them. For the uniform case, all that matters in the current compiler is that we declare them in the right order in the output HLSL/GLSL, but for resources to be supported we will need to compute this layout information and start associating it with the existential/interface-type fields.

- Nothing is being done to support `BindExistentials&lt;S, ...&gt;` where `S` is a `struct` type that might have existential-type fields (or nested fields...). Eventually we need to desugar a type like this into a fresh `struct` type that has the same field keys as `S`, but with fields replaced by suitable `BindExistentials` as needed. (The hard part of this would seem to be computing which slots go to which fields). As a practial matter, this missing feature means that interface-type members of `cbuffer` declarations won't work.

The current tests carefully avoid both of these problems. They don't declare any buffer/texture fields in the concrete types, and they don't make use of `cbuffer` declarations or `ConstantBuffer`s over structure types with interface-type fields.

* fixup: add override to methods

* fixup: typos
</content>
</entry>
<entry>
<title>A small refactor to how implicit constant buffers are getting created. (#871)</title>
<updated>2019-03-01T16:20:09+00:00</updated>
<author>
<name>Tim Foley</name>
<email>tfoleyNV@users.noreply.github.com</email>
</author>
<published>2019-03-01T16:20:09+00:00</published>
<link rel='alternate' type='text/html' href='https://git.yummers.dev/slang.git/commit/?id=efca2bb38700847adb2385d311b8b801376659bb'/>
<id>urn:sha1:efca2bb38700847adb2385d311b8b801376659bb</id>
<content type='text'>
This affects layout computation for both the global and entry-point scopes, where multiple discrete shader parameters can be declared, but for layout purposes they must be treated as if they lived in the same `struct` type. If that `struct` type ends up consuming any "ordinary" data (`LayoutResourceKind::Uniform`) then an implicit constant buffer will be needed for that scope (e.g., the way fxc produces a `$Globals` constant buffer for the global scope).

The logic for computing those scope layouts had a bug in it, in that the struct type was not being updated to have the right size for uniform data at the scope. That bug hasn't bitten anybody yet because no Slang users are relying on entry-point uniforms, and global-scope uniforms aren't fully implemented (and get diagnosed as an error elsewhere in the compiler). This change fixes that bug.

This change also refactors things so that the logic for creating a constant buffer layout if and only if needed is moved into `type-layout.cpp` instead of relying on `parameter-binding.cpp` to compute whether or not it needs a block on its own. This is anticipating the rules for deciding whether or not a constant buffer is needed being slightly more thorny once interface types are in the mix.</content>
</entry>
<entry>
<title>Simplify type layout (#867)</title>
<updated>2019-02-27T22:58:02+00:00</updated>
<author>
<name>Tim Foley</name>
<email>tfoleyNV@users.noreply.github.com</email>
</author>
<published>2019-02-27T22:58:02+00:00</published>
<link rel='alternate' type='text/html' href='https://git.yummers.dev/slang.git/commit/?id=15bab62e69286a835b68e3c3aab6ba6c946f3715'/>
<id>urn:sha1:15bab62e69286a835b68e3c3aab6ba6c946f3715</id>
<content type='text'>
* Make vector/matrix type layouts include element type layouts

Previously the `MatrixTypeLayout` class was a leaf node in the layout hierarchy, and vector types just used `TypeLayout` with no further refinement.

This change adds a `VectorTypeLayout`, and makes all of vector, matrix, and array types inherit form a common base class for `SequenceTypeLayout`s.
The actual layout computation logic was updated to compute layouts for the element types of vectors, and for the row (and element) types of matrices.

Notes:

* Because of the way varying input/output parameters are being handled, their type layouts won't include this new information, and they will just use `TypeLayout`. This was true even for the matrix case before.

* I made the design choice in this change to have a matrix type always treat rows as the logical element type (since that is what is surfaced to ther user in the HLSL syntax). We could potentially make our lives easier during layout computation if we made the element type of a `MatrixTypeLayout` depend on the row-/column-major layout choice, but that would then require any algorithm that uses the new layout information to take row-vs-column-major into account.

* No code is actually *using* this new information yet, although the work in `ir-union.cpp` could probably benefit from it. The main expected use case going forward is representing constant buffers as a "bag of bits."

* Add a specialized type layout approach for varying parameters

There is a lot of complexity in `GetLayoutImpl` because it needs to service both the "normal" case, which always wants a `TypeLayout` object to be returned, and the varying parameter case, where we currently don't care about getting back a `TypeLayout` object.

Confusingly, the varying parameter layout logic actually *does* construct `TypeLayout` objects, and it just does it inside of `parameter-binding.cpp` rather than in `type-layout.cpp`. That logic cannot (easily) be shared with the `GetLayoutImpl` path because:

* The varying case needs to deal with system-value semantics and also parameters that may be inputs, outputs, or both (so that they need to combine resource usage computed for inputs and outputs).

* The varying case needs to special-case vectors (and to a lesser extent matrices) because of the quirks of uniform layout (e.g., four `float` varying inputs consume four `locations`, but a `float4` consumes only one location).

This change introduces a customized layout function just for varying parameters, that only handles the scalar, vector, and matrix cases (since `parameter-binding.cpp` will have recursed through any strucures/arrays, and should error out on any other types that are illegal in varying parameter lists).

In the long run we could consider trying to deduplicate code and share more of this logic with `GetLayoutImpl`, but that would require a more significant refactoring of type layout, which should probably wait until we are doing layout on IR types.

* Rename CreateTypeLayout to createTypeLayout

This is just a fixup to better reflect our established naming conventions.

* Simplify type layout so that it always returns a layout object

The core `GetLayoutImpl` routine included a fair bit of complexity to deal with the fact that its `outTypeLayout` parameter was optional.
The caller could pass in null to say that it doesn't want a `TypeLayout` object to be constructed, and the routine would conditionalize a lot of its logic to deal with this case.

This change simplifies the logic so that a `TypeLayout` is always constructed and returned. Instead of using a combination of a function result (for the `SimpleLayoutInfo`) and an output parameter (for the `TypeLayout`) we use a new `TypeLayoutResult` that acts as a tuple over the two.

I had hoped for a more significant cleanup by also eliminating the need to return the `SimpleLayoutInfo` separately from the `TypeLayout`, but the simple layout info is what the underlying per-API/-context "rules" implementations use (so that they can avoid all the complexity of `TypeLayout`), and refactoring to derive the simple layout infor from a computed `TypeLayout` would be a bigger refactoring than I was ready for.

* fixup: typos
</content>
</entry>
<entry>
<title>First steps toward supporting interface-type parameters on shaders (#852)</title>
<updated>2019-02-19T19:46:05+00:00</updated>
<author>
<name>Tim Foley</name>
<email>tfoleyNV@users.noreply.github.com</email>
</author>
<published>2019-02-19T19:46:05+00:00</published>
<link rel='alternate' type='text/html' href='https://git.yummers.dev/slang.git/commit/?id=32135c5bdfb4d387f8227742a2d2fd555898aca8'/>
<id>urn:sha1:32135c5bdfb4d387f8227742a2d2fd555898aca8</id>
<content type='text'>
* First steps toward supporting interface-type parameters on shaders

What's New
----------

From the perspective of a user, the main thing this change adds is the ability to declare top-level shader parameters (either at global scope, or in an entry-point parameter list) with interface types. For example, the following becomes possible:

```hlsl
// Define an interface to modify values
interface IModifier { float4 modify(float4 val); }

// Define some concrete implementations
struct Doubler : IModifier
{
    float4 modify(float4 val) { return val + val; }
}
struct Squarer : IModifier { ... }

// Define a global shader parameter of interface type
IModifier gGlobalModifier;

// Define an entry point with an interface-type `uniform` parameter
void myShader(
    unifrom IModifier entryPointModifier,
            float4    inColor  : COLOR,
        out float4    outColor : SV_Target)
{
    // Use the interface-type parameters to compute things
    float4 color = inColor;
    color = gGlobalModifier.modify(color);
    color = entryPointModifier.modify(color);
    outColor = color;
}
```

The user can specialize that shader by specifying the concrete types to use for global and entry-point parameters of interface types (e.g., plugging in `Doubler` for `gGlobalModifier` and `Squarer` for `entryPointModifier`).

The "plugging in" process is done in terms of a concept of both global and local "existential slots" which are a new `LayoutResourceKind` that represents the holes where concrete types need to be plugged in for existential/interface types.

In simple cases like the above, each interface-type parameter will yield a single existential slot in either the global or entry-point parameter layout. Users can query the start slot and number of slots for each shader parameter, just like they would for any other resource that a parameter can consume. Before generating specialized code, the user plugs in the name of the concrete type they would like to use for each slot using `spSetTypeNameForGlobalExistentialSlot` and/or `spSetTypeNameForEntryPointExistentialSlot`.

There are some major limitations to the implementation in this first change:

* Parameters must be of interface type (e.g., `IFoo`) and not an array (`IFoo[3]`), or buffer (`ConstantBuffer&lt;IFoo&gt;`) over an interface type. Similarly, `struct` types with interface-type fields still don't work.

* The work on interface-type function parameters still doesn't include support for `out` or `inout` parameters, nor for functions that return interface types (that isn't technically related to this change, but affects its usefullness).

* No work is being done to correctly lay out shader parameters once the concrete types for existential slots are known, so that this change really only works when the concrete type that gets plugged in is empty.

These limitations are severe enough that this feature isn't really usable as implemented in this change, and this merely represents a stepping stone toward a more complete implementation.

Implementation
--------------

The API side of thing largely mirrors what was already done to support passing strings for the type names to use for global/entry-point generic arguments, so there should be no major surprises there.

The logic in `check.cpp` computes the list of existential slots when creating unspecialized `Program`s and `EntryPoint`s (this is logically the "front end" of the compiler), and then checks the supplied argument types against what is expected in each slot when creating specialized `Program`s and `EntryPoint`s. This again mirrors how generic arguments are handled.

Type layout was extended to compute the number of existential slots that a type consumes, and will thus automatically assign ranges of slots to top-level and entry-point shader parameters in the same way it already allocates `register`s and `binding`s. The big missing feature is the ability to specialize a layout to account for the concrete types plugged into the existential-type slots.

IR generation for specialized programs and entry points was slightly extended so that it attaches information about the concrete types plugged into the existential slots, and the witness tables that show how they conform to the interface for that slot. The linking step needed some small tweaks to make sure that information gets copied over to the target-specific program when we start code generation.

The meat of the IR-level work is in `ir-bind-existentials.cpp`, which takes the information that was placed in the IR module by the generation/linking steps and uses it to rewrite shader parameters. For example, if there is a shader parameter `p` of type `IModifier`, and the corresponding existential slot has the type `Doubler` in it, we will rewrite the parameter to have type `Doubler`, and rewrite any uses of `p` to instead use `makeExistential(p, /*witness that Doubler conforms to IModifier*/)`.

Once the replacement is done on the parameters, the existing work for specializing existential-based code when the input type(s) are known kicks in and does the rest.

Testing
-------

A single compute test is added to validate that this feature works. It is narrowly tailored to not require any of the features not supported by the initial implementation (e.g., all of the concrete types used have no members).

The test case *does* include use of an associated type through one of these existential-type parameters, which has exposed a subtle bug in how "opening" of existential values is implemented in the front-end. Rather than fix the underlying problem, I cleaned up the code in the front-end to special case when the existential value being opened is a variable bound with `let`, to directly use a reference to that variable rather than introduce a temporary. Similarly, in the IR generation step, I added an optimization to make variables declared with `let` skip introducing an IR-level variable and just use the SSA value of their initializer directly instead.

* fixup: missing files

* fixup: incorrect type for unreachable return

* fixup: actually comment ir-bind-existentials.cpp
</content>
</entry>
</feed>
