This makes the binding structure in a DXILResource default to empty and need a separate call to set up, and also moves the unique ID into it since bindings are the only place where those are actually used. This will put us in a better position when dealing with resource handles in libraries. Pull Request: https://github.com/llvm/llvm-project/pull/100623
350 lines
12 KiB
C++
350 lines
12 KiB
C++
//===- DXILResource.cpp - Representations of DXIL resources ---------------===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "llvm/Analysis/DXILResource.h"
|
|
#include "llvm/ADT/APInt.h"
|
|
#include "llvm/IR/DerivedTypes.h"
|
|
#include "llvm/IR/Metadata.h"
|
|
|
|
using namespace llvm;
|
|
using namespace dxil;
|
|
|
|
bool ResourceInfo::isUAV() const { return RC == ResourceClass::UAV; }
|
|
|
|
bool ResourceInfo::isCBuffer() const { return RC == ResourceClass::CBuffer; }
|
|
|
|
bool ResourceInfo::isSampler() const { return RC == ResourceClass::Sampler; }
|
|
|
|
bool ResourceInfo::isStruct() const {
|
|
return Kind == ResourceKind::StructuredBuffer;
|
|
}
|
|
|
|
bool ResourceInfo::isTyped() const {
|
|
switch (Kind) {
|
|
case ResourceKind::Texture1D:
|
|
case ResourceKind::Texture2D:
|
|
case ResourceKind::Texture2DMS:
|
|
case ResourceKind::Texture3D:
|
|
case ResourceKind::TextureCube:
|
|
case ResourceKind::Texture1DArray:
|
|
case ResourceKind::Texture2DArray:
|
|
case ResourceKind::Texture2DMSArray:
|
|
case ResourceKind::TextureCubeArray:
|
|
case ResourceKind::TypedBuffer:
|
|
return true;
|
|
case ResourceKind::RawBuffer:
|
|
case ResourceKind::StructuredBuffer:
|
|
case ResourceKind::FeedbackTexture2D:
|
|
case ResourceKind::FeedbackTexture2DArray:
|
|
case ResourceKind::CBuffer:
|
|
case ResourceKind::Sampler:
|
|
case ResourceKind::TBuffer:
|
|
case ResourceKind::RTAccelerationStructure:
|
|
return false;
|
|
case ResourceKind::Invalid:
|
|
case ResourceKind::NumEntries:
|
|
llvm_unreachable("Invalid resource kind");
|
|
}
|
|
llvm_unreachable("Unhandled ResourceKind enum");
|
|
}
|
|
|
|
bool ResourceInfo::isFeedback() const {
|
|
return Kind == ResourceKind::FeedbackTexture2D ||
|
|
Kind == ResourceKind::FeedbackTexture2DArray;
|
|
}
|
|
|
|
bool ResourceInfo::isMultiSample() const {
|
|
return Kind == ResourceKind::Texture2DMS ||
|
|
Kind == ResourceKind::Texture2DMSArray;
|
|
}
|
|
|
|
ResourceInfo ResourceInfo::SRV(Value *Symbol, StringRef Name,
|
|
ElementType ElementTy, uint32_t ElementCount,
|
|
ResourceKind Kind) {
|
|
ResourceInfo RI(ResourceClass::SRV, Kind, Symbol, Name);
|
|
assert(RI.isTyped() && !(RI.isStruct() || RI.isMultiSample()) &&
|
|
"Invalid ResourceKind for SRV constructor.");
|
|
RI.Typed.ElementTy = ElementTy;
|
|
RI.Typed.ElementCount = ElementCount;
|
|
return RI;
|
|
}
|
|
|
|
ResourceInfo ResourceInfo::RawBuffer(Value *Symbol, StringRef Name) {
|
|
ResourceInfo RI(ResourceClass::SRV, ResourceKind::RawBuffer, Symbol, Name);
|
|
return RI;
|
|
}
|
|
|
|
ResourceInfo ResourceInfo::StructuredBuffer(Value *Symbol, StringRef Name,
|
|
uint32_t Stride, Align Alignment) {
|
|
ResourceInfo RI(ResourceClass::SRV, ResourceKind::StructuredBuffer, Symbol,
|
|
Name);
|
|
RI.Struct.Stride = Stride;
|
|
RI.Struct.Alignment = Alignment;
|
|
return RI;
|
|
}
|
|
|
|
ResourceInfo ResourceInfo::Texture2DMS(Value *Symbol, StringRef Name,
|
|
ElementType ElementTy,
|
|
uint32_t ElementCount,
|
|
uint32_t SampleCount) {
|
|
ResourceInfo RI(ResourceClass::SRV, ResourceKind::Texture2DMS, Symbol, Name);
|
|
RI.Typed.ElementTy = ElementTy;
|
|
RI.Typed.ElementCount = ElementCount;
|
|
RI.MultiSample.Count = SampleCount;
|
|
return RI;
|
|
}
|
|
|
|
ResourceInfo ResourceInfo::Texture2DMSArray(Value *Symbol, StringRef Name,
|
|
ElementType ElementTy,
|
|
uint32_t ElementCount,
|
|
uint32_t SampleCount) {
|
|
ResourceInfo RI(ResourceClass::SRV, ResourceKind::Texture2DMSArray, Symbol,
|
|
Name);
|
|
RI.Typed.ElementTy = ElementTy;
|
|
RI.Typed.ElementCount = ElementCount;
|
|
RI.MultiSample.Count = SampleCount;
|
|
return RI;
|
|
}
|
|
|
|
ResourceInfo ResourceInfo::UAV(Value *Symbol, StringRef Name,
|
|
ElementType ElementTy, uint32_t ElementCount,
|
|
bool GloballyCoherent, bool IsROV,
|
|
ResourceKind Kind) {
|
|
ResourceInfo RI(ResourceClass::UAV, Kind, Symbol, Name);
|
|
assert(RI.isTyped() && !(RI.isStruct() || RI.isMultiSample()) &&
|
|
"Invalid ResourceKind for UAV constructor.");
|
|
RI.Typed.ElementTy = ElementTy;
|
|
RI.Typed.ElementCount = ElementCount;
|
|
RI.UAVFlags.GloballyCoherent = GloballyCoherent;
|
|
RI.UAVFlags.IsROV = IsROV;
|
|
RI.UAVFlags.HasCounter = false;
|
|
return RI;
|
|
}
|
|
|
|
ResourceInfo ResourceInfo::RWRawBuffer(Value *Symbol, StringRef Name,
|
|
bool GloballyCoherent, bool IsROV) {
|
|
ResourceInfo RI(ResourceClass::UAV, ResourceKind::RawBuffer, Symbol, Name);
|
|
RI.UAVFlags.GloballyCoherent = GloballyCoherent;
|
|
RI.UAVFlags.IsROV = IsROV;
|
|
RI.UAVFlags.HasCounter = false;
|
|
return RI;
|
|
}
|
|
|
|
ResourceInfo ResourceInfo::RWStructuredBuffer(Value *Symbol, StringRef Name,
|
|
uint32_t Stride, Align Alignment,
|
|
bool GloballyCoherent, bool IsROV,
|
|
bool HasCounter) {
|
|
ResourceInfo RI(ResourceClass::UAV, ResourceKind::StructuredBuffer, Symbol,
|
|
Name);
|
|
RI.Struct.Stride = Stride;
|
|
RI.Struct.Alignment = Alignment;
|
|
RI.UAVFlags.GloballyCoherent = GloballyCoherent;
|
|
RI.UAVFlags.IsROV = IsROV;
|
|
RI.UAVFlags.HasCounter = HasCounter;
|
|
return RI;
|
|
}
|
|
|
|
ResourceInfo ResourceInfo::RWTexture2DMS(Value *Symbol, StringRef Name,
|
|
ElementType ElementTy,
|
|
uint32_t ElementCount,
|
|
uint32_t SampleCount,
|
|
bool GloballyCoherent) {
|
|
ResourceInfo RI(ResourceClass::UAV, ResourceKind::Texture2DMS, Symbol, Name);
|
|
RI.Typed.ElementTy = ElementTy;
|
|
RI.Typed.ElementCount = ElementCount;
|
|
RI.UAVFlags.GloballyCoherent = GloballyCoherent;
|
|
RI.UAVFlags.IsROV = false;
|
|
RI.UAVFlags.HasCounter = false;
|
|
RI.MultiSample.Count = SampleCount;
|
|
return RI;
|
|
}
|
|
|
|
ResourceInfo ResourceInfo::RWTexture2DMSArray(Value *Symbol, StringRef Name,
|
|
ElementType ElementTy,
|
|
uint32_t ElementCount,
|
|
uint32_t SampleCount,
|
|
bool GloballyCoherent) {
|
|
ResourceInfo RI(ResourceClass::UAV, ResourceKind::Texture2DMSArray, Symbol,
|
|
Name);
|
|
RI.Typed.ElementTy = ElementTy;
|
|
RI.Typed.ElementCount = ElementCount;
|
|
RI.UAVFlags.GloballyCoherent = GloballyCoherent;
|
|
RI.UAVFlags.IsROV = false;
|
|
RI.UAVFlags.HasCounter = false;
|
|
RI.MultiSample.Count = SampleCount;
|
|
return RI;
|
|
}
|
|
|
|
ResourceInfo ResourceInfo::FeedbackTexture2D(Value *Symbol, StringRef Name,
|
|
SamplerFeedbackType FeedbackTy) {
|
|
ResourceInfo RI(ResourceClass::UAV, ResourceKind::FeedbackTexture2D, Symbol,
|
|
Name);
|
|
RI.UAVFlags.GloballyCoherent = false;
|
|
RI.UAVFlags.IsROV = false;
|
|
RI.UAVFlags.HasCounter = false;
|
|
RI.Feedback.Type = FeedbackTy;
|
|
return RI;
|
|
}
|
|
|
|
ResourceInfo
|
|
ResourceInfo::FeedbackTexture2DArray(Value *Symbol, StringRef Name,
|
|
SamplerFeedbackType FeedbackTy) {
|
|
ResourceInfo RI(ResourceClass::UAV, ResourceKind::FeedbackTexture2DArray,
|
|
Symbol, Name);
|
|
RI.UAVFlags.GloballyCoherent = false;
|
|
RI.UAVFlags.IsROV = false;
|
|
RI.UAVFlags.HasCounter = false;
|
|
RI.Feedback.Type = FeedbackTy;
|
|
return RI;
|
|
}
|
|
|
|
ResourceInfo ResourceInfo::CBuffer(Value *Symbol, StringRef Name,
|
|
uint32_t Size) {
|
|
ResourceInfo RI(ResourceClass::CBuffer, ResourceKind::CBuffer, Symbol, Name);
|
|
RI.CBufferSize = Size;
|
|
return RI;
|
|
}
|
|
|
|
ResourceInfo ResourceInfo::Sampler(Value *Symbol, StringRef Name,
|
|
SamplerType SamplerTy) {
|
|
ResourceInfo RI(ResourceClass::Sampler, ResourceKind::Sampler, Symbol, Name);
|
|
RI.SamplerTy = SamplerTy;
|
|
return RI;
|
|
}
|
|
|
|
bool ResourceInfo::operator==(const ResourceInfo &RHS) const {
|
|
if (std::tie(Symbol, Name, Binding, RC, Kind) !=
|
|
std::tie(RHS.Symbol, RHS.Name, RHS.Binding, RHS.RC, RHS.Kind))
|
|
return false;
|
|
if (isCBuffer())
|
|
return CBufferSize == RHS.CBufferSize;
|
|
if (isSampler())
|
|
return SamplerTy == RHS.SamplerTy;
|
|
if (isUAV() && UAVFlags != RHS.UAVFlags)
|
|
return false;
|
|
|
|
if (isStruct())
|
|
return Struct == RHS.Struct;
|
|
if (isFeedback())
|
|
return Feedback == RHS.Feedback;
|
|
if (isTyped() && Typed != RHS.Typed)
|
|
return false;
|
|
|
|
if (isMultiSample())
|
|
return MultiSample == RHS.MultiSample;
|
|
|
|
assert((Kind == ResourceKind::RawBuffer) && "Unhandled resource kind");
|
|
return true;
|
|
}
|
|
|
|
MDTuple *ResourceInfo::getAsMetadata(LLVMContext &Ctx) const {
|
|
SmallVector<Metadata *, 11> MDVals;
|
|
|
|
Type *I32Ty = Type::getInt32Ty(Ctx);
|
|
Type *I1Ty = Type::getInt1Ty(Ctx);
|
|
auto getIntMD = [&I32Ty](uint32_t V) {
|
|
return ConstantAsMetadata::get(
|
|
Constant::getIntegerValue(I32Ty, APInt(32, V)));
|
|
};
|
|
auto getBoolMD = [&I1Ty](uint32_t V) {
|
|
return ConstantAsMetadata::get(
|
|
Constant::getIntegerValue(I1Ty, APInt(1, V)));
|
|
};
|
|
|
|
MDVals.push_back(getIntMD(Binding.UniqueID));
|
|
MDVals.push_back(ValueAsMetadata::get(Symbol));
|
|
MDVals.push_back(MDString::get(Ctx, Name));
|
|
MDVals.push_back(getIntMD(Binding.Space));
|
|
MDVals.push_back(getIntMD(Binding.LowerBound));
|
|
MDVals.push_back(getIntMD(Binding.Size));
|
|
|
|
if (isCBuffer()) {
|
|
MDVals.push_back(getIntMD(CBufferSize));
|
|
MDVals.push_back(nullptr);
|
|
} else if (isSampler()) {
|
|
MDVals.push_back(getIntMD(llvm::to_underlying(SamplerTy)));
|
|
MDVals.push_back(nullptr);
|
|
} else {
|
|
MDVals.push_back(getIntMD(llvm::to_underlying(Kind)));
|
|
|
|
if (isUAV()) {
|
|
MDVals.push_back(getBoolMD(UAVFlags.GloballyCoherent));
|
|
MDVals.push_back(getBoolMD(UAVFlags.HasCounter));
|
|
MDVals.push_back(getBoolMD(UAVFlags.IsROV));
|
|
} else {
|
|
// All SRVs include sample count in the metadata, but it's only meaningful
|
|
// for multi-sampled textured. Also, UAVs can be multisampled in SM6.7+,
|
|
// but this just isn't reflected in the metadata at all.
|
|
uint32_t SampleCount = isMultiSample() ? MultiSample.Count : 0;
|
|
MDVals.push_back(getIntMD(SampleCount));
|
|
}
|
|
|
|
// Further properties are attached to a metadata list of tag-value pairs.
|
|
SmallVector<Metadata *> Tags;
|
|
if (isStruct()) {
|
|
Tags.push_back(
|
|
getIntMD(llvm::to_underlying(ExtPropTags::StructuredBufferStride)));
|
|
Tags.push_back(getIntMD(Struct.Stride));
|
|
} else if (isTyped()) {
|
|
Tags.push_back(getIntMD(llvm::to_underlying(ExtPropTags::ElementType)));
|
|
Tags.push_back(getIntMD(llvm::to_underlying(Typed.ElementTy)));
|
|
} else if (isFeedback()) {
|
|
Tags.push_back(
|
|
getIntMD(llvm::to_underlying(ExtPropTags::SamplerFeedbackKind)));
|
|
Tags.push_back(getIntMD(llvm::to_underlying(Feedback.Type)));
|
|
}
|
|
MDVals.push_back(Tags.empty() ? nullptr : MDNode::get(Ctx, Tags));
|
|
}
|
|
|
|
return MDNode::get(Ctx, MDVals);
|
|
}
|
|
|
|
std::pair<uint32_t, uint32_t> ResourceInfo::getAnnotateProps() const {
|
|
uint32_t ResourceKind = llvm::to_underlying(Kind);
|
|
uint32_t AlignLog2 = isStruct() ? Log2(Struct.Alignment) : 0;
|
|
bool IsUAV = isUAV();
|
|
bool IsROV = IsUAV && UAVFlags.IsROV;
|
|
bool IsGloballyCoherent = IsUAV && UAVFlags.GloballyCoherent;
|
|
uint8_t SamplerCmpOrHasCounter = 0;
|
|
if (IsUAV)
|
|
SamplerCmpOrHasCounter = UAVFlags.HasCounter;
|
|
else if (isSampler())
|
|
SamplerCmpOrHasCounter = SamplerTy == SamplerType::Comparison;
|
|
|
|
// TODO: Document this format. Currently the only reference is the
|
|
// implementation of dxc's DxilResourceProperties struct.
|
|
uint32_t Word0 = 0;
|
|
Word0 |= ResourceKind & 0xFF;
|
|
Word0 |= (AlignLog2 & 0xF) << 8;
|
|
Word0 |= (IsUAV & 1) << 12;
|
|
Word0 |= (IsROV & 1) << 13;
|
|
Word0 |= (IsGloballyCoherent & 1) << 14;
|
|
Word0 |= (SamplerCmpOrHasCounter & 1) << 15;
|
|
|
|
uint32_t Word1 = 0;
|
|
if (isStruct())
|
|
Word1 = Struct.Stride;
|
|
else if (isCBuffer())
|
|
Word1 = CBufferSize;
|
|
else if (isFeedback())
|
|
Word1 = llvm::to_underlying(Feedback.Type);
|
|
else if (isTyped()) {
|
|
uint32_t CompType = llvm::to_underlying(Typed.ElementTy);
|
|
uint32_t CompCount = Typed.ElementCount;
|
|
uint32_t SampleCount = isMultiSample() ? MultiSample.Count : 0;
|
|
|
|
Word1 |= (CompType & 0xFF) << 0;
|
|
Word1 |= (CompCount & 0xFF) << 8;
|
|
Word1 |= (SampleCount & 0xFF) << 16;
|
|
}
|
|
|
|
return {Word0, Word1};
|
|
}
|
|
|
|
#define DEBUG_TYPE "dxil-resource"
|