Ver Fonte

Add Subobjects: classes, metadata, serialization, reflection, disasm

Tex Riddell há 6 anos atrás
pai
commit
9678588269

+ 25 - 0
include/dxc/DXIL/DxilConstants.h

@@ -1131,6 +1131,31 @@ namespace DXIL {
 
   const unsigned ShaderFeatureInfoCount = 19;
 
+  // DxilSubobjectType must match D3D12_STATE_SUBOBJECT_TYPE, with
+  // certain values reserved, since they cannot be used from Dxil.
+  enum class SubobjectKind : uint32_t {
+    StateObjectConfig                 = 0,
+    GlobalRootSignature               = 1,
+    LocalRootSignature                = 2,
+    // 3-7 are reserved (not supported in Dxil)
+    SubobjectToExportsAssociation     = 8,
+    RaytracingShaderConfig            = 9,
+    RaytracingPipelineConfig          = 10,
+    HitGroup                          = 11,
+    NumKinds // aka D3D12_STATE_SUBOBJECT_TYPE_MAX_VALID
+  };
+  inline bool IsValidSubobjectKind(SubobjectKind kind) {
+    return (kind < SubobjectKind::NumKinds &&
+      ( kind <= SubobjectKind::LocalRootSignature ||
+        kind >= SubobjectKind::SubobjectToExportsAssociation));
+  }
+
+  enum class StateObjectFlags : uint32_t {
+    AllowLocalDependenciesOnExternalDefinitions = 0x1,
+    AllowExternalDependenciesOnLocalDefinitions = 0x2,
+    ValidMask = 0x3,
+  };
+
   extern const char* kLegacyLayoutString;
   extern const char* kNewLayoutString;
   extern const char* kFP32DenormKindString;

+ 12 - 0
include/dxc/DXIL/DxilMetadataHelper.h

@@ -29,6 +29,7 @@ class MDTuple;
 class MDNode;
 class NamedMDNode;
 class GlobalVariable;
+class StringRef;
 }
 
 namespace hlsl {
@@ -49,6 +50,8 @@ class DxilFunctionAnnotation;
 class DxilParameterAnnotation;
 class RootSignatureHandle;
 struct DxilFunctionProps;
+class DxilSubobjects;
+class DxilSubobject;
 
 /// Use this class to manipulate DXIL-spcific metadata.
 // In our code, only DxilModule and HLModule should use this class.
@@ -80,6 +83,9 @@ public:
   // ViewId state.
   static const char kDxilViewIdStateMDName[];
 
+  // Subobjects
+  static const char kDxilSubobjectsMDName[];
+
   // Source info.
   static const char kDxilSourceContentsMDName[];
   static const char kDxilSourceDefinesMDName[];
@@ -357,6 +363,11 @@ public:
   // Control flow hints.
   static llvm::MDNode *EmitControlFlowHints(llvm::LLVMContext &Ctx, std::vector<DXIL::ControlFlowHint> &hints);
 
+  // Subobjects
+  void EmitSubobjects(const DxilSubobjects &Subobjects);
+  void LoadSubobjects(DxilSubobjects &Subobjects);
+  llvm::Metadata *EmitSubobject(const DxilSubobject &obj);
+  void LoadSubobject(const llvm::MDNode &MDO, DxilSubobjects &Subobjects);
 
   // Shader specific.
 private:
@@ -408,6 +419,7 @@ public:
   static bool ConstMDToBool(const llvm::MDOperand &MDO);
   static float ConstMDToFloat(const llvm::MDOperand &MDO);
   static std::string StringMDToString(const llvm::MDOperand &MDO);
+  static llvm::StringRef StringMDToStringRef(const llvm::MDOperand &MDO);
   static llvm::Value *ValueMDToValue(const llvm::MDOperand &MDO);
   llvm::MDTuple *Uint32VectorToConstMDTuple(const std::vector<unsigned> &Vec);
   void ConstMDTupleToUint32Vector(llvm::MDTuple *pTupleMD, std::vector<unsigned> &Vec);

+ 11 - 1
include/dxc/DXIL/DxilModule.h

@@ -11,13 +11,14 @@
 
 #pragma once
 
+#include "dxc/DXIL/DxilConstants.h"
 #include "dxc/DXIL/DxilMetadataHelper.h"
 #include "dxc/DXIL/DxilCBuffer.h"
 #include "dxc/DXIL/DxilResource.h"
 #include "dxc/DXIL/DxilSampler.h"
 #include "dxc/DXIL/DxilShaderFlags.h"
 #include "dxc/DXIL/DxilSignature.h"
-#include "dxc/DXIL/DxilConstants.h"
+#include "dxc/DXIL/DxilSubobject.h"
 #include "dxc/DXIL/DxilTypeSystem.h"
 
 #include <memory>
@@ -147,6 +148,8 @@ public:
 
   // Remove Root Signature from module metadata
   void StripRootSignatureFromMetadata();
+  // Remove Subobjects from module metadata
+  void StripSubobjectsFromMetadata();
   // Update validator version metadata to current setting
   void UpdateValidatorVersionMetadata();
 
@@ -268,6 +271,11 @@ public:
 
   void SetShaderProperties(DxilFunctionProps *props);
 
+  DxilSubobjects *GetSubobjects();
+  const DxilSubobjects *GetSubobjects() const;
+  DxilSubobjects *ReleaseSubobjects();
+  void ResetSubobjects(DxilSubobjects *subobjects);
+
 private:
   // Signatures.
   std::vector<uint8_t> m_SerializedRootSignature;
@@ -326,6 +334,8 @@ private:
   bool m_bUseMinPrecision;
   bool m_bAllResourcesBound;
   uint32_t m_AutoBindingSpace;
+
+  std::unique_ptr<DxilSubobjects> m_pSubobjects;
 };
 
 } // namespace hlsl

+ 154 - 0
include/dxc/DXIL/DxilSubobject.h

@@ -0,0 +1,154 @@
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// DxilSubobject.h                                                           //
+// Copyright (C) Microsoft Corporation. All rights reserved.                 //
+// This file is distributed under the University of Illinois Open Source     //
+// License. See LICENSE.TXT for details.                                     //
+//                                                                           //
+// Defines Subobject types for DxilModule.                                   //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+#pragma once
+
+#include <vector>
+#include <memory>
+#include <unordered_map>
+#include <map>
+#include "DxilConstants.h"
+#include "llvm/ADT/MapVector.h"
+#include "llvm/ADT/StringRef.h"
+
+using namespace llvm;
+
+namespace hlsl {
+
+class DxilSubobjects;
+
+class DxilSubobject {
+public:
+  using Kind = DXIL::SubobjectKind;
+
+  DxilSubobject() = delete;
+  DxilSubobject(const DxilSubobject &other) = delete;
+  DxilSubobject(DxilSubobject &&other);
+  ~DxilSubobject();
+
+  DxilSubobject &operator=(const DxilSubobject &other) = delete;
+
+  Kind GetKind() const { return m_Kind; }
+  llvm::StringRef GetName() const { return m_Name; }
+
+  // Note: strings and root signature data is owned by DxilModule
+  // When creating subobjects, use canonical strings from module
+
+
+  bool GetStateObjectConfig(uint32_t &Flags) const;
+  bool GetRootSignature(bool local, const void * &Data, uint32_t &Size) const;
+  bool GetSubobjectToExportsAssociation(llvm::StringRef &Subobject,
+                                        const char * const * &Exports,
+                                        uint32_t &NumExports) const;
+  bool GetRaytracingShaderConfig(uint32_t &MaxPayloadSizeInBytes,
+                                 uint32_t &MaxAttributeSizeInBytes) const;
+  bool GetRaytracingPipelineConfig(uint32_t &MaxTraceRecursionDepth) const;
+  bool GetHitGroup(llvm::StringRef &Intersection,
+                   llvm::StringRef &AnyHit,
+                   llvm::StringRef &ClosestHit) const;
+
+private:
+  DxilSubobject(DxilSubobjects &owner, Kind kind, llvm::StringRef name);
+  DxilSubobject(DxilSubobjects &owner, const DxilSubobject &other, llvm::StringRef name);
+  void CopyUnionedContents(const DxilSubobject &other);
+  void InternStrings();
+
+  DxilSubobjects &m_Owner;
+  Kind m_Kind;
+  llvm::StringRef m_Name;
+
+  std::vector<const char*> m_Exports;
+
+  union {
+    struct {
+      uint32_t Flags;   // DXIL::StateObjectFlags
+    } StateObjectConfig;
+    struct {
+      uint32_t Size;
+      const void *Data;
+    } RootSignature;
+    struct {
+      const char *Subobject;
+      // see m_Exports for export list
+    } SubobjectToExportsAssociation;
+    struct {
+      uint32_t MaxPayloadSizeInBytes;
+      uint32_t MaxAttributeSizeInBytes;
+    } RaytracingShaderConfig;
+    struct {
+      uint32_t MaxTraceRecursionDepth;
+    } RaytracingPipelineConfig;
+    struct {
+      const char *Intersection;
+      const char *AnyHit;
+      const char *ClosestHit;
+    } HitGroup;
+  };
+
+  friend class DxilSubobjects;
+};
+
+class DxilSubobjects {
+public:
+  typedef llvm::MapVector< llvm::StringRef, std::string > StringStorage;
+  typedef llvm::MapVector< const void*, std::vector<char> > RawBytesStorage;
+  typedef llvm::MapVector< llvm::StringRef, std::unique_ptr<DxilSubobject> > SubobjectStorage;
+  using Kind = DXIL::SubobjectKind;
+
+  DxilSubobjects();
+  DxilSubobjects(const DxilSubobjects &other) = delete;
+  DxilSubobjects(DxilSubobjects &&other);
+  ~DxilSubobjects();
+
+  DxilSubobjects &operator=(const DxilSubobjects &other) = delete;
+
+  // Add/find string in owned subobject strings, returning canonical ptr
+  llvm::StringRef GetSubobjectString(StringRef value);
+  // Add/find raw bytes, returning canonical ptr
+  const void *GetRawBytes(const void *ptr, size_t size);
+  DxilSubobject *FindSubobject(StringRef name);
+  void RemoveSubobject(StringRef name);
+  DxilSubobject &CloneSubobject(const DxilSubobject &Subobject, llvm::StringRef Name);
+  const SubobjectStorage &GetSubobjects() const { return m_Subobjects;  }
+
+  // Create DxilSubobjects
+
+  DxilSubobject &CreateStateObjectConfig(llvm::StringRef Name,
+                                         uint32_t Flags);
+  // Local/Global RootSignature
+  DxilSubobject &CreateRootSignature(llvm::StringRef Name,
+                                     bool local,
+                                     const void *Data,
+                                     uint32_t Size);
+  DxilSubobject &CreateSubobjectToExportsAssociation(
+    llvm::StringRef Name,
+    llvm::StringRef Subobject, const char * const *Exports, uint32_t NumExports);
+  DxilSubobject &CreateRaytracingShaderConfig(
+    llvm::StringRef Name,
+    uint32_t MaxPayloadSizeInBytes,
+    uint32_t MaxAttributeSizeInBytes);
+  DxilSubobject &CreateRaytracingPipelineConfig(
+    llvm::StringRef Name,
+    uint32_t MaxTraceRecursionDepth);
+  DxilSubobject &CreateHitGroup(llvm::StringRef Name,
+                                llvm::StringRef Intersection,
+                                llvm::StringRef AnyHit,
+                                llvm::StringRef ClosestHit);
+
+private:
+  DxilSubobject &CreateSubobject(Kind kind, llvm::StringRef Name);
+
+  StringStorage m_StringStorage;
+  RawBytesStorage m_RawBytesStorage;
+  SubobjectStorage m_Subobjects;
+};
+
+} // namespace hlsl

