Forráskód Böngészése

add barycentrics ordering check onto existing barycentrics test (#4635)

* add barycentrics ordering check onto existing barycentrics test, with extra shader
Joshua Batista 2 éve
szülő
commit
ee0994e58e

+ 37 - 7
tools/clang/test/HLSL/ShaderOpArith.xml

@@ -1493,12 +1493,9 @@
 
   <ShaderOp Name="Barycentrics" PS="PS" VS="VS">
     <RootSignature>RootFlags(ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT)</RootSignature>
-    <Resource Name="VBuffer" Dimension="BUFFER" Width="1024" Flags="ALLOW_UNORDERED_ACCESS" InitialResourceState="COPY_DEST" Init="FromBytes" ReadBack="true">
-        { {   0.0f,  1.0f , 0.0f }, { 1.0f, 0.0f, 0.0f, 1.0f } },
-        { {   1.0f, -1.0f , 0.0f }, { 0.0f, 1.0f, 0.0f, 1.0f } },
-        { {  -1.0f, -1.0f , 0.0f }, { 0.0f, 0.0f, 1.0f, 1.0f } }
-      </Resource>
-    <Resource Name="RTarget" Dimension="TEXTURE2D" Width="1280" Height="2400" Format="R32G32B32A32_FLOAT" Flags="ALLOW_RENDER_TARGET" InitialResourceState="COPY_DEST" ReadBack="true" />
+    <Resource Name="VBuffer" Dimension="BUFFER" Width="1024" Flags="ALLOW_UNORDERED_ACCESS" InitialResourceState="COPY_DEST" Init="ByName" ReadBack="true">
+    </Resource>
+    <Resource Name="RTarget" Dimension="TEXTURE2D" Width="64" Height="64" Format="R32G32B32A32_FLOAT" Flags="ALLOW_RENDER_TARGET" InitialResourceState="COPY_DEST" ReadBack="true" />
     <DescriptorHeap Name="RtvHeap" NumDescriptors="1" Type="RTV">
       <Descriptor Name="RTarget" Kind="RTV"/>
     </DescriptorHeap>
@@ -1535,7 +1532,40 @@
         float4 vColor2 = GetAttributeAtVertex(input.color, 2);
         return bary.x * vColor0 + bary.y * vColor1 + bary.z * vColor2;
       }
-      ]]>
+      ]]>          
+    </Shader>
+    
+    <!-- This part of the shader op is for the barycentrics ordering part of the barycentrics test -->
+    <Shader Name="PSordering" Target="ps_6_1" EntryPoint="PSMain" Text="@MAIN"/>
+    <Shader Name="VSordering" Target="vs_6_1" EntryPoint="VSMain" Text="@MAIN"/>
+
+    <Shader Name="MAIN" Target="vs_6_1" EntryPoint="VSMain">
+      <![CDATA[
+    struct PSInput {
+      float4 position : SV_POSITION;
+      nointerpolation float4 color : COLOR;
+      uint svid : SVertexID;
+    };    
+            
+    PSInput VSMain(float4 position : POSITION, float4 color : COLOR, uint svid : SV_VertexID) {
+      PSInput result;
+      result.position = position;
+      result.color = color;
+      result.svid = svid;
+         
+      return result;
+    }
+    
+    float4 PSMain(PSInput input) : SV_Target {
+      // check to make sure that the pixel shader will see the barycentric weight associated
+      // with the first vertex in the x component of the SV_Barycentric vector, and likewise for subsequent vertices
+      
+      return float4(float3(GetAttributeAtVertex(input.svid, 0),
+                     GetAttributeAtVertex(input.svid, 1),
+                     GetAttributeAtVertex(input.svid, 2)) * 0.5, 1.0);    
+    }
+      
+    ]]>
     </Shader>
   </ShaderOp>
 

+ 91 - 28
tools/clang/unittests/HLSL/ExecutionTest.cpp

@@ -8988,22 +8988,7 @@ TEST_F(ExecutionTest, CBufferTestHalf) {
   }
 }
 
