Browse Source

This change implements the `FeedbackTexture2D[Array](MinLOD|Tiled)` types in HLSL and the backing `WriteSamplerFeedback[Bias|Level|Grad]` DXIL intrinsics.

Tristan Labelle 6 years ago
parent
commit
b7868f8081

+ 10 - 6
docs/DXIL.rst

@@ -2263,12 +2263,16 @@ ID  Name                          Description
 165 WaveMatch                     returns the bitmask of active lanes that have the same value
 166 WaveMultiPrefixOp             returns the result of the operation on groups of lanes identified by a bitmask
 167 WaveMultiPrefixBitCount       returns the count of bits set to 1 on groups of lanes identified by a bitmask
-168 SetMeshOutputCounts           Mesh shader intrinsic SetMeshOutputCounts
-169 EmitIndices                   emit a primitive's vertex indices in a mesh shader
-170 GetMeshPayload                get the mesh payload which is from amplification shader
-171 StoreVertexOutput             stores the value to mesh shader vertex output
-172 StorePrimitiveOutput          stores the value to mesh shader primitive output
-173 DispatchMesh                  Amplification shader intrinsic DispatchMesh
+168 WriteSamplerFeedback          updates a feedback texture for a sampling operation
+169 WriteSamplerFeedbackBias      updates a feedback texture for a sampling operation with a bias on the mipmap level
+170 WriteSamplerFeedbackLevel     updates a feedback texture for a sampling operation with a mipmap-level offset
+171 WriteSamplerFeedbackGrad      updates a feedback texture for a sampling operation with explicit gradients
+172 SetMeshOutputCounts           Mesh shader intrinsic SetMeshOutputCounts
+173 EmitIndices                   emit a primitive's vertex indices in a mesh shader
+174 GetMeshPayload                get the mesh payload which is from amplification shader
+175 StoreVertexOutput             stores the value to mesh shader vertex output
+176 StorePrimitiveOutput          stores the value to mesh shader primitive output
+177 DispatchMesh                  Amplification shader intrinsic DispatchMesh
 === ============================= =======================================================================================================================================================================================================================
 
 

+ 26 - 10
include/dxc/DXIL/DxilConstants.h

@@ -314,6 +314,10 @@ namespace DXIL {
     Sampler,
     TBuffer,
     RTAccelerationStructure,
+    FeedbackTexture2DMinLOD,
+    FeedbackTexture2DTiled,
+    FeedbackTexture2DArrayMinLOD,
+    FeedbackTexture2DArrayTiled,
     NumEntries,
   };
 