+ 206 - 12
include/dxc/HLSL/DxilRuntimeReflection.h

@@ -30,17 +30,20 @@ namespace RDAT {
 //    - else if part.Type is Index:
 //      uint32_t IndexData[part.Size / 4];
 
-enum class RuntimeDataPartType : uint32_t { // TODO: Rename: PartType
-  Invalid = 0,
-  StringBuffer = 1,
-  IndexArrays = 2,
-  ResourceTable = 3,
-  FunctionTable = 4,
+enum class RuntimeDataPartType : uint32_t {
+  Invalid         = 0,
+  StringBuffer    = 1,
+  IndexArrays     = 2,
+  ResourceTable   = 3,
+  FunctionTable   = 4,
+  RawBytes        = 5,
+  SubobjectTable  = 6,
 };
 
 enum RuntimeDataVersion {
   // Cannot be mistaken for part count from prerelease version
-  RDAT_Version_0 = 0x10,
+  RDAT_Version_10 = 0x10,
+  RDAT_Version_11 = 0x11,
 };
 
 struct RuntimeDataHeader {
@@ -165,7 +168,7 @@ struct RuntimeDataFunctionInfo {
   uint32_t FunctionDependencies; // index to a list of functions that function
                                  // depends on
   uint32_t ShaderKind;
-  uint32_t PayloadSizeInBytes;   // 1) hit, miss, or closest shader: payload count
+  uint32_t PayloadSizeInBytes;   // 1) any/closest hit or miss shader: payload size
                                  // 2) call shader: parameter size 
   uint32_t AttributeSizeInBytes; // attribute size for closest hit and any hit
   uint32_t FeatureInfo1;         // first 32 bits of feature flag
@@ -174,14 +177,62 @@ struct RuntimeDataFunctionInfo {
   uint32_t MinShaderTarget;      // minimum shader target.
 };
 
+class RawBytesReader {
+  const void *m_table;
+  uint32_t m_size;
+public:
+  RawBytesReader() : m_table(nullptr), m_size(0) {}
+  RawBytesReader(const void *table, uint32_t size)
+      : m_table(table), m_size(size) {}
+  const void *Get(uint32_t offset) const {
+    _Analysis_assume_(offset < m_size && m_table);
+    return (const void*)(((const char*)m_table) + offset);
+  }
+};
+
+struct RuntimeDataSobobjectInfo {
+  uint32_t Kind;
+  uint32_t Name;
+  union {
+    struct {
+      uint32_t Flags;
+    } StateObjectConfig;
+    struct {
+      uint32_t RawBytesOffset;
+      uint32_t SizeInBytes;
+    } RootSignature;
+    struct {
+      uint32_t Sobobject;       // string table offset for name of subobject
+      uint32_t Exports;         // index table offset for array of string table offsets for export names
+    } SubobjectToExportsAssociation;
+    struct {
+      uint32_t MaxPayloadSizeInBytes;
+      uint32_t MaxAttributeSizeInBytes;
+    } RaytracingShaderConfig;
+    struct {
+      uint32_t MaxTraceRecursionDepth;
+    } RaytracingPipelineConfig;
+    struct {
+      // each is a string table offset for the shader name
+      // 0 points to empty name, indicating no shader.
+      uint32_t Intersection;
+      uint32_t AnyHit;
+      uint32_t ClosestHit;
+    } HitGroup;
+  };
+};
+
 class ResourceTableReader;
 class FunctionTableReader;
+class SubobjectTableReader;
 
 struct RuntimeDataContext {
   StringTableReader *pStringTableReader;
   IndexTableReader *pIndexTableReader;
+  RawBytesReader *pRawBytesReader;
   ResourceTableReader *pResourceTableReader;
   FunctionTableReader *pFunctionTableReader;
+  SubobjectTableReader *pSubobjectTableReader;
 };
 
 class ResourceReader {
@@ -379,20 +430,132 @@ public:
 class FunctionTableReader {
 private:
   TableReader m_Table;
-  RuntimeDataContext *m_context;
+  RuntimeDataContext *m_Context;
 
 public:
-  FunctionTableReader() : m_context(nullptr) {}
+  FunctionTableReader() : m_Context(nullptr) {}
 
   FunctionReader GetItem(uint32_t i) const {
-    return FunctionReader(m_Table.Row<RuntimeDataFunctionInfo>(i), m_context);
+    return FunctionReader(m_Table.Row<RuntimeDataFunctionInfo>(i), m_Context);
   }
   uint32_t GetNumFunctions() const { return m_Table.Count(); }
 
   void SetFunctionInfo(const char *ptr, uint32_t count, uint32_t recordStride) {
     m_Table.Init(ptr, count, recordStride);
   }
-  void SetContext(RuntimeDataContext *context) { m_context = context; }
+  void SetContext(RuntimeDataContext *context) { m_Context = context; }
+};
+
+class SubobjectReader {
+private:
+  const RuntimeDataSobobjectInfo *m_SubobjectInfo;
+  RuntimeDataContext *m_Context;
+
+public:
+  SubobjectReader(const RuntimeDataSobobjectInfo *info, RuntimeDataContext *context)
+    : m_SubobjectInfo(info), m_Context(context) {}
+
+  DXIL::SubobjectKind GetKind() const {
+    return m_SubobjectInfo ? (DXIL::SubobjectKind)(m_SubobjectInfo->Kind) :
+                             (DXIL::SubobjectKind)(-1);
+  }
+  const char *GetName() const {
+    return m_SubobjectInfo && m_SubobjectInfo->Name ?
+      m_Context->pStringTableReader->Get(m_SubobjectInfo->Name) : "";
+  }
+
+  // StateObjectConfig
+  uint32_t GetStateObjectConfig_Flags() const {
+    return (GetKind() == DXIL::SubobjectKind::StateObjectConfig) ?
+      m_SubobjectInfo->StateObjectConfig.Flags : (uint32_t)0;
+  }
+
+  // [Global|Local]RootSignature
+  // returns true if valid non-zero-length buffer found and set to output params
+  bool GetRootSignature(const void **ppOutBytes, uint32_t *pOutSizeInBytes) const {
+    if (!ppOutBytes || !pOutSizeInBytes)
+      return false;
+    if (m_SubobjectInfo &&
+        ( GetKind() == DXIL::SubobjectKind::GlobalRootSignature ||
+          GetKind() == DXIL::SubobjectKind::LocalRootSignature ) &&
+        m_SubobjectInfo->RootSignature.SizeInBytes > 0) {
+      *ppOutBytes = m_Context->pRawBytesReader->Get(m_SubobjectInfo->RootSignature.RawBytesOffset);
+      *pOutSizeInBytes = m_SubobjectInfo->RootSignature.SizeInBytes;
+      return true;
+    } else {
+      *ppOutBytes = nullptr;
+      *pOutSizeInBytes = 0;
+    }
+    return false;
+  }
+
+  // SubobjectToExportsAssociation
+  const char *GetSubobjectToExportsAssociation_Subobject() const {
+    return (GetKind() == DXIL::SubobjectKind::SubobjectToExportsAssociation) ?
+      m_Context->pStringTableReader->Get(m_SubobjectInfo->SubobjectToExportsAssociation.Sobobject) : "";
+  }
+  uint32_t GetSubobjectToExportsAssociation_NumExports() const {
+    return (GetKind() == DXIL::SubobjectKind::SubobjectToExportsAssociation) ?
+      m_Context->pIndexTableReader->getRow(m_SubobjectInfo->SubobjectToExportsAssociation.Exports).Count() : 0;
+  }
+  const char *GetSubobjectToExportsAssociation_Export(uint32_t index) const {
+    if (!(GetKind() == DXIL::SubobjectKind::SubobjectToExportsAssociation))
+      return "";
+    auto row = m_Context->pIndexTableReader->getRow(
+      m_SubobjectInfo->SubobjectToExportsAssociation.Exports);
+    if (index >= row.Count())
+      return "";
+    return m_Context->pStringTableReader->Get(row.At(index));
+  }
+
+  // RaytracingShaderConfig
+  uint32_t GetRaytracingShaderConfig_MaxPayloadSizeInBytes() const {
+    return (GetKind() == DXIL::SubobjectKind::RaytracingShaderConfig) ?
+      m_SubobjectInfo->RaytracingShaderConfig.MaxPayloadSizeInBytes : 0;
+  }
+  uint32_t GetRaytracingShaderConfig_MaxAttributeSizeInBytes() const {
+    return (GetKind() == DXIL::SubobjectKind::RaytracingShaderConfig) ?
+      m_SubobjectInfo->RaytracingShaderConfig.MaxAttributeSizeInBytes : 0;
+  }
+
+  // RaytracingPipelineConfig
+  uint32_t GetRaytracingPipelineConfig_MaxTraceRecursionDepth() const {
+    return (GetKind() == DXIL::SubobjectKind::RaytracingPipelineConfig) ?
+      m_SubobjectInfo->RaytracingPipelineConfig.MaxTraceRecursionDepth : 0;
+  }
+
+  // HitGroup
+  const char *GetHitGroup_Intersection() const {
+    return (GetKind() == DXIL::SubobjectKind::HitGroup) ?
+      m_Context->pStringTableReader->Get(m_SubobjectInfo->HitGroup.Intersection) : "";
+  }
+  const char *GetHitGroup_AnyHit() const {
+    return (GetKind() == DXIL::SubobjectKind::HitGroup) ?
+      m_Context->pStringTableReader->Get(m_SubobjectInfo->HitGroup.AnyHit) : "";
+  }
+  const char *GetHitGroup_ClosestHit() const {
+    return (GetKind() == DXIL::SubobjectKind::HitGroup) ?
+      m_Context->pStringTableReader->Get(m_SubobjectInfo->HitGroup.ClosestHit) : "";
+  }
+};
+
+class SubobjectTableReader {
+private:
+  TableReader m_Table;
+  RuntimeDataContext *m_Context;
+
+public:
+  SubobjectTableReader() : m_Context(nullptr) {}
+
+  void SetContext(RuntimeDataContext *context) { m_Context = context; }
+  void SetSubobjectInfo(const char *ptr, uint32_t count, uint32_t recordStride) {
+    m_Table.Init(ptr, count, recordStride);
+  }
+
+  uint32_t GetCount() const { return m_Table.Count(); }
+  SubobjectReader GetItem(uint32_t i) const {
+    return SubobjectReader(m_Table.Row<RuntimeDataSobobjectInfo>(i), m_Context);
+  }
 };
 
 class DxilRuntimeData {
@@ -400,8 +563,10 @@ private:
   uint32_t m_TableCount;
   StringTableReader m_StringReader;
   IndexTableReader m_IndexTableReader;
+  RawBytesReader m_RawBytesReader;
   ResourceTableReader m_ResourceTableReader;
   FunctionTableReader m_FunctionTableReader;
+  SubobjectTableReader m_SubobjectTableReader;
   RuntimeDataContext m_Context;
 
 public:
@@ -413,6 +578,7 @@ public:
   bool InitFromRDAT_Prerelease(const void *pRDAT, size_t size);
   FunctionTableReader *GetFunctionTableReader();
   ResourceTableReader *GetResourceTableReader();
+  SubobjectTableReader *GetSubobjectTableReader();
 };
 
 //////////////////////////////////
@@ -447,6 +613,34 @@ typedef struct DxilFunctionDesc {
 } DxilFunctionDesc;
 
 typedef struct DxilSubobjectDesc {
+  uint32_t Kind;        // DXIL::SubobjectKind / D3D12_STATE_SUBOBJECT_TYPE
+  LPCWSTR Name;
+  union {
+    struct {
+      uint32_t Flags;   // DXIL::StateObjectFlags / D3D12_STATE_OBJECT_FLAGS
+    } StateObjectConfig;
+    struct {
+      LPCVOID pSerializedSignature;
+      uint32_t SizeInBytes;
+    } RootSignature;    // GlobalRootSignature or LocalRootSignature
+    struct {
+      LPCWSTR Subobject;
+      uint32_t NumExports;
+      const LPCWSTR* Exports;
+    } SubobjectToExportsAssociation;
+    struct {
+      uint32_t MaxPayloadSizeInBytes;
+      uint32_t MaxAttributeSizeInBytes;
+    } RaytracingShaderConfig;
+    struct {
+      uint32_t MaxTraceRecursionDepth;
+    } RaytracingPipelineConfig;
+    struct {
+      LPCWSTR Intersection;
+      LPCWSTR AnyHit;
+      LPCWSTR ClosestHit;
+    } HitGroup;
+  };
 } DxilSubobjectDesc;
 
 typedef struct DxilLibraryDesc {

+ 94 - 7
include/dxc/HLSL/DxilRuntimeReflection.inl

@@ -93,12 +93,15 @@ public:
 DxilRuntimeData::DxilRuntimeData() : DxilRuntimeData(nullptr, 0) {}
 
 DxilRuntimeData::DxilRuntimeData(const char *ptr, size_t size)
-    : m_TableCount(0), m_StringReader(), m_ResourceTableReader(),
-      m_FunctionTableReader(), m_IndexTableReader(), m_Context() {
-  m_Context = {&m_StringReader, &m_IndexTableReader, &m_ResourceTableReader,
-               &m_FunctionTableReader};
+    : m_TableCount(0), m_StringReader(), m_IndexTableReader(), m_RawBytesReader(),
+      m_ResourceTableReader(), m_FunctionTableReader(),
+      m_SubobjectTableReader(), m_Context() {
+  m_Context = {&m_StringReader, &m_IndexTableReader, &m_RawBytesReader,
+               &m_ResourceTableReader, &m_FunctionTableReader,
+               &m_SubobjectTableReader};
   m_ResourceTableReader.SetContext(&m_Context);
   m_FunctionTableReader.SetContext(&m_Context);
+  m_SubobjectTableReader.SetContext(&m_Context);
   InitFromRDAT(ptr, size);
 }
 
@@ -108,7 +111,7 @@ bool DxilRuntimeData::InitFromRDAT(const void *pRDAT, size_t size) {
     try {
       CheckedReader Reader(pRDAT, size);
       RuntimeDataHeader RDATHeader = Reader.Read<RuntimeDataHeader>();
-      if (RDATHeader.Version < RDAT_Version_0) {
+      if (RDATHeader.Version < RDAT_Version_10) {
         // Prerelease version, fallback to that Init
         return InitFromRDAT_Prerelease(pRDAT, size);
       }
@@ -129,6 +132,11 @@ bool DxilRuntimeData::InitFromRDAT(const void *pRDAT, size_t size) {
             PR.ReadArray<uint32_t>(count), count);
           break;
         }
+        case RuntimeDataPartType::RawBytes: {
+          m_RawBytesReader = RawBytesReader(
+            PR.ReadArray<char>(part.Size), part.Size);
+          break;
+        }
         case RuntimeDataPartType::ResourceTable: {
           RuntimeDataTableHeader table = PR.Read<RuntimeDataTableHeader>();
           size_t tableSize = table.RecordCount * table.RecordStride;
@@ -143,6 +151,13 @@ bool DxilRuntimeData::InitFromRDAT(const void *pRDAT, size_t size) {
             table.RecordCount, table.RecordStride);
           break;
         }
+        case RuntimeDataPartType::SubobjectTable: {
+          RuntimeDataTableHeader table = PR.Read<RuntimeDataTableHeader>();
+          size_t tableSize = table.RecordCount * table.RecordStride;
+          m_SubobjectTableReader.SetSubobjectInfo(PR.ReadArray<char>(tableSize),
+            table.RecordCount, table.RecordStride);
+          break;
+        }
         default:
           continue; // Skip unrecognized parts
         }
@@ -226,6 +241,10 @@ ResourceTableReader *DxilRuntimeData::GetResourceTableReader() {
   return &m_ResourceTableReader;
 }
 
+SubobjectTableReader *DxilRuntimeData::GetSubobjectTableReader() {
+  return &m_SubobjectTableReader;
+}
+
 }} // hlsl::RDAT
 
 using namespace hlsl;
@@ -245,18 +264,21 @@ namespace {
 class DxilRuntimeReflection_impl : public DxilRuntimeReflection {
 private:
   typedef std::unordered_map<const char *, std::unique_ptr<wchar_t[]>> StringMap;
+  typedef std::vector<const wchar_t *> WStringList;
   typedef std::vector<DxilResourceDesc> ResourceList;
   typedef std::vector<DxilResourceDesc *> ResourceRefList;
   typedef std::vector<DxilFunctionDesc> FunctionList;
-  typedef std::vector<const wchar_t *> WStringList;
+  typedef std::vector<DxilSubobjectDesc> SubobjectList;
 
   DxilRuntimeData m_RuntimeData;
   StringMap m_StringMap;
   ResourceList m_Resources;
   FunctionList m_Functions;
+  SubobjectList m_Subobjects;
   std::unordered_map<ResourceKey, DxilResourceDesc *> m_ResourceMap;
   std::unordered_map<DxilFunctionDesc *, ResourceRefList> m_FuncToResMap;
   std::unordered_map<DxilFunctionDesc *, WStringList> m_FuncToStringMap;
+  std::unordered_map<DxilSubobjectDesc *, WStringList> m_SubobjectToStringMap;
   bool m_initialized;
 
   const wchar_t *GetWideString(const char *ptr);
@@ -266,15 +288,19 @@ private:
                              const FunctionReader &functionReader);
   const wchar_t **GetDependenciesForFunction(DxilFunctionDesc &function,
                              const FunctionReader &functionReader);
+  const wchar_t **GetExportsForAssociation(DxilSubobjectDesc &subobject,
+                             const SubobjectReader &subobjectReader);
   DxilResourceDesc *AddResource(const ResourceReader &resourceReader);
   DxilFunctionDesc *AddFunction(const FunctionReader &functionReader);
+  DxilSubobjectDesc *AddSubobject(const SubobjectReader &subobjectReader);
 
 public:
   // TODO: Implement pipeline state validation with runtime data
   // TODO: Update BlobContainer.h to recognize 'RDAT' blob
   DxilRuntimeReflection_impl()
       : m_RuntimeData(), m_StringMap(), m_Resources(), m_Functions(),
-        m_FuncToResMap(), m_FuncToStringMap(), m_initialized(false) {}
+        m_FuncToResMap(), m_FuncToStringMap(), m_SubobjectToStringMap(),
+        m_initialized(false) {}
   virtual ~DxilRuntimeReflection_impl() {}
   // This call will allocate memory for GetLibraryReflection call
   bool InitFromRDAT(const void *pRDAT, size_t size) override;
@@ -342,6 +368,13 @@ void DxilRuntimeReflection_impl::InitializeReflection() {
     AddString(functionReader.GetName());
     AddFunction(functionReader);
   }
+  const SubobjectTableReader *subobjectTableReader = m_RuntimeData.GetSubobjectTableReader();
+  m_Subobjects.reserve(subobjectTableReader->GetCount());
+  for (uint32_t i = 0; i < subobjectTableReader->GetCount(); ++i) {
+    SubobjectReader subobjectReader = subobjectTableReader->GetItem(i);
+    AddString(subobjectReader.GetName());
+    AddSubobject(subobjectReader);
+  }
 }
 
 DxilResourceDesc *
@@ -418,6 +451,60 @@ DxilRuntimeReflection_impl::AddFunction(const FunctionReader &functionReader) {
   return &function;
 }
 
+const wchar_t **DxilRuntimeReflection_impl::GetExportsForAssociation(
+  DxilSubobjectDesc &subobject, const SubobjectReader &subobjectReader) {
+  if (m_SubobjectToStringMap.find(&subobject) == m_SubobjectToStringMap.end())
+    m_SubobjectToStringMap.insert(
+      std::pair<DxilSubobjectDesc *, WStringList>(&subobject, WStringList()));
+  WStringList &wStringList = m_SubobjectToStringMap.at(&subobject);
+  for (uint32_t i = 0; i < subobjectReader.GetSubobjectToExportsAssociation_NumExports(); ++i) {
+    wStringList.emplace_back(GetWideString(subobjectReader.GetSubobjectToExportsAssociation_Export(i)));
+  }
+  return wStringList.empty() ? nullptr : wStringList.data();
+}
+
+DxilSubobjectDesc *DxilRuntimeReflection_impl::AddSubobject(const SubobjectReader &subobjectReader) {
+  assert(m_Subobjects.size() < m_Subobjects.capacity() && "Otherwise, number of subobjects was incorrect");
+  if (!(m_Subobjects.size() < m_Subobjects.capacity()))
+    return nullptr;
+  m_Subobjects.emplace_back(DxilSubobjectDesc({0}));
+  DxilSubobjectDesc &subobject = m_Subobjects.back();
+  subobject.Name = GetWideString(subobjectReader.GetName());
+  subobject.Kind = (uint32_t)subobjectReader.GetKind();
+  switch (subobjectReader.GetKind()) {
+  case DXIL::SubobjectKind::StateObjectConfig:
+    subobject.StateObjectConfig.Flags = subobjectReader.GetStateObjectConfig_Flags();
+    break;
+  case DXIL::SubobjectKind::GlobalRootSignature:
+  case DXIL::SubobjectKind::LocalRootSignature:
+    if (!subobjectReader.GetRootSignature(&subobject.RootSignature.pSerializedSignature, &subobject.RootSignature.SizeInBytes))
+      return nullptr;
+    break;
+  case DXIL::SubobjectKind::SubobjectToExportsAssociation:
+    subobject.SubobjectToExportsAssociation.Subobject =
+      GetWideString(subobjectReader.GetSubobjectToExportsAssociation_Subobject());
+    subobject.SubobjectToExportsAssociation.NumExports = subobjectReader.GetSubobjectToExportsAssociation_NumExports();
+    subobject.SubobjectToExportsAssociation.Exports = GetExportsForAssociation(subobject, subobjectReader);
+    break;
+  case DXIL::SubobjectKind::RaytracingShaderConfig:
+    subobject.RaytracingShaderConfig.MaxPayloadSizeInBytes = subobjectReader.GetRaytracingShaderConfig_MaxPayloadSizeInBytes();
+    subobject.RaytracingShaderConfig.MaxAttributeSizeInBytes = subobjectReader.GetRaytracingShaderConfig_MaxAttributeSizeInBytes();
+    break;
+  case DXIL::SubobjectKind::RaytracingPipelineConfig:
+    subobject.RaytracingPipelineConfig.MaxTraceRecursionDepth = subobjectReader.GetRaytracingPipelineConfig_MaxTraceRecursionDepth();
+    break;
+  case DXIL::SubobjectKind::HitGroup:
+    subobject.HitGroup.Intersection = GetWideString(subobjectReader.GetHitGroup_Intersection());
+    subobject.HitGroup.AnyHit = GetWideString(subobjectReader.GetHitGroup_AnyHit());
+    subobject.HitGroup.ClosestHit = GetWideString(subobjectReader.GetHitGroup_ClosestHit());
+    break;
+  default:
+    // Ignore contents of unrecognized subobject type (forward-compat)
+    break;
+  }
+  return &subobject;
+}
+
 } // namespace anon
 
 DxilRuntimeReflection *hlsl::RDAT::CreateDxilRuntimeReflection() {

+ 7 - 0
include/dxc/HLSL/HLModule.h

@@ -20,6 +20,7 @@
 #include "dxc/DXIL/DxilShaderModel.h"
 #include "dxc/DXIL/DxilSignature.h"
 #include "dxc/DXIL/DxilFunctionProps.h"
+#include "dxc/DXIL/DxilSubobject.h"
 #include <memory>
 #include <string>
 #include <vector>
@@ -242,6 +243,11 @@ public:
                                 llvm::DebugInfoFinder &DbgInfoFinder,
                                 llvm::GlobalVariable *NewGV);
 
+  DxilSubobjects *GetSubobjects();
+  const DxilSubobjects *GetSubobjects() const;
+  DxilSubobjects *ReleaseSubobjects();
+  void ResetSubobjects(DxilSubobjects *subobjects);
+
 private:
   // Signatures.
   std::vector<uint8_t> m_SerializedRootSignature;
@@ -280,6 +286,7 @@ private:
   size_t m_pUnused;
   uint32_t m_AutoBindingSpace;
   DXIL::DefaultLinkage m_DefaultLinkage;
+  std::unique_ptr<DxilSubobjects> m_pSubobjects;
 
   // DXIL metadata serialization/deserialization.
   llvm::MDTuple *EmitHLResources();

+ 1 - 0
lib/DXIL/CMakeLists.txt

@@ -15,6 +15,7 @@ add_llvm_library(LLVMDXIL
   DxilShaderModel.cpp
   DxilSignature.cpp
   DxilSignatureElement.cpp
+  DxilSubobject.cpp
   DxilTypeSystem.cpp
   DxilUtil.cpp
 

+ 162 - 0
lib/DXIL/DxilMetadataHelper.cpp

@@ -18,6 +18,7 @@
 #include "dxc/DXIL/DxilTypeSystem.h"
 #include "dxc/DXIL/DxilFunctionProps.h"
 #include "dxc/DXIL/DxilShaderFlags.h"
+#include "dxc/DXIL/DxilSubobject.h"
 
 #include "llvm/IR/Constants.h"
 #include "llvm/IR/Function.h"
@@ -54,6 +55,7 @@ const char DxilMDHelper::kDxilValidatorVersionMDName[]                = "dx.valv
 // This named metadata is not valid in final module (should be moved to DxilContainer)
 const char DxilMDHelper::kDxilRootSignatureMDName[]                   = "dx.rootSignature";
 const char DxilMDHelper::kDxilViewIdStateMDName[]                     = "dx.viewIdState";
+const char DxilMDHelper::kDxilSubobjectsMDName[]                      = "dx.subobjects";
 
 const char DxilMDHelper::kDxilSourceContentsMDName[]                  = "dx.source.contents";
 const char DxilMDHelper::kDxilSourceDefinesMDName[]                   = "dx.source.defines";
@@ -1329,6 +1331,160 @@ MDNode *DxilMDHelper::EmitControlFlowHints(llvm::LLVMContext &Ctx, std::vector<D
   return hintsNode;
 }
 
+void DxilMDHelper::EmitSubobjects(const DxilSubobjects &Subobjects) {
+  NamedMDNode *pSubobjectsNamedMD = m_pModule->getNamedMetadata(kDxilSubobjectsMDName);
+  IFTBOOL(pSubobjectsNamedMD == nullptr, DXC_E_INCORRECT_DXIL_METADATA);
+  pSubobjectsNamedMD = m_pModule->getOrInsertNamedMetadata(kDxilSubobjectsMDName);
+
+  const auto &objMap = Subobjects.GetSubobjects();
+  for (auto &it : objMap)
+    pSubobjectsNamedMD->addOperand(cast<MDNode>(EmitSubobject(*it.second)));
+}
+
+void DxilMDHelper::LoadSubobjects(DxilSubobjects &Subobjects) {
+  NamedMDNode *pSubobjectsNamedMD = m_pModule->getNamedMetadata(kDxilSubobjectsMDName);
+  if (!pSubobjectsNamedMD)
+    return;
+
+  for (unsigned i = 0; i < pSubobjectsNamedMD->getNumOperands(); ++i)
+    LoadSubobject(*pSubobjectsNamedMD->getOperand(i), Subobjects);
+}
+
+Metadata *DxilMDHelper::EmitSubobject(const DxilSubobject &obj) {
+  SmallVector<Metadata *, 6> Args;
+  Args.emplace_back(MDString::get(m_Ctx, obj.GetName()));
+  Args.emplace_back(Uint32ToConstMD((unsigned)obj.GetKind()));
+  bool bLocalRS = false;
+  IFTBOOL(DXIL::IsValidSubobjectKind(obj.GetKind()), DXC_E_INCORRECT_DXIL_METADATA);
+  switch (obj.GetKind()) {
+  case DXIL::SubobjectKind::StateObjectConfig: {
+    uint32_t Flags;
+    IFTBOOL(!obj.GetStateObjectConfig(Flags),
+      DXC_E_INCORRECT_DXIL_METADATA);
+    Args.emplace_back(Uint32ToConstMD((unsigned)Flags));
+    break;
+  }
+  case DXIL::SubobjectKind::LocalRootSignature:
+    bLocalRS = true;
+  case DXIL::SubobjectKind::GlobalRootSignature: {
+    const void * Data;
+    uint32_t Size;
+    IFTBOOL(!obj.GetRootSignature(bLocalRS, Data, Size),
+      DXC_E_INCORRECT_DXIL_METADATA);
+    Constant *V = ConstantDataArray::get(m_Ctx,
+      ArrayRef<uint8_t>((const uint8_t *)Data, Size));
+    Args.emplace_back(MDNode::get(m_Ctx, { ConstantAsMetadata::get(V) }));
+    break;
+  }
+  case DXIL::SubobjectKind::SubobjectToExportsAssociation: {
+    StringRef Subobj;
+    const char * const * Exports;
+    uint32_t NumExports;
+    IFTBOOL(!obj.GetSubobjectToExportsAssociation(Subobj, Exports, NumExports),
+      DXC_E_INCORRECT_DXIL_METADATA);
+    SmallVector<Metadata *, 4> strArgs;
+    for (unsigned i = 0; i < NumExports; ++i) {
+      strArgs.emplace_back(MDString::get(m_Ctx, Exports[i]));
+    }
+    Args.emplace_back(MDNode::get(m_Ctx, strArgs));
+    break;
+  }
+  case DXIL::SubobjectKind::RaytracingShaderConfig: {
+    uint32_t MaxPayloadSizeInBytes;
+    uint32_t MaxAttributeSizeInBytes;
+    IFTBOOL(!obj.GetRaytracingShaderConfig(MaxPayloadSizeInBytes,
+                                           MaxAttributeSizeInBytes),
+      DXC_E_INCORRECT_DXIL_METADATA);
+    Args.emplace_back(Uint32ToConstMD(MaxPayloadSizeInBytes));
+    Args.emplace_back(Uint32ToConstMD(MaxAttributeSizeInBytes));
+    break;
+  }
+  case DXIL::SubobjectKind::RaytracingPipelineConfig: {
+    uint32_t MaxTraceRecursionDepth;
+    IFTBOOL(!obj.GetRaytracingPipelineConfig(MaxTraceRecursionDepth),
+      DXC_E_INCORRECT_DXIL_METADATA);
+    Args.emplace_back(Uint32ToConstMD(MaxTraceRecursionDepth));
+    break;
+  }
+  case DXIL::SubobjectKind::HitGroup: {
+    llvm::StringRef Intersection, AnyHit, ClosestHit;
+    IFTBOOL(!obj.GetHitGroup(Intersection, AnyHit, ClosestHit),
+      DXC_E_INCORRECT_DXIL_METADATA);
+    Args.emplace_back(MDString::get(m_Ctx, Intersection));
+    Args.emplace_back(MDString::get(m_Ctx, AnyHit));
+    Args.emplace_back(MDString::get(m_Ctx, ClosestHit));
+    break;
+  }
+  default:
+    DXASSERT(false, "otherwise, we didn't handle a valid subobject kind");
+    break;
+  }
+  return MDNode::get(m_Ctx, Args);
+}
+void DxilMDHelper::LoadSubobject(const llvm::MDNode &MD, DxilSubobjects &Subobjects) {
+  IFTBOOL(MD.getNumOperands() >= 2, DXC_E_INCORRECT_DXIL_METADATA);
+  unsigned i = 0;
+  StringRef name(StringMDToStringRef(MD.getOperand(i++)));
+  DXIL::SubobjectKind kind = (DXIL::SubobjectKind)ConstMDToUint32(MD.getOperand(i++));
+  IFTBOOL(DXIL::IsValidSubobjectKind(kind), DXC_E_INCORRECT_DXIL_METADATA);
+  bool bLocalRS = false;
+  switch (kind) {
+  case DXIL::SubobjectKind::StateObjectConfig: {
+    uint32_t Flags = ConstMDToUint32(MD.getOperand(i++));
+    IFTBOOL(0 == ((~(uint32_t)DXIL::StateObjectFlags::ValidMask) & Flags),
+            DXC_E_INCORRECT_DXIL_METADATA);
+    Subobjects.CreateStateObjectConfig(name, Flags);
+    break;
+  }
+  case DXIL::SubobjectKind::LocalRootSignature:
+    bLocalRS = true;
+  case DXIL::SubobjectKind::GlobalRootSignature: {
+    const ConstantAsMetadata *pMetaData = dyn_cast<ConstantAsMetadata>(MD.getOperand(i++));
+    IFTBOOL(pMetaData != nullptr, DXC_E_INCORRECT_DXIL_METADATA);
+    const ConstantDataArray *pData = dyn_cast<ConstantDataArray>(pMetaData->getValue());
+    IFTBOOL(pData != nullptr, DXC_E_INCORRECT_DXIL_METADATA);
+    IFTBOOL(pData->getElementType() == Type::getInt8Ty(m_Ctx), DXC_E_INCORRECT_DXIL_METADATA);
+    IFTBOOL(pData->getRawDataValues().size() < UINT_MAX &&
+            (pData->getRawDataValues().size() & 3) == 0, DXC_E_INCORRECT_DXIL_METADATA);
+    const void *Data = pData->getRawDataValues().begin();
+    uint32_t Size = pData->getRawDataValues().size();
+    Subobjects.CreateRootSignature(name, bLocalRS, Data, Size);
+    break;
+  }
+  case DXIL::SubobjectKind::SubobjectToExportsAssociation: {
+    StringRef Subobj(StringMDToStringRef(MD.getOperand(i++)));
+    const MDNode *exportMD = dyn_cast<MDNode>(MD.getOperand(i++));
+    SmallVector<const char *, 4> Exports;
+    for (unsigned iExport = 0; iExport < exportMD->getNumOperands(); iExport++) {
+      Exports.push_back(StringMDToStringRef(exportMD->getOperand(iExport)).data());
+    }
+    Subobjects.CreateSubobjectToExportsAssociation(name, Subobj, Exports.data(), Exports.size());
+    break;
+  }
+  case DXIL::SubobjectKind::RaytracingShaderConfig: {
+    uint32_t MaxPayloadSizeInBytes = ConstMDToUint32(MD.getOperand(i++));;
+    uint32_t MaxAttributeSizeInBytes = ConstMDToUint32(MD.getOperand(i++));;
+    Subobjects.CreateRaytracingShaderConfig(name, MaxPayloadSizeInBytes, MaxAttributeSizeInBytes);
+    break;
+  }
+  case DXIL::SubobjectKind::RaytracingPipelineConfig: {
+    uint32_t MaxTraceRecursionDepth = ConstMDToUint32(MD.getOperand(i++));;
+    Subobjects.CreateRaytracingPipelineConfig(name, MaxTraceRecursionDepth);
+    break;
+  }
+  case DXIL::SubobjectKind::HitGroup: {
+    StringRef Intersection(StringMDToStringRef(MD.getOperand(i++)));
+    StringRef AnyHit(StringMDToStringRef(MD.getOperand(i++)));
+    StringRef ClosestHit(StringMDToStringRef(MD.getOperand(i++)));
+    Subobjects.CreateHitGroup(name, Intersection, AnyHit, ClosestHit);
+    break;
+  }
+  default:
+    DXASSERT(false, "otherwise, we didn't handle a valid subobject kind");
+    break;
+  }
+}
+
 MDTuple *DxilMDHelper::EmitDxilSampler(const DxilSampler &S) {
   Metadata *MDVals[kDxilSamplerNumFields];
 
@@ -1828,6 +1984,12 @@ string DxilMDHelper::StringMDToString(const MDOperand &MDO) {
   return pMDString->getString();
 }
 
+StringRef DxilMDHelper::StringMDToStringRef(const MDOperand &MDO) {
+  MDString *pMDString = dyn_cast<MDString>(MDO.get());
+  IFTBOOL(pMDString != nullptr, DXC_E_INCORRECT_DXIL_METADATA);
+  return pMDString->getString();
+}
+
 Value *DxilMDHelper::ValueMDToValue(const MDOperand &MDO) {
   IFTBOOL(MDO.get() != nullptr, DXC_E_INCORRECT_DXIL_METADATA);
   ValueAsMetadata *pValAsMD = dyn_cast<ValueAsMetadata>(MDO.get());

+ 37 - 1
lib/DXIL/DxilModule.cpp

@@ -16,6 +16,7 @@
 #include "dxc/DXIL/DxilFunctionProps.h"
 #include "dxc/Support/WinAdapter.h"
 #include "dxc/DXIL/DxilEntryProps.h"
+#include "dxc/DXIL/DxilSubobject.h"
 
 #include "llvm/IR/Constants.h"
 #include "llvm/IR/Function.h"
@@ -97,7 +98,9 @@ DxilModule::DxilModule(Module *pModule)
 , m_bDisableOptimizations(false)
 , m_bUseMinPrecision(true) // use min precision by default
 , m_bAllResourcesBound(false)
-, m_AutoBindingSpace(UINT_MAX) {
+, m_AutoBindingSpace(UINT_MAX)
+, m_pSubobjects(nullptr)
+{
 
   DXASSERT_NOMSG(m_pModule != nullptr);
 
@@ -1041,6 +1044,26 @@ void DxilModule::StripRootSignatureFromMetadata() {
   }
 }
 
+DxilSubobjects *DxilModule::GetSubobjects() {
+  return m_pSubobjects.get();
+}
+const DxilSubobjects *DxilModule::GetSubobjects() const {
+  return m_pSubobjects.get();
+}
+DxilSubobjects *DxilModule::ReleaseSubobjects() {
+  return m_pSubobjects.release();
+}
+void DxilModule::ResetSubobjects(DxilSubobjects *subobjects) {
+  m_pSubobjects.reset(subobjects);
+}
+
+void DxilModule::StripSubobjectsFromMetadata() {
+  NamedMDNode *pSubobjectsNamedMD = GetModule()->getNamedMetadata(DxilMDHelper::kDxilSubobjectsMDName);
+  if (pSubobjectsNamedMD) {
+    GetModule()->eraseNamedMetadata(pSubobjectsNamedMD);
+  }
+}
+
 void DxilModule::UpdateValidatorVersionMetadata() {
   m_pMDHelper->EmitValidatorVersion(m_ValMajor, m_ValMinor);
 }
@@ -1145,6 +1168,7 @@ void DxilModule::ClearDxilMetadata(Module &M) {
       name == DxilMDHelper::kDxilResourcesMDName ||
       name == DxilMDHelper::kDxilTypeSystemMDName ||
       name == DxilMDHelper::kDxilViewIdStateMDName ||
+      name == DxilMDHelper::kDxilSubobjectsMDName ||
       name.startswith(DxilMDHelper::kDxilTypeSystemHelperVariablePrefix)) {
       nodes.push_back(&b);
     }
@@ -1215,6 +1239,11 @@ void DxilModule::EmitDxilMetadata() {
       Entries.emplace_back(pSubEntry);
     }
     funcOrder.clear();
+
+    // Save Subobjects
+    if (GetSubobjects()) {
+      m_pMDHelper->EmitSubobjects(*GetSubobjects());
+    }
   }
   m_pMDHelper->EmitDxilEntryPoints(Entries);
 
@@ -1301,6 +1330,13 @@ void DxilModule::LoadDxilMetadata() {
 
       m_DxilEntryPropsMap[pFunc] = std::move(pEntryProps);
     }
+
+    // Load Subobjects
+    std::unique_ptr<DxilSubobjects> pSubobjects(new DxilSubobjects());
+    m_pMDHelper->LoadSubobjects(*pSubobjects);
+    if (pSubobjects->GetSubobjects().size()) {
+      ResetSubobjects(pSubobjects.release());
+    }
   } else {
     std::unique_ptr<DxilEntryProps> pEntryProps =
         llvm::make_unique<DxilEntryProps>(entryFuncProps, m_bUseMinPrecision);

+ 312 - 0
lib/DXIL/DxilSubobject.cpp

@@ -0,0 +1,312 @@
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// DxilSubobject.cpp                                                         //
+// Copyright (C) Microsoft Corporation. All rights reserved.                 //
+// This file is distributed under the University of Illinois Open Source     //
+// License. See LICENSE.TXT for details.                                     //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+#include "dxc/Support/Global.h"
+#include "dxc/DXIL/DxilSubobject.h"
+#include "llvm/ADT/STLExtras.h"
+
+
+namespace hlsl {
+
+//------------------------------------------------------------------------------
+//
+// Subobject methods.
+//
+
+DxilSubobject::DxilSubobject(DxilSubobject &&other)
+  : m_Owner(other.m_Owner),
+    m_Kind(other.m_Kind),
+    m_Name(m_Owner.GetSubobjectString(other.m_Name)),
+    m_Exports(std::move(other.m_Exports))
+{
+  DXASSERT_NOMSG(DXIL::IsValidSubobjectKind(m_Kind));
+  CopyUnionedContents(other);
+}
+
+DxilSubobject::DxilSubobject(DxilSubobjects &owner, Kind kind, llvm::StringRef name)
+  : m_Owner(owner),
+    m_Kind(kind),
+    m_Name(m_Owner.GetSubobjectString(name)),
+    m_Exports()
+{
+  DXASSERT_NOMSG(DXIL::IsValidSubobjectKind(m_Kind));
+}
+
+DxilSubobject::DxilSubobject(DxilSubobjects &owner, const DxilSubobject &other, llvm::StringRef name)
+  : m_Owner(owner),
+    m_Kind(other.m_Kind),
+    m_Name(name),
+    m_Exports(other.m_Exports.begin(), other.m_Exports.end())
+{
+  DXASSERT_NOMSG(DXIL::IsValidSubobjectKind(m_Kind));
+  CopyUnionedContents(other);
+  if (&m_Owner != &other.m_Owner)
+    InternStrings();
+}
+
+void DxilSubobject::CopyUnionedContents(const DxilSubobject &other) {
+  switch (m_Kind) {
+  case Kind::StateObjectConfig:
+    StateObjectConfig.Flags = other.StateObjectConfig.Flags;
+    break;
+  case Kind::GlobalRootSignature:
+  case Kind::LocalRootSignature:
+    RootSignature.Size = other.RootSignature.Size;
+    RootSignature.Data = other.RootSignature.Data;
+    break;
+  case Kind::SubobjectToExportsAssociation:
+    SubobjectToExportsAssociation.Subobject = other.SubobjectToExportsAssociation.Subobject;
+    break;
+  case Kind::RaytracingShaderConfig:
+    RaytracingShaderConfig.MaxPayloadSizeInBytes = other.RaytracingShaderConfig.MaxPayloadSizeInBytes;
+    RaytracingShaderConfig.MaxAttributeSizeInBytes = other.RaytracingShaderConfig.MaxAttributeSizeInBytes;
+    break;
+  case Kind::RaytracingPipelineConfig:
+    RaytracingPipelineConfig.MaxTraceRecursionDepth = other.RaytracingPipelineConfig.MaxTraceRecursionDepth;
+    break;
+  case Kind::HitGroup:
+    HitGroup.Intersection = other.HitGroup.Intersection;
+    HitGroup.AnyHit = other.HitGroup.AnyHit;
+    HitGroup.ClosestHit = other.HitGroup.ClosestHit;
+    break;
+  }
+}
+
+void DxilSubobject::InternStrings() {
+  // Transfer strings if necessary
+  m_Name = m_Owner.GetSubobjectString(m_Name).data();
+  switch (m_Kind) {
+  case Kind::SubobjectToExportsAssociation:
+    SubobjectToExportsAssociation.Subobject = m_Owner.GetSubobjectString(SubobjectToExportsAssociation.Subobject).data();
+    for (auto &ptr : m_Exports)
+      ptr = m_Owner.GetSubobjectString(ptr).data();
+    break;
+  case Kind::HitGroup:
+    HitGroup.Intersection = m_Owner.GetSubobjectString(HitGroup.Intersection).data();
+    HitGroup.AnyHit = m_Owner.GetSubobjectString(HitGroup.AnyHit).data();
+    HitGroup.ClosestHit = m_Owner.GetSubobjectString(HitGroup.ClosestHit).data();
+    break;
+  default:
+    break;
+  }
+}
+
+DxilSubobject::~DxilSubobject() {
+}
+
+
+// StateObjectConfig
+bool DxilSubobject::GetStateObjectConfig(uint32_t &Flags) const {
+  if (m_Kind == Kind::StateObjectConfig) {
+    Flags = StateObjectConfig.Flags;
+    return true;
+  }
+  return false;
+}
+
+// Local/Global RootSignature
+bool DxilSubobject::GetRootSignature(
+    bool local, const void * &Data, uint32_t &Size) const {
+  Kind expected = local ? Kind::LocalRootSignature : Kind::GlobalRootSignature;
+  if (m_Kind == expected) {
+    Data = RootSignature.Data;
+    Size = RootSignature.Size;
+    return true;
+  }
+  return false;
+}
+
+// SubobjectToExportsAssociation
+bool DxilSubobject::GetSubobjectToExportsAssociation(
+    llvm::StringRef &Subobject,
+    const char * const * &Exports,
+    uint32_t &NumExports) const {
+  if (m_Kind == Kind::SubobjectToExportsAssociation) {
+    Subobject = SubobjectToExportsAssociation.Subobject;
+    Exports = m_Exports.data();
+    NumExports = (uint32_t)m_Exports.size();
+    return true;
+  }
+  return false;
+}
+
+// RaytracingShaderConfig
+bool DxilSubobject::GetRaytracingShaderConfig(uint32_t &MaxPayloadSizeInBytes,
+                                              uint32_t &MaxAttributeSizeInBytes) const {
+  if (m_Kind == Kind::RaytracingShaderConfig) {
+    MaxPayloadSizeInBytes = RaytracingShaderConfig.MaxPayloadSizeInBytes;
+    MaxAttributeSizeInBytes = RaytracingShaderConfig.MaxAttributeSizeInBytes;
+    return true;
+  }
+  return false;
+}
+
+// RaytracingPipelineConfig
+bool DxilSubobject::GetRaytracingPipelineConfig(
+    uint32_t &MaxTraceRecursionDepth) const {
+  if (m_Kind == Kind::RaytracingPipelineConfig) {
+    MaxTraceRecursionDepth = RaytracingPipelineConfig.MaxTraceRecursionDepth;
+    return true;
+  }
+  return false;
+}
+
+// HitGroup
+bool DxilSubobject::GetHitGroup(llvm::StringRef &Intersection,
+                                llvm::StringRef &AnyHit,
+                                llvm::StringRef &ClosestHit) const {
+  if (m_Kind == Kind::HitGroup) {
+    Intersection = HitGroup.Intersection;
+    AnyHit = HitGroup.AnyHit;
+    ClosestHit = HitGroup.ClosestHit;
+    return true;
+  }
+  return false;
+}
+
+
+DxilSubobjects::DxilSubobjects()
+  : m_StringStorage()
+  , m_RawBytesStorage()
+  , m_Subobjects()
+{}
+DxilSubobjects::DxilSubobjects(DxilSubobjects &&other)
+  : m_StringStorage(std::move(other.m_StringStorage))
+  , m_RawBytesStorage(std::move(other.m_RawBytesStorage))
+  , m_Subobjects(std::move(other.m_Subobjects))
+{}
+DxilSubobjects::~DxilSubobjects() {}
+
+
+StringRef DxilSubobjects::GetSubobjectString(StringRef value) {
+  auto it = m_StringStorage.find(value);
+  if (it != m_StringStorage.end())
+    return it->first;
+
+  std::string stored(value.begin(), value.size());
+  const char *ptr = stored.c_str();
+  m_StringStorage[ptr] = std::move(stored);
+  return ptr;
+}
+
+const void *DxilSubobjects::GetRawBytes(const void *ptr, size_t size) {
+  auto it = m_RawBytesStorage.find(ptr);
+  if (it != m_RawBytesStorage.end())
+    return ptr;
+
+  DXASSERT_NOMSG(size < UINT_MAX);
+  if (size >= UINT_MAX)
+    return nullptr;
+  std::vector<char> stored;
+  stored.reserve(size);
+  stored.assign((const char*)ptr, (const char*)ptr + size);
+  ptr = stored.data();
+  m_RawBytesStorage[ptr] = std::move(stored);
+  return ptr;
+}
+
+DxilSubobject *DxilSubobjects::FindSubobject(StringRef name) {
+  auto it = m_Subobjects.find(name);
+  if (it != m_Subobjects.end())
+    return it->second.get();
+  return nullptr;
+}
+
+void DxilSubobjects::RemoveSubobject(StringRef name) {
+  auto it = m_Subobjects.find(name);
+  if (it != m_Subobjects.end())
+    m_Subobjects.erase(it);
+}
+
+DxilSubobject &DxilSubobjects::CloneSubobject(
+    const DxilSubobject &Subobject, llvm::StringRef Name) {
+  Name = GetSubobjectString(Name);
+  DXASSERT(FindSubobject(Name) == nullptr,
+    "otherwise, name collision between subobjects");
+  std::unique_ptr<DxilSubobject> ptr(new DxilSubobject(*this, Subobject, Name));
+  DxilSubobject &ref = *ptr;
+  m_Subobjects[Name] = std::move(ptr);
+  return ref;
+}
+
+// Create DxilSubobjects
+
+DxilSubobject &DxilSubobjects::CreateStateObjectConfig(
+    llvm::StringRef Name, uint32_t Flags) {
+  DXASSERT_NOMSG(0 == ((~(uint32_t)DXIL::StateObjectFlags::ValidMask) & Flags));
+  auto &obj = CreateSubobject(Kind::StateObjectConfig, Name);
+  obj.StateObjectConfig.Flags = Flags;
+  return obj;
+}
+
+DxilSubobject &DxilSubobjects::CreateRootSignature(
+    llvm::StringRef Name, bool local, const void *Data, uint32_t Size) {
+  auto &obj = CreateSubobject(local ? Kind::LocalRootSignature : Kind::GlobalRootSignature, Name);
+  obj.RootSignature.Data = Data;
+  obj.RootSignature.Size = Size;
+  return obj;
+}
+
+DxilSubobject &DxilSubobjects::CreateSubobjectToExportsAssociation(
+    llvm::StringRef Name,
+    llvm::StringRef Subobject,
+    const char * const *Exports,
+    uint32_t NumExports) {
+  auto &obj = CreateSubobject(Kind::SubobjectToExportsAssociation, Name);
+  Subobject = GetSubobjectString(Subobject);
+  obj.SubobjectToExportsAssociation.Subobject = Subobject.data();
+  obj.m_Exports.assign(Exports, Exports + NumExports);
+  return obj;
+}
+
+DxilSubobject &DxilSubobjects::CreateRaytracingShaderConfig(
+    llvm::StringRef Name,
+    uint32_t MaxPayloadSizeInBytes,
+    uint32_t MaxAttributeSizeInBytes) {
+  auto &obj = CreateSubobject(Kind::RaytracingShaderConfig, Name);
+  obj.RaytracingShaderConfig.MaxPayloadSizeInBytes = MaxPayloadSizeInBytes;
+  obj.RaytracingShaderConfig.MaxAttributeSizeInBytes = MaxAttributeSizeInBytes;
+  return obj;
+}
+
+DxilSubobject &DxilSubobjects::CreateRaytracingPipelineConfig(
+    llvm::StringRef Name,
+    uint32_t MaxTraceRecursionDepth) {
+  auto &obj = CreateSubobject(Kind::RaytracingPipelineConfig, Name);
+  obj.RaytracingPipelineConfig.MaxTraceRecursionDepth = MaxTraceRecursionDepth;
+  return obj;
+}
+
+DxilSubobject &DxilSubobjects::CreateHitGroup(llvm::StringRef Name,
+                                              llvm::StringRef Intersection,
+                                              llvm::StringRef AnyHit,
+                                              llvm::StringRef ClosestHit) {
+  auto &obj = CreateSubobject(Kind::HitGroup, Name);
+  Intersection = GetSubobjectString(Intersection);
+  AnyHit = GetSubobjectString(AnyHit);
+  ClosestHit = GetSubobjectString(ClosestHit);
+  obj.HitGroup.Intersection = Intersection.data();
+  obj.HitGroup.AnyHit = AnyHit.data();
+  obj.HitGroup.ClosestHit = ClosestHit.data();
+  return obj;
+}
+
+DxilSubobject &DxilSubobjects::CreateSubobject(Kind kind, llvm::StringRef Name) {
+  Name = GetSubobjectString(Name);
+  DXASSERT(FindSubobject(Name) == nullptr,
+    "otherwise, name collision between subobjects");
+  std::unique_ptr<DxilSubobject> ptr(new DxilSubobject(*this, kind, Name));
+  DxilSubobject &ref = *ptr;
+  m_Subobjects[Name] = std::move(ptr);
+  return ref;
+}
+
+
+} // namespace hlsl
+

+ 135 - 36
lib/DxilContainer/DxilContainerAssembler.cpp

@@ -938,6 +938,35 @@ public:
   }
 };
 
+class RawBytesPart : public RDATPart {
+private:
+  std::unordered_map<const void *, uint32_t> m_PtrMap;
+  std::vector<char> m_DataBuffer;
+public:
+  RawBytesPart() : m_DataBuffer() {}
+  uint32_t Insert(const void *pData, size_t dataSize) {
+    auto it = m_PtrMap.find(pData);
+    if (it != m_PtrMap.end())
+      return it->second;
+
+    if (dataSize + m_DataBuffer.size() > UINT_MAX)
+      return UINT_MAX;
+    uint32_t offset = (uint32_t)m_DataBuffer.size();
+    m_DataBuffer.reserve(m_DataBuffer.size() + dataSize);
+    m_DataBuffer.insert(m_DataBuffer.end(),
+      (const char*)pData, (const char*)pData + dataSize);
+    return offset;
+  }
+  RuntimeDataPartType GetType() const { return RuntimeDataPartType::RawBytes; }
+  uint32_t GetPartSize() const { return m_DataBuffer.size(); }
+  void Write(void *ptr) { memcpy(ptr, m_DataBuffer.data(), m_DataBuffer.size()); }
+};
+
+class SubobjectTable : public RDATTable<RuntimeDataSobobjectInfo> {
+public:
+  RuntimeDataPartType GetType() const { return RuntimeDataPartType::SubobjectTable; }
+};
+
 using namespace DXIL;
 
 class DxilRDATWriter : public DxilPartWriter {
@@ -1016,10 +1045,8 @@ private:
 
   void InsertToResourceTable(DxilResourceBase &resource,
                              ResourceClass resourceClass,
-                             ResourceTable &resourceTable,
-                             StringBufferPart &stringBufferPart,
                              uint32_t &resourceIndex) {
-    uint32_t stringIndex = stringBufferPart.Insert(resource.GetGlobalName());
+    uint32_t stringIndex = m_pStringBufferPart->Insert(resource.GetGlobalName());
     UpdateFunctionToResourceInfo(&resource, resourceIndex++);
     RuntimeDataResourceInfo info = {};
     info.ID = resource.GetID();
@@ -1040,38 +1067,32 @@ private:
         info.Flags |= static_cast<uint32_t>(DxilResourceFlag::UAVRasterizerOrderedView);
       // TODO: add dynamic index flag
     }
-    resourceTable.Insert(info);
+    m_pResourceTable->Insert(info);
   }
 
-  void UpdateResourceInfo(StringBufferPart &stringBufferPart) {
+  void UpdateResourceInfo() {
     // Try to allocate string table for resources. String table is a sequence
     // of strings delimited by \0
-    m_Parts.emplace_back(llvm::make_unique<ResourceTable>());
-    ResourceTable &resourceTable = *reinterpret_cast<ResourceTable*>(m_Parts.back().get());
     uint32_t resourceIndex = 0;
     for (auto &resource : m_Module.GetCBuffers()) {
-      InsertToResourceTable(*resource.get(), ResourceClass::CBuffer, resourceTable, stringBufferPart,
-                            resourceIndex);
+      InsertToResourceTable(*resource.get(), ResourceClass::CBuffer, resourceIndex);
 
     }
     for (auto &resource : m_Module.GetSamplers()) {
-      InsertToResourceTable(*resource.get(), ResourceClass::Sampler, resourceTable, stringBufferPart,
-                            resourceIndex);
+      InsertToResourceTable(*resource.get(), ResourceClass::Sampler, resourceIndex);
     }
     for (auto &resource : m_Module.GetSRVs()) {
-      InsertToResourceTable(*resource.get(), ResourceClass::SRV, resourceTable, stringBufferPart,
-                            resourceIndex);
+      InsertToResourceTable(*resource.get(), ResourceClass::SRV, resourceIndex);
     }
     for (auto &resource : m_Module.GetUAVs()) {
-      InsertToResourceTable(*resource.get(), ResourceClass::UAV, resourceTable, stringBufferPart,
-                            resourceIndex);
+      InsertToResourceTable(*resource.get(), ResourceClass::UAV, resourceIndex);
     }
   }
 
-  void UpdateFunctionDependency(llvm::Function *F, StringBufferPart &stringBufferPart) {
+  void UpdateFunctionDependency(llvm::Function *F) {
     for (const auto &user : F->users()) {
       const llvm::Function *userFunction = FindUsingFunction(user);
-      uint32_t index = stringBufferPart.Insert(F->getName());
+      uint32_t index = m_pStringBufferPart->Insert(F->getName());
       if (m_FuncToDependencies.find(userFunction) ==
           m_FuncToDependencies.end()) {
         m_FuncToDependencies[userFunction] =
@@ -1081,11 +1102,7 @@ private:
     }
   }
 
-  void UpdateFunctionInfo(StringBufferPart &stringBufferPart) {
-    m_Parts.emplace_back(llvm::make_unique<FunctionTable>());
-    FunctionTable &functionTable = *reinterpret_cast<FunctionTable*>(m_Parts.back().get());
-    m_Parts.emplace_back(llvm::make_unique<IndexArraysPart>());
-    IndexArraysPart &indexArraysPart = *reinterpret_cast<IndexArraysPart*>(m_Parts.back().get());
+  void UpdateFunctionInfo() {
     for (auto &function : m_Module.GetModule()->getFunctionList()) {
       if (function.isDeclaration() && !function.isIntrinsic()) {
         if (OP::IsDxilOpFunc(&function)) {
@@ -1093,7 +1110,7 @@ private:
           UpdateFunctionToShaderCompat(&function);
         } else {
           // collect unresolved dependencies per function
-          UpdateFunctionDependency(&function, stringBufferPart);
+          UpdateFunctionDependency(&function);
         }
       }
     }
@@ -1101,8 +1118,8 @@ private:
       if (!function.isDeclaration()) {
         StringRef mangled = function.getName();
         StringRef unmangled = hlsl::dxilutil::DemangleFunctionName(function.getName());
-        uint32_t mangledIndex = stringBufferPart.Insert(mangled);
-        uint32_t unmangledIndex = stringBufferPart.Insert(unmangled);
+        uint32_t mangledIndex = m_pStringBufferPart->Insert(mangled);
+        uint32_t unmangledIndex = m_pStringBufferPart->Insert(unmangled);
         // Update resource Index
         uint32_t resourceIndex = UINT_MAX;
         uint32_t functionDependencies = UINT_MAX;
@@ -1112,11 +1129,11 @@ private:
 
         if (m_FuncToResNameOffset.find(&function) != m_FuncToResNameOffset.end())
           resourceIndex =
-              indexArraysPart.AddIndex(m_FuncToResNameOffset[&function].begin(),
+          m_pIndexArraysPart->AddIndex(m_FuncToResNameOffset[&function].begin(),
                                   m_FuncToResNameOffset[&function].end());
         if (m_FuncToDependencies.find(&function) != m_FuncToDependencies.end())
           functionDependencies =
-              indexArraysPart.AddIndex(m_FuncToDependencies[&function].begin(),
+              m_pIndexArraysPart->AddIndex(m_FuncToDependencies[&function].begin(),
                                   m_FuncToDependencies[&function].end());
         if (m_Module.HasDxilFunctionProps(&function)) {
           auto props = m_Module.GetDxilFunctionProps(&function);
@@ -1171,19 +1188,99 @@ private:
           info.ShaderStageFlag &= compatInfo.mask;
         }
         info.MinShaderTarget = EncodeVersion((DXIL::ShaderKind)shaderKind, minMajor, minMinor);
-        functionTable.Insert(info);
+        m_pFunctionTable->Insert(info);
+      }
+    }
+  }
+
+  void UpdateSubobjectInfo() {
+    if (!m_Module.GetSubobjects())
+      return;
+    for (auto &it : m_Module.GetSubobjects()->GetSubobjects()) {
+      auto &obj = *it.second;
+      RuntimeDataSobobjectInfo info = {};
+      info.Name = m_pStringBufferPart->Insert(obj.GetName());
+      info.Kind = (uint32_t)obj.GetKind();
+      bool bLocalRS = false;
+      switch (obj.GetKind()) {
+      case DXIL::SubobjectKind::StateObjectConfig:
+        obj.GetStateObjectConfig(info.StateObjectConfig.Flags);
+        break;
+      case DXIL::SubobjectKind::LocalRootSignature:
+        bLocalRS = true;
+      case DXIL::SubobjectKind::GlobalRootSignature: {
+        const void *Data;
+        obj.GetRootSignature(bLocalRS, Data, info.RootSignature.SizeInBytes);
+        info.RootSignature.RawBytesOffset =
+          m_pRawBytesPart->Insert(Data, info.RootSignature.SizeInBytes);
+        break;
+      }
+      case DXIL::SubobjectKind::SubobjectToExportsAssociation: {
+        llvm::StringRef Subobject;
+        const char * const * Exports;
+        uint32_t NumExports;
+        std::vector<uint32_t> ExportIndices;
+        obj.GetSubobjectToExportsAssociation(Subobject, Exports, NumExports);
+        info.SubobjectToExportsAssociation.Sobobject =
+          m_pStringBufferPart->Insert(Subobject);
+        ExportIndices.resize(NumExports);
+        for (unsigned i = 0; i < NumExports; ++i) {
+          ExportIndices[i] = m_pStringBufferPart->Insert(Exports[i]);
+        }
+        m_pIndexArraysPart->AddIndex(
+          ExportIndices.begin(), ExportIndices.end());
+        break;
+      }
+      case DXIL::SubobjectKind::RaytracingShaderConfig:
+        obj.GetRaytracingShaderConfig(
+          info.RaytracingShaderConfig.MaxPayloadSizeInBytes,
+          info.RaytracingShaderConfig.MaxAttributeSizeInBytes);
+        break;
+      case DXIL::SubobjectKind::RaytracingPipelineConfig:
+        obj.GetRaytracingPipelineConfig(
+          info.RaytracingPipelineConfig.MaxTraceRecursionDepth);
+        break;
+      case DXIL::SubobjectKind::HitGroup:
+        StringRef Intersection;
+        StringRef AnyHit;
+        StringRef ClosestHit;
+        obj.GetHitGroup(Intersection, AnyHit, ClosestHit);
+        info.HitGroup.Intersection = m_pStringBufferPart->Insert(Intersection);
+        info.HitGroup.AnyHit = m_pStringBufferPart->Insert(AnyHit);
+        info.HitGroup.ClosestHit = m_pStringBufferPart->Insert(ClosestHit);
+        break;
       }
+      m_pSubobjectTable->Insert(info);
     }
   }
 
+  void CreateParts() {
+#define ADD_PART(type) \
+    m_Parts.emplace_back(llvm::make_unique<type>()); \
+    m_p##type = reinterpret_cast<type*>(m_Parts.back().get());
+    ADD_PART(StringBufferPart);
+    ADD_PART(IndexArraysPart);
+    ADD_PART(RawBytesPart);
+    ADD_PART(FunctionTable);
+    ADD_PART(ResourceTable);
+    ADD_PART(SubobjectTable);
+#undef ADD_PART
+  }
+
+  StringBufferPart *m_pStringBufferPart;
+  IndexArraysPart *m_pIndexArraysPart;
+  RawBytesPart *m_pRawBytesPart;
+  FunctionTable *m_pFunctionTable;
+  ResourceTable *m_pResourceTable;
+  SubobjectTable *m_pSubobjectTable;
+
 public:
   DxilRDATWriter(const DxilModule &module, uint32_t InfoVersion = 0)
       : m_Module(module), m_RDATBuffer(), m_Parts(), m_FuncToResNameOffset() {
-    // It's important to keep the order of this update
-    m_Parts.emplace_back(llvm::make_unique<StringBufferPart>());
-    StringBufferPart &stringBufferPart = *reinterpret_cast<StringBufferPart*>(m_Parts.back().get());
-    UpdateResourceInfo(stringBufferPart);
-    UpdateFunctionInfo(stringBufferPart);
+    CreateParts();
+    UpdateResourceInfo();
+    UpdateFunctionInfo();
+    UpdateSubobjectInfo();
 
     // Delete any empty parts:
     std::vector<std::unique_ptr<RDATPart>>::iterator it = m_Parts.begin();
@@ -1211,7 +1308,7 @@ public:
       CheckedWriter W(m_RDATBuffer.data(), m_RDATBuffer.size());
       // write RDAT header
       RuntimeDataHeader &header = W.Map<RuntimeDataHeader>();
-      header.Version = RDAT_Version_0;
+      header.Version = RDAT_Version_10;
       header.PartCount = m_Parts.size();
       // map offsets
       uint32_t *offsets = W.MapArray<uint32_t>(header.PartCount);
@@ -1421,17 +1518,19 @@ void hlsl::SerializeDxilContainerForModule(DxilModule *pModule,
                      });
     }
   }
-  // Write the DxilPipelineStateValidation (PSV0) part.
   std::unique_ptr<DxilRDATWriter> pRDATWriter = nullptr;
   std::unique_ptr<DxilPSVWriter> pPSVWriter = nullptr;
   unsigned int major, minor;
   pModule->GetDxilVersion(major, minor);
   if (pModule->GetShaderModel()->IsLib()) {
+    // Write the DxilRuntimeData (RDAT) part.
     pRDATWriter = llvm::make_unique<DxilRDATWriter>(*pModule);
     writer.AddPart(
         DFCC_RuntimeData, pRDATWriter->size(),
         [&](AbstractMemoryStream *pStream) { pRDATWriter->write(pStream); });
-  } else if (!pModule->GetShaderModel()->IsLib()) {
+    pModule->StripSubobjectsFromMetadata();
+  } else {
+    // Write the DxilPipelineStateValidation (PSV0) part.
     pPSVWriter = llvm::make_unique<DxilPSVWriter>(*pModule);
     writer.AddPart(
         DFCC_PipelineStateValidation, pPSVWriter->size(),

+ 3 - 0
lib/HLSL/DxilGenerationPass.cpp

@@ -186,6 +186,9 @@ void InitDxilModuleFromHLModule(HLModule &H, DxilModule &M, bool HasDebugInfo) {
   // Signatures.
   M.ResetSerializedRootSignature(H.GetSerializedRootSignature());
 
+  // Subobjects.
+  M.ResetSubobjects(H.ReleaseSubobjects());
+
   // Shader properties.
   //bool m_bDisableOptimizations;
   M.SetDisableOptimization(H.GetHLOptions().bDisableOptimizations);

+ 35 - 0
lib/HLSL/HLModule.cpp

@@ -50,7 +50,12 @@ HLModule::HLModule(Module *pModule)
     , m_pSM(nullptr)
     , m_DxilMajor(DXIL::kDxilMajor)
     , m_DxilMinor(DXIL::kDxilMinor)
+    , m_ValMajor(0)
+    , m_ValMinor(0)
+    , m_Float32DenormMode(DXIL::Float32DenormMode::Any)
     , m_pOP(llvm::make_unique<OP>(pModule->getContext(), pModule))
+    , m_AutoBindingSpace(UINT_MAX)
+    , m_DefaultLinkage(DXIL::DefaultLinkage::Default)
     , m_pTypeSystem(llvm::make_unique<DxilTypeSystem>(pModule)) {
   DXASSERT_NOMSG(m_pModule != nullptr);
 
@@ -479,6 +484,11 @@ void HLModule::EmitHLMetadata() {
   if (!m_SerializedRootSignature.empty()) {
     m_pMDHelper->EmitRootSignature(m_SerializedRootSignature);
   }
+
+  // Save Subobjects
+  if (GetSubobjects()) {
+    m_pMDHelper->EmitSubobjects(*GetSubobjects());
+  }
 }
 
 void HLModule::LoadHLMetadata() {
@@ -533,6 +543,13 @@ void HLModule::LoadHLMetadata() {
   }
 
   m_pMDHelper->LoadRootSignature(m_SerializedRootSignature);
+
+  // Load Subobjects
+  std::unique_ptr<DxilSubobjects> pSubobjects(new DxilSubobjects());
+  m_pMDHelper->LoadSubobjects(*pSubobjects);
+  if (pSubobjects->GetSubobjects().size()) {
+    ResetSubobjects(pSubobjects.release());
+  }
 }
 
 void HLModule::ClearHLMetadata(llvm::Module &M) {
@@ -1235,6 +1252,24 @@ DebugInfoFinder &HLModule::GetOrCreateDebugInfoFinder() {
   }
   return *m_pDebugInfoFinder;
 }
+
+//------------------------------------------------------------------------------
+//
+// Subobject methods.
+//
+DxilSubobjects *HLModule::GetSubobjects() {
+  return m_pSubobjects.get();
+}
+const DxilSubobjects *HLModule::GetSubobjects() const {
+  return m_pSubobjects.get();
+}
+DxilSubobjects *HLModule::ReleaseSubobjects() {
+  return m_pSubobjects.release();
+}
+void HLModule::ResetSubobjects(DxilSubobjects *subobjects) {
+  m_pSubobjects.reset(subobjects);
+}
+
 //------------------------------------------------------------------------------
 //
 // Signature methods.

+ 210 - 0
tools/clang/tools/dxcompiler/dxcdisassembler.cpp

@@ -26,6 +26,7 @@
 #include "llvm/Support/FormattedStream.h"
 #include "llvm/Support/Format.h"
 #include "dxc/HLSL/DxilPipelineStateValidation.h"
+#include "dxc/HLSL/DxilRuntimeReflection.h"
 #include "dxc/HLSL/ComputeViewIdState.h"
 #include "dxc/DxilContainer/DxilContainer.h"
 #include "dxc/DXIL/DxilUtil.h"
@@ -575,6 +576,143 @@ void PrintViewIdState(DxilModule &M, raw_string_ostream &OS,
   OS << comment << "\n";
 }
 
+static const char *SubobjectKindToString(DXIL::SubobjectKind kind) {
+  switch (kind) {
+  case DXIL::SubobjectKind::StateObjectConfig: return "StateObjectConfig";
+  case DXIL::SubobjectKind::GlobalRootSignature: return "GlobalRootSignature";
+  case DXIL::SubobjectKind::LocalRootSignature: return "LocalRootSignature";
+  case DXIL::SubobjectKind::SubobjectToExportsAssociation: return "SubobjectToExportsAssociation";
+  case DXIL::SubobjectKind::RaytracingShaderConfig: return "RaytracingShaderConfig";
+  case DXIL::SubobjectKind::RaytracingPipelineConfig: return "RaytracingPipelineConfig";
+  case DXIL::SubobjectKind::HitGroup: return "HitGroup";
+  }
+  return "<invalid kind>";
+}
+
+static const char *FlagToString(DXIL::StateObjectFlags Flag) {
+  switch (Flag) {
+  case DXIL::StateObjectFlags::AllowLocalDependenciesOnExternalDefinitions:
+    return "AllowLocalDependenciesOnExternalDefinitions";
+  case DXIL::StateObjectFlags::AllowExternalDependenciesOnLocalDefinitions:
+    return "AllowExternalDependenciesOnLocalDefinitions";
+  }
+  return "<invalid StateObjectFlag>";
+}
+
+template <typename _T>
+void PrintFlags(raw_string_ostream &OS, uint32_t Flags) {
+  if (!Flags) {
+    OS << "0";
+    return;
+  }
+  uint32_t flag = 0;
+  while (Flags) {
+    if (flag)
+      OS << " | ";
+    flag = (Flags & ~(Flags - 1));
+    Flags ^= flag;
+    OS << FlagToString((_T)flag);
+  }
+}
+
+void PrintSubobjects(const DxilSubobjects &subobjects,
+                     raw_string_ostream &OS,
+                     StringRef comment) {
+  if (subobjects.GetSubobjects().empty())
+    return;
+
+  OS << comment << "\n";
+  OS << comment << " Subobjects:\n";
+  OS << comment << "\n";
+
+  for (auto &it : subobjects.GetSubobjects()) {
+    StringRef name = it.first;
+    if (!it.second) {
+      OS << comment << "  " << name << " = <null>" << "\n";
+      continue;
+    }
+    const DxilSubobject &obj = *it.second.get();
+    OS << comment << "  " << SubobjectKindToString(obj.GetKind()) << " " << name << " = " << "{ ";
+    bool bLocalRS = false;
+    switch (obj.GetKind()) {
+    case DXIL::SubobjectKind::StateObjectConfig: {
+      uint32_t Flags = 0;
+      if (!obj.GetStateObjectConfig(Flags)) {
+        OS << "<error getting subobject>";
+        break;
+      }
+      PrintFlags<DXIL::StateObjectFlags>(OS, Flags);
+      break;
+    }
+    case DXIL::SubobjectKind::LocalRootSignature:
+      bLocalRS = true;
+    case DXIL::SubobjectKind::GlobalRootSignature: {
+      const void *Data = nullptr;
+      uint32_t Size = 0;
+      if (!obj.GetRootSignature(bLocalRS, Data, Size)) {
+        OS << "<error getting subobject>";
+        break;
+      }
+      // TODO: Deserialize root signature?
+      OS << "<" << Size << " bytes>";
+      break;
+    }
+    case DXIL::SubobjectKind::SubobjectToExportsAssociation: {
+      llvm::StringRef Subobject;
+      const char * const * Exports = nullptr;
+      uint32_t NumExports;
+      if (!obj.GetSubobjectToExportsAssociation(Subobject, Exports, NumExports)) {
+        OS << "<error getting subobject>";
+        break;
+      }
+      OS << "\"" << Subobject << "\", { ";
+      if (Exports) {
+        for (unsigned i = 0; i < NumExports; ++i) {
+          OS << "\"" << Exports[i] << "\"" << (i ? ", " : "");
+        }
+      }
+      OS << " } ";
+      break;
+    }
+    case DXIL::SubobjectKind::RaytracingShaderConfig: {
+      uint32_t MaxPayloadSizeInBytes;
+      uint32_t MaxAttributeSizeInBytes;
+      if (!obj.GetRaytracingShaderConfig(MaxPayloadSizeInBytes,
+                                         MaxAttributeSizeInBytes)) {
+        OS << "<error getting subobject>";
+        break;
+      }
+      OS << "MaxPayloadSizeInBytes = " << MaxPayloadSizeInBytes
+         << "MaxAttributeSizeInBytes = " << MaxAttributeSizeInBytes;
+      break;
+    }
+    case DXIL::SubobjectKind::RaytracingPipelineConfig: {
+      uint32_t MaxTraceRecursionDepth;
+      if (!obj.GetRaytracingPipelineConfig(MaxTraceRecursionDepth)) {
+        OS << "<error getting subobject>";
+        break;
+      }
+      OS << "MaxTraceRecursionDepth = " << MaxTraceRecursionDepth;
+      break;
+    }
+    case DXIL::SubobjectKind::HitGroup: {
+      StringRef Intersection;
+      StringRef AnyHit;
+      StringRef ClosestHit;
+      if (!obj.GetHitGroup(Intersection, AnyHit, ClosestHit)) {
+        OS << "<error getting subobject>";
+        break;
+      }
+      OS << "intersection = \"" << Intersection
+         << "\", anyhit = \"" << AnyHit
+         << "\", closesthit = \"" << ClosestHit << "\"";
+      break;
+    }
+    }
+    OS << " };\n";
+  }
+}
+
 void PrintStructLayout(StructType *ST, DxilTypeSystem &typeSys,
                               raw_string_ostream &OS, StringRef comment,
                               StringRef varName, unsigned offset,
@@ -1289,6 +1427,61 @@ void PrintPipelineStateValidationRuntimeInfo(const char *pBuffer,
 
 
 namespace dxcutil {
+
+// TODO: Move DeserializeSubobjectsFromRuntimeData to more appropriate place
+void DeserializeSubobjectsFromRuntimeData(DxilSubobjects &subobjects, RDAT::DxilRuntimeData &runtimeData) {
+  RDAT::SubobjectTableReader *pSubobjectTableReader = runtimeData.GetSubobjectTableReader();
+  if (!pSubobjectTableReader)
+    return;
+  for (unsigned i = 0; i < pSubobjectTableReader->GetCount(); ++i) {
+    auto reader = pSubobjectTableReader->GetItem(i);
+    DXIL::SubobjectKind kind = reader.GetKind();
+    bool bLocalRS = false;
+    switch (kind) {
+    case DXIL::SubobjectKind::StateObjectConfig:
+      subobjects.CreateStateObjectConfig(reader.GetName(),
+        reader.GetStateObjectConfig_Flags());
+      break;
+    case DXIL::SubobjectKind::LocalRootSignature:
+      bLocalRS = true;
+    case DXIL::SubobjectKind::GlobalRootSignature: {
+      const void *pOutBytes;
+      uint32_t OutSizeInBytes;
+      reader.GetRootSignature(&pOutBytes, &OutSizeInBytes);
+      subobjects.CreateRootSignature(reader.GetName(), bLocalRS, pOutBytes, OutSizeInBytes);
+      break;
+    }
+    case DXIL::SubobjectKind::SubobjectToExportsAssociation: {
+      uint32_t NumExports = reader.GetSubobjectToExportsAssociation_NumExports();
+      std::vector<const char*> Exports;
+      Exports.resize(NumExports);
+      for (unsigned i = 0; i < NumExports; ++i) {
+        Exports[i] = reader.GetSubobjectToExportsAssociation_Export(i);
+      }
+      subobjects.CreateSubobjectToExportsAssociation(reader.GetName(),
+        reader.GetSubobjectToExportsAssociation_Subobject(),
+        Exports.data(), NumExports);
+      break;
+    }
+    case DXIL::SubobjectKind::RaytracingShaderConfig:
+      subobjects.CreateRaytracingShaderConfig(reader.GetName(),
+        reader.GetRaytracingShaderConfig_MaxPayloadSizeInBytes(),
+        reader.GetRaytracingShaderConfig_MaxAttributeSizeInBytes());
+      break;
+    case DXIL::SubobjectKind::RaytracingPipelineConfig:
+      subobjects.CreateRaytracingPipelineConfig(reader.GetName(),
+        reader.GetRaytracingPipelineConfig_MaxTraceRecursionDepth());
+      break;
+    case DXIL::SubobjectKind::HitGroup:
+      subobjects.CreateHitGroup(reader.GetName(),
+        reader.GetHitGroup_Intersection(),
+        reader.GetHitGroup_AnyHit(),
+        reader.GetHitGroup_ClosestHit());
+      break;
+    }
+  }
+}
+
 HRESULT Disassemble(IDxcBlob *pProgram, raw_string_ostream &Stream) {
   const char *pIL = (const char *)pProgram->GetBufferPointer();
   uint32_t pILLength = pProgram->GetBufferSize();
@@ -1369,6 +1562,20 @@ HRESULT Disassemble(IDxcBlob *pProgram, raw_string_ostream &Stream) {
           GetVersionShaderType(pProgramHeader->ProgramVersion), Stream,
           /*comment*/ ";");
     }
+
+    // RDAT
+    it = std::find_if(begin(pContainer), end(pContainer),
+      DxilPartIsType(DFCC_RuntimeData));
+    if (it != end(pContainer)) {
+      RDAT::DxilRuntimeData runtimeData(GetDxilPartData(*it), (*it)->PartSize);
+      Stream << ";" << " [RDAT] Begin\n";
+      // TODO: Print the rest of the RDAT info
+      DxilSubobjects subobjects;
+      DeserializeSubobjectsFromRuntimeData(subobjects, runtimeData);
+      PrintSubobjects(subobjects, Stream, /*comment*/ ";");
+      Stream << ";" << " [RDAT] End\n";
+    }
+
     GetDxilProgramBitcode(pProgramHeader, &pIL, &pILLength);
   } else {
     const DxilProgramHeader *pProgramHeader =
@@ -1400,6 +1607,9 @@ HRESULT Disassemble(IDxcBlob *pProgram, raw_string_ostream &Stream) {
     PrintBufferDefinitions(dxilModule, Stream, /*comment*/ ";");
     PrintResourceBindings(dxilModule, Stream, /*comment*/ ";");
     PrintViewIdState(dxilModule, Stream, /*comment*/ ";");
+    if (dxilModule.GetSubobjects()) {
+      PrintSubobjects(*dxilModule.GetSubobjects(), Stream, /*comment*/ ";");
+    }
   }
   DxcAssemblyAnnotationWriter w;
   pModule->print(Stream, &w);