1 | //===- DXILResource.cpp - Tools to translate DXIL resources ---------------===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | |
9 | #include "llvm/Transforms/Utils/DXILResource.h" |
10 | #include "llvm/ADT/APInt.h" |
11 | #include "llvm/IR/DerivedTypes.h" |
12 | |
13 | using namespace llvm; |
14 | using namespace dxil; |
15 | |
16 | bool ResourceInfo::isUAV() const { return RC == ResourceClass::UAV; } |
17 | |
18 | bool ResourceInfo::isCBuffer() const { return RC == ResourceClass::CBuffer; } |
19 | |
20 | bool ResourceInfo::isSampler() const { return RC == ResourceClass::Sampler; } |
21 | |
22 | bool ResourceInfo::isStruct() const { |
23 | return Kind == ResourceKind::StructuredBuffer; |
24 | } |
25 | |
26 | bool ResourceInfo::isTyped() const { |
27 | switch (Kind) { |
28 | case ResourceKind::Texture1D: |
29 | case ResourceKind::Texture2D: |
30 | case ResourceKind::Texture2DMS: |
31 | case ResourceKind::Texture3D: |
32 | case ResourceKind::TextureCube: |
33 | case ResourceKind::Texture1DArray: |
34 | case ResourceKind::Texture2DArray: |
35 | case ResourceKind::Texture2DMSArray: |
36 | case ResourceKind::TextureCubeArray: |
37 | case ResourceKind::TypedBuffer: |
38 | return true; |
39 | case ResourceKind::RawBuffer: |
40 | case ResourceKind::StructuredBuffer: |
41 | case ResourceKind::FeedbackTexture2D: |
42 | case ResourceKind::FeedbackTexture2DArray: |
43 | case ResourceKind::CBuffer: |
44 | case ResourceKind::Sampler: |
45 | case ResourceKind::TBuffer: |
46 | case ResourceKind::RTAccelerationStructure: |
47 | return false; |
48 | case ResourceKind::Invalid: |
49 | case ResourceKind::NumEntries: |
50 | llvm_unreachable("Invalid resource kind" ); |
51 | } |
52 | llvm_unreachable("Unhandled ResourceKind enum" ); |
53 | } |
54 | |
55 | bool ResourceInfo::isFeedback() const { |
56 | return Kind == ResourceKind::FeedbackTexture2D || |
57 | Kind == ResourceKind::FeedbackTexture2DArray; |
58 | } |
59 | |
60 | bool ResourceInfo::isMultiSample() const { |
61 | return Kind == ResourceKind::Texture2DMS || |
62 | Kind == ResourceKind::Texture2DMSArray; |
63 | } |
64 | |
65 | ResourceInfo ResourceInfo::SRV(Value *Symbol, StringRef Name, |
66 | ResourceBinding Binding, uint32_t UniqueID, |
67 | ElementType ElementTy, uint32_t ElementCount, |
68 | ResourceKind Kind) { |
69 | ResourceInfo RI(ResourceClass::SRV, Kind, Symbol, Name, Binding, UniqueID); |
70 | assert(RI.isTyped() && !(RI.isStruct() || RI.isMultiSample()) && |
71 | "Invalid ResourceKind for SRV constructor." ); |
72 | RI.Typed.ElementTy = ElementTy; |
73 | RI.Typed.ElementCount = ElementCount; |
74 | return RI; |
75 | } |
76 | |
77 | ResourceInfo ResourceInfo::RawBuffer(Value *Symbol, StringRef Name, |
78 | ResourceBinding Binding, |
79 | uint32_t UniqueID) { |
80 | ResourceInfo RI(ResourceClass::SRV, ResourceKind::RawBuffer, Symbol, Name, |
81 | Binding, UniqueID); |
82 | return RI; |
83 | } |
84 | |
85 | ResourceInfo ResourceInfo::StructuredBuffer(Value *Symbol, StringRef Name, |
86 | ResourceBinding Binding, |
87 | uint32_t UniqueID, uint32_t Stride, |
88 | Align Alignment) { |
89 | ResourceInfo RI(ResourceClass::SRV, ResourceKind::StructuredBuffer, Symbol, |
90 | Name, Binding, UniqueID); |
91 | RI.Struct.Stride = Stride; |
92 | RI.Struct.Alignment = Alignment; |
93 | return RI; |
94 | } |
95 | |
96 | ResourceInfo ResourceInfo::Texture2DMS(Value *Symbol, StringRef Name, |
97 | ResourceBinding Binding, |
98 | uint32_t UniqueID, ElementType ElementTy, |
99 | uint32_t ElementCount, |
100 | uint32_t SampleCount) { |
101 | ResourceInfo RI(ResourceClass::SRV, ResourceKind::Texture2DMS, Symbol, Name, |
102 | Binding, UniqueID); |
103 | RI.Typed.ElementTy = ElementTy; |
104 | RI.Typed.ElementCount = ElementCount; |
105 | RI.MultiSample.Count = SampleCount; |
106 | return RI; |
107 | } |
108 | |
109 | ResourceInfo ResourceInfo::Texture2DMSArray( |
110 | Value *Symbol, StringRef Name, ResourceBinding Binding, uint32_t UniqueID, |
111 | ElementType ElementTy, uint32_t ElementCount, uint32_t SampleCount) { |
112 | ResourceInfo RI(ResourceClass::SRV, ResourceKind::Texture2DMSArray, Symbol, |
113 | Name, Binding, UniqueID); |
114 | RI.Typed.ElementTy = ElementTy; |
115 | RI.Typed.ElementCount = ElementCount; |
116 | RI.MultiSample.Count = SampleCount; |
117 | return RI; |
118 | } |
119 | |
120 | ResourceInfo ResourceInfo::UAV(Value *Symbol, StringRef Name, |
121 | ResourceBinding Binding, uint32_t UniqueID, |
122 | ElementType ElementTy, uint32_t ElementCount, |
123 | bool GloballyCoherent, bool IsROV, |
124 | ResourceKind Kind) { |
125 | ResourceInfo RI(ResourceClass::UAV, Kind, Symbol, Name, Binding, UniqueID); |
126 | assert(RI.isTyped() && !(RI.isStruct() || RI.isMultiSample()) && |
127 | "Invalid ResourceKind for UAV constructor." ); |
128 | RI.Typed.ElementTy = ElementTy; |
129 | RI.Typed.ElementCount = ElementCount; |
130 | RI.UAVFlags.GloballyCoherent = GloballyCoherent; |
131 | RI.UAVFlags.IsROV = IsROV; |
132 | RI.UAVFlags.HasCounter = false; |
133 | return RI; |
134 | } |
135 | |
136 | ResourceInfo ResourceInfo::RWRawBuffer(Value *Symbol, StringRef Name, |
137 | ResourceBinding Binding, |
138 | uint32_t UniqueID, bool GloballyCoherent, |
139 | bool IsROV) { |
140 | ResourceInfo RI(ResourceClass::UAV, ResourceKind::RawBuffer, Symbol, Name, |
141 | Binding, UniqueID); |
142 | RI.UAVFlags.GloballyCoherent = GloballyCoherent; |
143 | RI.UAVFlags.IsROV = IsROV; |
144 | RI.UAVFlags.HasCounter = false; |
145 | return RI; |
146 | } |
147 | |
148 | ResourceInfo ResourceInfo::RWStructuredBuffer(Value *Symbol, StringRef Name, |
149 | ResourceBinding Binding, |
150 | uint32_t UniqueID, |
151 | uint32_t Stride, Align Alignment, |
152 | bool GloballyCoherent, bool IsROV, |
153 | bool HasCounter) { |
154 | ResourceInfo RI(ResourceClass::UAV, ResourceKind::StructuredBuffer, Symbol, |
155 | Name, Binding, UniqueID); |
156 | RI.Struct.Stride = Stride; |
157 | RI.Struct.Alignment = Alignment; |
158 | RI.UAVFlags.GloballyCoherent = GloballyCoherent; |
159 | RI.UAVFlags.IsROV = IsROV; |
160 | RI.UAVFlags.HasCounter = HasCounter; |
161 | return RI; |
162 | } |
163 | |
164 | ResourceInfo |
165 | ResourceInfo::RWTexture2DMS(Value *Symbol, StringRef Name, |
166 | ResourceBinding Binding, uint32_t UniqueID, |
167 | ElementType ElementTy, uint32_t ElementCount, |
168 | uint32_t SampleCount, bool GloballyCoherent) { |
169 | ResourceInfo RI(ResourceClass::UAV, ResourceKind::Texture2DMS, Symbol, Name, |
170 | Binding, UniqueID); |
171 | RI.Typed.ElementTy = ElementTy; |
172 | RI.Typed.ElementCount = ElementCount; |
173 | RI.UAVFlags.GloballyCoherent = GloballyCoherent; |
174 | RI.UAVFlags.IsROV = false; |
175 | RI.UAVFlags.HasCounter = false; |
176 | RI.MultiSample.Count = SampleCount; |
177 | return RI; |
178 | } |
179 | |
180 | ResourceInfo |
181 | ResourceInfo::RWTexture2DMSArray(Value *Symbol, StringRef Name, |
182 | ResourceBinding Binding, uint32_t UniqueID, |
183 | ElementType ElementTy, uint32_t ElementCount, |
184 | uint32_t SampleCount, bool GloballyCoherent) { |
185 | ResourceInfo RI(ResourceClass::UAV, ResourceKind::Texture2DMSArray, Symbol, |
186 | Name, Binding, UniqueID); |
187 | RI.Typed.ElementTy = ElementTy; |
188 | RI.Typed.ElementCount = ElementCount; |
189 | RI.UAVFlags.GloballyCoherent = GloballyCoherent; |
190 | RI.UAVFlags.IsROV = false; |
191 | RI.UAVFlags.HasCounter = false; |
192 | RI.MultiSample.Count = SampleCount; |
193 | return RI; |
194 | } |
195 | |
196 | ResourceInfo ResourceInfo::FeedbackTexture2D(Value *Symbol, StringRef Name, |
197 | ResourceBinding Binding, |
198 | uint32_t UniqueID, |
199 | SamplerFeedbackType FeedbackTy) { |
200 | ResourceInfo RI(ResourceClass::UAV, ResourceKind::FeedbackTexture2D, Symbol, |
201 | Name, Binding, UniqueID); |
202 | RI.UAVFlags.GloballyCoherent = false; |
203 | RI.UAVFlags.IsROV = false; |
204 | RI.UAVFlags.HasCounter = false; |
205 | RI.Feedback.Type = FeedbackTy; |
206 | return RI; |
207 | } |
208 | |
209 | ResourceInfo |
210 | ResourceInfo::FeedbackTexture2DArray(Value *Symbol, StringRef Name, |
211 | ResourceBinding Binding, uint32_t UniqueID, |
212 | SamplerFeedbackType FeedbackTy) { |
213 | ResourceInfo RI(ResourceClass::UAV, ResourceKind::FeedbackTexture2DArray, |
214 | Symbol, Name, Binding, UniqueID); |
215 | RI.UAVFlags.GloballyCoherent = false; |
216 | RI.UAVFlags.IsROV = false; |
217 | RI.UAVFlags.HasCounter = false; |
218 | RI.Feedback.Type = FeedbackTy; |
219 | return RI; |
220 | } |
221 | |
222 | ResourceInfo ResourceInfo::CBuffer(Value *Symbol, StringRef Name, |
223 | ResourceBinding Binding, uint32_t UniqueID, |
224 | uint32_t Size) { |
225 | ResourceInfo RI(ResourceClass::CBuffer, ResourceKind::CBuffer, Symbol, Name, |
226 | Binding, UniqueID); |
227 | RI.CBufferSize = Size; |
228 | return RI; |
229 | } |
230 | |
231 | ResourceInfo ResourceInfo::Sampler(Value *Symbol, StringRef Name, |
232 | ResourceBinding Binding, uint32_t UniqueID, |
233 | SamplerType SamplerTy) { |
234 | ResourceInfo RI(ResourceClass::Sampler, ResourceKind::Sampler, Symbol, Name, |
235 | Binding, UniqueID); |
236 | RI.SamplerTy = SamplerTy; |
237 | return RI; |
238 | } |
239 | |
240 | bool ResourceInfo::operator==(const ResourceInfo &RHS) const { |
241 | if (std::tie(args: Symbol, args: Name, args: Binding, args: UniqueID, args: RC, args: Kind) != |
242 | std::tie(args: RHS.Symbol, args: RHS.Name, args: RHS.Binding, args: RHS.UniqueID, args: RHS.RC, |
243 | args: RHS.Kind)) |
244 | return false; |
245 | if (isCBuffer()) |
246 | return CBufferSize == RHS.CBufferSize; |
247 | if (isSampler()) |
248 | return SamplerTy == RHS.SamplerTy; |
249 | if (isUAV() && UAVFlags != RHS.UAVFlags) |
250 | return false; |
251 | |
252 | if (isStruct()) |
253 | return Struct == RHS.Struct; |
254 | if (isFeedback()) |
255 | return Feedback == RHS.Feedback; |
256 | if (isTyped() && Typed != RHS.Typed) |
257 | return false; |
258 | |
259 | if (isMultiSample()) |
260 | return MultiSample == RHS.MultiSample; |
261 | |
262 | assert((Kind == ResourceKind::RawBuffer) && "Unhandled resource kind" ); |
263 | return true; |
264 | } |
265 | |
266 | MDTuple *ResourceInfo::getAsMetadata(LLVMContext &Ctx) const { |
267 | SmallVector<Metadata *, 11> MDVals; |
268 | |
269 | Type *I32Ty = Type::getInt32Ty(C&: Ctx); |
270 | Type *I1Ty = Type::getInt1Ty(C&: Ctx); |
271 | auto getIntMD = [&I32Ty](uint32_t V) { |
272 | return ConstantAsMetadata::get( |
273 | C: Constant::getIntegerValue(Ty: I32Ty, V: APInt(32, V))); |
274 | }; |
275 | auto getBoolMD = [&I1Ty](uint32_t V) { |
276 | return ConstantAsMetadata::get( |
277 | C: Constant::getIntegerValue(Ty: I1Ty, V: APInt(1, V))); |
278 | }; |
279 | |
280 | MDVals.push_back(Elt: getIntMD(UniqueID)); |
281 | MDVals.push_back(Elt: ValueAsMetadata::get(V: Symbol)); |
282 | MDVals.push_back(Elt: MDString::get(Context&: Ctx, Str: Name)); |
283 | MDVals.push_back(Elt: getIntMD(Binding.Space)); |
284 | MDVals.push_back(Elt: getIntMD(Binding.LowerBound)); |
285 | MDVals.push_back(Elt: getIntMD(Binding.Size)); |
286 | |
287 | if (isCBuffer()) { |
288 | MDVals.push_back(Elt: getIntMD(CBufferSize)); |
289 | MDVals.push_back(Elt: nullptr); |
290 | } else if (isSampler()) { |
291 | MDVals.push_back(Elt: getIntMD(llvm::to_underlying(E: SamplerTy))); |
292 | MDVals.push_back(Elt: nullptr); |
293 | } else { |
294 | MDVals.push_back(Elt: getIntMD(llvm::to_underlying(E: Kind))); |
295 | |
296 | if (isUAV()) { |
297 | MDVals.push_back(Elt: getBoolMD(UAVFlags.GloballyCoherent)); |
298 | MDVals.push_back(Elt: getBoolMD(UAVFlags.HasCounter)); |
299 | MDVals.push_back(Elt: getBoolMD(UAVFlags.IsROV)); |
300 | } else { |
301 | // All SRVs include sample count in the metadata, but it's only meaningful |
302 | // for multi-sampled textured. Also, UAVs can be multisampled in SM6.7+, |
303 | // but this just isn't reflected in the metadata at all. |
304 | uint32_t SampleCount = isMultiSample() ? MultiSample.Count : 0; |
305 | MDVals.push_back(Elt: getIntMD(SampleCount)); |
306 | } |
307 | |
308 | // Further properties are attached to a metadata list of tag-value pairs. |
309 | SmallVector<Metadata *> Tags; |
310 | if (isStruct()) { |
311 | Tags.push_back( |
312 | Elt: getIntMD(llvm::to_underlying(E: ExtPropTags::StructuredBufferStride))); |
313 | Tags.push_back(Elt: getIntMD(Struct.Stride)); |
314 | } else if (isTyped()) { |
315 | Tags.push_back(Elt: getIntMD(llvm::to_underlying(E: ExtPropTags::ElementType))); |
316 | Tags.push_back(Elt: getIntMD(llvm::to_underlying(E: Typed.ElementTy))); |
317 | } else if (isFeedback()) { |
318 | Tags.push_back( |
319 | Elt: getIntMD(llvm::to_underlying(E: ExtPropTags::SamplerFeedbackKind))); |
320 | Tags.push_back(Elt: getIntMD(llvm::to_underlying(E: Feedback.Type))); |
321 | } |
322 | MDVals.push_back(Elt: Tags.empty() ? nullptr : MDNode::get(Context&: Ctx, MDs: Tags)); |
323 | } |
324 | |
325 | return MDNode::get(Context&: Ctx, MDs: MDVals); |
326 | } |
327 | |
328 | std::pair<uint32_t, uint32_t> ResourceInfo::getAnnotateProps() const { |
329 | uint32_t ResourceKind = llvm::to_underlying(E: Kind); |
330 | uint32_t AlignLog2 = isStruct() ? Log2(A: Struct.Alignment) : 0; |
331 | bool IsUAV = isUAV(); |
332 | bool IsROV = IsUAV && UAVFlags.IsROV; |
333 | bool IsGloballyCoherent = IsUAV && UAVFlags.GloballyCoherent; |
334 | uint8_t SamplerCmpOrHasCounter = 0; |
335 | if (IsUAV) |
336 | SamplerCmpOrHasCounter = UAVFlags.HasCounter; |
337 | else if (isSampler()) |
338 | SamplerCmpOrHasCounter = SamplerTy == SamplerType::Comparison; |
339 | |
340 | // TODO: Document this format. Currently the only reference is the |
341 | // implementation of dxc's DxilResourceProperties struct. |
342 | uint32_t Word0 = 0; |
343 | Word0 |= ResourceKind & 0xFF; |
344 | Word0 |= (AlignLog2 & 0xF) << 8; |
345 | Word0 |= (IsUAV & 1) << 12; |
346 | Word0 |= (IsROV & 1) << 13; |
347 | Word0 |= (IsGloballyCoherent & 1) << 14; |
348 | Word0 |= (SamplerCmpOrHasCounter & 1) << 15; |
349 | |
350 | uint32_t Word1 = 0; |
351 | if (isStruct()) |
352 | Word1 = Struct.Stride; |
353 | else if (isCBuffer()) |
354 | Word1 = CBufferSize; |
355 | else if (isFeedback()) |
356 | Word1 = llvm::to_underlying(E: Feedback.Type); |
357 | else if (isTyped()) { |
358 | uint32_t CompType = llvm::to_underlying(E: Typed.ElementTy); |
359 | uint32_t CompCount = Typed.ElementCount; |
360 | uint32_t SampleCount = isMultiSample() ? MultiSample.Count : 0; |
361 | |
362 | Word1 |= (CompType & 0xFF) << 0; |
363 | Word1 |= (CompCount & 0xFF) << 8; |
364 | Word1 |= (SampleCount & 0xFF) << 16; |
365 | } |
366 | |
367 | return {Word0, Word1}; |
368 | } |
369 | |
370 | #define DEBUG_TYPE "dxil-resource" |
371 | |