Jelajahi Sumber

[spirv] Require ClipDistance/CullDistance capability on use (#769)

Declaring but not using (reading/writing) ClipDistance/CullDistance
does not require the ClipDistance/CullDistance capability.
Lei Zhang 7 tahun lalu
induk
melakukan
dc3d2c7921

+ 8 - 0
docs/SPIR-V.rst

@@ -802,6 +802,14 @@ asecendingly according to ``X``, and then concatenate them tightly. For example,
 Then we have an float array of size (1 + 2 + 3 =) 6 for ``ClipDistance``, with
 ``clip0`` at offset 0, ``clip2`` at offset 1, ``clip5`` at offset 3.
 
+Decorating a variable or struct member with the ``ClipDistance`` builtin but not
+requiring the ``ClipDistance`` capability is legal as long as we don't read or
+write the variable or struct member. But as per the way we handle `shader entry
+function`_, this is not satisfied because we need to read their contents to
+prepare for the source code entry function call or write back them after the
+call. So annotating a variable or struct member with ``SV_ClipDistanceX`` means
+requiring the ``ClipDistance`` capability in the generated SPIR-V.
+
 Variables decorated with ``SV_CullDistanceX`` are mapped similarly as above.
 
 HLSL register and Vulkan binding

+ 8 - 0
tools/clang/lib/SPIRV/GlPerVertex.cpp

@@ -122,6 +122,14 @@ llvm::SmallVector<uint32_t, 4> GlPerVertex::getStageOutVars() const {
   return vars;
 }
 
+void GlPerVertex::requireCapabilityIfNecessary() {
+  if (!inClipType.empty() || !outClipType.empty())
+    theBuilder.requireCapability(spv::Capability::ClipDistance);
+
+  if (!inCullType.empty() || !outCullType.empty())
+    theBuilder.requireCapability(spv::Capability::CullDistance);
+}
+
 bool GlPerVertex::recordClipCullDistanceDecl(const DeclaratorDecl *decl,
                                              bool asInput) {
   const QualType type = getTypeOrFnRetType(decl);

+ 4 - 0
tools/clang/lib/SPIRV/GlPerVertex.h

@@ -79,6 +79,10 @@ public:
   /// Returns the <result-id>s for stage output variables.
   llvm::SmallVector<uint32_t, 4> getStageOutVars() const;
 
+  /// Requires the ClipDistance/CullDistance capability if we've seen
+  /// definition of SV_ClipDistance/SV_CullDistance.
+  void requireCapabilityIfNecessary();
+
   /// Tries to access the builtin translated from the given HLSL semantic of the
   /// given index. If sigPoint indicates this is input, builtins will be read
   /// to compose a new temporary value of the correct type and writes to *value.

+ 10 - 0
tools/clang/lib/SPIRV/SPIRVEmitter.cpp

@@ -5722,6 +5722,16 @@ bool SPIRVEmitter::emitEntryFunctionWrapper(const FunctionDecl *decl,
     declIdMapper.glPerVertex.generateVars(inputArraySize, outputArraySize);
   }
 
+  // Require the ClipDistance/CullDistance capability if necessary.
+  // It is legal to just use the ClipDistance/CullDistance builtin without
+  // requiring the ClipDistance/CullDistance capability, as long as we don't
+  // read or write the builtin variable.
+  // For our CodeGen, that corresponds to not seeing SV_ClipDistance or
+  // SV_CullDistance at all. If we see them, we will generate code to read
+  // them to initialize temporary variable for calling the source code entry
+  // function or write to them after calling the source code entry function.
+  declIdMapper.glPerVertex.requireCapabilityIfNecessary();
+
   // The entry basic block.
   const uint32_t entryLabel = theBuilder.createBasicBlock();
   theBuilder.setInsertPoint(entryLabel);

+ 3 - 0
tools/clang/test/CodeGenSPIRV/spirv.interface.ds.hlsl

@@ -1,5 +1,8 @@
 // Run: %dxc -T ds_6_0 -E main
 
+// CHECK: OpCapability ClipDistance
+// CHECK: OpCapability CullDistance
+
 // HS PCF output
 
 struct HsPcfOut {

+ 3 - 0
tools/clang/test/CodeGenSPIRV/spirv.interface.hs.hlsl

@@ -4,6 +4,9 @@
 
 #define NumOutPoints 2
 
+// CHECK: OpCapability ClipDistance
+// CHECK: OpCapability CullDistance
+
 // Input control point
 struct HsCpIn
 {

+ 3 - 0
tools/clang/test/CodeGenSPIRV/spirv.interface.ps.hlsl

@@ -1,5 +1,8 @@
 // Run: %dxc -T ps_6_0 -E main
 
+// CHECK: OpCapability ClipDistance
+// CHECK: OpCapability CullDistance
+
 struct Inner {
     float2 cull2 : SV_CullDistance2;            // Builtin CullDistance
     float3 foo   : FOO;                         // Input variable

+ 3 - 0
tools/clang/test/CodeGenSPIRV/spirv.interface.vs.hlsl

@@ -1,5 +1,8 @@
 // Run: %dxc -T vs_6_0 -E main
 
+// CHECK: OpCapability ClipDistance
+// CHECK: OpCapability CullDistance
+
 // CHECK: OpEntryPoint Vertex %main "main" %gl_PerVertexOut %in_var_TEXCOORD %in_var_SV_Position %out_var_COLOR %out_var_TEXCOORD
 
 // CHECK: OpMemberDecorate %type_gl_PerVertex 0 BuiltIn Position