Skip to content

Commit 3055d46

Browse files
authored
Resource constructors proposal (#197)
Proposal for resource classes constructors. Closes #209
1 parent 4d3bf14 commit 3055d46

File tree

1 file changed

+222
-0
lines changed

1 file changed

+222
-0
lines changed
Lines changed: 222 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,222 @@
1+
* Proposal: [0025 - Resource Constructors](0025-resource-constructors.md)
2+
* Author(s): [Helena Kotas](https://github.com/hekota)
3+
* Status: **Design In Progress**
4+
5+
## Introduction
6+
7+
HLSL resource classes are represented in Clang as struct types, or template
8+
struct types with the resource element type as the template argument. The
9+
resource structs have a member field `__handle` of type `__hlsl_resource_t` that
10+
is decorated with type attributes specifying the resource class, contained type,
11+
whether it is a handle for a raw buffer or ROV, and other properties. These
12+
builtin types are constructed in `HLSLExternalSemaSource`.
13+
14+
For example, the source code for `RWBuffer<T>` would look like this:
15+
16+
```c++
17+
template <typename T> struct RWBuffer {
18+
private:
19+
using handle_t = __hlsl_resource_t
20+
[[hlsl::contained_type(T)]] [[hlsl::resource_class(UAV)]];
21+
handle_t __handle;
22+
};
23+
```
24+
_* The resource declaration also includes element type validation via C++20
25+
concepts which I have not included here for readability._
26+
27+
Depending on the resource type its definition will include methods for accessing
28+
or manipulating the resource, such as subscript operators, `Load` and `Store`
29+
methods, etc.
30+
31+
Note that while the HLSL resources are defined as structs, they are often
32+
referred to as _resource classes_ or _resource records_. These terms can be used
33+
interchangebly.
34+
35+
The record classes can be declared at the global scope, used as function in/out
36+
parameters, or as local variables. They need to be properly initialized
37+
depending on the declaration scope, and this should be done by resource class
38+
constructors.
39+
40+
## Proposed solution
41+
42+
Each resource class should have a set of constructors that will initialize its
43+
`__handle` based on the scope where the resource was declared, its binding, or
44+
whether it is a dynamically bound resource. Each resource class should also have
45+
a copy constructor and/or assignment operator that will take care of copying the
46+
resource handle, for example when an existing resource is assigned to a local
47+
resource variable.
48+
49+
### Default constructor
50+
51+
Default constructor does not take any arguments and will initialize the
52+
`__handle` member to `poison` value, which means that its value is undefined.
53+
This constructor will be used for resources that are declared as local
54+
variables.
55+
56+
```c++
57+
template <typename T> struct RWBuffer {
58+
...
59+
public:
60+
// For uninitialized handles
61+
RWBuffer() {
62+
__handle = __builtin_hlsl_resource_createpoisonhandle(__handle);
63+
}
64+
...
65+
};
66+
```
67+
68+
The `__handle` argument of the `__builtin_hlsl_resource_createpoisonhandle` Clang
69+
builtin function will be used to infer the return type of that function. This is
70+
the same way we infer return types for HLSL intrinsic builtins based on their
71+
arguments, except in the case only the type of the argument is used and not its
72+
(uninitialized) value.
73+
74+
There might be a way of encoding the handle type into the
75+
builtin call without explicitly passing in the `__handle`. If that is the case
76+
and it is not overly complicated, we should use that instead.
77+
78+
A call to the default resource constructor is automatically generated by Clang
79+
for any uninitialized resource class. For resources declared at global scope
80+
Sema analysis will set the initialization expression to use a different
81+
constructor based on whether the resource has an explicit binding or not.
82+
83+
### Constructor for resources with explicit binding
84+
85+
Resources declared at the global scope can have an explicit binding and will be
86+
initialized by the following constructor.
87+
88+
```c++
89+
template <typename T> struct RWBuffer {
90+
...
91+
private:
92+
// For resources with explicit binding
93+
RWBuffer(unsigned register, unsigned space, int range, unsigned index) {
94+
__handle = __builtin_hlsl_resource_createhandlefrombinding(__handle, register, space, range, index);
95+
}
96+
...
97+
};
98+
```
99+
100+
The `__handle` argument passed into the
101+
`__builtin_hlsl_resource_createhandlefrombinding` Clang builtin function will be used
102+
to infer the return type of the that function (the same way as for the default
103+
construtor).
104+
105+
A call to this constructor will be created by Sema as part of uninitialized
106+
variable declaration processing (`Sema::ActOnUninitializedDecl`). It will
107+
work as if it would replace:
108+
109+
`RWBuffer<float> A : register(u3);`
110+
111+
with
112+
113+
`RWBuffer<float> A(3,0,1,0);`.
114+
115+
### Constructor for resources with implicit binding
116+
117+
If a resource does not have an explicit binding annotation, or if it has one but
118+
it only specifies the virtual register space, it has _implicit binding_. The
119+
actual binding will be assigned later on by the compiler.
120+
121+
The constructor for resources with implicit binding looks like this:
122+
123+
```c++
124+
template <typename T> struct RWBuffer {
125+
...
126+
private:
127+
// For resources with implicit binding
128+
RWBuffer(unsigned space, int range, unsigned index) {
129+
__handle = __builtin_hlsl_resource_createhandlefromimplicitbinding(__handle, space, range, index);
130+
}
131+
...
132+
};
133+
```
134+
135+
The `__handle` argument passed into the
136+
`__builtin_hlsl_resource_createhandlefromimplicitbinding` Clang builtin function will
137+
be used to infer the return type of the that function (the same way as for the
138+
default construtor).
139+
140+
A call to this constructor will be created by Sema as part of uninitialized
141+
variable declaration processing (`Sema::ActOnUninitializedDecl`). It will
142+
work as if it would replace:
143+
144+
`RWBuffer<float> A;`
145+
146+
with
147+
148+
`RWBuffer<float> A(0,1,0);`.
149+
150+
Or if the resource has a space-only binding annotation, it will work as if it
151+
would replace:
152+
153+
`RWBuffer<float> A : register(space13);`
154+
155+
with
156+
157+
`RWBuffer<float> A(13,1,0);`.
158+
159+
### Copy constructor and assignment operator
160+
161+
The copy constructor and/or the assignment operator will take care of copying the
162+
resource handle between resource class instances.
163+
164+
```c++
165+
template <typename T> struct RWBuffer {
166+
...
167+
public:
168+
// Resources are copyable.
169+
RWBuffer(RWBuffer &LHS) = default;
170+
171+
// Resources are assignable.
172+
RWBuffer &operator=(RWBuffer &LHS) = default;
173+
...
174+
};
175+
```
176+
177+
### Dynamically-bound resources
178+
179+
TBD
180+
181+
### Summary
182+
183+
```c++
184+
template <typename T> struct RWBuffer {
185+
private:
186+
// resource handle
187+
using handle_t = __hlsl_resource_t
188+
[[hlsl::contained_type(T)]] [[hlsl::resource_class(UAV)]];
189+
handle_t __handle;
190+
191+
// For resources with explicit binding
192+
RWBuffer(unsigned register, unsigned space, int rage, unsigned index) {
193+
__handle = __builtin_hlsl_resource_createhandlefrombinding(__handle, register, space, range, index);
194+
}
195+
196+
// For resources with implicit binding
197+
RWBuffer(unsigned space, int rage, unsigned index) {
198+
__handle = __builtin_hlsl_resource_createhandlefromimplicitbinding(__handle, space, range, index);
199+
}
200+
201+
public:
202+
// For uninitialized handles
203+
RWBuffer() {
204+
__handle = __builtin_hlsl_resource_createpoisonhandle(__handle);
205+
}
206+
207+
// Resources are copyable.
208+
RWBuffer(RWBuffer &LHS) = default;
209+
210+
// Resources are assignable.
211+
RWBuffer &operator=(RWBuffer &LHS) = default;
212+
...
213+
};
214+
```
215+
216+
## Alternatives considered (Optional)
217+
218+
## Acknowledgments (Optional)
219+
220+
Chris Bieneman
221+
222+
<!-- {% endraw %} -->

0 commit comments

Comments
 (0)