Skip to content

[HLSL][RootSignature] Implement serialization of remaining Root Elements #143198

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Jun 17, 2025

Conversation

inbelic
Copy link
Contributor

@inbelic inbelic commented Jun 6, 2025

Implements serialization of the remaining RootElements, namely RootDescriptors and StaticSamplers.

  • Adds unit testing for the serialization methods

Resolves #138191
Resolves #138193

@llvmbot llvmbot added the HLSL HLSL Language Support label Jun 6, 2025
@llvmbot
Copy link
Member

llvmbot commented Jun 6, 2025

@llvm/pr-subscribers-hlsl

Author: Finn Plummer (inbelic)

Changes

Implements serialization of the remaining completely defined RootElements, namely RootDescriptors and RootFlags.

  • Adds unit testing for the serialization methods

Resolves #138191
Resolves #138193


Full diff: https://github.com/llvm/llvm-project/pull/143198.diff

3 Files Affected:

  • (modified) llvm/include/llvm/Frontend/HLSL/HLSLRootSignatureUtils.h (+6)
  • (modified) llvm/lib/Frontend/HLSL/HLSLRootSignatureUtils.cpp (+254)
  • (modified) llvm/unittests/Frontend/HLSLRootSignatureDumpTest.cpp (+121)
diff --git a/llvm/include/llvm/Frontend/HLSL/HLSLRootSignatureUtils.h b/llvm/include/llvm/Frontend/HLSL/HLSLRootSignatureUtils.h
index ca20e6719f3a4..7489777670703 100644
--- a/llvm/include/llvm/Frontend/HLSL/HLSLRootSignatureUtils.h
+++ b/llvm/include/llvm/Frontend/HLSL/HLSLRootSignatureUtils.h
@@ -32,6 +32,12 @@ LLVM_ABI raw_ostream &operator<<(raw_ostream &OS, const RootFlags &Flags);
 LLVM_ABI raw_ostream &operator<<(raw_ostream &OS,
                                  const RootConstants &Constants);
 
+LLVM_ABI raw_ostream &operator<<(raw_ostream &OS,
+                                 const RootDescriptor &Descriptor);
+
+LLVM_ABI raw_ostream &operator<<(raw_ostream &OS,
+                                 const StaticSampler &StaticSampler);
+
 LLVM_ABI raw_ostream &operator<<(raw_ostream &OS,
                                  const DescriptorTableClause &Clause);
 
diff --git a/llvm/lib/Frontend/HLSL/HLSLRootSignatureUtils.cpp b/llvm/lib/Frontend/HLSL/HLSLRootSignatureUtils.cpp
index 24486a55ecf6a..70c3e72c1f806 100644
--- a/llvm/lib/Frontend/HLSL/HLSLRootSignatureUtils.cpp
+++ b/llvm/lib/Frontend/HLSL/HLSLRootSignatureUtils.cpp
@@ -71,6 +71,199 @@ static raw_ostream &operator<<(raw_ostream &OS,
   return OS;
 }
 