-TEST_F(ExecutionTest, BarycentricsTest) {
-    WEX::TestExecution::SetVerifyOutput verifySettings(WEX::TestExecution::VerifyOutputSettings::LogOnlyFailures);
-    CComPtr<IStream> pStream;
-    ReadHlslDataIntoNewStream(L"ShaderOpArith.xml", &pStream);
-
-    CComPtr<ID3D12Device> pDevice;
-    if (!CreateDevice(&pDevice, D3D_SHADER_MODEL_6_1))
-        return;
-
-    if (!DoesDeviceSupportBarycentrics(pDevice)) {
-      WEX::Logging::Log::Comment(L"Device does not support barycentrics.");
-      WEX::Logging::Log::Result(WEX::Logging::TestResults::Skipped);
-      return;
-    }
-
-    std::shared_ptr<ShaderOpTestResult> test = RunShaderOpTest(pDevice, m_support, pStream, "Barycentrics", nullptr);
+void TestBarycentricVariant(bool checkOrdering, std::shared_ptr<ShaderOpTestResult> test){
     MappedData data;
     D3D12_RESOURCE_DESC &D = test->ShaderOp->GetResourceByName("RTarget")->Desc;
     UINT width = (UINT)D.Width;
@@ -9011,7 +8996,7 @@ TEST_F(ExecutionTest, BarycentricsTest) {
     UINT pixelSize = GetByteSizeForFormat(D.Format);
 
     test->Test->GetReadBackData("RTarget", &data);
-    //const uint8_t *pPixels = (uint8_t *)data.data();
+    
     const float *pPixels = (float *)data.data();
     // Get the vertex of barycentric coordinate using VBuffer
     MappedData triangleData;
@@ -9025,15 +9010,16 @@ TEST_F(ExecutionTest, BarycentricsTest) {
     XMFLOAT2 p0(pTriangleData[0], pTriangleData[1]);
     XMFLOAT2 p1(pTriangleData[triangleVertexSizeInFloat], pTriangleData[triangleVertexSizeInFloat + 1]);
     XMFLOAT2 p2(pTriangleData[triangleVertexSizeInFloat * 2], pTriangleData[triangleVertexSizeInFloat * 2 + 1]);
-
+    
+    // Seems like the 3 floats must add up to 1 to get accurate results.
     XMFLOAT3 barycentricWeights[4] = {
-        XMFLOAT3(0.3333f, 0.3333f, 0.3333f),
+        XMFLOAT3(0.4f, 0.2f, 0.4f),
         XMFLOAT3(0.5f, 0.25f, 0.25f),
         XMFLOAT3(0.25f, 0.5f, 0.25f),
         XMFLOAT3(0.25f, 0.25f, 0.50f)
-    };
+    };    
 
-    float tolerance = 0.001f;
+    float tolerance = 0.02f;
     for (unsigned i = 0; i < sizeof(barycentricWeights) / sizeof(XMFLOAT3); ++i) {
         float w0 = barycentricWeights[i].x;
         float w1 = barycentricWeights[i].y;
@@ -9041,17 +9027,89 @@ TEST_F(ExecutionTest, BarycentricsTest) {
         float x1 = w0 * p0.x + w1 * p1.x + w2 * p2.x;
         float y1 = w0 * p0.y + w1 * p1.y + w2 * p2.y;
         // map from x1 y1 to rtv pixels
-        int pixelX = (int)((x1 + 1) * (width - 1) / 2);
-        int pixelY = (int)((1 - y1) * (height - 1) / 2);
+        int pixelX = (int)round((x1 + 1) * (width - 1) / 2.0);
+        int pixelY = (int)round((1 - y1) * (height - 1) / 2.0);
         int offset = pixelSize * (pixelX + pixelY * width) / sizeof(pPixels[0]);
         LogCommentFmt(L"location  %u %u, value %f, %f, %f", pixelX, pixelY, pPixels[offset], pPixels[offset + 1], pPixels[offset + 2]);
-        VERIFY_IS_TRUE(CompareFloatEpsilon(pPixels[offset], w0, tolerance));
-        VERIFY_IS_TRUE(CompareFloatEpsilon(pPixels[offset + 1], w1, tolerance));
-        VERIFY_IS_TRUE(CompareFloatEpsilon(pPixels[offset + 2], w2, tolerance));
+        if (!checkOrdering){
+            VERIFY_IS_TRUE(CompareFloatEpsilon(pPixels[offset], w0, tolerance));
+            VERIFY_IS_TRUE(CompareFloatEpsilon(pPixels[offset + 1], w1, tolerance));
+            VERIFY_IS_TRUE(CompareFloatEpsilon(pPixels[offset + 2], w2, tolerance));
+        }
+        else{
+            // If the ordering constraint is met, then this pixel's RGBA should be all 1.0's
+            // since the shader only returns float4<1.0,1.0,1.0,1.0> when this condition is met.
+            VERIFY_IS_TRUE(CompareFloatEpsilon(pPixels[offset]    , 0.0, tolerance));
+            VERIFY_IS_TRUE(CompareFloatEpsilon(pPixels[offset + 1], 0.5, tolerance));
+            VERIFY_IS_TRUE(CompareFloatEpsilon(pPixels[offset + 2], 1.0, tolerance));
+            VERIFY_IS_TRUE(CompareFloatEpsilon(pPixels[offset + 3], 1.0, tolerance));        
+        }  
+    }
+}
+
+st::ShaderOpTest::TInitCallbackFn MakeBarycentricsResourceInitCallbackFn(int &vertexShift){
+    return [&](LPCSTR Name, std::vector<BYTE>& Data, st::ShaderOp* pShaderOp) {
+        std::vector<float> bary = { 0.0f,  1.0f , 0.0f,   1.0f, 0.0f, 0.0f, 1.0f,
+                                    1.0f, -1.0f , 0.0f,   0.0f, 1.0f, 0.0f, 1.0f,
+                                  -1.0f, -1.0f , 0.0f,   0.0f, 0.0f, 1.0f, 1.0f };
+        const int barysize = 21;
+
+        UNREFERENCED_PARAMETER(pShaderOp);
+        VERIFY_IS_TRUE(0 == _stricmp(Name, "VBuffer"));
+        size_t size = sizeof(float) * barysize;
+        Data.resize(size);
+        float* vb = (float*)Data.data();
+        for (size_t i = 0; i < barysize; ++i) {
+          float* p = &vb[i];
+          float tempfloat = bary[(i + (7 * vertexShift)) % barysize];
+          *p = tempfloat;
+        }
+    };
+
+}
+
+TEST_F(ExecutionTest, BarycentricsTest) {
+    WEX::TestExecution::SetVerifyOutput verifySettings(WEX::TestExecution::VerifyOutputSettings::LogOnlyFailures);
+    CComPtr<IStream> pStream;
+    ReadHlslDataIntoNewStream(L"ShaderOpArith.xml", &pStream);
+
+    CComPtr<ID3D12Device> pDevice;
+    if (!CreateDevice(&pDevice, D3D_SHADER_MODEL_6_1))
+        return;
+
+    if (!DoesDeviceSupportBarycentrics(pDevice)) {
+      WEX::Logging::Log::Comment(L"Device does not support barycentrics.");
+      WEX::Logging::Log::Result(WEX::Logging::TestResults::Skipped);
+      return;
     }
-    //SavePixelsToFile(pPixels, DXGI_FORMAT_R32G32B32A32_FLOAT, width, height, L"barycentric.bmp");
+
+    DXASSERT_NOMSG(pStream != nullptr);
+    std::shared_ptr<st::ShaderOpSet> ShaderOpSet =
+      std::make_shared<st::ShaderOpSet>();
+    st::ParseShaderOpSetFromStream(pStream, ShaderOpSet.get());
+    st::ShaderOp* pShaderOp =
+      ShaderOpSet->GetShaderOp("Barycentrics");
+
+    int test_iteration = 0;
+    auto ResourceCallbackFnNoShift = MakeBarycentricsResourceInitCallbackFn(test_iteration);
+     
+    std::shared_ptr<ShaderOpTestResult> test = RunShaderOpTestAfterParse(pDevice, m_support, "Barycentrics", ResourceCallbackFnNoShift, ShaderOpSet);
+    TestBarycentricVariant(false, test);     
+    
+    // Now test that barycentric ordering is consistent
+    LogCommentFmt(L"Now testing that the barycentric ordering constraint is upheld for each pixel...");
+    pShaderOp->VS = pShaderOp->GetString("VSordering");
+    pShaderOp->PS = pShaderOp->GetString("PSordering");
+    for(; test_iteration < 3; test_iteration++)
+    {
+        auto ResourceCallbackFn = MakeBarycentricsResourceInitCallbackFn(test_iteration);
+
+        std::shared_ptr<ShaderOpTestResult> test2 = RunShaderOpTestAfterParse(pDevice, m_support, "Barycentrics", ResourceCallbackFn, ShaderOpSet);
+        TestBarycentricVariant(true, test2);
+    }   
 }
 
+
 static const char RawBufferTestShaderDeclarations[] =
 "// Note: COMPONENT_TYPE and COMPONENT_SIZE will be defined via compiler option -D\r\n"
 "typedef COMPONENT_TYPE scalar; \r\n"
@@ -11488,7 +11546,12 @@ TEST_F(ExecutionTest, IsNormalTest) {
   st::ParseShaderOpSetFromStream(pStream, ShaderOpSet.get());
   st::ShaderOp *pShaderOp = ShaderOpSet->GetShaderOp("IsNormal");
   vector<st::ShaderOpRootValue> fallbackRootValues = pShaderOp->RootValues;
- 
+
+  D3D_SHADER_MODEL sm = D3D_SHADER_MODEL_6_0;
+  LogCommentFmt(L"\r\nVerifying isNormal in shader "
+                L"model 6.%1u",
+                ((UINT)sm & 0x0f));
+
   size_t count = Validation_Input->size();
 
   auto ShaderInitFn = MakeShaderReplacementCallback(