فهرست منبع

Allow two SV_Barycentrics (#282)

 unlike other system value semantics, pixel shader is allowed to declare at most two input attributes with SV_Barycentrics, with one declaration uses perspective interpolation type while other one uses noperspective interpolation type.
Young Kim 8 سال پیش
والد
کامیت
f66e8083d6

+ 1 - 0
docs/DXIL.rst

@@ -2777,6 +2777,7 @@ INSTR.WRITEMASKFORTYPEDUAVSTORE        store on typed uav must write to all four
 INSTR.WRITEMASKMATCHVALUEFORUAVSTORE   uav store write mask must match store value mask, write mask is %0 and store value mask is %1
 META.BARYCENTRICSFLOAT3                only 'float3' type is allowed for SV_Barycentrics.
 META.BARYCENTRICSINTERPOLATION         SV_Barycentrics cannot be used with 'nointerpolation' type
+META.BARYCENTRICSTWOPERSPECTIVES       There can only be up to two input attributes of SV_Barycentrics with different perspective interpolation mode.
 META.BRANCHFLATTEN                     Can't use branch and flatten attributes together
 META.CLIPCULLMAXCOMPONENTS             Combined elements of SV_ClipDistance and SV_CullDistance must fit in 8 components
 META.CLIPCULLMAXROWS                   Combined elements of SV_ClipDistance and SV_CullDistance must fit in two rows.

+ 1 - 0
include/dxc/HLSL/DxilValidation.h

@@ -117,6 +117,7 @@ enum class ValidationRule : unsigned {
   // Metadata
   MetaBarycentricsFloat3, // only 'float3' type is allowed for SV_Barycentrics.
   MetaBarycentricsInterpolation, // SV_Barycentrics cannot be used with 'nointerpolation' type
+  MetaBarycentricsTwoPerspectives, // There can only be up to two input attributes of SV_Barycentrics with different perspective interpolation mode.
   MetaBranchFlatten, // Can't use branch and flatten attributes together
   MetaClipCullMaxComponents, // Combined elements of SV_ClipDistance and SV_CullDistance must fit in 8 components
   MetaClipCullMaxRows, // Combined elements of SV_ClipDistance and SV_CullDistance must fit in two rows.

+ 29 - 2
lib/HLSL/DxilValidation.cpp

@@ -107,6 +107,7 @@ const char *hlsl::GetValidationRuleText(ValidationRule value) {
     case hlsl::ValidationRule::MetaTextureType: return "elements of typed buffers and textures must fit in four 32-bit quantities";
     case hlsl::ValidationRule::MetaBarycentricsInterpolation: return "SV_Barycentrics cannot be used with 'nointerpolation' type";
     case hlsl::ValidationRule::MetaBarycentricsFloat3: return "only 'float3' type is allowed for SV_Barycentrics.";
+    case hlsl::ValidationRule::MetaBarycentricsTwoPerspectives: return "There can only be up to two input attributes of SV_Barycentrics with different perspective interpolation mode.";
     case hlsl::ValidationRule::InstrOload: return "DXIL intrinsic overload must be valid";
     case hlsl::ValidationRule::InstrCallOload: return "Call to DXIL intrinsic '%0' does not match an allowed overload signature";
     case hlsl::ValidationRule::InstrPtrBitCast: return "Pointer type bitcast must be have same size";
@@ -3198,6 +3199,7 @@ static void ValidateSignatureElement(DxilSignatureElement &SE,
 
   bool bIsClipCull = false;
   bool bIsTessfactor = false;
+  bool bIsBarycentric = false;
 
   switch (semanticKind) {
   case DXIL::SemanticKind::Depth:
@@ -3276,6 +3278,7 @@ static void ValidateSignatureElement(DxilSignatureElement &SE,
     DXASSERT(!bAllowedInSig, "else internal inconsistency between semantic interpretation table and validation code");
     break;
   case DXIL::SemanticKind::Barycentrics:
+    bIsBarycentric = true;
     if (compKind != DXIL::ComponentType::F32) {
       ValCtx.EmitFormatError(ValidationRule::MetaSemanticCompType, {SE.GetSemantic()->GetName(), "float"});
     }
@@ -3338,7 +3341,12 @@ static void ValidateSignatureElement(DxilSignatureElement &SE,
       ValCtx.EmitFormatError(ValidationRule::MetaSemanticIndexMax, {"SV_Target", "7"});
     }
   } else if (bAllowedInSig && semanticKind != DXIL::SemanticKind::Arbitrary) {
-    if (!bIsClipCull && SE.GetSemanticStartIndex() > 0) {
+    if (bIsBarycentric) {
+      if (SE.GetSemanticStartIndex() > 1) {
+        ValCtx.EmitFormatError(ValidationRule::MetaSemanticIndexMax, { SE.GetSemantic()->GetName(), "1" });
+      }
+    }
+    else if (!bIsClipCull && SE.GetSemanticStartIndex() > 0) {
       ValCtx.EmitFormatError(ValidationRule::MetaSemanticIndexMax, {SE.GetSemantic()->GetName(), "0"});
     }
     // Maximum rows is 1 for system values other than Target
@@ -3454,10 +3462,12 @@ static void ValidateSignature(ValidationContext &ValCtx, const DxilSignature &S,
   unsigned TargetMask = 0;
   DXIL::SemanticKind DepthKind = DXIL::SemanticKind::Invalid;
 
+  const InterpolationMode *prevBaryInterpMode = nullptr;
+  unsigned numBarycentrics = 0;
+
   for (auto &E : S.GetElements()) {
     DXIL::SemanticKind semanticKind = E->GetSemantic()->GetKind();
     ValidateSignatureElement(*E, ValCtx);
-
     // Avoid OOB indexing on streamId.
     unsigned streamId = E->GetOutputStream();
     if (streamId >= DXIL::kNumOutputStreams ||
@@ -3523,6 +3533,23 @@ static void ValidateSignature(ValidationContext &ValCtx, const DxilSignature &S,
       }
       DepthKind = semanticKind;
       break;
+    case DXIL::SemanticKind::Barycentrics: {
+      // There can only be up to two SV_Barycentrics
+      // with differeent perspective interpolation modes.
+      if (numBarycentrics++ > 1) {
+        ValCtx.EmitError(ValidationRule::MetaBarycentricsTwoPerspectives);
+        break;
+      }
+      const InterpolationMode *mode = E->GetInterpolationMode();
+      if (prevBaryInterpMode) {
+        if ((mode->IsAnyNoPerspective() && prevBaryInterpMode->IsAnyNoPerspective())
+          || (!mode->IsAnyNoPerspective() && !prevBaryInterpMode->IsAnyNoPerspective())) {
+          ValCtx.EmitError(ValidationRule::MetaBarycentricsTwoPerspectives);
+        }
+      }
+      prevBaryInterpMode = mode;
+      break;
+    }
     default:
       if (semanticUsageSet[streamId].count(semanticKind) > 0) {
         ValCtx.EmitFormatError(ValidationRule::MetaDuplicateSysValue,

+ 16 - 0
tools/clang/test/CodeGenHLSL/barycentrics1.hlsl

@@ -0,0 +1,16 @@
+// RUN: %dxc -E main -T ps_6_1 %s | FileCheck %s
+
+// CHECK: ; SV_Barycentrics
+// CHECK: ; SV_Barycentrics
+// CHECK: ; SV_Barycentrics
+// CHECK: ; SV_Barycentrics
+
+float4 main(float3 bary : SV_Barycentrics, noperspective float3 bary1 : SV_Barycentrics1) : SV_Target
+{
+  float4 vcolor0 = float4(1,0,0,1);
+  float4 vcolor1 = float4(0,1,0,1);
+  float4 vcolor2 = float4(0,0,0,1);
+  float4 vcolorPerspective =  bary.x * vcolor0 + bary.y * vcolor1 + bary.z * vcolor2;
+  float4 vcolorNoPerspectiveCentroid = bary1.x * vcolor0 + bary1.y * vcolor1 + bary1.z * vcolor2;
+  return (vcolorPerspective + vcolorNoPerspectiveCentroid) / 2;
+}

+ 8 - 0
tools/clang/test/CodeGenHLSL/barycentricsThreeSV.hlsl

@@ -0,0 +1,8 @@
+// RUN: %dxc -E main -T ps_6_1 %s | FileCheck %s
+
+// CHECK: There can only be up to two input attributes of SV_Barycentrics with different perspective interpolation mode.
+
+float4 main(float3 bary : SV_Barycentrics, noperspective float3 bary1 : SV_Barycentrics1, float3 bary2 : SV_Barycentrics2) : SV_Target
+{
+  return 1;
+}

+ 2 - 0
tools/clang/tools/dxcompiler/dxcompilerobj.cpp

@@ -985,6 +985,8 @@ static void PrintSignature(LPCSTR pName, const DxilProgramSignature *pSignature,
     case DxilProgramSigSemantic::FinalLineDensityTessfactor:
       pSysValue = "LINEDEN";
       break;
+    case DxilProgramSigSemantic::Barycentrics:
+      pSysValue = "BARYCEN";
     }
     OS << right_justify(pSysValue, 9);
 

+ 12 - 0
tools/clang/unittests/HLSL/CompilerTest.cpp

@@ -375,6 +375,8 @@ public:
   TEST_METHOD(CodeGenAtomic)
   TEST_METHOD(CodeGenAttributeAtVertex)
   TEST_METHOD(CodeGenBarycentrics)
+  TEST_METHOD(CodeGenBarycentrics1)
+  TEST_METHOD(CodeGenBarycentricsThreeSV)
   TEST_METHOD(CodeGenBinary1)
   TEST_METHOD(CodeGenBoolComb)
   TEST_METHOD(CodeGenBoolSvTarget)
@@ -2234,6 +2236,16 @@ TEST_F(CompilerTest, CodeGenBarycentrics) {
   CodeGenTestCheck(L"..\\CodeGenHLSL\\barycentrics.hlsl");
 }
 
+TEST_F(CompilerTest, CodeGenBarycentrics1) {
+  if (m_ver.SkipDxil_1_1_Test()) return;
+  CodeGenTestCheck(L"..\\CodeGenHLSL\\barycentrics1.hlsl");
+}
+
+TEST_F(CompilerTest, CodeGenBarycentricsThreeSV) {
+  if (m_ver.SkipDxil_1_1_Test()) return;
+  CodeGenTestCheck(L"..\\CodeGenHLSL\\barycentricsThreeSV.hlsl");
+}
+
 TEST_F(CompilerTest, CodeGenBinary1) {
   CodeGenTest(L"..\\CodeGenHLSL\\binary1.hlsl");
 }

+ 31 - 0
tools/clang/unittests/HLSL/ValidationTest.cpp

@@ -202,7 +202,9 @@ public:
   TEST_METHOD(AddUint64Odd)
 
   TEST_METHOD(BarycentricFloat4Fail)
+  TEST_METHOD(BarycentricMaxIndexFail)
   TEST_METHOD(BarycentricNoInterpolationFail)
+  TEST_METHOD(BarycentricSamePerspectiveFail)
   TEST_METHOD(ClipCullMaxComponents)
   TEST_METHOD(ClipCullMaxRows)
   TEST_METHOD(DuplicateSysValue)
@@ -2977,6 +2979,21 @@ TEST_F(ValidationTest, GetAttributeAtVertexInterpFail) {
                           /*bRegex*/ true);
 }
 
+TEST_F(ValidationTest, BarycentricMaxIndexFail) {
+  if (m_ver.SkipDxil_1_1_Test()) return;
+  RewriteAssemblyCheckMsg(
+      "float4 main(float3 bary : SV_Barycentrics, noperspective float3 bary1 : "
+      "SV_Barycentrics1) : SV_Target { return 1; }",
+      "ps_6_1",
+      {"!([0-9]+) = !{i32 0, !\"SV_Barycentrics\", i8 9, i8 28, !([0-9]+), i8 "
+       "2, i32 1, i8 3, i32 -1, i8 -1, null}\n"
+       "!([0-9]+) = !{i32 0}"},
+      {"!\\1 = !{i32 0, !\"SV_Barycentrics\", i8 9, i8 28, !\\2, i8 2, i32 1, "
+       "i8 3, i32 -1, i8 -1, null}\n"
+       "!\\3 = !{i32 2}"},
+      "SV_Barycentrics semantic index exceeds maximum", /*bRegex*/ true);
+}
+
 TEST_F(ValidationTest, BarycentricNoInterpolationFail) {
   if (m_ver.SkipDxil_1_1_Test()) return;
   RewriteAssemblyCheckMsg(
@@ -2997,4 +3014,18 @@ TEST_F(ValidationTest, BarycentricFloat4Fail) {
       "only 'float3' type is allowed for SV_Barycentrics.", false);
 }
 
+TEST_F(ValidationTest, BarycentricSamePerspectiveFail) {
+  if (m_ver.SkipDxil_1_1_Test()) return;
+  RewriteAssemblyCheckMsg(
+      "float4 main(float3 bary : SV_Barycentrics, noperspective float3 bary1 : "
+      "SV_Barycentrics1) : SV_Target { return 1; }",
+      "ps_6_1", {"!\"SV_Barycentrics\", i8 9, i8 28, (![0-9]+), i8 4"},
+      {"!\"SV_Barycentrics\", i8 9, i8 28, \\1, i8 2"},
+      "There can only be up to two input attributes of SV_Barycentrics with "
+      "different perspective interpolation mode.",
+      true);
+}
+
+
+
 // TODO: reject non-zero padding

+ 1 - 0
utils/hct/hctdb.py

@@ -1546,6 +1546,7 @@ class db_dxil(object):
         self.add_valrule("Meta.TextureType", "elements of typed buffers and textures must fit in four 32-bit quantities")
         self.add_valrule("Meta.BarycentricsInterpolation", "SV_Barycentrics cannot be used with 'nointerpolation' type")
         self.add_valrule("Meta.BarycentricsFloat3", "only 'float3' type is allowed for SV_Barycentrics.")
+        self.add_valrule("Meta.BarycentricsTwoPerspectives", "There can only be up to two input attributes of SV_Barycentrics with different perspective interpolation mode.")
 
         self.add_valrule("Instr.Oload", "DXIL intrinsic overload must be valid")
         self.add_valrule_msg("Instr.CallOload", "Call to DXIL intrinsic must match overload signature", "Call to DXIL intrinsic '%0' does not match an allowed overload signature")