Skip to content

Commit 06203dc

Browse files
committed
SPIRV resource representation
Adds a proposal for how HLSL resources will be represented in llvm-ir when targeting SPIR-V.
1 parent 19dee9e commit 06203dc

File tree

1 file changed

+225
-0
lines changed

1 file changed

+225
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,225 @@
1+
<!-- {% raw %} -->
2+
3+
# HLSL resources in SPIR-V
4+
5+
* Proposal: [NNNN](NNNN-spirv-resource-representation.md)
6+
* Author(s): [Steven Perron](https://github.com/s-perron)
7+
* Status: **Design In Progress**
8+
9+
*During the review process, add the following fields as needed:*
10+
11+
* PRs: [#114273](https://github.com/llvm/llvm-project/pull/114273),
12+
[#111052](https://github.com/llvm/llvm-project/pull/111052),
13+
[#111564](https://github.com/llvm/llvm-project/pull/111564),
14+
[#115178](https://github.com/llvm/llvm-project/pull/115178)
15+
16+
## Introduction
17+
18+
There is a need to represent the HLSL resources in llvm-ir in a way that the
19+
SPIR-V backend is able to create the correct code. We have already done some
20+
implementation work for `Buffer` and `RWBuffer`. This was done as a
21+
proof-of-concept, and now we needed to determine how the other resource types
22+
will be represented.
23+
24+
## Motivation
25+
26+
The HLSL resources are fundamental to HLSL, and they are required in a Vulkan
27+
implementation.
28+
29+
## Proposed solution
30+
31+
We want to match the general solution proposed in
32+
[0006-resource-representations.md](0006-resource-representations.md). The
33+
`@llvm.spv.handle.fromBinding` intrinsic will be used to get a handle to the
34+
resource. It will return a target type to represent the handle. Then other
35+
intrinsics will be used to access the resource using the handle. Previous
36+
proposals left open what the target types should be for SPIR-V.
37+
38+
The general pattern for the solution will be that `@llvm.spv.handle.fromBinding`
39+
will return a SPIR-V pointer to a type `T`. The type for `T` will be detailed
40+
when discusses each HLSL resource type. The SPIR-V backend will create a global
41+
variable with type `T` if `range_size` is 1, and `T[range_size]` otherwise.
42+
43+
The reason we want `@llvm.spv.handle.fromBinding` to return a pointer is to make
44+
it easier to satisfy the SPIR-V requirements in the
45+
[Universal Validation Rules](https://registry.khronos.org/SPIR-V/specs/unified1/SPIRV.html#_universal_validation_rules).
46+
Specifically,
47+
48+
> All OpSampledImage instructions, or instructions that load an image or sampler
49+
> reference, must be in the same block in which their Result <id> are consumed.
50+
51+
It is the responsibility of the intrinsics that use the handles to load the
52+
images and samplers.
53+
54+
The following sections will reference table 4 in the
55+
[shader resrouce interface](https://docs.vulkan.org/spec/latest/chapters/interfaces.html#interfaces-resources)
56+
for Vulkan.
57+
58+
### Textures and typed buffers
59+
60+
All of these resource types are represented using an image type in SPIRV. The
61+
`Texture*` types are implemented as sampled images. the `RWTexture*` types are
62+
implemented as storage images. `Buffer` is implemented as a uniform buffer, and
63+
`RWBuffer` is implemented as a storage buffer.
64+
65+
For these cases the return type from `@llvm.spv.handle.fromBinding` would be:
66+
67+
```llvm-ir
68+
target("spirv.Pointer", 0 /* UniformConstantStorageClass */, target("spirv.Image", ...))
69+
```
70+
71+
The details of the `spirv.Image` type depend on the specific declaration.
72+
73+
TODO: We need to determine the image format.
74+
75+
### Structured buffers and texture buffers
76+
77+
All structured buffers and texture buffers are represented as storge buffers in
78+
SPIR-V. The Vulkan documentation has two ways to represent a storage buffer. The
79+
first representation was removed in SPIR-V 1.3 (Vulkan 1.1). We will generate
80+
only the second representation.
81+
82+
For these cases the return type from `@llvm.spv.handle.fromBinding` for
83+
`RWStructuredBuffer<T>` would be:
84+
85+
```llvm-ir
86+
target("spirv.Pointer", 12 /* StorageBuffer */, T')
87+
```
88+
89+
Where `T' = struct { T t[]; }`.
90+
91+
For `StructuredBuffer<T>`,
92+
93+
```llvm-ir
94+
target("spirv.Pointer", 12 /* StorageBuffer */, const T')
95+
```
96+
97+
TODO: We need to determine how the Block decoration will be added. The current
98+
idea will have clang describe the type in detail, which means that clang needs a
99+
way to say that the type `T'` requires the decoration. There is a
100+
`spirv.Decoration` metadata, but that works on global variable only at this
101+
time. We could have the target spirv type access the metadata node as an
102+
operand. This interacts with the implementation of `vk::ext_decorate`, which
103+
will have to be able to apply decoration to members of types.
104+
105+
TODO: We need to determine what the layout of the struct should be. Will we
106+
support multiple layout as we do in DXC? This could be communicated to the back
107+
end by adding the decorations to the type in the same way as the previous todo.
108+
109+
Note: We are in the middle of implementing `vk::SpirvType` in clang. That should
110+
add a way to implement the target types without adding a specific
111+
`spirv.Pointer` target type.
112+
113+
### Constant buffers
114+
115+
Constant buffers are implemented as uniform buffers. They will have the exact
116+
same representation as a structured buffer except that the storage class will be
117+
`Uniform` instead of `UniformConstant`.
118+
119+
### Samplers
120+
121+
For these cases the return type from `@llvm.spv.handle.fromBinding` would be:
122+
123+
```llvm-ir
124+
target("spirv.Pointer", 0 /* UniformConstantStorageClass */, target("spirv.Sampler"))
125+
```
126+
127+
This is the same for a `SamplerState` and `SamplerComparisonState`.
128+
129+
### Byte address buffers
130+
131+
If
132+
[untyped pointers](https://htmlpreview.github.io/?https://github.com/KhronosGroup/SPIRV-Registry/blob/main/extensions/KHR/SPV_KHR_untyped_pointers.html)
133+
are available, we will want to use the untyped pointers. However, if they are
134+
not available, we will need to represent it as an array of integers, as is done
135+
in DXC.
136+
137+
TODO: I'm thinking it is the responsibility of SPIRVTargetInfo to make this
138+
decision.
139+
140+
If
141+
[untyped pointers](https://htmlpreview.github.io/?https://github.com/KhronosGroup/SPIRV-Registry/blob/main/extensions/KHR/SPV_KHR_untyped_pointers.html)
142+
are available, then the return type from `@llvm.spv.handle.fromBinding` would
143+
be:
144+
145+
```llvm-ir
146+
target("spirv.UntypedPointer", 12 /* StorageBuffer */)
147+
```
148+
149+
If untyped pointers are not available, then the return type from
150+
`@llvm.spv.handle.fromBinding` would be:
151+
152+
```llvm-ir
153+
target("spirv.Pointer", 12 /* StorageBuffer */, { uint32_t[] })
154+
```
155+
156+
TODO: Add the `block` decoration.
157+
158+
The intrinsics that use the ByteAddressBuffers will not change depending on the
159+
type used. The SPIR-V backend should recognize the type and implement
160+
accordingly.
161+
162+
### Rasterizer Order Views
163+
164+
If a resource is a rasterizer order view it will generate the exact same code as
165+
its regular version except
166+
167+
1. All uses of the resource will have a call site attribute indicating that
168+
this call must be part of the fragment shader's critical section. This is a
169+
new target attribute which will be call `spirv.InterlockedCritical`.
170+
2. The entry points (that reference directly or indirectly?) the ROVs will have
171+
an attribute `spirv.InterlockMode` which could have the value
172+
`SampleOrdered`, `SampleUnordered`, `PixelOrdered`, `PixelUnordered`,
173+
`ShadingRateOrdered`, or `ShadingRateUnordered`.
174+
175+
A pass similar to the `InvocationInterlockPlacementPass` pass in SPIR-V Tools
176+
will be run in the SPIR-V backend to add instructions to begin and end the
177+
critical section. This pass will be run after structurizing the llvm-ir, and
178+
before ISel.
179+
180+
The SPIR-V backend will add the appropriate interlock execution mode to the
181+
module based on the attribute on the entry point.
182+
183+
### Feedback textures
184+
185+
These resources do not have a straight-forward implementation in SPIR-V, and
186+
they were not implemented in DXC. We will issue an error if these resource are
187+
used when targeting SPIR-V.
188+
189+
## Detailed design
190+
191+
*The detailed design is not required until the feature is under review.*
192+
193+
This section should grow into a full specification that will provide enough
194+
information for someone who isn't the proposal author to implement the feature.
195+
It should also serve as the basis for documentation for the feature. Each
196+
feature will need different levels of detail here, but some common things to
197+
think through are:
198+
199+
* Is there any potential for changed behavior?
200+
* Will this expose new interfaces that will have support burden?
201+
* How will this proposal be tested?
202+
* Does this require additional hardware/software/human resources?
203+
* What documentation should be updated or authored?
204+
205+
## Alternatives considered (Optional)
206+
207+
### Returning an image type in `@llvm.spv.handle.fromBinding`
208+
209+
We considered implementing returning the `target("spirv.Image", ...)` type from
210+
`@llvm.spv.handle.fromBinding` instead of returning a pointer to the type. This
211+
caused problems because the uses of the image have to be in the same basic
212+
block, and, in general, the uses of the handle are not in the same basic block
213+
as the call to `@llvm.spv.handle.fromBinding`.
214+
215+
To fix this, we would have to add a pass in the backend to fix up the problem by
216+
replicating code, but this seems less desirable when we can generate the code
217+
correctly.
218+
219+
It also makes the implementation of `@llvm.spv.handle.fromBinding` more
220+
complicated because it will have to be treated differently than structured
221+
buffers.
222+
223+
## Acknowledgments (Optional)
224+
225+
<!-- {% endraw %} -->

0 commit comments

Comments
 (0)