@@ -323,7 +327,7 @@ namespace DXIL {
   // Enumeration for operations specified by DXIL
   enum class OpCode : unsigned {
     // Amplification shader instructions
-    DispatchMesh = 173, // Amplification shader intrinsic DispatchMesh
+    DispatchMesh = 177, // Amplification shader intrinsic DispatchMesh
   
     // AnyHit Terminals
     AcceptHitAndEndSearch = 156, // Used in an any hit shader to abort the ray query and the intersection shader (if any). The current hit is committed and execution passes to the closest hit shader with the closest hit recorded so far
@@ -419,11 +423,11 @@ namespace DXIL {
     CreateHandleForLib = 160, // create resource handle from resource struct for library
   
     // Mesh shader instructions
-    EmitIndices = 169, // emit a primitive's vertex indices in a mesh shader
-    GetMeshPayload = 170, // get the mesh payload which is from amplification shader
-    SetMeshOutputCounts = 168, // Mesh shader intrinsic SetMeshOutputCounts
-    StorePrimitiveOutput = 172, // stores the value to mesh shader primitive output
-    StoreVertexOutput = 171, // stores the value to mesh shader vertex output
+    EmitIndices = 173, // emit a primitive's vertex indices in a mesh shader
+    GetMeshPayload = 174, // get the mesh payload which is from amplification shader
+    SetMeshOutputCounts = 172, // Mesh shader intrinsic SetMeshOutputCounts
+    StorePrimitiveOutput = 176, // stores the value to mesh shader primitive output
+    StoreVertexOutput = 175, // stores the value to mesh shader vertex output
   
     // Other
     CycleCounterLegacy = 109, // CycleCounterLegacy
@@ -506,6 +510,12 @@ namespace DXIL {
     TextureLoad = 66, // reads texel data without any filtering or sampling
     TextureStore = 67, // reads texel data without any filtering or sampling
   
+    // Sampler Feedback
+    WriteSamplerFeedback = 168, // updates a feedback texture for a sampling operation
+    WriteSamplerFeedbackBias = 169, // updates a feedback texture for a sampling operation with a bias on the mipmap level
+    WriteSamplerFeedbackGrad = 171, // updates a feedback texture for a sampling operation with explicit gradients
+    WriteSamplerFeedbackLevel = 170, // updates a feedback texture for a sampling operation with a mipmap-level offset
+  
     // Synchronization
     AtomicBinOp = 78, // performs an atomic operation on two operands
     AtomicCompareExchange = 79, // atomic compare and exchange to memory
@@ -595,9 +605,9 @@ namespace DXIL {
     NumOpCodes_Dxil_1_2 = 141,
     NumOpCodes_Dxil_1_3 = 162,
     NumOpCodes_Dxil_1_4 = 165,
-    NumOpCodes_Dxil_1_5 = 174,
+    NumOpCodes_Dxil_1_5 = 178,
   
-    NumOpCodes = 174 // exclusive last value of enumeration
+    NumOpCodes = 178 // exclusive last value of enumeration
   };
   // OPCODE-ENUM:END
 
@@ -774,6 +784,12 @@ namespace DXIL {
     TextureLoad,
     TextureStore,
   
+    // Sampler Feedback
+    WriteSamplerFeedback,
+    WriteSamplerFeedbackBias,
+    WriteSamplerFeedbackGrad,
+    WriteSamplerFeedbackLevel,
+  
     // Synchronization
     AtomicBinOp,
     AtomicCompareExchange,
@@ -821,9 +837,9 @@ namespace DXIL {
     NumOpClasses_Dxil_1_2 = 97,
     NumOpClasses_Dxil_1_3 = 118,
     NumOpClasses_Dxil_1_4 = 120,
-    NumOpClasses_Dxil_1_5 = 129,
+    NumOpClasses_Dxil_1_5 = 133,
   
-    NumOpClasses = 129 // exclusive last value of enumeration
+    NumOpClasses = 133 // exclusive last value of enumeration
   };
   // OPCODECLASS-ENUM:END
 

+ 181 - 0
include/dxc/DXIL/DxilInstructions.h

@@ -5550,6 +5550,187 @@ struct DxilInst_WaveMultiPrefixBitCount {
   void set_mask3(llvm::Value *val) { Instr->setOperand(5, val); }
 };
 
+/// This instruction updates a feedback texture for a sampling operation
+struct DxilInst_WriteSamplerFeedback {
+  llvm::Instruction *Instr;
+  // Construction and identification
+  DxilInst_WriteSamplerFeedback(llvm::Instruction *pInstr) : Instr(pInstr) {}
+  operator bool() const {
+    return hlsl::OP::IsDxilOpFuncCallInst(Instr, hlsl::OP::OpCode::WriteSamplerFeedback);
+  }
+  // Validation support
+  bool isAllowed() const { return true; }
+  bool isArgumentListValid() const {
+    if (8 != llvm::dyn_cast<llvm::CallInst>(Instr)->getNumArgOperands()) return false;
+    return true;
+  }
+  // Metadata
+  bool requiresUniformInputs() const { return false; }
+  // Operand indexes
+  enum OperandIdx {
+    arg_feedbackTex = 1,
+    arg_sampledTex = 2,
+    arg_sampler = 3,
+    arg_c0 = 4,
+    arg_c1 = 5,
+    arg_c2 = 6,
+    arg_clamp = 7,
+  };
+  // Accessors
+  llvm::Value *get_feedbackTex() const { return Instr->getOperand(1); }
+  void set_feedbackTex(llvm::Value *val) { Instr->setOperand(1, val); }
+  llvm::Value *get_sampledTex() const { return Instr->getOperand(2); }
+  void set_sampledTex(llvm::Value *val) { Instr->setOperand(2, val); }
+  llvm::Value *get_sampler() const { return Instr->getOperand(3); }
+  void set_sampler(llvm::Value *val) { Instr->setOperand(3, val); }
+  llvm::Value *get_c0() const { return Instr->getOperand(4); }
+  void set_c0(llvm::Value *val) { Instr->setOperand(4, val); }
+  llvm::Value *get_c1() const { return Instr->getOperand(5); }
+  void set_c1(llvm::Value *val) { Instr->setOperand(5, val); }
+  llvm::Value *get_c2() const { return Instr->getOperand(6); }
+  void set_c2(llvm::Value *val) { Instr->setOperand(6, val); }
+  llvm::Value *get_clamp() const { return Instr->getOperand(7); }
+  void set_clamp(llvm::Value *val) { Instr->setOperand(7, val); }
+};
+
+/// This instruction updates a feedback texture for a sampling operation with a bias on the mipmap level
+struct DxilInst_WriteSamplerFeedbackBias {
+  llvm::Instruction *Instr;
+  // Construction and identification
+  DxilInst_WriteSamplerFeedbackBias(llvm::Instruction *pInstr) : Instr(pInstr) {}
+  operator bool() const {
+    return hlsl::OP::IsDxilOpFuncCallInst(Instr, hlsl::OP::OpCode::WriteSamplerFeedbackBias);
+  }
+  // Validation support
+  bool isAllowed() const { return true; }
+  bool isArgumentListValid() const {
+    if (9 != llvm::dyn_cast<llvm::CallInst>(Instr)->getNumArgOperands()) return false;
+    return true;
+  }
+  // Metadata
+  bool requiresUniformInputs() const { return false; }
+  // Operand indexes
+  enum OperandIdx {
+    arg_feedbackTex = 1,
+    arg_sampledTex = 2,
+    arg_sampler = 3,
+    arg_c0 = 4,
+    arg_c1 = 5,
+    arg_c2 = 6,
+    arg_bias = 7,
+    arg_clamp = 8,
+  };
+  // Accessors
+  llvm::Value *get_feedbackTex() const { return Instr->getOperand(1); }
+  void set_feedbackTex(llvm::Value *val) { Instr->setOperand(1, val); }
+  llvm::Value *get_sampledTex() const { return Instr->getOperand(2); }
+  void set_sampledTex(llvm::Value *val) { Instr->setOperand(2, val); }
+  llvm::Value *get_sampler() const { return Instr->getOperand(3); }
+  void set_sampler(llvm::Value *val) { Instr->setOperand(3, val); }
+  llvm::Value *get_c0() const { return Instr->getOperand(4); }
+  void set_c0(llvm::Value *val) { Instr->setOperand(4, val); }
+  llvm::Value *get_c1() const { return Instr->getOperand(5); }
+  void set_c1(llvm::Value *val) { Instr->setOperand(5, val); }
+  llvm::Value *get_c2() const { return Instr->getOperand(6); }
+  void set_c2(llvm::Value *val) { Instr->setOperand(6, val); }
+  llvm::Value *get_bias() const { return Instr->getOperand(7); }
+  void set_bias(llvm::Value *val) { Instr->setOperand(7, val); }
+  llvm::Value *get_clamp() const { return Instr->getOperand(8); }
+  void set_clamp(llvm::Value *val) { Instr->setOperand(8, val); }
+};
+
+/// This instruction updates a feedback texture for a sampling operation with a mipmap-level offset
+struct DxilInst_WriteSamplerFeedbackLevel {
+  llvm::Instruction *Instr;
+  // Construction and identification
+  DxilInst_WriteSamplerFeedbackLevel(llvm::Instruction *pInstr) : Instr(pInstr) {}
+  operator bool() const {
+    return hlsl::OP::IsDxilOpFuncCallInst(Instr, hlsl::OP::OpCode::WriteSamplerFeedbackLevel);
+  }
+  // Validation support
+  bool isAllowed() const { return true; }
+  bool isArgumentListValid() const {
+    if (8 != llvm::dyn_cast<llvm::CallInst>(Instr)->getNumArgOperands()) return false;
+    return true;
+  }
+  // Metadata
+  bool requiresUniformInputs() const { return false; }
+  // Operand indexes
+  enum OperandIdx {
+    arg_feedbackTex = 1,
+    arg_sampledTex = 2,
+    arg_sampler = 3,
+    arg_c0 = 4,
+    arg_c1 = 5,
+    arg_c2 = 6,
+    arg_lod = 7,
+  };
+  // Accessors
+  llvm::Value *get_feedbackTex() const { return Instr->getOperand(1); }
+  void set_feedbackTex(llvm::Value *val) { Instr->setOperand(1, val); }
+  llvm::Value *get_sampledTex() const { return Instr->getOperand(2); }
+  void set_sampledTex(llvm::Value *val) { Instr->setOperand(2, val); }
+  llvm::Value *get_sampler() const { return Instr->getOperand(3); }
+  void set_sampler(llvm::Value *val) { Instr->setOperand(3, val); }
+  llvm::Value *get_c0() const { return Instr->getOperand(4); }
+  void set_c0(llvm::Value *val) { Instr->setOperand(4, val); }
+  llvm::Value *get_c1() const { return Instr->getOperand(5); }
+  void set_c1(llvm::Value *val) { Instr->setOperand(5, val); }
+  llvm::Value *get_c2() const { return Instr->getOperand(6); }
+  void set_c2(llvm::Value *val) { Instr->setOperand(6, val); }
+  llvm::Value *get_lod() const { return Instr->getOperand(7); }
+  void set_lod(llvm::Value *val) { Instr->setOperand(7, val); }
+};
+
+/// This instruction updates a feedback texture for a sampling operation with explicit gradients
+struct DxilInst_WriteSamplerFeedbackGrad {
+  llvm::Instruction *Instr;
+  // Construction and identification
+  DxilInst_WriteSamplerFeedbackGrad(llvm::Instruction *pInstr) : Instr(pInstr) {}
+  operator bool() const {
+    return hlsl::OP::IsDxilOpFuncCallInst(Instr, hlsl::OP::OpCode::WriteSamplerFeedbackGrad);
+  }
+  // Validation support
+  bool isAllowed() const { return true; }
+  bool isArgumentListValid() const {
+    if (10 != llvm::dyn_cast<llvm::CallInst>(Instr)->getNumArgOperands()) return false;
+    return true;
+  }
+  // Metadata
+  bool requiresUniformInputs() const { return false; }
+  // Operand indexes
+  enum OperandIdx {
+    arg_feedbackTex = 1,
+    arg_sampledTex = 2,
+    arg_sampler = 3,
+    arg_c0 = 4,
+    arg_c1 = 5,
+    arg_c2 = 6,
+    arg_ddx = 7,
+    arg_ddy = 8,
+    arg_clamp = 9,
+  };
+  // Accessors
+  llvm::Value *get_feedbackTex() const { return Instr->getOperand(1); }
+  void set_feedbackTex(llvm::Value *val) { Instr->setOperand(1, val); }
+  llvm::Value *get_sampledTex() const { return Instr->getOperand(2); }
+  void set_sampledTex(llvm::Value *val) { Instr->setOperand(2, val); }
+  llvm::Value *get_sampler() const { return Instr->getOperand(3); }
+  void set_sampler(llvm::Value *val) { Instr->setOperand(3, val); }
+  llvm::Value *get_c0() const { return Instr->getOperand(4); }
+  void set_c0(llvm::Value *val) { Instr->setOperand(4, val); }
+  llvm::Value *get_c1() const { return Instr->getOperand(5); }
+  void set_c1(llvm::Value *val) { Instr->setOperand(5, val); }
+  llvm::Value *get_c2() const { return Instr->getOperand(6); }
+  void set_c2(llvm::Value *val) { Instr->setOperand(6, val); }
+  llvm::Value *get_ddx() const { return Instr->getOperand(7); }
+  void set_ddx(llvm::Value *val) { Instr->setOperand(7, val); }
+  llvm::Value *get_ddy() const { return Instr->getOperand(8); }
+  void set_ddy(llvm::Value *val) { Instr->setOperand(8, val); }
+  llvm::Value *get_clamp() const { return Instr->getOperand(9); }
+  void set_clamp(llvm::Value *val) { Instr->setOperand(9, val); }
+};
+
 /// This instruction Mesh shader intrinsic SetMeshOutputCounts
 struct DxilInst_SetMeshOutputCounts {
   llvm::Instruction *Instr;

+ 8 - 0
include/dxc/HLSL/HLOperations.h

@@ -296,6 +296,14 @@ const unsigned kGatherCmpStatusArgIndex = 6;
 const unsigned kGatherCmpSampleOffsetArgIndex = 6;
 const unsigned kGatherCmpStatusWithSampleOffsetArgIndex = 9;
 
+// WriteSamplerFeedback.
+const unsigned kWriteSamplerFeedbackSampledArgIndex = 2;
+const unsigned kWriteSamplerFeedbackSamplerArgIndex = 3;
+const unsigned kWriteSamplerFeedbackCoordArgIndex = 4;
+const unsigned kWriteSamplerFeedbackBiasOrLodArgIndex = 5;
+const unsigned kWriteSamplerFeedbackDdxArgIndex = 5;
+const unsigned kWriteSamplerFeedbackDdyArgIndex = 6;
+
 // StreamAppend.
 const unsigned kStreamAppendStreamOpIndex = 1;
 const unsigned kStreamAppendDataOpIndex = 2;

+ 4 - 0
include/dxc/HlslIntrinsicOp.h

@@ -262,6 +262,10 @@ import hctdb_instrhelp
   MOP_DecrementCounter,
   MOP_IncrementCounter,
   MOP_Consume,
+  MOP_WriteSamplerFeedback,
+  MOP_WriteSamplerFeedbackBias,
+  MOP_WriteSamplerFeedbackGrad,
+  MOP_WriteSamplerFeedbackLevel,
 #ifdef ENABLE_SPIRV_CODEGEN
   MOP_SubpassLoad,
 #endif // ENABLE_SPIRV_CODEGEN

+ 4 - 1
include/dxc/dxcapi.internal.h

@@ -87,7 +87,10 @@ enum LEGAL_INTRINSIC_COMPTYPES {
   LICOMPTYPE_ACCELERATION_STRUCT = 31,
   LICOMPTYPE_USER_DEFINED_TYPE = 32,
 
-  LICOMPTYPE_COUNT = 33
+  LICOMPTYPE_TEXTURE2D = 33,
+  LICOMPTYPE_TEXTURE2DARRAY = 34,
+
+  LICOMPTYPE_COUNT = 35
 };
 
 static const BYTE IA_SPECIAL_BASE = 0xf0;

+ 30 - 7
lib/DXIL/DxilOperations.cpp

@@ -322,6 +322,12 @@ const OP::OpCodeProperty OP::m_OpCodeProps[(unsigned)OP::OpCode::NumOpCodes] = {
   {  OC::WaveMultiPrefixOp,       "WaveMultiPrefixOp",        OCC::WaveMultiPrefixOp,        "waveMultiPrefixOp",         { false,  true,  true,  true, false,  true,  true,  true,  true, false, false}, Attribute::None,     },
   {  OC::WaveMultiPrefixBitCount, "WaveMultiPrefixBitCount",  OCC::WaveMultiPrefixBitCount,  "waveMultiPrefixBitCount",   {  true, false, false, false, false, false, false, false, false, false, false}, Attribute::None,     },
 
+  // Sampler Feedback                                                                                                        void,     h,     f,     d,    i1,    i8,   i16,   i32,   i64,   udt,   obj ,  function attribute
+  {  OC::WriteSamplerFeedback,    "WriteSamplerFeedback",     OCC::WriteSamplerFeedback,     "writeSamplerFeedback",      {  true, false, false, false, false, false, false, false, false, false, false}, Attribute::None,     },
+  {  OC::WriteSamplerFeedbackBias, "WriteSamplerFeedbackBias", OCC::WriteSamplerFeedbackBias, "writeSamplerFeedbackBias",  {  true, false, false, false, false, false, false, false, false, false, false}, Attribute::None,     },
+  {  OC::WriteSamplerFeedbackLevel, "WriteSamplerFeedbackLevel", OCC::WriteSamplerFeedbackLevel, "writeSamplerFeedbackLevel", {  true, false, false, false, false, false, false, false, false, false, false}, Attribute::None,     },
+  {  OC::WriteSamplerFeedbackGrad, "WriteSamplerFeedbackGrad", OCC::WriteSamplerFeedbackGrad, "writeSamplerFeedbackGrad",  {  true, false, false, false, false, false, false, false, false, false, false}, Attribute::None,     },
+
   // Mesh shader instructions                                                                                                void,     h,     f,     d,    i1,    i8,   i16,   i32,   i64,   udt,   obj ,  function attribute
   {  OC::SetMeshOutputCounts,     "SetMeshOutputCounts",      OCC::SetMeshOutputCounts,      "setMeshOutputCounts",       {  true, false, false, false, false, false, false, false, false, false, false}, Attribute::None,     },
   {  OC::EmitIndices,             "EmitIndices",              OCC::EmitIndices,              "emitIndices",               {  true, false, false, false, false, false, false, false, false, false, false}, Attribute::None,     },
@@ -667,20 +673,27 @@ void OP::GetMinShaderModelAndMask(OpCode C, bool bWithTranslation,
     return;
   }
   // Instructions: WaveMatch=165, WaveMultiPrefixOp=166,
-  // WaveMultiPrefixBitCount=167
-  if ((165 <= op && op <= 167)) {
+  // WaveMultiPrefixBitCount=167, WriteSamplerFeedbackLevel=170,
+  // WriteSamplerFeedbackGrad=171
+  if ((165 <= op && op <= 167) || (170 <= op && op <= 171)) {
     major = 6;  minor = 5;
     return;
   }
-  // Instructions: DispatchMesh=173
-  if (op == 173) {
+  // Instructions: DispatchMesh=177
+  if (op == 177) {
     major = 6;  minor = 5;
     mask = SFLAG(Amplification);
     return;
   }
-  // Instructions: SetMeshOutputCounts=168, EmitIndices=169, GetMeshPayload=170,
-  // StoreVertexOutput=171, StorePrimitiveOutput=172
-  if ((168 <= op && op <= 172)) {
+  // Instructions: WriteSamplerFeedback=168, WriteSamplerFeedbackBias=169
+  if ((168 <= op && op <= 169)) {
+    major = 6;  minor = 5;
+    mask = SFLAG(Library) | SFLAG(Pixel);
+    return;
+  }
+  // Instructions: SetMeshOutputCounts=172, EmitIndices=173, GetMeshPayload=174,
+  // StoreVertexOutput=175, StorePrimitiveOutput=176
+  if ((172 <= op && op <= 176)) {
     major = 6;  minor = 5;
     mask = SFLAG(Mesh);
     return;
@@ -1086,6 +1099,12 @@ Function *OP::GetOpFunc(OpCode opCode, Type *pOverloadType) {
   case OpCode::WaveMultiPrefixOp:      A(pETy);     A(pI32); A(pETy); A(pI32); A(pI32); A(pI32); A(pI32); A(pI8);  A(pI8);  break;
   case OpCode::WaveMultiPrefixBitCount:A(pI32);     A(pI32); A(pI1);  A(pI32); A(pI32); A(pI32); A(pI32); break;
 
+    // Sampler Feedback
+  case OpCode::WriteSamplerFeedback:   A(pV);       A(pI32); A(pRes); A(pRes); A(pRes); A(pF32); A(pF32); A(pF32); A(pF32); break;
+  case OpCode::WriteSamplerFeedbackBias:A(pV);       A(pI32); A(pRes); A(pRes); A(pRes); A(pF32); A(pF32); A(pF32); A(pF32); A(pF32); break;
+  case OpCode::WriteSamplerFeedbackLevel:A(pV);       A(pI32); A(pRes); A(pRes); A(pRes); A(pF32); A(pF32); A(pF32); A(pF32); break;
+  case OpCode::WriteSamplerFeedbackGrad:A(pV);       A(pI32); A(pRes); A(pRes); A(pRes); A(pF32); A(pF32); A(pF32); A(pF32); A(pF32); A(pF32); break;
+
     // Mesh shader instructions
   case OpCode::SetMeshOutputCounts:    A(pV);       A(pI32); A(pI32); A(pI32); break;
   case OpCode::EmitIndices:            A(pV);       A(pI32); A(pI32); A(pI32); A(pI32); A(pI32); break;
@@ -1251,6 +1270,10 @@ llvm::Type *OP::GetOverloadType(OpCode opCode, llvm::Function *F) {
   case OpCode::IgnoreHit:
   case OpCode::AcceptHitAndEndSearch:
   case OpCode::WaveMultiPrefixBitCount:
+  case OpCode::WriteSamplerFeedback:
+  case OpCode::WriteSamplerFeedbackBias:
+  case OpCode::WriteSamplerFeedbackLevel:
+  case OpCode::WriteSamplerFeedbackGrad:
   case OpCode::SetMeshOutputCounts:
   case OpCode::EmitIndices:
     return Type::getVoidTy(m_Ctx);

+ 16 - 0
lib/DXIL/DxilResource.cpp

@@ -146,6 +146,10 @@ unsigned DxilResource::GetNumCoords(Kind ResourceKind) {
       0, // Sampler,
       1, // TBuffer,
       0, // RaytracingAccelerationStructure,
+      2, // FeedbackTexture2DMinLOD,
+      2, // FeedbackTexture2DTiled,
+      3, // FeedbackTexture2DArrayMinLOD,
+      3, // FeedbackTexture2DArrayTiled,
   };
   static_assert(_countof(CoordSizeTab) == (unsigned)Kind::NumEntries, "check helper array size");
   DXASSERT(ResourceKind > Kind::Invalid && ResourceKind < Kind::NumEntries, "otherwise the caller passed wrong resource type");
@@ -171,6 +175,10 @@ unsigned DxilResource::GetNumDimensions(Kind ResourceKind) {
       0, // Sampler,
       1, // TBuffer,
       0, // RaytracingAccelerationStructure,
+      2, // FeedbackTexture2DMinLOD,
+      2, // FeedbackTexture2DTiled,
+      2, // FeedbackTexture2DArrayMinLOD,
+      2, // FeedbackTexture2DArrayTiled,
   };
   static_assert(_countof(NumDimTab) == (unsigned)Kind::NumEntries, "check helper array size");
   DXASSERT(ResourceKind > Kind::Invalid && ResourceKind < Kind::NumEntries, "otherwise the caller passed wrong resource type");
@@ -196,6 +204,10 @@ unsigned DxilResource::GetNumDimensionsForCalcLOD(Kind ResourceKind) {
       0, // Sampler,
       1, // TBuffer,
       0, // RaytracingAccelerationStructure,
+      2, // FeedbackTexture2DMinLOD,
+      2, // FeedbackTexture2DTiled,
+      2, // FeedbackTexture2DArrayMinLOD,
+      2, // FeedbackTexture2DArrayTiled,
   };
   static_assert(_countof(NumDimTab) == (unsigned)Kind::NumEntries, "check helper array size");
   DXASSERT(ResourceKind > Kind::Invalid && ResourceKind < Kind::NumEntries, "otherwise the caller passed wrong resource type");
@@ -221,6 +233,10 @@ unsigned DxilResource::GetNumOffsets(Kind ResourceKind) {
       0, // Sampler,
       1, // TBuffer,
       0, // RaytracingAccelerationStructure,
+      2, // FeedbackTexture2DMinLOD,
+      2, // FeedbackTexture2DTiled,
+      2, // FeedbackTexture2DArrayMinLOD,
+      2, // FeedbackTexture2DArrayTiled,
   };
   static_assert(_countof(OffsetSizeTab) == (unsigned)Kind::NumEntries, "check helper array size");
   DXASSERT(ResourceKind > Kind::Invalid && ResourceKind < Kind::NumEntries, "otherwise the caller passed wrong resource type");

+ 15 - 7
lib/DXIL/DxilResourceBase.cpp

@@ -56,36 +56,44 @@ void DxilResourceBase::SetGlobalSymbol(llvm::Constant *pGV)       { m_pSymbol =
 void DxilResourceBase::SetGlobalName(const std::string &Name)     { m_Name = Name; }
 void DxilResourceBase::SetHandle(llvm::Value *pHandle)            { m_pHandle = pHandle; }
 
-static const char *s_ResourceClassNames[(unsigned)DxilResourceBase::Class::Invalid] = {
+static const char *s_ResourceClassNames[] = {
     "texture", "UAV", "cbuffer", "sampler"
 };
+static_assert(_countof(s_ResourceClassNames) == (unsigned)DxilResourceBase::Class::Invalid,
+  "Resource class names array must be updated when new resource class enums are added.");
 
 const char *DxilResourceBase::GetResClassName() const {
   return s_ResourceClassNames[(unsigned)m_Class];
 }
 
-static const char *s_ResourceIDPrefixs[(unsigned)DxilResourceBase::Class::Invalid] = {
+static const char *s_ResourceIDPrefixes[] = {
     "T", "U", "CB", "S"
 };
+static_assert(_countof(s_ResourceIDPrefixes) == (unsigned)DxilResourceBase::Class::Invalid,
+  "Resource id prefixes array must be updated when new resource class enums are added.");
 
 const char *DxilResourceBase::GetResIDPrefix() const {
-  return s_ResourceIDPrefixs[(unsigned)m_Class];
+  return s_ResourceIDPrefixes[(unsigned)m_Class];
 }
 
-static const char *s_ResourceBindPrefixs[(unsigned)DxilResourceBase::Class::Invalid] = {
+static const char *s_ResourceBindPrefixes[] = {
     "t", "u", "cb", "s"
 };
+static_assert(_countof(s_ResourceBindPrefixes) == (unsigned)DxilResourceBase::Class::Invalid,
+  "Resource bind prefixes array must be updated when new resource class enums are added.");
 
 const char *DxilResourceBase::GetResBindPrefix() const {
-  return s_ResourceBindPrefixs[(unsigned)m_Class];
+  return s_ResourceBindPrefixes[(unsigned)m_Class];
 }
 
-static const char *s_ResourceDimNames[(unsigned)DxilResourceBase::Kind::NumEntries] = {
+static const char *s_ResourceDimNames[] = {
         "invalid", "1d",        "2d",      "2dMS",      "3d",
         "cube",    "1darray",   "2darray", "2darrayMS", "cubearray",
         "buf",     "rawbuf",    "structbuf", "cbuffer", "sampler",
-        "tbuffer", "ras",
+        "tbuffer", "ras", "fbtex2dML", "fbtex2dT", "fbtex2darrayML", "fbtex2darrayT"
 };
+static_assert(_countof(s_ResourceDimNames) == (unsigned)DxilResourceBase::Kind::NumEntries,
+  "Resource dim names array must be updated when new resource kind enums are added.");
 
 const char *DxilResourceBase::GetResDimName() const {
   return s_ResourceDimNames[(unsigned)m_Kind];

+ 19 - 8
lib/DXIL/DxilUtil.cpp

@@ -467,11 +467,17 @@ llvm::Instruction *FirstNonAllocaInsertionPt(llvm::Function* F) {
   return SkipAllocas(FindAllocaInsertionPt(F));
 }
 
+static bool ConsumePrefix(StringRef &Str, StringRef Prefix) {
+  if (!Str.startswith(Prefix)) return false;
+  Str = Str.substr(Prefix.size());
+  return true;
+}
+
 bool IsHLSLResourceType(llvm::Type *Ty) {
   if (llvm::StructType *ST = dyn_cast<llvm::StructType>(Ty)) {
     StringRef name = ST->getName();
-    name = name.ltrim("class.");
-    name = name.ltrim("struct.");
+    ConsumePrefix(name, "class.");
+    ConsumePrefix(name, "struct.");
 
     if (name == "SamplerState")
       return true;
@@ -489,8 +495,13 @@ bool IsHLSLResourceType(llvm::Type *Ty) {
     if (name == "RaytracingAccelerationStructure")
       return true;
 
-    name = name.ltrim("RasterizerOrdered");
-    name = name.ltrim("RW");
+    if (ConsumePrefix(name, "FeedbackTexture2D")) {
+      ConsumePrefix(name, "Array");
+      return name == "MinLOD" || name == "Tiled";
+    }
+
+    ConsumePrefix(name, "RasterizerOrdered");
+    ConsumePrefix(name, "RW");
     if (name == "ByteAddressBuffer")
       return true;
 
@@ -499,8 +510,7 @@ bool IsHLSLResourceType(llvm::Type *Ty) {
     if (name.startswith("StructuredBuffer<"))
       return true;
 
-    if (name.startswith("Texture")) {
-      name = name.ltrim("Texture");
+    if (ConsumePrefix(name, "Texture")) {
       if (name.startswith("1D<"))
         return true;
       if (name.startswith("1DArray<"))
@@ -519,6 +529,7 @@ bool IsHLSLResourceType(llvm::Type *Ty) {
         return true;
       if (name.startswith("2DMSArray<"))
         return true;
+      return false;
     }
   }
   return false;
@@ -537,8 +548,8 @@ bool IsHLSLObjectType(llvm::Type *Ty) {
     if (IsHLSLResourceType(Ty))
       return true;
 
-    name = name.ltrim("class.");
-    name = name.ltrim("struct.");
+    ConsumePrefix(name, "class.");
+    ConsumePrefix(name, "struct.");
 
     if (name.startswith("TriangleStream<"))
       return true;

+ 43 - 36
lib/DxilPIXPasses/DxilShaderAccessTracking.cpp

@@ -439,41 +439,44 @@ bool DxilShaderAccessTracking::runOnModule(Module &M)
     {
       DXIL::OpCode opcode;
       ShaderAccessFlags readWrite;
-      bool functionUsesSamplerAtIndex2;
-      std::vector<Type*> overloads;
+      ArrayRef<Type*> overloads;
     };
 
-    std::vector<Type*> voidType = { Type::getVoidTy(Ctx) };
-    std::vector<Type*> i32 = { Type::getInt32Ty(Ctx) };
-    std::vector<Type*> f16f32 = { Type::getHalfTy(Ctx), Type::getFloatTy(Ctx) };
-    std::vector<Type*> f32i32 = { Type::getFloatTy(Ctx), Type::getInt32Ty(Ctx) };
-    std::vector<Type*> f32i32f64 = { Type::getFloatTy(Ctx), Type::getInt32Ty(Ctx), Type::getDoubleTy(Ctx) };
-    std::vector<Type*> f16f32i16i32 = { Type::getHalfTy(Ctx), Type::getFloatTy(Ctx), Type::getInt16Ty(Ctx), Type::getInt32Ty(Ctx) };
-    std::vector<Type*> f16f32f64i16i32i64 = { Type::getHalfTy(Ctx), Type::getFloatTy(Ctx), Type::getDoubleTy(Ctx), Type::getInt16Ty(Ctx), Type::getInt32Ty(Ctx), Type::getInt64Ty(Ctx) };
+    Type* voidType[] = { Type::getVoidTy(Ctx) };
+    Type* i32[] = { Type::getInt32Ty(Ctx) };
+    Type* f16f32[] = { Type::getHalfTy(Ctx), Type::getFloatTy(Ctx) };
+    Type* f32i32[] = { Type::getFloatTy(Ctx), Type::getInt32Ty(Ctx) };
+    Type* f32i32f64[] = { Type::getFloatTy(Ctx), Type::getInt32Ty(Ctx), Type::getDoubleTy(Ctx) };
+    Type* f16f32i16i32[] = { Type::getHalfTy(Ctx), Type::getFloatTy(Ctx), Type::getInt16Ty(Ctx), Type::getInt32Ty(Ctx) };
+    Type* f16f32f64i16i32i64[] = { Type::getHalfTy(Ctx), Type::getFloatTy(Ctx), Type::getDoubleTy(Ctx), Type::getInt16Ty(Ctx), Type::getInt32Ty(Ctx), Type::getInt64Ty(Ctx) };
 
 
     // todo: should "GetDimensions" mean a resource access?
-    static_assert(DXIL::OpCode::NumOpCodes == static_cast<DXIL::OpCode>(174), "Please update PIX passes if any resource access opcodes are added");
+    static_assert(DXIL::OpCode::NumOpCodes == static_cast<DXIL::OpCode>(178), "Please update PIX passes if any resource access opcodes are added");
     ResourceAccessFunction raFunctions[] = {
-      { DXIL::OpCode::CBufferLoadLegacy     , ShaderAccessFlags::Read   , false, f32i32f64 },
-      { DXIL::OpCode::CBufferLoad           , ShaderAccessFlags::Read   , false, f16f32f64i16i32i64 },
-      { DXIL::OpCode::Sample                , ShaderAccessFlags::Read   , true , f16f32 },
-      { DXIL::OpCode::SampleBias            , ShaderAccessFlags::Read   , true , f16f32 },
-      { DXIL::OpCode::SampleLevel           , ShaderAccessFlags::Read   , true , f16f32 },
-      { DXIL::OpCode::SampleGrad            , ShaderAccessFlags::Read   , true , f16f32 },
-      { DXIL::OpCode::SampleCmp             , ShaderAccessFlags::Read   , true , f16f32 },
-      { DXIL::OpCode::SampleCmpLevelZero    , ShaderAccessFlags::Read   , true , f16f32 },
-      { DXIL::OpCode::TextureLoad           , ShaderAccessFlags::Read   , false, f16f32i16i32 },
-      { DXIL::OpCode::TextureStore          , ShaderAccessFlags::Write  , false, f16f32i16i32 },
-      { DXIL::OpCode::TextureGather         , ShaderAccessFlags::Read   , true , f16f32i16i32 },
-      { DXIL::OpCode::TextureGatherCmp      , ShaderAccessFlags::Read   , false, f16f32i16i32 },
-      { DXIL::OpCode::BufferLoad            , ShaderAccessFlags::Read   , false, f32i32 },
-      { DXIL::OpCode::RawBufferLoad         , ShaderAccessFlags::Read   , false, f16f32i16i32 },
-      { DXIL::OpCode::RawBufferStore        , ShaderAccessFlags::Write  , false, f16f32i16i32 },
-      { DXIL::OpCode::BufferStore           , ShaderAccessFlags::Write  , false, f32i32 },
-      { DXIL::OpCode::BufferUpdateCounter   , ShaderAccessFlags::Counter, false, voidType },
-      { DXIL::OpCode::AtomicBinOp           , ShaderAccessFlags::Write  , false, i32 },
-      { DXIL::OpCode::AtomicCompareExchange , ShaderAccessFlags::Write  , false, i32 },
+      { DXIL::OpCode::CBufferLoadLegacy             , ShaderAccessFlags::Read   , f32i32f64 },
+      { DXIL::OpCode::CBufferLoad                   , ShaderAccessFlags::Read   , f16f32f64i16i32i64 },
+      { DXIL::OpCode::Sample                        , ShaderAccessFlags::Read   , f16f32 },
+      { DXIL::OpCode::SampleBias                    , ShaderAccessFlags::Read   , f16f32 },
+      { DXIL::OpCode::SampleLevel                   , ShaderAccessFlags::Read   , f16f32 },
+      { DXIL::OpCode::SampleGrad                    , ShaderAccessFlags::Read   , f16f32 },
+      { DXIL::OpCode::SampleCmp                     , ShaderAccessFlags::Read   , f16f32 },
+      { DXIL::OpCode::SampleCmpLevelZero            , ShaderAccessFlags::Read   , f16f32 },
+      { DXIL::OpCode::TextureLoad                   , ShaderAccessFlags::Read   , f16f32i16i32 },
+      { DXIL::OpCode::TextureStore                  , ShaderAccessFlags::Write  , f16f32i16i32 },
+      { DXIL::OpCode::TextureGather                 , ShaderAccessFlags::Read   , f16f32i16i32 },
+      { DXIL::OpCode::TextureGatherCmp              , ShaderAccessFlags::Read   , f16f32i16i32 },
+      { DXIL::OpCode::BufferLoad                    , ShaderAccessFlags::Read   , f32i32 },
+      { DXIL::OpCode::RawBufferLoad                 , ShaderAccessFlags::Read   , f16f32i16i32 },
+      { DXIL::OpCode::RawBufferStore                , ShaderAccessFlags::Write  , f16f32i16i32 },
+      { DXIL::OpCode::BufferStore                   , ShaderAccessFlags::Write  , f32i32 },
+      { DXIL::OpCode::BufferUpdateCounter           , ShaderAccessFlags::Counter, voidType },
+      { DXIL::OpCode::AtomicBinOp                   , ShaderAccessFlags::Write  , i32 },
+      { DXIL::OpCode::AtomicCompareExchange         , ShaderAccessFlags::Write  , i32 },
+      { DXIL::OpCode::WriteSamplerFeedback          , ShaderAccessFlags::Write  , voidType },
+      { DXIL::OpCode::WriteSamplerFeedbackBias      , ShaderAccessFlags::Write  , voidType },
+      { DXIL::OpCode::WriteSamplerFeedbackGrad      , ShaderAccessFlags::Write  , voidType },
+      { DXIL::OpCode::WriteSamplerFeedbackLevel     , ShaderAccessFlags::Write  , voidType },
     };
 
     for (const auto & raFunction : raFunctions) {
@@ -483,23 +486,27 @@ bool DxilShaderAccessTracking::runOnModule(Module &M)
         for (auto FI = TexLoadFunctionUses.begin(); FI != TexLoadFunctionUses.end(); ) {
           auto & FunctionUse = *FI++;
           auto FunctionUser = FunctionUse.getUser();
-          auto instruction = cast<Instruction>(FunctionUser);
+          auto Call = cast<CallInst>(FunctionUser);
 
-          auto res = GetResourceFromHandle(instruction->getOperand(1), DM);
+          auto res = GetResourceFromHandle(Call->getArgOperand(1), DM);
 
           // Don't instrument the accesses to the UAV that we just added
           if (res.resource->GetSpaceID() == (unsigned)-2) {
             continue;
           }
 
-          if (EmitResourceAccess(res, instruction, HlslOP, Ctx, raFunction.readWrite)) {
+          if (EmitResourceAccess(res, Call, HlslOP, Ctx, raFunction.readWrite)) {
             Modified = true;
           }
 
-          if (raFunction.functionUsesSamplerAtIndex2) {
-            auto sampler = GetResourceFromHandle(instruction->getOperand(2), DM);
-            if (EmitResourceAccess(sampler, instruction, HlslOP, Ctx, ShaderAccessFlags::Read)) {
-              Modified = true;
+          // Find any secondary resource operand, typically a sampler, and mark it as read.
+          for (unsigned i = 2; i < Call->getNumArgOperands(); ++i) {
+            Value *Arg = Call->getOperand(i);
+            if (Arg->getType() == HlslOP->GetHandleType()) {
+              DxilResourceAndClass SecondaryResource = GetResourceFromHandle(Arg, DM);
+              if (EmitResourceAccess(SecondaryResource, Call, HlslOP, Ctx, ShaderAccessFlags::Read)) {
+                Modified = true;
+              }
             }
           }
         }

+ 17 - 7
lib/HLSL/DxilValidation.cpp

@@ -874,16 +874,21 @@ static bool ValidateOpcodeInProfile(DXIL::OpCode opcode,
   if ((162 <= op && op <= 164))
     return (major > 6 || (major == 6 && minor >= 4));
   // Instructions: WaveMatch=165, WaveMultiPrefixOp=166,
-  // WaveMultiPrefixBitCount=167
-  if ((165 <= op && op <= 167))
+  // WaveMultiPrefixBitCount=167, WriteSamplerFeedbackLevel=170,
+  // WriteSamplerFeedbackGrad=171
+  if ((165 <= op && op <= 167) || (170 <= op && op <= 171))
     return (major > 6 || (major == 6 && minor >= 5));
-  // Instructions: DispatchMesh=173
-  if (op == 173)
+  // Instructions: DispatchMesh=177
+  if (op == 177)
     return (major > 6 || (major == 6 && minor >= 5))
         && (SK == DXIL::ShaderKind::Amplification);
-  // Instructions: SetMeshOutputCounts=168, EmitIndices=169, GetMeshPayload=170,
-  // StoreVertexOutput=171, StorePrimitiveOutput=172
-  if ((168 <= op && op <= 172))
+  // Instructions: WriteSamplerFeedback=168, WriteSamplerFeedbackBias=169
+  if ((168 <= op && op <= 169))
+    return (major > 6 || (major == 6 && minor >= 5))
+        && (SK == DXIL::ShaderKind::Library || SK == DXIL::ShaderKind::Pixel);
+  // Instructions: SetMeshOutputCounts=172, EmitIndices=173, GetMeshPayload=174,
+  // StoreVertexOutput=175, StorePrimitiveOutput=176
+  if ((172 <= op && op <= 176))
     return (major > 6 || (major == 6 && minor >= 5))
         && (SK == DXIL::ShaderKind::Mesh);
   return true;
@@ -3880,6 +3885,11 @@ static void ValidateResource(hlsl::DxilResource &res,
   case DXIL::ResourceKind::RTAccelerationStructure:
     // TODO: check profile.
     break;
+  case DXIL::ResourceKind::FeedbackTexture2DMinLOD:
+  case DXIL::ResourceKind::FeedbackTexture2DTiled:
+  case DXIL::ResourceKind::FeedbackTexture2DArrayMinLOD:
+  case DXIL::ResourceKind::FeedbackTexture2DArrayTiled:
+    break;
   default:
     ValCtx.EmitResourceError(&res, ValidationRule::SmInvalidResourceKind);
     break;

+ 68 - 1
lib/HLSL/HLOperationLower.cpp

@@ -3244,6 +3244,67 @@ Value *TranslateGather(CallInst *CI, IntrinsicOp IOP, OP::OpCode opcode,
   return nullptr;
 }
 
+static Value* TranslateWriteSamplerFeedback(CallInst* CI, IntrinsicOp IOP, OP::OpCode opcode,
+  HLOperationLowerHelper& helper, HLObjectOperationLowerHelper* pObjHelper, bool& Translated) {
+
+  hlsl::OP* hlslOP = &helper.hlslOP;
+
+  IRBuilder<> Builder(CI);
+
+  // Build the DXIL operands
+  SmallVector<Value*, 8> DxilOperands;
+  DxilOperands.emplace_back(Builder.getInt32((unsigned)opcode));
+  DxilOperands.emplace_back(CI->getArgOperand(HLOperandIndex::kHandleOpIdx));
+  DxilOperands.emplace_back(CI->getArgOperand(HLOperandIndex::kWriteSamplerFeedbackSampledArgIndex));
+  DxilOperands.emplace_back(CI->getArgOperand(HLOperandIndex::kWriteSamplerFeedbackSamplerArgIndex));
+
+  // Coords operands
+  constexpr unsigned NumDxilCoordsOperands = 3;
+  Value* CoordsVec = CI->getArgOperand(HLOperandIndex::kWriteSamplerFeedbackCoordArgIndex);
+  VectorType *CoordsVecTy = cast<VectorType>(CoordsVec->getType());
+  DXASSERT_NOMSG(CoordsVecTy->getNumElements() <= NumDxilCoordsOperands);
+  for (unsigned i = 0; i < NumDxilCoordsOperands; ++i) {
+    Value *Coord = i < CoordsVecTy->getNumElements()
+      ? Builder.CreateExtractElement(CoordsVec, i)
+      : UndefValue::get(CoordsVecTy->getElementType());
+    DxilOperands.emplace_back(Coord);
+  }
+
+  unsigned LastHLOperandRead = HLOperandIndex::kWriteSamplerFeedbackCoordArgIndex;
+
+  // Bias/level/grad operands
+  if (opcode == OP::OpCode::WriteSamplerFeedbackBias
+    || opcode == OP::OpCode::WriteSamplerFeedbackLevel) {
+    DxilOperands.emplace_back(CI->getArgOperand(HLOperandIndex::kWriteSamplerFeedbackBiasOrLodArgIndex));
+    LastHLOperandRead = HLOperandIndex::kWriteSamplerFeedbackBiasOrLodArgIndex;
+  }
+  else if (opcode == OP::OpCode::WriteSamplerFeedbackGrad) {
+    DxilOperands.emplace_back(CI->getArgOperand(HLOperandIndex::kWriteSamplerFeedbackDdxArgIndex));
+    DxilOperands.emplace_back(CI->getArgOperand(HLOperandIndex::kWriteSamplerFeedbackDdyArgIndex));
+    LastHLOperandRead = HLOperandIndex::kWriteSamplerFeedbackDdyArgIndex;
+  }
+
+  // Append the optional clamp argument as needed.
+  bool HasOptionalClampOperand = opcode == OP::OpCode::WriteSamplerFeedback
+    || opcode == OP::OpCode::WriteSamplerFeedbackBias
+    || opcode == OP::OpCode::WriteSamplerFeedbackGrad;
+  if (HasOptionalClampOperand) {
+    if (LastHLOperandRead == CI->getNumArgOperands() - 1)
+      DxilOperands.emplace_back(UndefValue::get(Builder.getFloatTy()));
+    else {
+      LastHLOperandRead++;
+      DxilOperands.emplace_back(CI->getArgOperand(LastHLOperandRead));
+    }
+  }
+
+  DXASSERT(LastHLOperandRead == CI->getNumArgOperands() - 1,
+    "Unexpected trailing hlsl intrinsic arguments.");
+
+  // Call the DXIL operation
+  Function* DxilFunc = hlslOP->GetOpFunc(opcode, Builder.getVoidTy());
+  return Builder.CreateCall(DxilFunc, DxilOperands);
+}
+
 // Load/Store intrinsics.
 struct ResLoadHelper {
   ResLoadHelper(CallInst *CI, DxilResource::Kind RK, DxilResourceBase::Class RC,
@@ -4819,7 +4880,7 @@ Value *StreamOutputLower(CallInst *CI, IntrinsicOp IOP, DXIL::OpCode opcode,
 }
 
 // This table has to match IntrinsicOp orders
-IntrinsicLower gLowerTable[static_cast<unsigned>(IntrinsicOp::Num_Intrinsics)] = {
+IntrinsicLower gLowerTable[] = {
     {IntrinsicOp::IOP_AcceptHitAndEndSearch, TranslateNoArgNoReturnPreserveOutput, DXIL::OpCode::AcceptHitAndEndSearch},
     {IntrinsicOp::IOP_AddUint64,  TranslateAddUint64,  DXIL::OpCode::UAddc},
     {IntrinsicOp::IOP_AllMemoryBarrier, TrivialBarrier, DXIL::OpCode::Barrier},
@@ -5062,6 +5123,10 @@ IntrinsicLower gLowerTable[static_cast<unsigned>(IntrinsicOp::Num_Intrinsics)] =
     {IntrinsicOp::MOP_DecrementCounter, GenerateUpdateCounter, DXIL::OpCode::NumOpCodes},
     {IntrinsicOp::MOP_IncrementCounter, GenerateUpdateCounter, DXIL::OpCode::NumOpCodes},
     {IntrinsicOp::MOP_Consume, EmptyLower, DXIL::OpCode::NumOpCodes},
+    {IntrinsicOp::MOP_WriteSamplerFeedback, TranslateWriteSamplerFeedback, DXIL::OpCode::WriteSamplerFeedback},
+    {IntrinsicOp::MOP_WriteSamplerFeedbackBias, TranslateWriteSamplerFeedback, DXIL::OpCode::WriteSamplerFeedbackBias},
+    {IntrinsicOp::MOP_WriteSamplerFeedbackGrad, TranslateWriteSamplerFeedback, DXIL::OpCode::WriteSamplerFeedbackGrad},
+    {IntrinsicOp::MOP_WriteSamplerFeedbackLevel, TranslateWriteSamplerFeedback, DXIL::OpCode::WriteSamplerFeedbackLevel},
 
     // SPIRV change starts
 #ifdef ENABLE_SPIRV_CODEGEN
@@ -5092,6 +5157,8 @@ IntrinsicLower gLowerTable[static_cast<unsigned>(IntrinsicOp::Num_Intrinsics)] =
     { IntrinsicOp::MOP_InterlockedUMin, TranslateMopAtomicBinaryOperation, DXIL::OpCode::NumOpCodes },
 };
 }
+static_assert(sizeof(gLowerTable) / sizeof(gLowerTable[0]) == static_cast<size_t>(IntrinsicOp::Num_Intrinsics),
+  "Intrinsic lowering table must be updated to account for new intrinsics.");
 
 static void TranslateBuiltinIntrinsic(CallInst *CI,
                                       HLOperationLowerHelper &helper,  HLObjectOperationLowerHelper *pObjHelper, bool &Translated) {

+ 5 - 0
tools/clang/lib/AST/HlslTypes.cpp

@@ -511,6 +511,11 @@ bool IsHLSLResourceType(clang::QualType type) {
     if (name == "TextureCubeArray" || name == "RWTextureCubeArray")
       return true;
 
+    if (name == "FeedbackTexture2DMinLOD" || name == "FeedbackTexture2DTiled")
+      return true;
+    if (name == "FeedbackTexture2DArrayMinLOD" || name == "FeedbackTexture2DArrayTiled")
+      return true;
+
     if (name == "ByteAddressBuffer" || name == "RWByteAddressBuffer")
       return true;
 

+ 14 - 0
tools/clang/lib/CodeGen/CGHLSLMS.cpp

@@ -1073,6 +1073,10 @@ static DxilResource::Kind KeywordToKind(StringRef keyword) {
     return DxilResource::Kind::Texture2D;
   if (keyword == "Texture2DMS" || keyword == "RWTexture2DMS")
     return DxilResource::Kind::Texture2DMS;
+  if (keyword == "FeedbackTexture2DMinLOD")
+    return DxilResource::Kind::FeedbackTexture2DMinLOD;
+  if (keyword == "FeedbackTexture2DTiled")
+    return DxilResource::Kind::FeedbackTexture2DTiled;
   if (keyword == "Texture3D" || keyword == "RWTexture3D" || keyword == "RasterizerOrderedTexture3D")
     return DxilResource::Kind::Texture3D;
   if (keyword == "TextureCube" || keyword == "RWTextureCube")
@@ -1082,6 +1086,10 @@ static DxilResource::Kind KeywordToKind(StringRef keyword) {
     return DxilResource::Kind::Texture1DArray;
   if (keyword == "Texture2DArray" || keyword == "RWTexture2DArray" || keyword == "RasterizerOrderedTexture2DArray")
     return DxilResource::Kind::Texture2DArray;
+  if (keyword == "FeedbackTexture2DArrayMinLOD")
+    return DxilResource::Kind::FeedbackTexture2DArrayMinLOD;
+  if (keyword == "FeedbackTexture2DArrayTiled")
+    return DxilResource::Kind::FeedbackTexture2DArrayTiled;
   if (keyword == "Texture2DMSArray" || keyword == "RWTexture2DMSArray")
     return DxilResource::Kind::Texture2DMSArray;
   if (keyword == "TextureCubeArray" || keyword == "RWTextureCubeArray")
@@ -2494,6 +2502,10 @@ static DxilResourceBase::Class KeywordToClass(const std::string &keyword) {
   isUAV |= keyword == "RasterizerOrderedTexture2D";
   isUAV |= keyword == "RasterizerOrderedTexture2DArray";
   isUAV |= keyword == "RasterizerOrderedTexture3D";
+  isUAV |= keyword == "FeedbackTexture2DMinLOD";
+  isUAV |= keyword == "FeedbackTexture2DTiled";
+  isUAV |= keyword == "FeedbackTexture2DArrayMinLOD";
+  isUAV |= keyword == "FeedbackTexture2DArrayTiled";
   if (isUAV)
     return DxilResourceBase::Class::UAV;
 
@@ -2824,6 +2836,8 @@ bool CGMSHLSLRuntime::SetUAVSRV(SourceLocation loc,
   RecordDecl *RD = QualTy->getAs<RecordType>()->getDecl();
 
   hlsl::DxilResource::Kind kind = KeywordToKind(RD->getName());
+  DXASSERT_NOMSG(kind != hlsl::DxilResource::Kind::Invalid);
+
   hlslRes->SetKind(kind);
   
   QualType resultTy = hlsl::GetHLSLResourceResultType(QualTy);

+ 68 - 3
tools/clang/lib/Sema/SemaHLSL.cpp

@@ -171,6 +171,11 @@ enum ArBasicKind {
   AR_OBJECT_ROVTEXTURE2D_ARRAY,
   AR_OBJECT_ROVTEXTURE3D,
 
+  AR_OBJECT_FEEDBACKTEXTURE2D_MINLOD,
+  AR_OBJECT_FEEDBACKTEXTURE2D_TILED,
+  AR_OBJECT_FEEDBACKTEXTURE2D_ARRAY_MINLOD,
+  AR_OBJECT_FEEDBACKTEXTURE2D_ARRAY_TILED,
+
   // SPIRV change starts
 #ifdef ENABLE_SPIRV_CODEGEN
   AR_OBJECT_VK_SUBPASS_INPUT,
@@ -276,7 +281,8 @@ enum ArBasicKind {
 #define BPROP_PRIMITIVE         0x00100000  // Whether the type is a primitive scalar type.
 #define BPROP_MIN_PRECISION     0x00200000  // Whether the type is qualified with a minimum precision.
 #define BPROP_ROVBUFFER         0x00400000  // Whether the type is a ROV object.
-#define BPROP_ENUM              0x00800000  // Whether the type is a enum
+#define BPROP_FEEDBACKTEXTURE   0x00800000  // Whether the type is a feedback texture.
+#define BPROP_ENUM              0x01000000  // Whether the type is a enum
 
 #define GET_BPROP_PRIM_KIND(_Props) \
     ((_Props) & (BPROP_BOOLEAN | BPROP_INTEGER | BPROP_FLOATING))
@@ -448,6 +454,11 @@ const UINT g_uBasicKindProps[] =
   BPROP_OBJECT | BPROP_RWBUFFER | BPROP_ROVBUFFER,    // AR_OBJECT_ROVTEXTURE2D_ARRAY
   BPROP_OBJECT | BPROP_RWBUFFER | BPROP_ROVBUFFER,    // AR_OBJECT_ROVTEXTURE3D
 
+  BPROP_OBJECT | BPROP_TEXTURE | BPROP_FEEDBACKTEXTURE, // AR_OBJECT_FEEDBACKTEXTURE2D_MINLOD
+  BPROP_OBJECT | BPROP_TEXTURE | BPROP_FEEDBACKTEXTURE, // AR_OBJECT_FEEDBACKTEXTURE2D_TILED
+  BPROP_OBJECT | BPROP_TEXTURE | BPROP_FEEDBACKTEXTURE, // AR_OBJECT_FEEDBACKTEXTURE2D_ARRAY_MINLOD
+  BPROP_OBJECT | BPROP_TEXTURE | BPROP_FEEDBACKTEXTURE, // AR_OBJECT_FEEDBACKTEXTURE2D_ARRAY_TILED
+
   // SPIRV change starts
 #ifdef ENABLE_SPIRV_CODEGEN
   BPROP_OBJECT | BPROP_RBUFFER,   // AR_OBJECT_VK_SUBPASS_INPUT
@@ -1092,6 +1103,18 @@ static const ArBasicKind g_SamplerCT[] =
   AR_BASIC_UNKNOWN
 };
 
+static const ArBasicKind g_Texture2DCT[] =
+{
+  AR_OBJECT_TEXTURE2D,
+  AR_BASIC_UNKNOWN
+};
+
+static const ArBasicKind g_Texture2DArrayCT[] =
+{
+  AR_OBJECT_TEXTURE2D_ARRAY,
+  AR_BASIC_UNKNOWN
+};
+
 static const ArBasicKind g_RayDescCT[] =
 {
   AR_OBJECT_RAY_DESC,
@@ -1203,8 +1226,11 @@ const ArBasicKind* g_LegalIntrinsicCompTypes[] =
   g_RayDescCT,          // LICOMPTYPE_RAYDESC
   g_AccelerationStructCT,   // LICOMPTYPE_ACCELERATION_STRUCT,
   g_UDTCT,              // LICOMPTYPE_USER_DEFINED_TYPE
+  g_Texture2DCT,        // LICOMPTYPE_TEXTURE2D
+  g_Texture2DArrayCT,   // LICOMPTYPE_TEXTURE2DARRAY
 };
-C_ASSERT(ARRAYSIZE(g_LegalIntrinsicCompTypes) == LICOMPTYPE_COUNT);
+static_assert(ARRAYSIZE(g_LegalIntrinsicCompTypes) == LICOMPTYPE_COUNT,
+  "Intrinsic comp type table must be updated when new enumerants are added.");
 
 // Decls.cpp constants ends here - these should be refactored or, better, replaced with clang::Type-based constructs.
 
@@ -1264,6 +1290,11 @@ const ArBasicKind g_ArBasicKindsAsTypes[] =
   AR_OBJECT_ROVTEXTURE2D_ARRAY,
   AR_OBJECT_ROVTEXTURE3D,
 
+  AR_OBJECT_FEEDBACKTEXTURE2D_MINLOD,
+  AR_OBJECT_FEEDBACKTEXTURE2D_TILED,
+  AR_OBJECT_FEEDBACKTEXTURE2D_ARRAY_MINLOD,
+  AR_OBJECT_FEEDBACKTEXTURE2D_ARRAY_TILED,
+
   // SPIRV change starts
 #ifdef ENABLE_SPIRV_CODEGEN
   AR_OBJECT_VK_SUBPASS_INPUT,
@@ -1345,6 +1376,11 @@ const uint8_t g_ArBasicKindsTemplateCount[] =
   1, // AR_OBJECT_ROVTEXTURE2D_ARRAY
   1, // AR_OBJECT_ROVTEXTURE3D
 
+  0, // AR_OBJECT_FEEDBACKTEXTURE2D_MINLOD
+  0, // AR_OBJECT_FEEDBACKTEXTURE2D_TILED
+  0, // AR_OBJECT_FEEDBACKTEXTURE2D_ARRAY_MINLOD
+  0, // AR_OBJECT_FEEDBACKTEXTURE2D_ARRAY_TILED
+
   // SPIRV change starts
 #ifdef ENABLE_SPIRV_CODEGEN
   1, // AR_OBJECT_VK_SUBPASS_INPUT
@@ -1434,6 +1470,11 @@ const SubscriptOperatorRecord g_ArBasicKindsSubscripts[] =
   { 3, MipsFalse, SampleFalse }, // AR_OBJECT_ROVTEXTURE2D_ARRAY (ROVTexture2DArray)
   { 3, MipsFalse, SampleFalse }, // AR_OBJECT_ROVTEXTURE3D (ROVTexture3D)
 
+  { 0, MipsFalse, SampleFalse }, // AR_OBJECT_FEEDBACKTEXTURE2D_MINLOD
+  { 0, MipsFalse, SampleFalse }, // AR_OBJECT_FEEDBACKTEXTURE2D_TILED
+  { 0, MipsFalse, SampleFalse }, // AR_OBJECT_FEEDBACKTEXTURE2D_ARRAY_MINLOD
+  { 0, MipsFalse, SampleFalse }, // AR_OBJECT_FEEDBACKTEXTURE2D_ARRAY_TILED
+
   // SPIRV change starts
 #ifdef ENABLE_SPIRV_CODEGEN
   { 0, MipsFalse, SampleFalse }, // AR_OBJECT_VK_SUBPASS_INPUT (SubpassInput)
@@ -1544,6 +1585,11 @@ const char* g_ArBasicTypeNames[] =
   "RasterizerOrderedTexture2DArray",
   "RasterizerOrderedTexture3D",
 
+  "FeedbackTexture2DMinLOD",
+  "FeedbackTexture2DTiled",
+  "FeedbackTexture2DArrayMinLOD",
+  "FeedbackTexture2DArrayTiled",
+
   // SPIRV change starts
 #ifdef ENABLE_SPIRV_CODEGEN
   "SubpassInput",
@@ -2089,6 +2135,16 @@ void GetIntrinsicMethods(ArBasicKind kind, _Outptr_result_buffer_(*intrinsicCoun
     *intrinsics = g_RWTexture3DMethods;
     *intrinsicCount = _countof(g_RWTexture3DMethods);
     break;
+  case AR_OBJECT_FEEDBACKTEXTURE2D_MINLOD:
+  case AR_OBJECT_FEEDBACKTEXTURE2D_TILED:
+    *intrinsics = g_FeedbackTexture2DMethods;
+    *intrinsicCount = _countof(g_FeedbackTexture2DMethods);
+    break;
+  case AR_OBJECT_FEEDBACKTEXTURE2D_ARRAY_MINLOD:
+  case AR_OBJECT_FEEDBACKTEXTURE2D_ARRAY_TILED:
+    *intrinsics = g_FeedbackTexture2DArrayMethods;
+    *intrinsicCount = _countof(g_FeedbackTexture2DArrayMethods);
+    break;
   case AR_OBJECT_RWBUFFER:
   case AR_OBJECT_ROVBUFFER:
     *intrinsics = g_RWBufferMethods;
@@ -5603,7 +5659,12 @@ bool HLSLExternalSource::MatchArguments(
         return false;
       }
       pNewType = objectElement;
-    } else {
+    }
+    else if (pArgument->uLegalComponentTypes == LICOMPTYPE_TEXTURE2D
+      || pArgument->uLegalComponentTypes == LICOMPTYPE_TEXTURE2DARRAY) {
+      pNewType = Args[i - 1]->getType().getNonReferenceType();
+    }
+    else {
       ArBasicKind pEltType;
 
       // ComponentType, if the Id is special then it gets the
@@ -9655,6 +9716,10 @@ void hlsl::DiagnoseRegisterType(
   case AR_OBJECT_ROVTEXTURE2D:
   case AR_OBJECT_ROVTEXTURE2D_ARRAY:
   case AR_OBJECT_ROVTEXTURE3D:
+  case AR_OBJECT_FEEDBACKTEXTURE2D_MINLOD:
+  case AR_OBJECT_FEEDBACKTEXTURE2D_TILED:
+  case AR_OBJECT_FEEDBACKTEXTURE2D_ARRAY_MINLOD:
+  case AR_OBJECT_FEEDBACKTEXTURE2D_ARRAY_TILED:
     expected = "'u'";
     isValid = registerType == 'u';
     break;

+ 164 - 0
tools/clang/lib/Sema/gen_intrin_main_tables_15.h

@@ -5805,6 +5805,168 @@ static const HLSL_INTRINSIC g_ConsumeStructuredBufferMethods[] =
     {(UINT)hlsl::IntrinsicOp::MOP_GetDimensions, false, false, -1, 3, g_ConsumeStructuredBufferMethods_Args1},
 };
 
+//
+// Start of FeedbackTexture2DMethods
+//
+
+static const HLSL_INTRINSIC_ARGUMENT g_FeedbackTexture2DMethods_Args0[] =
+{
+    {"WriteSamplerFeedback", 0, 0, LITEMPLATE_VOID, 0, LICOMPTYPE_VOID, 0, 0},
+    {"t", AR_QUAL_IN, 1, LITEMPLATE_OBJECT, 1, LICOMPTYPE_TEXTURE2D, 1, 1},
+    {"s", AR_QUAL_IN, 2, LITEMPLATE_OBJECT, 2, LICOMPTYPE_SAMPLER, 1, 1},
+    {"x", AR_QUAL_IN, 3, LITEMPLATE_VECTOR, 3, LICOMPTYPE_FLOAT, 1, 2},
+};
+
+static const HLSL_INTRINSIC_ARGUMENT g_FeedbackTexture2DMethods_Args1[] =
+{
+    {"WriteSamplerFeedback", 0, 0, LITEMPLATE_VOID, 0, LICOMPTYPE_VOID, 0, 0},
+    {"t", AR_QUAL_IN, 1, LITEMPLATE_OBJECT, 1, LICOMPTYPE_TEXTURE2D, 1, 1},
+    {"s", AR_QUAL_IN, 2, LITEMPLATE_OBJECT, 2, LICOMPTYPE_SAMPLER, 1, 1},
+    {"x", AR_QUAL_IN, 3, LITEMPLATE_VECTOR, 3, LICOMPTYPE_FLOAT, 1, 2},
+    {"clamp", AR_QUAL_IN, 4, LITEMPLATE_SCALAR, 4, LICOMPTYPE_FLOAT, 1, 1},
+};
+
+static const HLSL_INTRINSIC_ARGUMENT g_FeedbackTexture2DMethods_Args2[] =
+{
+    {"WriteSamplerFeedbackBias", 0, 0, LITEMPLATE_VOID, 0, LICOMPTYPE_VOID, 0, 0},
+    {"t", AR_QUAL_IN, 1, LITEMPLATE_OBJECT, 1, LICOMPTYPE_TEXTURE2D, 1, 1},
+    {"s", AR_QUAL_IN, 2, LITEMPLATE_OBJECT, 2, LICOMPTYPE_SAMPLER, 1, 1},
+    {"x", AR_QUAL_IN, 3, LITEMPLATE_VECTOR, 3, LICOMPTYPE_FLOAT, 1, 2},
+    {"bias", AR_QUAL_IN, 4, LITEMPLATE_SCALAR, 4, LICOMPTYPE_FLOAT, 1, 1},
+};
+
+static const HLSL_INTRINSIC_ARGUMENT g_FeedbackTexture2DMethods_Args3[] =
+{
+    {"WriteSamplerFeedbackBias", 0, 0, LITEMPLATE_VOID, 0, LICOMPTYPE_VOID, 0, 0},
+    {"t", AR_QUAL_IN, 1, LITEMPLATE_OBJECT, 1, LICOMPTYPE_TEXTURE2D, 1, 1},
+    {"s", AR_QUAL_IN, 2, LITEMPLATE_OBJECT, 2, LICOMPTYPE_SAMPLER, 1, 1},
+    {"x", AR_QUAL_IN, 3, LITEMPLATE_VECTOR, 3, LICOMPTYPE_FLOAT, 1, 2},
+    {"bias", AR_QUAL_IN, 4, LITEMPLATE_SCALAR, 4, LICOMPTYPE_FLOAT, 1, 1},
+    {"clamp", AR_QUAL_IN, 5, LITEMPLATE_SCALAR, 5, LICOMPTYPE_FLOAT, 1, 1},
+};
+
+static const HLSL_INTRINSIC_ARGUMENT g_FeedbackTexture2DMethods_Args4[] =
+{
+    {"WriteSamplerFeedbackGrad", 0, 0, LITEMPLATE_VOID, 0, LICOMPTYPE_VOID, 0, 0},
+    {"t", AR_QUAL_IN, 1, LITEMPLATE_OBJECT, 1, LICOMPTYPE_TEXTURE2D, 1, 1},
+    {"s", AR_QUAL_IN, 2, LITEMPLATE_OBJECT, 2, LICOMPTYPE_SAMPLER, 1, 1},
+    {"x", AR_QUAL_IN, 3, LITEMPLATE_VECTOR, 3, LICOMPTYPE_FLOAT, 1, 2},
+    {"ddx", AR_QUAL_IN, 4, LITEMPLATE_SCALAR, 4, LICOMPTYPE_FLOAT, 1, 1},
+    {"ddy", AR_QUAL_IN, 5, LITEMPLATE_SCALAR, 5, LICOMPTYPE_FLOAT, 1, 1},
+};
+
+static const HLSL_INTRINSIC_ARGUMENT g_FeedbackTexture2DMethods_Args5[] =
+{
+    {"WriteSamplerFeedbackGrad", 0, 0, LITEMPLATE_VOID, 0, LICOMPTYPE_VOID, 0, 0},
+    {"t", AR_QUAL_IN, 1, LITEMPLATE_OBJECT, 1, LICOMPTYPE_TEXTURE2D, 1, 1},
+    {"s", AR_QUAL_IN, 2, LITEMPLATE_OBJECT, 2, LICOMPTYPE_SAMPLER, 1, 1},
+    {"x", AR_QUAL_IN, 3, LITEMPLATE_VECTOR, 3, LICOMPTYPE_FLOAT, 1, 2},
+    {"ddx", AR_QUAL_IN, 4, LITEMPLATE_SCALAR, 4, LICOMPTYPE_FLOAT, 1, 1},
+    {"ddy", AR_QUAL_IN, 5, LITEMPLATE_SCALAR, 5, LICOMPTYPE_FLOAT, 1, 1},
+    {"clamp", AR_QUAL_IN, 6, LITEMPLATE_SCALAR, 6, LICOMPTYPE_FLOAT, 1, 1},
+};
+
+static const HLSL_INTRINSIC_ARGUMENT g_FeedbackTexture2DMethods_Args6[] =
+{
+    {"WriteSamplerFeedbackLevel", 0, 0, LITEMPLATE_VOID, 0, LICOMPTYPE_VOID, 0, 0},
+    {"t", AR_QUAL_IN, 1, LITEMPLATE_OBJECT, 1, LICOMPTYPE_TEXTURE2D, 1, 1},
+    {"s", AR_QUAL_IN, 2, LITEMPLATE_OBJECT, 2, LICOMPTYPE_SAMPLER, 1, 1},
+    {"x", AR_QUAL_IN, 3, LITEMPLATE_VECTOR, 3, LICOMPTYPE_FLOAT, 1, 2},
+    {"lod", AR_QUAL_IN, 4, LITEMPLATE_SCALAR, 4, LICOMPTYPE_FLOAT, 1, 1},
+};
+
+static const HLSL_INTRINSIC g_FeedbackTexture2DMethods[] =
+{
+    {(UINT)hlsl::IntrinsicOp::MOP_WriteSamplerFeedback, false, false, -1, 4, g_FeedbackTexture2DMethods_Args0},
+    {(UINT)hlsl::IntrinsicOp::MOP_WriteSamplerFeedback, false, false, -1, 5, g_FeedbackTexture2DMethods_Args1},
+    {(UINT)hlsl::IntrinsicOp::MOP_WriteSamplerFeedbackBias, false, false, -1, 5, g_FeedbackTexture2DMethods_Args2},
+    {(UINT)hlsl::IntrinsicOp::MOP_WriteSamplerFeedbackBias, false, false, -1, 6, g_FeedbackTexture2DMethods_Args3},
+    {(UINT)hlsl::IntrinsicOp::MOP_WriteSamplerFeedbackGrad, false, false, -1, 6, g_FeedbackTexture2DMethods_Args4},
+    {(UINT)hlsl::IntrinsicOp::MOP_WriteSamplerFeedbackGrad, false, false, -1, 7, g_FeedbackTexture2DMethods_Args5},
+    {(UINT)hlsl::IntrinsicOp::MOP_WriteSamplerFeedbackLevel, false, false, -1, 5, g_FeedbackTexture2DMethods_Args6},
+};
+
+//
+// Start of FeedbackTexture2DArrayMethods
+//
+
+static const HLSL_INTRINSIC_ARGUMENT g_FeedbackTexture2DArrayMethods_Args0[] =
+{
+    {"WriteSamplerFeedback", 0, 0, LITEMPLATE_VOID, 0, LICOMPTYPE_VOID, 0, 0},
+    {"t", AR_QUAL_IN, 1, LITEMPLATE_OBJECT, 1, LICOMPTYPE_TEXTURE2DARRAY, 1, 1},
+    {"s", AR_QUAL_IN, 2, LITEMPLATE_OBJECT, 2, LICOMPTYPE_SAMPLER, 1, 1},
+    {"x", AR_QUAL_IN, 3, LITEMPLATE_VECTOR, 3, LICOMPTYPE_FLOAT, 1, 3},
+};
+
+static const HLSL_INTRINSIC_ARGUMENT g_FeedbackTexture2DArrayMethods_Args1[] =
+{
+    {"WriteSamplerFeedback", 0, 0, LITEMPLATE_VOID, 0, LICOMPTYPE_VOID, 0, 0},
+    {"t", AR_QUAL_IN, 1, LITEMPLATE_OBJECT, 1, LICOMPTYPE_TEXTURE2DARRAY, 1, 1},
+    {"s", AR_QUAL_IN, 2, LITEMPLATE_OBJECT, 2, LICOMPTYPE_SAMPLER, 1, 1},
+    {"x", AR_QUAL_IN, 3, LITEMPLATE_VECTOR, 3, LICOMPTYPE_FLOAT, 1, 3},
+    {"clamp", AR_QUAL_IN, 4, LITEMPLATE_SCALAR, 4, LICOMPTYPE_FLOAT, 1, 1},
+};
+
+static const HLSL_INTRINSIC_ARGUMENT g_FeedbackTexture2DArrayMethods_Args2[] =
+{
+    {"WriteSamplerFeedbackBias", 0, 0, LITEMPLATE_VOID, 0, LICOMPTYPE_VOID, 0, 0},
+    {"t", AR_QUAL_IN, 1, LITEMPLATE_OBJECT, 1, LICOMPTYPE_TEXTURE2DARRAY, 1, 1},
+    {"s", AR_QUAL_IN, 2, LITEMPLATE_OBJECT, 2, LICOMPTYPE_SAMPLER, 1, 1},
+    {"x", AR_QUAL_IN, 3, LITEMPLATE_VECTOR, 3, LICOMPTYPE_FLOAT, 1, 3},
+    {"bias", AR_QUAL_IN, 4, LITEMPLATE_SCALAR, 4, LICOMPTYPE_FLOAT, 1, 1},
+};
+
+static const HLSL_INTRINSIC_ARGUMENT g_FeedbackTexture2DArrayMethods_Args3[] =
+{
+    {"WriteSamplerFeedbackBias", 0, 0, LITEMPLATE_VOID, 0, LICOMPTYPE_VOID, 0, 0},
+    {"t", AR_QUAL_IN, 1, LITEMPLATE_OBJECT, 1, LICOMPTYPE_TEXTURE2DARRAY, 1, 1},
+    {"s", AR_QUAL_IN, 2, LITEMPLATE_OBJECT, 2, LICOMPTYPE_SAMPLER, 1, 1},
+    {"x", AR_QUAL_IN, 3, LITEMPLATE_VECTOR, 3, LICOMPTYPE_FLOAT, 1, 3},
+    {"bias", AR_QUAL_IN, 4, LITEMPLATE_SCALAR, 4, LICOMPTYPE_FLOAT, 1, 1},
+    {"clamp", AR_QUAL_IN, 5, LITEMPLATE_SCALAR, 5, LICOMPTYPE_FLOAT, 1, 1},
+};
+
+static const HLSL_INTRINSIC_ARGUMENT g_FeedbackTexture2DArrayMethods_Args4[] =
+{
+    {"WriteSamplerFeedbackGrad", 0, 0, LITEMPLATE_VOID, 0, LICOMPTYPE_VOID, 0, 0},
+    {"t", AR_QUAL_IN, 1, LITEMPLATE_OBJECT, 1, LICOMPTYPE_TEXTURE2DARRAY, 1, 1},
+    {"s", AR_QUAL_IN, 2, LITEMPLATE_OBJECT, 2, LICOMPTYPE_SAMPLER, 1, 1},
+    {"x", AR_QUAL_IN, 3, LITEMPLATE_VECTOR, 3, LICOMPTYPE_FLOAT, 1, 3},
+    {"ddx", AR_QUAL_IN, 4, LITEMPLATE_SCALAR, 4, LICOMPTYPE_FLOAT, 1, 1},
+    {"ddy", AR_QUAL_IN, 5, LITEMPLATE_SCALAR, 5, LICOMPTYPE_FLOAT, 1, 1},
+};
+
+static const HLSL_INTRINSIC_ARGUMENT g_FeedbackTexture2DArrayMethods_Args5[] =
+{
+    {"WriteSamplerFeedbackGrad", 0, 0, LITEMPLATE_VOID, 0, LICOMPTYPE_VOID, 0, 0},
+    {"t", AR_QUAL_IN, 1, LITEMPLATE_OBJECT, 1, LICOMPTYPE_TEXTURE2DARRAY, 1, 1},
+    {"s", AR_QUAL_IN, 2, LITEMPLATE_OBJECT, 2, LICOMPTYPE_SAMPLER, 1, 1},
+    {"x", AR_QUAL_IN, 3, LITEMPLATE_VECTOR, 3, LICOMPTYPE_FLOAT, 1, 3},
+    {"ddx", AR_QUAL_IN, 4, LITEMPLATE_SCALAR, 4, LICOMPTYPE_FLOAT, 1, 1},
+    {"ddy", AR_QUAL_IN, 5, LITEMPLATE_SCALAR, 5, LICOMPTYPE_FLOAT, 1, 1},
+    {"clamp", AR_QUAL_IN, 6, LITEMPLATE_SCALAR, 6, LICOMPTYPE_FLOAT, 1, 1},
+};
+
+static const HLSL_INTRINSIC_ARGUMENT g_FeedbackTexture2DArrayMethods_Args6[] =
+{
+    {"WriteSamplerFeedbackLevel", 0, 0, LITEMPLATE_VOID, 0, LICOMPTYPE_VOID, 0, 0},
+    {"t", AR_QUAL_IN, 1, LITEMPLATE_OBJECT, 1, LICOMPTYPE_TEXTURE2DARRAY, 1, 1},
+    {"s", AR_QUAL_IN, 2, LITEMPLATE_OBJECT, 2, LICOMPTYPE_SAMPLER, 1, 1},
+    {"x", AR_QUAL_IN, 3, LITEMPLATE_VECTOR, 3, LICOMPTYPE_FLOAT, 1, 3},
+    {"lod", AR_QUAL_IN, 4, LITEMPLATE_SCALAR, 4, LICOMPTYPE_FLOAT, 1, 1},
+};
+
+static const HLSL_INTRINSIC g_FeedbackTexture2DArrayMethods[] =
+{
+    {(UINT)hlsl::IntrinsicOp::MOP_WriteSamplerFeedback, false, false, -1, 4, g_FeedbackTexture2DArrayMethods_Args0},
+    {(UINT)hlsl::IntrinsicOp::MOP_WriteSamplerFeedback, false, false, -1, 5, g_FeedbackTexture2DArrayMethods_Args1},
+    {(UINT)hlsl::IntrinsicOp::MOP_WriteSamplerFeedbackBias, false, false, -1, 5, g_FeedbackTexture2DArrayMethods_Args2},
+    {(UINT)hlsl::IntrinsicOp::MOP_WriteSamplerFeedbackBias, false, false, -1, 6, g_FeedbackTexture2DArrayMethods_Args3},
+    {(UINT)hlsl::IntrinsicOp::MOP_WriteSamplerFeedbackGrad, false, false, -1, 6, g_FeedbackTexture2DArrayMethods_Args4},
+    {(UINT)hlsl::IntrinsicOp::MOP_WriteSamplerFeedbackGrad, false, false, -1, 7, g_FeedbackTexture2DArrayMethods_Args5},
+    {(UINT)hlsl::IntrinsicOp::MOP_WriteSamplerFeedbackLevel, false, false, -1, 5, g_FeedbackTexture2DArrayMethods_Args6},
+};
+
 //
 // Start of VkSubpassInputMethods
 //
@@ -5849,6 +6011,8 @@ static const UINT g_uAppendStructuredBufferMethodsCount = 2;
 static const UINT g_uBufferMethodsCount = 3;
 static const UINT g_uByteAddressBufferMethodsCount = 9;
 static const UINT g_uConsumeStructuredBufferMethodsCount = 2;
+static const UINT g_uFeedbackTexture2DArrayMethodsCount = 7;
+static const UINT g_uFeedbackTexture2DMethodsCount = 7;
 static const UINT g_uIntrinsicsCount = 218;
 static const UINT g_uRWBufferMethodsCount = 3;
 static const UINT g_uRWByteAddressBufferMethodsCount = 28;

+ 66 - 0
tools/clang/test/CodeGenHLSL/batch/declarations/resources/textures/feedback.hlsl

@@ -0,0 +1,66 @@
+// RUN: %dxc -E main -T ps_6_5 %s | FileCheck %s
+
+// Test FeedbackTexture2D*** and their WriteSamplerFeedback methods
+
+FeedbackTexture2DMinLOD feedbackMinLOD;
+FeedbackTexture2DTiled feedbackTiled;
+FeedbackTexture2DArrayMinLOD feedbackMinLODArray;
+FeedbackTexture2DArrayTiled feebackTiledArray;
+Texture2D<float> texture2D;
+Texture2D<float4> texture2D_float4;
+Texture2DArray<float> texture2DArray;
+SamplerState samp;
+
+float main() : SV_Target
+{
+    float2 coords2D = float2(1, 2);
+    float3 coords2DArray = float3(1, 2, 3);
+    float clamp = 4;
+    float bias = 5;
+    float lod = 6;
+    float ddx = 7;
+    float ddy = 8;
+    
+    // Test every dxil intrinsic
+    // CHECK: call void @dx.op.writeSamplerFeedback(
+    // CHECK: float 1.000000e+00, float 2.000000e+00, float undef, float 4.000000e+00)
+    feedbackMinLOD.WriteSamplerFeedback(texture2D, samp, coords2D, clamp);
+    // CHECK: call void @dx.op.writeSamplerFeedbackBias(
+    // CHECK: float 1.000000e+00, float 2.000000e+00, float undef, float 5.000000e+00, float 4.000000e+00)
+    feedbackMinLOD.WriteSamplerFeedbackBias(texture2D, samp, coords2D, bias, clamp);
+    // CHECK: call void @dx.op.writeSamplerFeedbackLevel(
+    // CHECK: float 1.000000e+00, float 2.000000e+00, float undef, float 6.000000e+00)
+    feedbackMinLOD.WriteSamplerFeedbackLevel(texture2D, samp, coords2D, lod);
+    // CHECK: call void @dx.op.writeSamplerFeedbackGrad(
+    // CHECK: float 1.000000e+00, float 2.000000e+00, float undef, float 7.000000e+00, float 8.000000e+00, float 4.000000e+00)
+    feedbackMinLOD.WriteSamplerFeedbackGrad(texture2D, samp, coords2D, ddx, ddy, clamp);
+    
+    // Test with undef clamp
+    // CHECK: call void @dx.op.writeSamplerFeedback(
+    // CHECK: float 1.000000e+00, float 2.000000e+00, float undef, float undef)
+    feedbackMinLOD.WriteSamplerFeedback(texture2D, samp, coords2D);
+    // CHECK: call void @dx.op.writeSamplerFeedbackBias(
+    // CHECK: float 1.000000e+00, float 2.000000e+00, float undef, float 5.000000e+00, float undef)
+    feedbackMinLOD.WriteSamplerFeedbackBias(texture2D, samp, coords2D, bias);
+    // CHECK: call void @dx.op.writeSamplerFeedbackGrad(
+    // CHECK: float 1.000000e+00, float 2.000000e+00, float undef, float 7.000000e+00, float 8.000000e+00, float undef)
+    feedbackMinLOD.WriteSamplerFeedbackGrad(texture2D, samp, coords2D, ddx, ddy);
+
+    // Test on every FeedbackTexture variant
+    // CHECK: call void @dx.op.writeSamplerFeedback(
+    // CHECK: float 1.000000e+00, float 2.000000e+00, float undef, float undef)
+    feedbackTiled.WriteSamplerFeedback(texture2D, samp, coords2D);
+    // CHECK: call void @dx.op.writeSamplerFeedback(
+    // CHECK: float 1.000000e+00, float 2.000000e+00, float 3.000000e+00, float undef)
+    feedbackMinLODArray.WriteSamplerFeedback(texture2DArray, samp, coords2DArray);
+    // CHECK: call void @dx.op.writeSamplerFeedback(
+    // CHECK: float 1.000000e+00, float 2.000000e+00, float 3.000000e+00, float undef)
+    feebackTiledArray.WriteSamplerFeedback(texture2DArray, samp, coords2DArray);
+
+    // Test with overloaded texture type
+    // CHECK: call void @dx.op.writeSamplerFeedback(
+    // CHECK: float 1.000000e+00, float 2.000000e+00, float undef, float undef)
+    feedbackMinLOD.WriteSamplerFeedback(texture2D_float4, samp, coords2D);
+
+    return 0;
+}

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

@@ -1192,6 +1192,10 @@ static const char *OpCodeSignatures[] = {
   "(value)",  // WaveMatch
   "(value,mask0,mask1,mask2,mask3,op,sop)",  // WaveMultiPrefixOp
   "(value,mask0,mask1,mask2,mask3)",  // WaveMultiPrefixBitCount
+  "(feedbackTex,sampledTex,sampler,c0,c1,c2,clamp)",  // WriteSamplerFeedback
+  "(feedbackTex,sampledTex,sampler,c0,c1,c2,bias,clamp)",  // WriteSamplerFeedbackBias
+  "(feedbackTex,sampledTex,sampler,c0,c1,c2,lod)",  // WriteSamplerFeedbackLevel
+  "(feedbackTex,sampledTex,sampler,c0,c1,c2,ddx,ddy,clamp)",  // WriteSamplerFeedbackGrad
   "(numVertices,numPrimitives)",  // SetMeshOutputCounts
   "(PrimitiveIndex,VertexIndex0,VertexIndex1,VertexIndex2)",  // EmitIndices
   "()",  // GetMeshPayload

+ 24 - 0
utils/hct/gen_intrin_main.txt

@@ -840,6 +840,30 @@ $classT [[]] Consume() : structuredbuffer_consume;
 
 } namespace
 
+namespace FeedbackTexture2DMethods {
+
+void [[]] WriteSamplerFeedback(in Texture2D t, in sampler s, in float<2> x);
+void [[]] WriteSamplerFeedback(in Texture2D t, in sampler s, in float<2> x, in float clamp);
+void [[]] WriteSamplerFeedbackBias(in Texture2D t, in sampler s, in float<2> x, in float bias);
+void [[]] WriteSamplerFeedbackBias(in Texture2D t, in sampler s, in float<2> x, in float bias, in float clamp);
+void [[]] WriteSamplerFeedbackGrad(in Texture2D t, in sampler s, in float<2> x, in float ddx, in float ddy);
+void [[]] WriteSamplerFeedbackGrad(in Texture2D t, in sampler s, in float<2> x, in float ddx, in float ddy, in float clamp);
+void [[]] WriteSamplerFeedbackLevel(in Texture2D t, in sampler s, in float<2> x, in float lod);
+
+} namespace
+
+namespace FeedbackTexture2DArrayMethods {
+
+void [[]] WriteSamplerFeedback(in Texture2DArray t, in sampler s, in float<3> x);
+void [[]] WriteSamplerFeedback(in Texture2DArray t, in sampler s, in float<3> x, in float clamp);
+void [[]] WriteSamplerFeedbackBias(in Texture2DArray t, in sampler s, in float<3> x, in float bias);
+void [[]] WriteSamplerFeedbackBias(in Texture2DArray t, in sampler s, in float<3> x, in float bias, in float clamp);
+void [[]] WriteSamplerFeedbackGrad(in Texture2DArray t, in sampler s, in float<3> x, in float ddx, in float ddy);
+void [[]] WriteSamplerFeedbackGrad(in Texture2DArray t, in sampler s, in float<3> x, in float ddx, in float ddy, in float clamp);
+void [[]] WriteSamplerFeedbackLevel(in Texture2DArray t, in sampler s, in float<3> x, in float lod);
+
+} namespace
+
 // SPIRV Change Starts
 
 namespace VkSubpassInputMethods {

+ 59 - 2
utils/hct/hctdb.py

@@ -390,6 +390,13 @@ class db_dxil(object):
             self.name_idx[i].category = "Amplification shader instructions"
             self.name_idx[i].shader_stages = ("amplification",)
             self.name_idx[i].shader_model = 6,5
+        for i in "WriteSamplerFeedback,WriteSamplerFeedbackBias".split(","):
+            self.name_idx[i].category = "Sampler Feedback"
+            self.name_idx[i].shader_model = 6,5
+            self.name_idx[i].shader_stages = ("library", "pixel",)
+        for i in "WriteSamplerFeedbackLevel,WriteSamplerFeedbackGrad".split(","):
+            self.name_idx[i].category = "Sampler Feedback"
+            self.name_idx[i].shader_model = 6,5
 
     def populate_llvm_instructions(self):
         # Add instructions that map to LLVM instructions.
@@ -1383,6 +1390,7 @@ class db_dxil(object):
             db_dxil_param(6, "i32", "mask3", "mask 3")])
         next_op_idx += 1
 
+        # Mesh Shader
         self.add_dxil_op("SetMeshOutputCounts", next_op_idx, "SetMeshOutputCounts", "Mesh shader intrinsic SetMeshOutputCounts", "v", "", [
             retvoid_param,
             db_dxil_param(2, "i32", "numVertices", "number of output vertices"),
@@ -1414,6 +1422,8 @@ class db_dxil(object):
             db_dxil_param(5, "$o", "value", "value to store"),
             db_dxil_param(6, "u32", "primitiveIndex", "primitive index")])
         next_op_idx += 1
+
+        # Amplification Shader
         self.add_dxil_op("DispatchMesh", next_op_idx, "DispatchMesh", "Amplification shader intrinsic DispatchMesh", "u", "", [
             retvoid_param,
             db_dxil_param(2, "i32", "threadGroupCountX", "thread group count x"),
@@ -1422,9 +1432,54 @@ class db_dxil(object):
             db_dxil_param(5, "$o", "payload", "payload")])
         next_op_idx += 1
 
+        # Sampler feedback
+        self.add_dxil_op("WriteSamplerFeedback", next_op_idx, "WriteSamplerFeedback", "updates a feedback texture for a sampling operation", "v", "", [
+            db_dxil_param(0, "v", "", ""),
+            db_dxil_param(2, "res", "feedbackTex", "handle of feedback texture UAV"),
+            db_dxil_param(3, "res", "sampledTex", "handled of sampled texture SRV"),
+            db_dxil_param(4, "res", "sampler", "handle of sampler"),
+            db_dxil_param(5, "f", "c0", "coordinate c0"),
+            db_dxil_param(6, "f", "c1", "coordinate c1"),
+            db_dxil_param(7, "f", "c2", "coordinate c2"),
+            db_dxil_param(8, "f", "clamp", "clamp")])
+        next_op_idx += 1
+        self.add_dxil_op("WriteSamplerFeedbackBias", next_op_idx, "WriteSamplerFeedbackBias", "updates a feedback texture for a sampling operation with a bias on the mipmap level", "v", "", [
+            db_dxil_param(0, "v", "", ""),
+            db_dxil_param(2, "res", "feedbackTex", "handle of feedback texture UAV"),
+            db_dxil_param(3, "res", "sampledTex", "handled of sampled texture SRV"),
+            db_dxil_param(4, "res", "sampler", "handle of sampler"),
+            db_dxil_param(5, "f", "c0", "coordinate c0"),
+            db_dxil_param(6, "f", "c1", "coordinate c1"),
+            db_dxil_param(7, "f", "c2", "coordinate c2"),
+            db_dxil_param(8, "f", "bias", "bias in [-16.f,15.99f]"),
+            db_dxil_param(9, "f", "clamp", "clamp")])
+        next_op_idx += 1
+        self.add_dxil_op("WriteSamplerFeedbackLevel", next_op_idx, "WriteSamplerFeedbackLevel", "updates a feedback texture for a sampling operation with a mipmap-level offset", "v", "", [
+            db_dxil_param(0, "v", "", ""),
+            db_dxil_param(2, "res", "feedbackTex", "handle of feedback texture UAV"),
+            db_dxil_param(3, "res", "sampledTex", "handled of sampled texture SRV"),
+            db_dxil_param(4, "res", "sampler", "handle of sampler"),
+            db_dxil_param(5, "f", "c0", "coordinate c0"),
+            db_dxil_param(6, "f", "c1", "coordinate c1"),
+            db_dxil_param(7, "f", "c2", "coordinate c2"),
+            db_dxil_param(8, "f", "lod", "LOD")])
+        next_op_idx += 1
+        self.add_dxil_op("WriteSamplerFeedbackGrad", next_op_idx, "WriteSamplerFeedbackGrad", "updates a feedback texture for a sampling operation with explicit gradients", "v", "", [
+            db_dxil_param(0, "v", "", ""),
+            db_dxil_param(2, "res", "feedbackTex", "handle of feedback texture UAV"),
+            db_dxil_param(3, "res", "sampledTex", "handled of sampled texture SRV"),
+            db_dxil_param(4, "res", "sampler", "handle of sampler"),
+            db_dxil_param(5, "f", "c0", "coordinate c0"),
+            db_dxil_param(6, "f", "c1", "coordinate c1"),
+            db_dxil_param(7, "f", "c2", "coordinate c2"),
+            db_dxil_param(8, "f", "ddx", "ddx"),
+            db_dxil_param(9, "f", "ddy", "ddy"),
+            db_dxil_param(10, "f", "clamp", "clamp")])
+        next_op_idx += 1
+
         # End of DXIL 1.5 opcodes.
         self.set_op_count_for_version(1, 5, next_op_idx)
-        assert next_op_idx == 174, "next operation index is %d rather than 174 and thus opcodes are broken" % next_op_idx
+        assert next_op_idx == 178, "next operation index is %d rather than 178 and thus opcodes are broken" % next_op_idx
 
         # Set interesting properties.
         self.build_indices()
@@ -2356,6 +2411,8 @@ class db_hlsl(object):
             "udt" : "LICOMPTYPE_USER_DEFINED_TYPE",
             "void": "LICOMPTYPE_VOID",
             "string": "LICOMPTYPE_STRING",
+            "Texture2D": "LICOMPTYPE_TEXTURE2D",
+            "Texture2DArray": "LICOMPTYPE_TEXTURE2DARRAY",
             "wave": "LICOMPTYPE_WAVE"}
         self.trans_rowcol = {
             "r": "IA_R",
@@ -2484,7 +2541,7 @@ class db_hlsl(object):
                         template_list = "LITEMPLATE_ANY"
                     else:
                         base_type = type_name
-                        if base_type.startswith("sampler") or base_type.startswith("string") or base_type.startswith("wave") or base_type.startswith("acceleration_struct") or base_type.startswith("ray_desc"):
+                        if base_type.startswith("sampler") or base_type.startswith("string") or base_type.startswith("Texture") or base_type.startswith("wave") or base_type.startswith("acceleration_struct") or base_type.startswith("ray_desc"):
                             template_list = "LITEMPLATE_OBJECT"
                         else:
                             template_list = "LITEMPLATE_SCALAR"