-
Notifications
You must be signed in to change notification settings - Fork 13
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
Constant buffers (cbuffer) #94
base: main
Are you sure you want to change the base?
Conversation
5446e5b
to
18cfed2
Compare
proposals/NNNN-constant-buffers.md
Outdated
|
||
These should be lowered to `target("dx.TypedBuffer", ..)`.Detailed design TBD. | ||
|
||
### Lowering constant buffer variable access |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm trying to understand how the layout rules for SPIR-V will work. The only real problem is cbuffers. There is a problem because cbuffers have a different layout than other buffer types, and I don't know how that will be represented in llvm-ir.
Here is the example I am thinking about: https://godbolt.org/z/f45r7vEoG.
In llvm-ir, will the load from the cbuffer be a single load of an object of type S
with the cbuffer layout? Will the store to the structured buffer store an object of type S
with the structured buffer layout? If the answer is yes to both, does there need to be a conversion from one to the other in between the load and store?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have just updated the document. We would like to include the cbuffer layout on the LLVM target type so the backend does not need to know the specific cbuffer layout rules. Alternatively, it could be a type annotation, but we would like to investigate the including in on the target type first. It probably does not answer your question though.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think that the conversion from one to the other will look like an address space cast, or something like that. We'll need to make sure we aren't mixing raw memory operations between cbuffer memory and other resource memories, but as long as we have each type of thing in its own address space the boundaries themselves should be clear at least.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@hekota Thanks. That answers part of my question and was in line with what I was thinking. The layout rules are a language feature. This is consistent with what I see in C/C++. The basic types are encoded in the data layout, and then the layout for the structs are set by being explicit with the padding in the struct.
@bogner I'll wait to see what you do. I don't see how the address space cast will work because that works on pointer, but we need to cast after the load. We also want to make sure that whatever we do, it can be easily optimized. In SPIRV there is an OpCopyLogical instruction to do the cast, when it cannot be optimized away.
proposals/NNNN-constant-buffers.md
Outdated
|
||
## Introduction | ||
|
||
Shader inputs usually include a number of constants which are stored in one or more buffer resources in memory with specific packing rules. These resources can be organized into two types of buffers: constant buffers and texture buffers. This document describes design decisions related to constant buffers. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: we try and format the source md to 80 columns.
- How to encode the cbuffer layout into LLVM target type | ||
- How to implement `ConstantBuffer` member access | ||
- Handling of `$Globals` constant buffer | ||
- Nested `cbuffer` declarations |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I put together a bit of an example that illustrates how cbuffer works in various interesting cases here:
https://godbolt.org/z/E4cdx7xj8
Same shader with FXC:
https://shader-playground.timjones.io/39c0683735c0cd79b5970b5116765940
proposals/NNNN-constant-buffers.md
Outdated
ConstantBuffer<MyConstants> CB; | ||
``` | ||
|
||
In this case the buffer variables are referenced as if they were members of the `ConstantBuffer` class: `CB.F`. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
as if they were members of the
ConstantBuffer
class:CB.F
I think it is more like as if CB
was of type MyConstants
and the fields are members of that object.
proposals/NNNN-constant-buffers.md
Outdated
|
||
### Parsing `cbuffer` Declaration | ||
|
||
In Clang frontend the `cbuffer` declaration will be parsed into a new AST Node called `HLSLConstantBufferDecl`. This class will be based on from `NameDecl` and `DeclContext`. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
be based on from
NameDecl
andDeclContext
.
I think the "from" shouldn't be there.
proposals/NNNN-constant-buffers.md
Outdated
|
||
`ConstantBuffer` definition will be added to the `HLSLExternalSemaSource` the same way as other resource classes. It will have a resource handle with `CBuffer` resource class and the contained type would be the template type argument. It will be handled as other resources classes, for example it can be passed into a function. | ||
|
||
At the same time Clang needs to recognize this class represents a constant buffer and the contained type fields are accessed using the `.` operator on `ConstantBuffer` instance. In other words treating `ConstantBuffer<MyConstants> CB;` as if it was declared as `cbuffer __CB { MyConstants CB; }`. The exact way how to do this is TBD. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
At the same time Clang needs to recognize this class represents a constant buffer and the contained type fields are accessed using the `.` operator on `ConstantBuffer` instance. In other words treating `ConstantBuffer<MyConstants> CB;` as if it was declared as `cbuffer __CB { MyConstants CB; }`. The exact way how to do this is TBD. | |
At the same time, Clang needs to recognize that this class represents a constant buffer and the contained type fields are accessed using the `.` operator on `ConstantBuffer` instance. In other words treating `ConstantBuffer<MyConstants> CB;` as if it was declared as `cbuffer __CB { MyConstants CB; }`. The exact way how to do this is TBD. |
Or:
At the same time Clang needs to recognize this class represents a constant buffer and the contained type fields are accessed using the `.` operator on `ConstantBuffer` instance. In other words treating `ConstantBuffer<MyConstants> CB;` as if it was declared as `cbuffer __CB { MyConstants CB; }`. The exact way how to do this is TBD. | |
Clang needs to recognize that this class represents a constant buffer and the contained type fields are accessed using the `.` operator on `ConstantBuffer` instance. In other words treating `ConstantBuffer<MyConstants> CB;` as if it was declared as `cbuffer __CB { MyConstants CB; }`. The exact way how to do this is TBD. |
proposals/NNNN-constant-buffers.md
Outdated
- Using type annotations to store cbuffer layout information. Subtypes would have its own layout annotations. | ||
- This is something we can fall back to if encoding the cbuffer layout on LLVM target type turns out to be too unwieldy, especially when it comes to encoding the layout of an array of structures. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd be interested to know why the proposed solution was chosen rather than the type annotation one. What's the downside to using type annotations?
proposals/NNNN-constant-buffers.md
Outdated
One possibility is compressing the list of offsets into a smaller number of integers - taking advantage of the fact that outside of `packoffset` use the difference between two adjancent offsets is never more than 16. The compression could also include repetition construct that would help with encoding of array offset. But, as with any compressions, there's always the chance of degenerate cases that will end up with the compressed shape being the same size or larger than the original. | ||
|
||
> Note: The most tricky part of the layout encoding are probably arrays of structures because the structure-specific layout gets repeated many times and might not be easy to compress. One idea how to solve this could be translating structures embedded in `cbuffer` into separate target types with their own encoded layout and including them in the `cbuffer` target type. It is not clear though if this is possible (probably yes) or if it would actually make things easier or not. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think we should be encoding the offset of each element of arrays, nor should we be encoding the offsets of inner struct members for each instance of them in the outer struct. I think we need to associate type information, containing member offsets, with struct types, like we use for type annotations in DXIL. This is a lot more efficient, only encoding the offsets we need once. Then we need some way to connect the target type with the annotated type, or the annotation metadata itself. Perhaps we can have cbuffer type metadata which references the target type and the contained type, then lists member info, including these offsets. Other member info will be useful/necessary, such as matrix identification and orientation information.
Initial description and design ideas.