+static raw_ostream &operator<<(raw_ostream &OS, const SamplerFilter &Filter) {
+  switch (Filter) {
+  case SamplerFilter::MinMagMipPoint:
+    OS << "MinMagMipPoint";
+    break;
+  case SamplerFilter::MinMagPointMipLinear:
+    OS << "MinMagPointMipLinear";
+    break;
+  case SamplerFilter::MinPointMagLinearMipPoint:
+    OS << "MinPointMagLinearMipPoint";
+    break;
+  case SamplerFilter::MinPointMagMipLinear:
+    OS << "MinPointMagMipLinear";
+    break;
+  case SamplerFilter::MinLinearMagMipPoint:
+    OS << "MinLinearMagMipPoint";
+    break;
+  case SamplerFilter::MinLinearMagPointMipLinear:
+    OS << "MinLinearMagPointMipLinear";
+    break;
+  case SamplerFilter::MinMagLinearMipPoint:
+    OS << "MinMagLinearMipPoint";
+    break;
+  case SamplerFilter::MinMagMipLinear:
+    OS << "MinMagMipLinear";
+    break;
+  case SamplerFilter::Anisotropic:
+    OS << "Anisotropic";
+    break;
+  case SamplerFilter::ComparisonMinMagMipPoint:
+    OS << "ComparisonMinMagMipPoint";
+    break;
+  case SamplerFilter::ComparisonMinMagPointMipLinear:
+    OS << "ComparisonMinMagPointMipLinear";
+    break;
+  case SamplerFilter::ComparisonMinPointMagLinearMipPoint:
+    OS << "ComparisonMinPointMagLinearMipPoint";
+    break;
+  case SamplerFilter::ComparisonMinPointMagMipLinear:
+    OS << "ComparisonMinPointMagMipLinear";
+    break;
+  case SamplerFilter::ComparisonMinLinearMagMipPoint:
+    OS << "ComparisonMinLinearMagMipPoint";
+    break;
+  case SamplerFilter::ComparisonMinLinearMagPointMipLinear:
+    OS << "ComparisonMinLinearMagPointMipLinear";
+    break;
+  case SamplerFilter::ComparisonMinMagLinearMipPoint:
+    OS << "ComparisonMinMagLinearMipPoint";
+    break;
+  case SamplerFilter::ComparisonMinMagMipLinear:
+    OS << "ComparisonMinMagMipLinear";
+    break;
+  case SamplerFilter::ComparisonAnisotropic:
+    OS << "ComparisonAnisotropic";
+    break;
+  case SamplerFilter::MinimumMinMagMipPoint:
+    OS << "MinimumMinMagMipPoint";
+    break;
+  case SamplerFilter::MinimumMinMagPointMipLinear:
+    OS << "MinimumMinMagPointMipLinear";
+    break;
+  case SamplerFilter::MinimumMinPointMagLinearMipPoint:
+    OS << "MinimumMinPointMagLinearMipPoint";
+    break;
+  case SamplerFilter::MinimumMinPointMagMipLinear:
+    OS << "MinimumMinPointMagMipLinear";
+    break;
+  case SamplerFilter::MinimumMinLinearMagMipPoint:
+    OS << "MinimumMinLinearMagMipPoint";
+    break;
+  case SamplerFilter::MinimumMinLinearMagPointMipLinear:
+    OS << "MinimumMinLinearMagPointMipLinear";
+    break;
+  case SamplerFilter::MinimumMinMagLinearMipPoint:
+    OS << "MinimumMinMagLinearMipPoint";
+    break;
+  case SamplerFilter::MinimumMinMagMipLinear:
+    OS << "MinimumMinMagMipLinear";
+    break;
+  case SamplerFilter::MinimumAnisotropic:
+    OS << "MinimumAnisotropic";
+    break;
+  case SamplerFilter::MaximumMinMagMipPoint:
+    OS << "MaximumMinMagMipPoint";
+    break;
+  case SamplerFilter::MaximumMinMagPointMipLinear:
+    OS << "MaximumMinMagPointMipLinear";
+    break;
+  case SamplerFilter::MaximumMinPointMagLinearMipPoint:
+    OS << "MaximumMinPointMagLinearMipPoint";
+    break;
+  case SamplerFilter::MaximumMinPointMagMipLinear:
+    OS << "MaximumMinPointMagMipLinear";
+    break;
+  case SamplerFilter::MaximumMinLinearMagMipPoint:
+    OS << "MaximumMinLinearMagMipPoint";
+    break;
+  case SamplerFilter::MaximumMinLinearMagPointMipLinear:
+    OS << "MaximumMinLinearMagPointMipLinear";
+    break;
+  case SamplerFilter::MaximumMinMagLinearMipPoint:
+    OS << "MaximumMinMagLinearMipPoint";
+    break;
+  case SamplerFilter::MaximumMinMagMipLinear:
+    OS << "MaximumMinMagMipLinear";
+    break;
+  case SamplerFilter::MaximumAnisotropic:
+    OS << "MaximumAnisotropic";
+    break;
+  }
+
+  return OS;
+}
+
+static raw_ostream &operator<<(raw_ostream &OS,
+                               const TextureAddressMode &Address) {
+  switch (Address) {
+  case TextureAddressMode::Wrap:
+    OS << "Wrap";
+    break;
+  case TextureAddressMode::Mirror:
+    OS << "Mirror";
+    break;
+  case TextureAddressMode::Clamp:
+    OS << "Clamp";
+    break;
+  case TextureAddressMode::Border:
+    OS << "Border";
+    break;
+  case TextureAddressMode::MirrorOnce:
+    OS << "MirrorOnce";
+    break;
+  }
+
+  return OS;
+}
+
+static raw_ostream &operator<<(raw_ostream &OS,
+                               const ComparisonFunc &CompFunc) {
+  switch (CompFunc) {
+  case ComparisonFunc::Never:
+    OS << "Never";
+    break;
+  case ComparisonFunc::Less:
+    OS << "Less";
+    break;
+  case ComparisonFunc::Equal:
+    OS << "Equal";
+    break;
+  case ComparisonFunc::LessEqual:
+    OS << "LessEqual";
+    break;
+  case ComparisonFunc::Greater:
+    OS << "Greater";
+    break;
+  case ComparisonFunc::NotEqual:
+    OS << "NotEqual";
+    break;
+  case ComparisonFunc::GreaterEqual:
+    OS << "GreaterEqual";
+    break;
+  case ComparisonFunc::Always:
+    OS << "Always";
+    break;
+  }
+
+  return OS;
+}
+
+static raw_ostream &operator<<(raw_ostream &OS,
+                               const StaticBorderColor &BorderColor) {
+  switch (BorderColor) {
+  case StaticBorderColor::TransparentBlack:
+    OS << "TransparentBlack";
+    break;
+  case StaticBorderColor::OpaqueBlack:
+    OS << "OpaqueBlack";
+    break;
+  case StaticBorderColor::OpaqueWhite:
+    OS << "OpaqueWhite";
+    break;
+  case StaticBorderColor::OpaqueBlackUint:
+    OS << "OpaqueBlackUint";
+    break;
+  case StaticBorderColor::OpaqueWhiteUint:
+    OS << "OpaqueWhiteUint";
+    break;
+  }
+
+  return OS;
+}
+
 static raw_ostream &operator<<(raw_ostream &OS, const ClauseType &Type) {
   switch (Type) {
   case ClauseType::CBuffer:
@@ -132,6 +325,42 @@ static raw_ostream &operator<<(raw_ostream &OS,
   return OS;
 }
 
+static raw_ostream &operator<<(raw_ostream &OS,
+                               const RootDescriptorFlags &Flags) {
+  bool FlagSet = false;
+  unsigned Remaining = llvm::to_underlying(Flags);
+  while (Remaining) {
+    unsigned Bit = 1u << llvm::countr_zero(Remaining);
+    if (Remaining & Bit) {
+      if (FlagSet)
+        OS << " | ";
+
+      switch (static_cast<RootDescriptorFlags>(Bit)) {
+      case RootDescriptorFlags::DataVolatile:
+        OS << "DataVolatile";
+        break;
+      case RootDescriptorFlags::DataStaticWhileSetAtExecute:
+        OS << "DataStaticWhileSetAtExecute";
+        break;
+      case RootDescriptorFlags::DataStatic:
+        OS << "DataStatic";
+        break;
+      default:
+        OS << "invalid: " << Bit;
+        break;
+      }
+
+      FlagSet = true;
+    }
+    Remaining &= ~Bit;
+  }
+
+  if (!FlagSet)
+    OS << "None";
+
+  return OS;
+}
+
 raw_ostream &operator<<(raw_ostream &OS, const RootFlags &Flags) {
   OS << "RootFlags(";
   bool FlagSet = false;
@@ -205,6 +434,31 @@ raw_ostream &operator<<(raw_ostream &OS, const RootConstants &Constants) {
   return OS;
 }
 
+raw_ostream &operator<<(raw_ostream &OS, const RootDescriptor &Descriptor) {
+  ClauseType Type = ClauseType(llvm::to_underlying(Descriptor.Type));
+  OS << "Root" << Type << "(" << Descriptor.Reg
+     << ", space = " << Descriptor.Space
+     << ", visibility = " << Descriptor.Visibility
+     << ", flags = " << Descriptor.Flags << ")";
+
+  return OS;
+}
+
+raw_ostream &operator<<(raw_ostream &OS, const StaticSampler &Sampler) {
+  OS << "StaticSampler(" << Sampler.Reg << ", filter = " << Sampler.Filter
+     << ", addressU = " << Sampler.AddressU
+     << ", addressV = " << Sampler.AddressV
+     << ", addressW = " << Sampler.AddressW
+     << ", mipLODBias = " << Sampler.MipLODBias
+     << ", maxAnisotropy = " << Sampler.MaxAnisotropy
+     << ", comparisonFunc = " << Sampler.CompFunc
+     << ", borderColor = " << Sampler.BorderColor
+     << ", minLOD = " << Sampler.MinLOD << ", maxLOD = " << Sampler.MaxLOD
+     << ", space = " << Sampler.Space << ", visibility = " << Sampler.Visibility
+     << ")";
+  return OS;
+}
+
 raw_ostream &operator<<(raw_ostream &OS, const DescriptorTable &Table) {
   OS << "DescriptorTable(numClauses = " << Table.NumClauses
      << ", visibility = " << Table.Visibility << ")";
diff --git a/llvm/unittests/Frontend/HLSLRootSignatureDumpTest.cpp b/llvm/unittests/Frontend/HLSLRootSignatureDumpTest.cpp
index 1a0c8e2a16396..831c5dd585fab 100644
--- a/llvm/unittests/Frontend/HLSLRootSignatureDumpTest.cpp
+++ b/llvm/unittests/Frontend/HLSLRootSignatureDumpTest.cpp
@@ -177,4 +177,125 @@ TEST(HLSLRootSignatureTest, AllRootFlagsDump) {
   EXPECT_EQ(Out, Expected);
 }
 
+TEST(HLSLRootSignatureTest, RootCBVDump) {
+  RootDescriptor Descriptor;
+  Descriptor.Type = DescriptorType::CBuffer;
+  Descriptor.Reg = {RegisterType::BReg, 0};
+  Descriptor.setDefaultFlags();
+
+  std::string Out;
+  llvm::raw_string_ostream OS(Out);
+  OS << Descriptor;
+  OS.flush();
+
+  std::string Expected = "RootCBV(b0, space = 0, "
+                         "visibility = All, "
+                         "flags = DataStaticWhileSetAtExecute)";
+  EXPECT_EQ(Out, Expected);
+}
+
+TEST(HLSLRootSignatureTest, RootSRVDump) {
+  RootDescriptor Descriptor;
+  Descriptor.Type = DescriptorType::SRV;
+  Descriptor.Reg = {RegisterType::TReg, 0};
+  Descriptor.Space = 42;
+  Descriptor.Visibility = ShaderVisibility::Geometry;
+  Descriptor.Flags = RootDescriptorFlags::None;
+
+  std::string Out;
+  llvm::raw_string_ostream OS(Out);
+  OS << Descriptor;
+  OS.flush();
+
+  std::string Expected =
+      "RootSRV(t0, space = 42, visibility = Geometry, flags = None)";
+  EXPECT_EQ(Out, Expected);
+}
+
+TEST(HLSLRootSignatureTest, RootUAVDump) {
+  RootDescriptor Descriptor;
+  Descriptor.Type = DescriptorType::UAV;
+  Descriptor.Reg = {RegisterType::UReg, 92374};
+  Descriptor.Space = 932847;
+  Descriptor.Visibility = ShaderVisibility::Hull;
+  Descriptor.Flags = RootDescriptorFlags::ValidFlags;
+
+  std::string Out;
+  llvm::raw_string_ostream OS(Out);
+  OS << Descriptor;
+  OS.flush();
+
+  std::string Expected =
+      "RootUAV(u92374, space = 932847, visibility = Hull, flags = "
+      "DataVolatile | "
+      "DataStaticWhileSetAtExecute | "
+      "DataStatic)";
+  EXPECT_EQ(Out, Expected);
+}
+
+TEST(HLSLRootSignatureTest, DefaultStaticSamplerDump) {
+  StaticSampler Sampler;
+  Sampler.Reg = {RegisterType::SReg, 0};
+
+  std::string Out;
+  llvm::raw_string_ostream OS(Out);
+  OS << Sampler;
+  OS.flush();
+
+  std::string Expected = "StaticSampler(s0, "
+                         "filter = Anisotropic, "
+                         "addressU = Wrap, "
+                         "addressV = Wrap, "
+                         "addressW = Wrap, "
+                         "mipLODBias = 0.000000e+00, "
+                         "maxAnisotropy = 16, "
+                         "comparisonFunc = LessEqual, "
+                         "borderColor = OpaqueWhite, "
+                         "minLOD = 0.000000e+00, "
+                         "maxLOD = 3.402823e+38, "
+                         "space = 0, "
+                         "visibility = All"
+                         ")";
+  EXPECT_EQ(Out, Expected);
+}
+
+TEST(HLSLRootSignatureTest, DefinedStaticSamplerDump) {
+  StaticSampler Sampler;
+  Sampler.Reg = {RegisterType::SReg, 0};
+
+  Sampler.Filter = SamplerFilter::ComparisonMinMagLinearMipPoint;
+  Sampler.AddressU = TextureAddressMode::Mirror;
+  Sampler.AddressV = TextureAddressMode::Border;
+  Sampler.AddressW = TextureAddressMode::Clamp;
+  Sampler.MipLODBias = 4.8f;
+  Sampler.MaxAnisotropy = 32;
+  Sampler.CompFunc = ComparisonFunc::NotEqual;
+  Sampler.BorderColor = StaticBorderColor::OpaqueBlack;
+  Sampler.MinLOD = 1.0f;
+  Sampler.MaxLOD = 32.0f;
+  Sampler.Space = 7;
+  Sampler.Visibility = ShaderVisibility::Domain;
+
+  std::string Out;
+  llvm::raw_string_ostream OS(Out);
+  OS << Sampler;
+  OS.flush();
+
+  std::string Expected = "StaticSampler(s0, "
+                         "filter = ComparisonMinMagLinearMipPoint, "
+                         "addressU = Mirror, "
+                         "addressV = Border, "
+                         "addressW = Clamp, "
+                         "mipLODBias = 4.800000e+00, "
+                         "maxAnisotropy = 32, "
+                         "comparisonFunc = NotEqual, "
+                         "borderColor = OpaqueBlack, "
+                         "minLOD = 1.000000e+00, "
+                         "maxLOD = 3.200000e+01, "
+                         "space = 7, "
+                         "visibility = Domain"
+                         ")";
+  EXPECT_EQ(Out, Expected);
+}
+
 } // namespace

static raw_ostream &operator<<(raw_ostream &OS, const SamplerFilter &Filter) {
switch (Filter) {
case SamplerFilter::MinMagMipPoint:
OS << "MinMagMipPoint";
Copy link
Collaborator

Choose a reason for hiding this comment

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

Could we instead use llvm::EnumEntry from llvm::ScopedPrinter to translate enums to strings? That allows the mechanism to be reused rather than single purpose.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes! Thank you

@inbelic inbelic marked this pull request as draft June 6, 2025 21:22
inbelic added a commit that referenced this pull request Jun 16, 2025
…Signature Elements (#144106)

It has pointed out
[here](#143198 (comment))
that we may be able to use `llvm::EnumEntry` so that we can re-use the
printing logic across enumerations.

- Enables re-use of `printEnum` and `printFlags` methods via templates
- Allows easy definition of `getEnumName` function for enum-to-string
conversion, eliminating the need to use a string stream for constructing
the Name SmallString

- Also, does a small fix-up of the operands for descriptor table clause
to be consistent with other `Build*` methods

For reference, the
[test-cases](https://github.com/llvm/llvm-project/blob/main/llvm/unittests/Frontend/HLSLRootSignatureDumpTest.cpp)
that must not change expected output.
llvm-sync bot pushed a commit to arm/arm-toolchain that referenced this pull request Jun 16, 2025
…on of Root Signature Elements (#144106)

It has pointed out
[here](llvm/llvm-project#143198 (comment))
that we may be able to use `llvm::EnumEntry` so that we can re-use the
printing logic across enumerations.

- Enables re-use of `printEnum` and `printFlags` methods via templates
- Allows easy definition of `getEnumName` function for enum-to-string
conversion, eliminating the need to use a string stream for constructing
the Name SmallString

- Also, does a small fix-up of the operands for descriptor table clause
to be consistent with other `Build*` methods

For reference, the
[test-cases](https://github.com/llvm/llvm-project/blob/main/llvm/unittests/Frontend/HLSLRootSignatureDumpTest.cpp)
that must not change expected output.
@inbelic inbelic changed the base branch from users/inbelic/pr-143019 to main June 16, 2025 21:19
@inbelic inbelic force-pushed the inbelic/rs-serial-rem branch from 9ae5c63 to aaa46bc Compare June 16, 2025 21:19
@inbelic inbelic marked this pull request as ready for review June 16, 2025 21:20
Copy link
Contributor

@kmpeng kmpeng left a comment

Choose a reason for hiding this comment

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

LGTM!

@inbelic inbelic merged commit 87b13ad into llvm:main Jun 17, 2025
8 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
HLSL HLSL Language Support
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[HLSL] Implement serialization of StaticSamplers [HLSL] Implement serialization of Root Descriptors
5 participants