Sfoglia il codice sorgente

[spirv] Add SubpassInput(MS) and vk::input_attachment_index (#1000)

Two new Vulkan specific intrinsic resource types, SubpassInput and
SubpassInputMS, are introduced to provide a way to use subpass inputs
in Vulkan. Their signatures:

template<typename T>
class SubpassInput {
  T SubpassLoad();
};

template<typename T>
class SubpassInputMS {
  T SubpassLoad(int sample);
};

T can be a scalar or vector type.

If compiled without ENABLE_SPIRV_CODEGEN, the compiler will report
unknown type name for SubpassInput(MS). If compiled with SPIR-V
CodeGen and trying to use SubpassInput(MS) in DXIL CodeGen, the
compiler will report an error saying the type is Vulkan-specific.

A new Vulkan-specific attribute, vk::input_attachment_index is
introduced to provide a way to set the input attachment index for
SubpassInput(MS) objects.
Lei Zhang 7 anni fa
parent
commit
fa1e7cddd0

+ 3 - 0
include/dxc/HlslIntrinsicOp.h

@@ -226,6 +226,9 @@ import hctdb_instrhelp
   MOP_DecrementCounter,
   MOP_IncrementCounter,
   MOP_Consume,
+#ifdef ENABLE_SPIRV_CODEGEN
+  MOP_SubpassLoad,
+#endif // ENABLE_SPIRV_CODEGEN
   // unsigned
   IOP_InterlockedUMax,
   IOP_InterlockedUMin,

+ 19 - 0
lib/HLSL/HLOperationLower.cpp

@@ -4238,6 +4238,19 @@ Value *EmptyLower(CallInst *CI, IntrinsicOp IOP, DXIL::OpCode opcode,
   return nullptr;
 }
 
+// SPIRV change starts
+#ifdef ENABLE_SPIRV_CODEGEN
+Value *UnsupportedVulkanIntrinsic(CallInst *CI, IntrinsicOp IOP,
+                                  DXIL::OpCode opcode,
+                                  HLOperationLowerHelper &helper,
+                                  HLObjectOperationLowerHelper *pObjHelper,
+                                  bool &Translated) {
+  DXASSERT(0, "unsupported Vulkan intrinsic");
+  return nullptr;
+}
+#endif // ENABLE_SPIRV_CODEGEN
+// SPIRV change ends
+
 Value *StreamOutputLower(CallInst *CI, IntrinsicOp IOP, DXIL::OpCode opcode,
                          HLOperationLowerHelper &helper,  HLObjectOperationLowerHelper *pObjHelper, bool &Translated) {
   // Translated in DxilGenerationPass::GenerateStreamOutputOperation.
@@ -4456,6 +4469,12 @@ IntrinsicLower gLowerTable[static_cast<unsigned>(IntrinsicOp::Num_Intrinsics)] =
     {IntrinsicOp::MOP_IncrementCounter, GenerateUpdateCounter, DXIL::OpCode::NumOpCodes},
     {IntrinsicOp::MOP_Consume, EmptyLower, DXIL::OpCode::NumOpCodes},
 
+    // SPIRV change starts
+#ifdef ENABLE_SPIRV_CODEGEN
+    {IntrinsicOp::MOP_SubpassLoad, UnsupportedVulkanIntrinsic, DXIL::OpCode::NumOpCodes},
+#endif // ENABLE_SPIRV_CODEGEN
+    // SPIRV change ends
+
     // Manully added part.
     { IntrinsicOp::IOP_InterlockedUMax, TranslateIopAtomicBinaryOperation, DXIL::OpCode::NumOpCodes },
     { IntrinsicOp::IOP_InterlockedUMin, TranslateIopAtomicBinaryOperation, DXIL::OpCode::NumOpCodes },

+ 15 - 0
tools/clang/include/clang/Basic/Attr.td

@@ -916,11 +916,26 @@ def VKPushConstant : InheritableAttr {
 
 def VKOffset : InheritableAttr {
   let Spellings = [CXX11<"vk", "offset">];
+  let Subjects = SubjectList<[Field], ErrorDiag, "ExpectedField">;
   let Args = [IntArgument<"Offset">];
   let LangOpts = [SPIRV];
   let Documentation = [Undocumented];
 }
 
+def SubpassInput : SubsetSubject<
+    Var,
+    [{S->hasGlobalStorage() && S->getType()->getAs<RecordType>() &&
+      (S->getType()->getAs<RecordType>()->getDecl()->getName() == "SubpassInput" ||
+       S->getType()->getAs<RecordType>()->getDecl()->getName() == "SubpassInputMS")}]>;
+
+def VKInputAttachmentIndex : InheritableAttr {
+  let Spellings = [CXX11<"vk", "input_attachment_index">];
+  let Subjects = SubjectList<[SubpassInput], ErrorDiag, "ExpectedSubpassInput">;
+  let Args = [IntArgument<"index">];
+  let LangOpts = [SPIRV];
+  let Documentation = [Undocumented];
+}
+
 // SPIRV Change Ends
 
 def C11NoReturn : InheritableAttr {

+ 6 - 0
tools/clang/include/clang/Basic/DiagnosticSemaKinds.td

@@ -2326,9 +2326,11 @@ def warn_attribute_wrong_decl_type : Warning<
   "functions and global variables|structs, unions, and typedefs|structs and typedefs|"
   "interface or protocol declarations|kernel functions|"
   // SPIRV Change Starts
+  "fields|"
   "global variables of struct type|"
   "global variables, cbuffers, and tbuffers|"
   "RWStructuredBuffers, AppendStructuredBuffers, and ConsumeStructuredBuffers|"
+  "SubpassInput, SubpassInputMS|"
   // SPIRV Change Ends
   // HLSL Change Starts - add 3 more enum values
   "varibales and parameters|functions, parameters, and fields|"
@@ -7666,6 +7668,10 @@ def err_hlsl_missing_inout_attr: Error<
    "stream-output object must be an inout parameter">;
 // HLSL Change Ends
 
+// SPIRV Change Starts
+def err_hlsl_vulkan_specific_feature: Error<"%0 is a Vulkan specific feature">;
+// SPIRV Change Ends
+
 let CategoryName = "OpenMP Issue" in {
 // OpenMP support.
 def err_omp_expected_var_arg : Error<

+ 2 - 0
tools/clang/include/clang/Sema/AttributeList.h

@@ -856,9 +856,11 @@ enum AttributeDeclKind {
   ExpectedObjectiveCInterfaceOrProtocol,
   ExpectedKernelFunction
   // SPIRV Change Begins
+  ,ExpectedField
   ,ExpectedStructGlobalVar
   ,ExpectedGlobalVarOrCTBuffer
   ,ExpectedCounterStructuredBuffer
+  ,ExpectedSubpassInput
   // SPIRV Change Ends
   // HLSL Change Begins - add attribute decl combinations
   ,ExpectedVariableOrParam,

+ 91 - 5
tools/clang/lib/Sema/SemaHLSL.cpp

@@ -167,6 +167,13 @@ enum ArBasicKind {
   AR_OBJECT_ROVTEXTURE2D_ARRAY,
   AR_OBJECT_ROVTEXTURE3D,
 
+  // SPIRV change starts
+#ifdef ENABLE_SPIRV_CODEGEN
+  AR_OBJECT_VK_SUBPASS_INPUT,
+  AR_OBJECT_VK_SUBPASS_INPUT_MS,
+#endif // ENABLE_SPIRV_CODEGEN
+  // SPIRV change ends
+
   AR_OBJECT_INNER,       // Used for internal type object
 
   AR_OBJECT_LEGACY_EFFECT,
@@ -418,6 +425,13 @@ const UINT g_uBasicKindProps[] =
   BPROP_OBJECT | BPROP_RWBUFFER | BPROP_ROVBUFFER,    // AR_OBJECT_ROVTEXTURE2D_ARRAY
   BPROP_OBJECT | BPROP_RWBUFFER | BPROP_ROVBUFFER,    // AR_OBJECT_ROVTEXTURE3D
 
+  // SPIRV change starts
+#ifdef ENABLE_SPIRV_CODEGEN
+  BPROP_OBJECT | BPROP_RBUFFER,   // AR_OBJECT_VK_SUBPASS_INPUT
+  BPROP_OBJECT | BPROP_RBUFFER,   // AR_OBJECT_VK_SUBPASS_INPUT_MS
+#endif // ENABLE_SPIRV_CODEGEN
+  // SPIRV change ends
+
   BPROP_OBJECT,   // AR_OBJECT_INNER
 
   BPROP_OBJECT,   // AR_OBJECT_LEGACY_EFFECT
@@ -1203,6 +1217,13 @@ const ArBasicKind g_ArBasicKindsAsTypes[] =
   AR_OBJECT_ROVTEXTURE2D_ARRAY,
   AR_OBJECT_ROVTEXTURE3D,
 
+  // SPIRV change starts
+#ifdef ENABLE_SPIRV_CODEGEN
+  AR_OBJECT_VK_SUBPASS_INPUT,
+  AR_OBJECT_VK_SUBPASS_INPUT_MS,
+#endif // ENABLE_SPIRV_CODEGEN
+  // SPIRV change ends
+
   AR_OBJECT_LEGACY_EFFECT,      // Used for all unsupported but ignored legacy effect types
 
   AR_OBJECT_WAVE
@@ -1264,6 +1285,13 @@ const uint8_t g_ArBasicKindsTemplateCount[] =
   1, // AR_OBJECT_ROVTEXTURE2D_ARRAY
   1, // AR_OBJECT_ROVTEXTURE3D
 
+  // SPIRV change starts
+#ifdef ENABLE_SPIRV_CODEGEN
+  1, // AR_OBJECT_VK_SUBPASS_INPUT
+  1, // AR_OBJECT_VK_SUBPASS_INPUT_MS
+#endif // ENABLE_SPIRV_CODEGEN
+  // SPIRV change ends
+
   0, // AR_OBJECT_LEGACY_EFFECT   // Used for all unsupported but ignored legacy effect types
   0, // AR_OBJECT_WAVE
 };
@@ -1334,6 +1362,13 @@ const SubscriptOperatorRecord g_ArBasicKindsSubscripts[] =
   { 3, MipsFalse, SampleFalse }, // AR_OBJECT_ROVTEXTURE2D_ARRAY (ROVTexture2DArray)
   { 3, MipsFalse, SampleFalse }, // AR_OBJECT_ROVTEXTURE3D (ROVTexture3D)
 
+  // SPIRV change starts
+#ifdef ENABLE_SPIRV_CODEGEN
+  { 0, MipsFalse, SampleFalse }, // AR_OBJECT_VK_SUBPASS_INPUT (SubpassInput)
+  { 0, MipsFalse, SampleFalse }, // AR_OBJECT_VK_SUBPASS_INPUT_MS (SubpassInputMS)
+#endif // ENABLE_SPIRV_CODEGEN
+  // SPIRV change ends
+
   { 0, MipsFalse, SampleFalse }, // AR_OBJECT_LEGACY_EFFECT (legacy effect objects)
   { 0, MipsFalse, SampleFalse }  // AR_OBJECT_WAVE
 };
@@ -1423,6 +1458,13 @@ const char* g_ArBasicTypeNames[] =
   "RasterizerOrderedTexture2DArray",
   "RasterizerOrderedTexture3D",
 
+  // SPIRV change starts
+#ifdef ENABLE_SPIRV_CODEGEN
+  "SubpassInput",
+  "SubpassInputMS",
+#endif // ENABLE_SPIRV_CODEGEN
+  // SPIRV change ends
+
   "<internal inner type object>",
 
   "deprecated effect object",
@@ -2023,6 +2065,18 @@ void GetIntrinsicMethods(ArBasicKind kind, _Outptr_result_buffer_(*intrinsicCoun
     *intrinsics = g_ConsumeStructuredBufferMethods;
     *intrinsicCount = _countof(g_ConsumeStructuredBufferMethods);
     break;
+  // SPIRV change starts
+#ifdef ENABLE_SPIRV_CODEGEN
+  case AR_OBJECT_VK_SUBPASS_INPUT:
+    *intrinsics = g_VkSubpassInputMethods;
+    *intrinsicCount = _countof(g_VkSubpassInputMethods);
+    break;
+  case AR_OBJECT_VK_SUBPASS_INPUT_MS:
+    *intrinsics = g_VkSubpassInputMSMethods;
+    *intrinsicCount = _countof(g_VkSubpassInputMSMethods);
+    break;
+#endif // ENABLE_SPIRV_CODEGEN
+  // SPIRV change ends
   default:
     *intrinsics = nullptr;
     *intrinsicCount = 0;
@@ -2102,11 +2156,24 @@ bool DoesIntrinsicRequireTemplate(const HLSL_INTRINSIC* intrinsic)
 static
 bool TemplateHasDefaultType(ArBasicKind kind)
 {
-  return
-    kind == AR_OBJECT_BUFFER ||
-    kind == AR_OBJECT_TEXTURE1D || kind == AR_OBJECT_TEXTURE2D || kind == AR_OBJECT_TEXTURE3D ||
-    kind == AR_OBJECT_TEXTURE1D_ARRAY || kind == AR_OBJECT_TEXTURE2D_ARRAY ||
-    kind == AR_OBJECT_TEXTURECUBE || kind == AR_OBJECT_TEXTURECUBE_ARRAY;
+  switch (kind) {
+  case AR_OBJECT_BUFFER:
+  case AR_OBJECT_TEXTURE1D:
+  case AR_OBJECT_TEXTURE2D:
+  case AR_OBJECT_TEXTURE3D:
+  case AR_OBJECT_TEXTURE1D_ARRAY:
+  case AR_OBJECT_TEXTURE2D_ARRAY:
+  case AR_OBJECT_TEXTURECUBE:
+  case AR_OBJECT_TEXTURECUBE_ARRAY:
+  // SPIRV change starts
+#ifdef ENABLE_SPIRV_CODEGEN
+  case AR_OBJECT_VK_SUBPASS_INPUT:
+  case AR_OBJECT_VK_SUBPASS_INPUT_MS:
+#endif // ENABLE_SPIRV_CODEGEN
+  // SPIRV change ends
+    return true;
+  }
+  return false;
 }
 
 /// <summary>
@@ -10398,6 +10465,11 @@ void hlsl::HandleDeclAttributeForHLSL(Sema &S, Decl *D, const AttributeList &A,
     declAttr = ::new (S.Context) VKOffsetAttr(A.getRange(), S.Context,
       ValidateAttributeIntArg(S, A), A.getAttributeSpellingListIndex());
     break;
+  case AttributeList::AT_VKInputAttachmentIndex:
+    declAttr = ::new (S.Context) VKInputAttachmentIndexAttr(
+        A.getRange(), S.Context, ValidateAttributeIntArg(S, A),
+        A.getAttributeSpellingListIndex());
+    break;
   default:
     Handled = false;
     return;
@@ -11065,6 +11137,20 @@ bool Sema::DiagnoseHLSLDecl(Declarator &D, DeclContext *DC,
     result = false;
   }
 
+  // SPIRV change starts
+#ifdef ENABLE_SPIRV_CODEGEN
+  // Validate that Vulkan specific feature is only used when targeting SPIR-V
+  if (!getLangOpts().SPIRV) {
+    if (basicKind == ArBasicKind::AR_OBJECT_VK_SUBPASS_INPUT ||
+        basicKind == ArBasicKind::AR_OBJECT_VK_SUBPASS_INPUT_MS) {
+      Diag(D.getLocStart(), diag::err_hlsl_vulkan_specific_feature)
+          << g_ArBasicTypeNames[basicKind];
+      result = false;
+    }
+  }
+#endif // ENABLE_SPIRV_CODEGEN
+  // SPIRV change ends
+
   // Validate unusual annotations.
   hlsl::DiagnoseUnusualAnnotationsForHLSL(*this, D.UnusualAnnotations);
   auto && unusualIter = D.UnusualAnnotations.begin();

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

@@ -5555,6 +5555,43 @@ static const HLSL_INTRINSIC g_ConsumeStructuredBufferMethods[] =
     {(UINT)hlsl::IntrinsicOp::MOP_Consume, false, false, -1, 1, g_ConsumeStructuredBufferMethods_Args0},
     {(UINT)hlsl::IntrinsicOp::MOP_GetDimensions, false, false, -1, 3, g_ConsumeStructuredBufferMethods_Args1},
 };
+
+//
+// Start of VkSubpassInputMethods
+//
+
+#ifdef ENABLE_SPIRV_CODEGEN
+
+static const HLSL_INTRINSIC_ARGUMENT g_VkSubpassInputMethods_Args0[] =
+{
+    {"SubpassLoad", AR_QUAL_OUT, INTRIN_TEMPLATE_FROM_TYPE, LITEMPLATE_VOID, 0, LICOMPTYPE_VOID, 0, 0},
+};
+
+static const HLSL_INTRINSIC g_VkSubpassInputMethods[] =
+{
+    {(UINT)hlsl::IntrinsicOp::MOP_SubpassLoad, false, false, -1, 1, g_VkSubpassInputMethods_Args0},
+};
+
+#endif // ENABLE_SPIRV_CODEGEN
+
+//
+// Start of VkSubpassInputMSMethods
+//
+
+#ifdef ENABLE_SPIRV_CODEGEN
+
+static const HLSL_INTRINSIC_ARGUMENT g_VkSubpassInputMSMethods_Args0[] =
+{
+    {"SubpassLoad", AR_QUAL_OUT, INTRIN_TEMPLATE_FROM_TYPE, LITEMPLATE_VOID, 0, LICOMPTYPE_VOID, 0, 0},
+    {"sample", AR_QUAL_IN, 1, LITEMPLATE_SCALAR, 1, LICOMPTYPE_INT, 1, 1},
+};
+
+static const HLSL_INTRINSIC g_VkSubpassInputMSMethods[] =
+{
+    {(UINT)hlsl::IntrinsicOp::MOP_SubpassLoad, false, false, -1, 2, g_VkSubpassInputMSMethods_Args0},
+};
+
+#endif // ENABLE_SPIRV_CODEGEN
 // HLSL-INTRINSICS:END
 
 /* <py::lines('HLSL-INTRINSIC-STATS')>hctdb_instrhelp.get_hlsl_intrinsic_stats()</py>*/
@@ -5583,6 +5620,8 @@ static const UINT g_uTexture2DMethodsCount = 77;
 static const UINT g_uTexture3DMethodsCount = 24;
 static const UINT g_uTextureCUBEArrayMethodsCount = 42;
 static const UINT g_uTextureCUBEMethodsCount = 42;
+static const UINT g_uVkSubpassInputMSMethodsCount = 1;
+static const UINT g_uVkSubpassInputMethodsCount = 1;
 
 static const int g_MaxIntrinsicName = 32; // Count of characters for longest intrinsic name - 'DeviceMemoryBarrierWithGroupSync'
 static const int g_MaxIntrinsicParamName = 22; // Count of characters for longest intrinsic parameter name - 'UnroundedInsideFactors'

+ 12 - 0
utils/hct/gen_intrin_main.txt

@@ -787,3 +787,15 @@ void [[]] GetDimensions(out uint_only count, out uint_only stride) : bufinfo;
 $unspec [[]] Consume() : structuredbuffer_consume;
 
 } namespace
+
+// SPIRV Change Starts
+
+namespace VkSubpassInputMethods {
+$unspec [[]] SubpassLoad() : subpassinput_load;
+} namespace
+
+namespace VkSubpassInputMSMethods {
+$unspec [[]] SubpassLoad(in int sample) : subpassinputms_load;
+} namespace
+
+// SPIRV Change Ends

+ 1 - 0
utils/hct/hctdb.py

@@ -1904,6 +1904,7 @@ class db_hlsl_intrinsic(object):
             self.unsigned_op = "%s_%s" % (id_prefix, unsigned_op)
         self.overload_param_index = overload_idx        # Parameter determines the overload type, -1 means ret type
         self.key = ("%3d" % ns_idx) + "!" + name + "!" + ("%2d" % len(params)) + "!" + ("%3d" % idx)    # Unique key
+        self.vulkanSpecific = ns.startswith("Vk")       # Vulkan specific intrinsic - SPIRV change
 
 class db_hlsl_namespace(object):
     "A grouping of HLSL intrinsics"

+ 21 - 1
utils/hct/hctdb_instrhelp.py

@@ -647,6 +647,7 @@ def get_hlsl_intrinsics():
     result = ""
     last_ns = ""
     ns_table = ""
+    is_vk_table = False  # SPIRV Change
     id_prefix = ""
     arg_idx = 0
     opcode_namespace = db.opcode_namespace
@@ -656,9 +657,19 @@ def get_hlsl_intrinsics():
             id_prefix = "IOP" if last_ns == "Intrinsics" else "MOP"
             if (len(ns_table)):
                 result += ns_table + "};\n"
+                # SPIRV Change Starts
+                if is_vk_table:
+                    result += "\n#endif // ENABLE_SPIRV_CODEGEN\n"
+                    is_vk_table = False
+                # SPIRV Change Ends
             result += "\n//\n// Start of %s\n//\n\n" % (last_ns)
             # This used to be qualified as __declspec(selectany), but that's no longer necessary.
             ns_table = "static const HLSL_INTRINSIC g_%s[] =\n{\n" % (last_ns)
+            # SPIRV Change Starts
+            if (i.vulkanSpecific):
+                is_vk_table = True
+                result += "#ifdef ENABLE_SPIRV_CODEGEN\n\n"
+            # SPIRV Change Ends
             arg_idx = 0
         ns_table += "    {(UINT)%s::%s_%s, %s, %s, %d, %d, g_%s_Args%s},\n" % (opcode_namespace, id_prefix, i.name, str(i.readonly).lower(), str(i.readnone).lower(), i.overload_param_index,len(i.params), last_ns, arg_idx)
         result += "static const HLSL_INTRINSIC_ARGUMENT g_%s_Args%s[] =\n{\n" % (last_ns, arg_idx)
@@ -669,15 +680,24 @@ def get_hlsl_intrinsics():
         result += "};\n\n"
         arg_idx += 1
     result += ns_table + "};\n"
+    result += "\n#endif // ENABLE_SPIRV_CODEGEN\n" if is_vk_table else ""  # SPIRV Change
     return result
 
+# SPIRV Change Starts
+def wrap_with_ifdef_if_vulkan_specific(intrinsic, text):
+    if intrinsic.vulkanSpecific:
+        return "#ifdef ENABLE_SPIRV_CODEGEN\n" + text + "#endif // ENABLE_SPIRV_CODEGEN\n"
+    return text
+# SPIRV Change Ends
+
 def enum_hlsl_intrinsics():
     db = get_db_hlsl()
     result = ""
     enumed = []
     for i in sorted(db.intrinsics, key=lambda x: x.key):
         if (i.enum_name not in enumed):
-            result += "  %s,\n" % (i.enum_name)
+            enumerant = "  %s,\n" % (i.enum_name)
+            result += wrap_with_ifdef_if_vulkan_specific(i, enumerant)  # SPIRV Change
             enumed.append(i.enum_name)
     # unsigned
     result += "  // unsigned\n"