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(Symbol, Name, Binding, UniqueID, RC, Kind) != 242 std::tie(RHS.Symbol, RHS.Name, RHS.Binding, RHS.UniqueID, RHS.RC, 243 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(Ctx); 270 Type *I1Ty = Type::getInt1Ty(Ctx); 271 auto getIntMD = [&I32Ty](uint32_t V) { 272 return ConstantAsMetadata::get( 273 Constant::getIntegerValue(I32Ty, APInt(32, V))); 274 }; 275 auto getBoolMD = [&I1Ty](uint32_t V) { 276 return ConstantAsMetadata::get( 277 Constant::getIntegerValue(I1Ty, APInt(1, V))); 278 }; 279 280 MDVals.push_back(getIntMD(UniqueID)); 281 MDVals.push_back(ValueAsMetadata::get(Symbol)); 282 MDVals.push_back(MDString::get(Ctx, Name)); 283 MDVals.push_back(getIntMD(Binding.Space)); 284 MDVals.push_back(getIntMD(Binding.LowerBound)); 285 MDVals.push_back(getIntMD(Binding.Size)); 286 287 if (isCBuffer()) { 288 MDVals.push_back(getIntMD(CBufferSize)); 289 MDVals.push_back(nullptr); 290 } else if (isSampler()) { 291 MDVals.push_back(getIntMD(llvm::to_underlying(SamplerTy))); 292 MDVals.push_back(nullptr); 293 } else { 294 MDVals.push_back(getIntMD(llvm::to_underlying(Kind))); 295 296 if (isUAV()) { 297 MDVals.push_back(getBoolMD(UAVFlags.GloballyCoherent)); 298 MDVals.push_back(getBoolMD(UAVFlags.HasCounter)); 299 MDVals.push_back(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(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 getIntMD(llvm::to_underlying(ExtPropTags::StructuredBufferStride))); 313 Tags.push_back(getIntMD(Struct.Stride)); 314 } else if (isTyped()) { 315 Tags.push_back(getIntMD(llvm::to_underlying(ExtPropTags::ElementType))); 316 Tags.push_back(getIntMD(llvm::to_underlying(Typed.ElementTy))); 317 } else if (isFeedback()) { 318 Tags.push_back( 319 getIntMD(llvm::to_underlying(ExtPropTags::SamplerFeedbackKind))); 320 Tags.push_back(getIntMD(llvm::to_underlying(Feedback.Type))); 321 } 322 MDVals.push_back(Tags.empty() ? nullptr : MDNode::get(Ctx, Tags)); 323 } 324 325 return MDNode::get(Ctx, MDVals); 326 } 327 328 std::pair<uint32_t, uint32_t> ResourceInfo::getAnnotateProps() const { 329 uint32_t ResourceKind = llvm::to_underlying(Kind); 330 uint32_t AlignLog2 = isStruct() ? Log2(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(Feedback.Type); 357 else if (isTyped()) { 358 uint32_t CompType = llvm::to_underlying(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