Skip to content
25 changes: 25 additions & 0 deletions llvm/include/llvm/BinaryFormat/DXContainer.h
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,15 @@ enum class DescriptorRangeFlags : uint32_t {

LLVM_ABI ArrayRef<EnumEntry<DescriptorRangeFlags>> getDescriptorRangeFlags();

#define STATIC_SAMPLER_FLAG(Num, Enum, Flag) Enum = Num,
enum class StaticSamplerFlags : uint32_t {
#include "DXContainerConstants.def"

LLVM_MARK_AS_BITMASK_ENUM(NonNormalizedCoordinates)
};

LLVM_ABI ArrayRef<EnumEntry<StaticSamplerFlags>> getStaticSamplerFlags();

#define ROOT_PARAMETER(Val, Enum) Enum = Val,
enum class RootParameterType : uint32_t {
#include "DXContainerConstants.def"
Expand Down Expand Up @@ -813,6 +822,22 @@ struct DescriptorRange {
}
};
} // namespace v2

namespace v3 {
struct StaticSampler : public v1::StaticSampler {
uint32_t Flags;

StaticSampler() = default;
explicit StaticSampler(v1::StaticSampler &Base)
: v1::StaticSampler(Base), Flags(0U) {}

void swapBytes() {
v1::StaticSampler::swapBytes();
sys::swapByteOrder(Flags);
}
};

} // namespace v3
} // namespace RTS0

