Преглед на файлове

[spirv] Support SPV_KHR_shader_draw_parameters (#1127)

Added support for the following SPIR-V builtins exposed in
SPV_KHR_shader_draw_parameters:
* BaseVertex
* BaseInstance
* DrawIndex
Lei Zhang преди 7 години
родител
ревизия
c859bb040f

+ 7 - 1
docs/SPIR-V.rst

@@ -231,10 +231,16 @@ Builtin variables
 
 Some of the Vulkan builtin variables have no equivalents in native HLSL
 language. To support them, ``[[vk::builtin("<builtin>")]]`` is introduced.
-Right now only two ``<builtin>`` are supported:
+Right now the following ``<builtin>`` are supported:
 
 * ``PointSize``: The GLSL equivalent is ``gl_PointSize``.
 * ``HelperInvocation``: The GLSL equivalent is ``gl_HelperInvocation``.
+* ``BaseVertex``: The GLSL equivalent is ``gl_BaseVertexARB``.
+  Need ``SPV_KHR_shader_draw_parameters`` extension.
+* ``BaseInstance``: The GLSL equivalent is ``gl_BaseInstanceARB``.
+  Need ``SPV_KHR_shader_draw_parameters`` extension.
+* ``DrawIndex``: The GLSL equivalent is ``gl_DrawIDARB``.
+  Need ``SPV_KHR_shader_draw_parameters`` extension.
 
 Please see Vulkan spec. `14.6. Built-In Variables <https://www.khronos.org/registry/vulkan/specs/1.0/html/vkspec.html#interfaces-builtin-variables>`_
 for detailed explanation of these builtins.

+ 26 - 0
tools/clang/lib/SPIRV/DeclResultIdMapper.cpp

@@ -1763,10 +1763,22 @@ uint32_t DeclResultIdMapper::createSpirvStageVar(StageVar *stageVar,
         llvm::StringSwitch<BuiltIn>(builtinAttr->getBuiltIn())
             .Case("PointSize", BuiltIn::PointSize)
             .Case("HelperInvocation", BuiltIn::HelperInvocation)
+            .Case("BaseVertex", BuiltIn::BaseVertex)
+            .Case("BaseInstance", BuiltIn::BaseInstance)
+            .Case("DrawIndex", BuiltIn::DrawIndex)
             .Default(BuiltIn::Max);
 
     assert(spvBuiltIn != BuiltIn::Max); // The frontend should guarantee this.
 
+    switch (spvBuiltIn) {
+    case BuiltIn::BaseVertex:
+    case BuiltIn::BaseInstance:
+    case BuiltIn::DrawIndex:
+      theBuilder.addExtension("SPV_KHR_shader_draw_parameters");
+      theBuilder.requireCapability(spv::Capability::DrawParameters);
+      break;
+    }
+
     return theBuilder.addStageBuiltinVar(type, sc, spvBuiltIn);
   }
 
@@ -2147,6 +2159,20 @@ bool DeclResultIdMapper::validateVKBuiltins(const NamedDecl *decl,
             << sigPoint->GetName();
         success = false;
       }
+    } else if (builtin == "BaseVertex" || builtin == "BaseInstance" ||
+               builtin == "DrawIndex") {
+      if (!declType->isSpecificBuiltinType(BuiltinType::Kind::Int) &&
+          !declType->isSpecificBuiltinType(BuiltinType::Kind::UInt)) {
+        emitError("%0 builtin must be of 32-bit scalar integer type", loc)
+            << builtin;
+        success = false;
+      }
+
+      if (sigPoint->GetKind() != hlsl::SigPoint::Kind::VSIn) {
+        emitError("%0 builtin can only be used in vertex shader input", loc)
+            << builtin;
+        success = false;
+      }
     }
   }
 

+ 1 - 1
tools/clang/lib/Sema/SemaHLSL.cpp

@@ -10446,7 +10446,7 @@ void hlsl::HandleDeclAttributeForHLSL(Sema &S, Decl *D, const AttributeList &A,
   {
   case AttributeList::AT_VKBuiltIn:
     declAttr = ::new (S.Context) VKBuiltInAttr(A.getRange(), S.Context,
-      ValidateAttributeStringArg(S, A, "PointSize,HelperInvocation"),
+      ValidateAttributeStringArg(S, A, "PointSize,HelperInvocation,BaseVertex,BaseInstance,DrawIndex"),
       A.getAttributeSpellingListIndex());
     break;
   case AttributeList::AT_VKLocation:

+ 21 - 0
tools/clang/test/CodeGenSPIRV/spirv.builtin.shader-draw-parameters.hlsl

@@ -0,0 +1,21 @@
+// Run: %dxc -T vs_6_0 -E main
+
+// CHECK: OpCapability DrawParameters
+
+// CHECK: OpExtension "SPV_KHR_shader_draw_parameters"
+
+
+// CHECK: OpDecorate [[a:%\d+]] BuiltIn BaseVertex
+// CHECK: OpDecorate [[b:%\d+]] BuiltIn BaseInstance
+// CHECK: OpDecorate [[c:%\d+]] BuiltIn DrawIndex
+
+float main(
+// CHECK: [[a]] = OpVariable %_ptr_Input_int Input
+    [[vk::builtin("BaseVertex")]]    int baseVertex : A,
+// CHECK: [[b]] = OpVariable %_ptr_Input_uint Input
+    [[vk::builtin("BaseInstance")]] uint baseInstance : B,
+// CHECK: [[c]] = OpVariable %_ptr_Input_int Input
+    [[vk::builtin("DrawIndex")]]     int drawIndex : C
+) : OUTPUT {
+    return baseVertex + baseInstance + drawIndex;
+}

+ 10 - 0
tools/clang/test/CodeGenSPIRV/spirv.builtin.shader-draw-parameters.invalid.hlsl

@@ -0,0 +1,10 @@
+// Run: %dxc -T ps_6_0 -E main
+
+float4 main(
+    [[vk::builtin("BaseVertex")]] float baseVertex : A
+) : SV_Target {
+    return baseVertex;
+}
+
+// CHECK: :4:7: error: BaseVertex builtin must be of 32-bit scalar integer type
+// CHECK: :4:7: error: BaseVertex builtin can only be used in vertex shader input

+ 7 - 0
tools/clang/unittests/SPIRV/CodeGenSPIRVTest.cpp

@@ -1021,6 +1021,13 @@ TEST_F(FileTest, SpirvBuiltInHelperInvocationInvalidUsage) {
 TEST_F(FileTest, SpirvBuiltInPointSizeInvalidUsage) {
   runFileTest("spirv.builtin.point-size.invalid.hlsl", Expect::Failure);
 }
+TEST_F(FileTest, SpirvBuiltInShaderDrawParameters) {
+  runFileTest("spirv.builtin.shader-draw-parameters.hlsl");
+}
+TEST_F(FileTest, SpirvBuiltInShaderDrawParametersInvalidUsage) {
+  runFileTest("spirv.builtin.shader-draw-parameters.invalid.hlsl",
+              Expect::Failure);
+}
 
 // For shader stage input/output interface
 // For semantic SV_Position, SV_ClipDistance, SV_CullDistance