Browse Source

[spirv] Support float[1] as the type of SV_InsideTessFactor (#1003)

Some developers use float[1] instead of float as the type for
SV_InsideTessFactor when input topology is "tri".
Lei Zhang 7 years ago
parent
commit
79f4da1500

+ 14 - 6
tools/clang/lib/SPIRV/DeclResultIdMapper.cpp

@@ -1243,9 +1243,14 @@ bool DeclResultIdMapper::createStageVars(
       // HLSL. If SV_InsideTessFactor is a scalar, only extract index 0 of
       // TessLevelInner.
       else if (semanticKind == hlsl::Semantic::Kind::InsideTessFactor &&
-               !type->isArrayType()) {
-        *value = theBuilder.createCompositeExtract(theBuilder.getFloat32Type(),
-                                                   *value, {0});
+               // Some developers use float[1] instead of a scalar float.
+               (!type->isArrayType() || hlsl::GetArraySize(type) == 1)) {
+        const auto f32Type = theBuilder.getFloat32Type();
+        *value = theBuilder.createCompositeExtract(f32Type, *value, {0});
+        if (type->isArrayType()) // float[1]
+          *value = theBuilder.createCompositeConstruct(
+              theBuilder.getArrayType(f32Type, theBuilder.getConstantUint32(1)),
+              {*value});
       }
       // SV_DomainLocation can refer to a float2 or a float3, whereas TessCoord
       // is always a float3. To ensure SPIR-V validity, a float3 stage variable
@@ -1307,11 +1312,14 @@ bool DeclResultIdMapper::createStageVars(
       // HLSL. If SV_InsideTessFactor is a scalar, only write to index 0 of
       // TessLevelInner.
       else if (semanticKind == hlsl::Semantic::Kind::InsideTessFactor &&
-               !type->isArrayType()) {
+               // Some developers use float[1] instead of a scalar float.
+               (!type->isArrayType() || hlsl::GetArraySize(type) == 1)) {
+        const auto f32Type = theBuilder.getFloat32Type();
         ptr = theBuilder.createAccessChain(
-            theBuilder.getPointerType(theBuilder.getFloat32Type(),
-                                      spv::StorageClass::Output),
+            theBuilder.getPointerType(f32Type, spv::StorageClass::Output),
             varId, theBuilder.getConstantUint32(0));
+        if (type->isArrayType()) // float[1]
+          *value = theBuilder.createCompositeExtract(f32Type, *value, {0});
         theBuilder.createStore(ptr, *value);
       }
       // Special handling of SV_Coverage, which is an unit value. We need to

+ 37 - 0
tools/clang/test/CodeGenSPIRV/semantic.inside-tess-factor.ds.array1.hlsl

@@ -0,0 +1,37 @@
+// Run: %dxc -T ds_6_0 -E main
+
+// CHECK: %gl_TessLevelInner = OpVariable %_ptr_Input__arr_float_uint_2 Input
+
+struct HS_CONSTANT_DATA_OUTPUT
+{
+  float Edges[3]        : SV_TessFactor;
+  // According to HLSL doc, this should actually be a scalar float.
+  // But developers sometimes use float[1].
+  float Inside[1]       : SV_InsideTessFactor;
+};
+
+// Output control point (output of hull shader)
+struct BEZIER_CONTROL_POINT
+{
+  float3 vPosition	: BEZIERPOS;
+};
+
+// The domain shader outputs
+struct DS_OUTPUT
+{
+  float4 vPosition  : SV_POSITION;
+};
+
+[domain("tri")]
+DS_OUTPUT main( HS_CONSTANT_DATA_OUTPUT input,
+                float2 UV : SV_DomainLocation,
+                const OutputPatch<BEZIER_CONTROL_POINT, 16> bezpatch )
+{
+// CHECK:       [[tli:%\d+]] = OpLoad %_arr_float_uint_2 %gl_TessLevelInner
+// CHECK-NEXT:   [[e0:%\d+]] = OpCompositeExtract %float [[tli]] 0
+// CHECK-NEXT: [[arr1:%\d+]] = OpCompositeConstruct %_arr_float_uint_1 [[e0]]
+// CHECK-NEXT:      {{%\d+}} = OpCompositeConstruct %HS_CONSTANT_DATA_OUTPUT {{%\d+}} [[arr1]]
+  DS_OUTPUT Output;
+  return Output;
+}
+

+ 42 - 0
tools/clang/test/CodeGenSPIRV/semantic.inside-tess-factor.hs.array1.hlsl

@@ -0,0 +1,42 @@
+// Run: %dxc -T hs_6_0 -E main
+
+#define NumOutPoints 2
+
+// CHECK: %gl_TessLevelInner = OpVariable %_ptr_Output__arr_float_uint_2 Output
+
+struct HsPcfOut
+{
+  float tessOuter[3] : SV_TessFactor;
+  // According to HLSL doc, this should actually be a scalar float.
+  // But developers sometimes use float[1].
+  float tessInner[1] : SV_InsideTessFactor;
+};
+
+struct HsCpOut
+{
+    float4   pos : SV_Position;
+};
+
+
+// Patch Constant Function
+HsPcfOut pcf() {
+  HsPcfOut output;
+  output = (HsPcfOut)0;
+  return output;
+}
+
+[domain("tri")]
+[partitioning("fractional_odd")]
+[outputtopology("triangle_ccw")]
+[outputcontrolpoints(NumOutPoints)]
+[patchconstantfunc("pcf")]
+HsCpOut main(uint cpId : SV_OutputControlPointID, uint patchId : SV_PrimitiveID) {
+// CHECK:      [[ret:%\d+]] = OpFunctionCall %HsPcfOut %pcf
+// CHECK:      [[itf:%\d+]] = OpCompositeExtract %_arr_float_uint_1 [[ret]] 1
+// CHECK-NEXT: [[ptr:%\d+]] = OpAccessChain %_ptr_Output_float %gl_TessLevelInner %uint_0
+// CHECK-NEXT:  [[e0:%\d+]] = OpCompositeExtract %float [[itf]] 0
+// CHECK-NEXT: OpStore [[ptr]] [[e0]]
+    HsCpOut output;
+    output = (HsCpOut)0;
+    return output;
+}

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

@@ -464,6 +464,10 @@ TEST_F(FileTest, SemanticTessFactorSizeMismatchDS) {
 TEST_F(FileTest, SemanticInsideTessFactorDS) {
   runFileTest("semantic.inside-tess-factor.ds.hlsl");
 }
+TEST_F(FileTest, SemanticInsideTessFactorDSArray1) {
+  // Test that SV_InsideTessFactor is of type float[1]
+  runFileTest("semantic.inside-tess-factor.ds.array1.hlsl");
+}
 TEST_F(FileTest, SemanticTessFactorHS) {
   runFileTest("semantic.tess-factor.hs.hlsl");
 }
@@ -473,6 +477,10 @@ TEST_F(FileTest, SemanticTessFactorSizeMismatchHS) {
 TEST_F(FileTest, SemanticInsideTessFactorHS) {
   runFileTest("semantic.inside-tess-factor.hs.hlsl");
 }
+TEST_F(FileTest, SemanticInsideTessFactorHSArray1) {
+  // Test that SV_InsideTessFactor is of type float[1]
+  runFileTest("semantic.inside-tess-factor.hs.array1.hlsl");
+}
 TEST_F(FileTest, SemanticPrimitiveIdHS) {
   runFileTest("semantic.primitive-id.hs.hlsl");
 }