// D3D_ROOT_SIGNATURE_VERSION
Expand Down
10 changes: 10 additions & 0 deletions llvm/include/llvm/BinaryFormat/DXContainerConstants.def
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,16 @@ DESCRIPTOR_RANGE_FLAG(0x10000, DescriptorsStaticKeepingBufferBoundsChecks, DESCR
#undef DESCRIPTOR_RANGE_FLAG
#endif // DESCRIPTOR_RANGE_FLAG

// STATIC_SAMPLER_FLAG(flag value, name, flag).
#ifdef STATIC_SAMPLER_FLAG

STATIC_SAMPLER_FLAG(0x0, None, SAMPLER_FLAG_NONE)
STATIC_SAMPLER_FLAG(0x1, UintBorderColor, SAMPLER_FLAG_UINT_BORDER_COLOR)
STATIC_SAMPLER_FLAG(0x2, NonNormalizedCoordinates, SAMPLER_FLAG_NON_NORMALIZED_COORDINATES)

#undef STATIC_SAMPLER_FLAG
#endif // STATIC_SAMPLER_FLAG

#ifdef ROOT_PARAMETER

ROOT_PARAMETER(0, DescriptorTable)
Expand Down
1 change: 1 addition & 0 deletions llvm/include/llvm/Frontend/HLSL/RootSignatureValidations.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ LLVM_ABI bool verifyRangeType(uint32_t Type);
LLVM_ABI bool verifyDescriptorRangeFlag(uint32_t Version,
dxil::ResourceClass Type,
dxbc::DescriptorRangeFlags FlagsVal);
LLVM_ABI bool verifyStaticSamplerFlags(uint32_t Version, uint32_t FlagsNumber);
LLVM_ABI bool verifyNumDescriptors(uint32_t NumDescriptors);
LLVM_ABI bool verifyMipLODBias(float MipLODBias);
LLVM_ABI bool verifyMaxAnisotropy(uint32_t MaxAnisotropy);
Expand Down
2 changes: 2 additions & 0 deletions llvm/include/llvm/MC/DXContainerRootSignature.h
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,8 @@ struct StaticSampler {
uint32_t ShaderRegister;
uint32_t RegisterSpace;
dxbc::ShaderVisibility ShaderVisibility;
// Version 3 onwards:
uint32_t Flags = 0;
};

struct RootParametersContainer {
Expand Down
5 changes: 5 additions & 0 deletions llvm/include/llvm/ObjectYAML/DXContainerYAML.h
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,11 @@ struct StaticSamplerYamlDesc {
uint32_t ShaderRegister;
uint32_t RegisterSpace;
dxbc::ShaderVisibility ShaderVisibility;

LLVM_ABI uint32_t getEncodedFlags() const;

#define STATIC_SAMPLER_FLAG(Num, Enum, Flag) bool Enum = false;
#include "llvm/BinaryFormat/DXContainerConstants.def"
};

struct RootSignatureYamlDesc {
Expand Down
9 changes: 9 additions & 0 deletions llvm/lib/BinaryFormat/DXContainer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,15 @@ ArrayRef<EnumEntry<DescriptorRangeFlags>> dxbc::getDescriptorRangeFlags() {
return ArrayRef(DescriptorRangeFlagNames);
}

static const EnumEntry<StaticSamplerFlags> StaticSamplerFlagNames[] = {
#define STATIC_SAMPLER_FLAG(Val, Enum, Flag) {#Enum, StaticSamplerFlags::Enum},
#include "llvm/BinaryFormat/DXContainerConstants.def"
};

ArrayRef<EnumEntry<StaticSamplerFlags>> dxbc::getStaticSamplerFlags() {
return ArrayRef(StaticSamplerFlagNames);
}

#define SHADER_VISIBILITY(Val, Enum) {#Enum, ShaderVisibility::Enum},

static const EnumEntry<ShaderVisibility> ShaderVisibilityValues[] = {
Expand Down
6 changes: 6 additions & 0 deletions llvm/lib/Frontend/HLSL/RootSignatureMetadata.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -651,6 +651,12 @@ Error MetadataParser::validateRootSignature(
joinErrors(std::move(DeferredErrs),
make_error<RootSignatureValidationError<uint32_t>>(
"RegisterSpace", Sampler.RegisterSpace));

if (!hlsl::rootsig::verifyStaticSamplerFlags(RSD.Version, Sampler.Flags))
DeferredErrs =
joinErrors(std::move(DeferredErrs),
make_error<RootSignatureValidationError<uint32_t>>(
"Static Sampler Flag", Sampler.Flags));
}

return DeferredErrs;
Expand Down
23 changes: 22 additions & 1 deletion llvm/lib/Frontend/HLSL/RootSignatureValidations.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,9 @@ namespace rootsig {

bool verifyRootFlag(uint32_t Flags) { return (Flags & ~0xfff) == 0; }

bool verifyVersion(uint32_t Version) { return (Version == 1 || Version == 2); }
bool verifyVersion(uint32_t Version) {
return (Version == 1 || Version == 2 || Version == 3);
}

bool verifyRegisterValue(uint32_t RegisterValue) {
return RegisterValue != ~0U;
Expand Down Expand Up @@ -111,6 +113,25 @@ bool verifyDescriptorRangeFlag(uint32_t Version, dxil::ResourceClass Type,
return (Flags & ~Mask) == FlagT::None;
}

bool verifyStaticSamplerFlags(uint32_t Version, uint32_t FlagsNumber) {
uint32_t LargestValue = llvm::to_underlying(
dxbc::StaticSamplerFlags::LLVM_BITMASK_LARGEST_ENUMERATOR);
if (FlagsNumber >= NextPowerOf2(LargestValue))
return false;

dxbc::StaticSamplerFlags Flags = dxbc::StaticSamplerFlags(FlagsNumber);
if (Version <= 2)
return Flags == dxbc::StaticSamplerFlags::None;

assert(Version == 3 && "Provided invalid root signature version");

dxbc::StaticSamplerFlags Mask =
dxbc::StaticSamplerFlags::NonNormalizedCoordinates |
dxbc::StaticSamplerFlags::UintBorderColor |
dxbc::StaticSamplerFlags::None;
return (Flags | Mask) == Mask;
}

bool verifyNumDescriptors(uint32_t NumDescriptors) {
return NumDescriptors > 0;
}
Expand Down
11 changes: 8 additions & 3 deletions llvm/lib/MC/DXContainerRootSignature.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,12 @@ static uint32_t rewriteOffsetToCurrentByte(raw_svector_ostream &Stream,

size_t RootSignatureDesc::getSize() const {
uint32_t StaticSamplersOffset = computeStaticSamplersOffset();
size_t StaticSamplersSize =
StaticSamplers.size() * sizeof(dxbc::RTS0::v1::StaticSampler);
size_t StaticSamplersSize = sizeof(dxbc::RTS0::v1::StaticSampler);
if (Version > 2)
StaticSamplersSize = sizeof(dxbc::RTS0::v3::StaticSampler);

return size_t(StaticSamplersOffset) + StaticSamplersSize;
return size_t(StaticSamplersOffset) +
(StaticSamplersSize * StaticSamplers.size());
}

uint32_t RootSignatureDesc::computeRootParametersOffset() const {
Expand Down Expand Up @@ -171,6 +173,9 @@ void RootSignatureDesc::write(raw_ostream &OS) const {
support::endian::write(BOS, S.ShaderRegister, llvm::endianness::little);
support::endian::write(BOS, S.RegisterSpace, llvm::endianness::little);
support::endian::write(BOS, S.ShaderVisibility, llvm::endianness::little);

if (Version > 2)
support::endian::write(BOS, S.Flags, llvm::endianness::little);
}
assert(Storage.size() == getSize());
OS.write(Storage.data(), Storage.size());
Expand Down
3 changes: 3 additions & 0 deletions llvm/lib/ObjectYAML/DXContainerEmitter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -343,6 +343,9 @@ Error DXContainerWriter::writeParts(raw_ostream &OS) {
NewSampler.RegisterSpace = Param.RegisterSpace;
NewSampler.ShaderVisibility = Param.ShaderVisibility;

if (RS.Version > 2)
NewSampler.Flags = Param.getEncodedFlags();

RS.StaticSamplers.push_back(NewSampler);
}

Expand Down
12 changes: 12 additions & 0 deletions llvm/lib/ObjectYAML/DXContainerYAML.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,15 @@ uint32_t DXContainerYAML::DescriptorRangeYaml::getEncodedFlags() const {
return Flags;
}

uint32_t DXContainerYAML::StaticSamplerYamlDesc::getEncodedFlags() const {
uint64_t Flags = 0;
#define STATIC_SAMPLER_FLAG(Num, Enum, Flag) \
if (Enum) \
Flags |= (uint32_t)dxbc::StaticSamplerFlags::Enum;
#include "llvm/BinaryFormat/DXContainerConstants.def"
return Flags;
}

uint64_t DXContainerYAML::ShaderFeatureFlags::getEncodedFlags() {
uint64_t Flag = 0;
#define SHADER_FEATURE_FLAG(Num, DxilModuleNum, Val, Str) \
Expand Down Expand Up @@ -512,6 +521,9 @@ void MappingTraits<llvm::DXContainerYAML::StaticSamplerYamlDesc>::mapping(
IO.mapRequired("ShaderRegister", S.ShaderRegister);
IO.mapRequired("RegisterSpace", S.RegisterSpace);
IO.mapRequired("ShaderVisibility", S.ShaderVisibility);
#define STATIC_SAMPLER_FLAG(Num, Enum, Flag) \
IO.mapOptional(#Flag, S.Enum, false);
#include "llvm/BinaryFormat/DXContainerConstants.def"
}

void MappingTraits<DXContainerYAML::Part>::mapping(IO &IO,
Expand Down
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we also add an equivalent test for invalid sampler flag values?

edit: I guess we haven't added that validation in this pr yet

Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
; RUN: not opt -passes='print<dxil-root-signature>' %s -S -o - 2>&1 | FileCheck %s

target triple = "dxil-unknown-shadermodel6.0-compute"


; CHECK: error: Invalid value for Version: 4
; CHECK-NOT: Root Signature Definitions
define void @main() #0 {
entry:
ret void
}
attributes #0 = { "hlsl.numthreads"="1,1,1" "hlsl.shader"="compute" }


!dx.rootsignatures = !{!2, !3, !4, !5} ; list of function/root signature pairs
!2 = !{ ptr @main, !6, i32 1 } ; function, root signature
!3 = !{ ptr @main, !6, i32 4 } ; function, root signature
!4 = !{ ptr @main, !6, i32 2 } ; function, root signature
!5 = !{ ptr @main, !6, i32 3 } ; function, root signature
!6 = !{ } ; list of root signature elements
51 changes: 51 additions & 0 deletions llvm/unittests/ObjectYAML/DXContainerYAMLTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -526,3 +526,54 @@ TEST(RootSignature, ParseStaticSamplers) {
EXPECT_EQ(Storage.size(), 144u);
EXPECT_TRUE(memcmp(Buffer, Storage.data(), 144u) == 0);
}

TEST(RootSignature, ParseStaticSamplersV13) {
SmallString<128> Storage;

// First read a fully explicit yaml with all sizes and offsets provided
ASSERT_TRUE(convert(Storage, R"(--- !dxcontainer
Header:
Hash: [ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0 ]
Version:
Major: 1
Minor: 0
PartCount: 1
PartOffsets: [ 60 ]
Parts:
- Name: RTS0
Size: 76
RootSignature:
Version: 3
NumRootParameters: 0
RootParametersOffset: 24
NumStaticSamplers: 1
StaticSamplersOffset: 24
Parameters: []
Samplers:
- ShaderRegister: 31
RegisterSpace: 32
ShaderVisibility: All
SAMPLER_FLAG_UINT_BORDER_COLOR: true
AllowInputAssemblerInputLayout: true
DenyGeometryShaderRootAccess: true
)"));

uint8_t Buffer[] = {
0x44, 0x58, 0x42, 0x43, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x90, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x52, 0x54, 0x53, 0x30, 0x4c, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x18, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x7f, 0x7f,
0x1f, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00};

EXPECT_EQ(Storage.size(), 148U);
EXPECT_TRUE(memcmp(Buffer, Storage.data(), 148U) == 0);
}