Account for VS executing more than once when atomics are used.
authorMatthew Netsch <quic_mnetsch@quicinc.com>
Fri, 4 Oct 2019 15:46:04 +0000 (11:46 -0400)
committerMatthew Netsch <quic_mnetsch@quicinc.com>
Fri, 20 Dec 2019 20:39:19 +0000 (15:39 -0500)
Components: Vulkan

Affects: dEQP-VK.glsl.opaque_type_indexing.atomic_counter.*
         dEQP-VK.glsl.atomic_operations.*

Change-Id: I15eabf9b47af204fd13370efdc323af141b6b11b

external/vulkancts/modules/vulkan/shaderexecutor/vktAtomicOperationTests.cpp
external/vulkancts/modules/vulkan/shaderexecutor/vktOpaqueTypeIndexingTests.cpp

index 8e46111..24c8940 100644 (file)
@@ -216,6 +216,7 @@ public:
                T                       input[NUM_ELEMENTS];
                T                       compare[NUM_ELEMENTS];
                T                       output[NUM_ELEMENTS];
+               T                       invocationHitCount[NUM_ELEMENTS];
                deInt32         index;
        };
 
@@ -247,6 +248,7 @@ public:
                {
                        m_ptr->input[i] = static_cast<dataTypeT>(rnd.getUint64());
                        m_ptr->output[i] = pattern;
+                       m_ptr->invocationHitCount[i] = 0;
                }
                m_ptr->index = 0;
 
@@ -675,6 +677,7 @@ void AtomicOperationCase::createShaderSpec (void)
                "    ${DATATYPE} inputValues[${N}];\n"
                "    ${DATATYPE} compareValues[${N}];\n"
                "    ${DATATYPE} outputValues[${N}];\n"
+               "    ${DATATYPE} invocationHitCount[${N}];\n"
                "    int index;\n"
                "} buf;\n");
 
@@ -694,14 +697,22 @@ void AtomicOperationCase::createShaderSpec (void)
        specializations["N"] = de::toString((int)NUM_ELEMENTS);
        specializations["COMPARE_ARG"] = m_atomicOp == ATOMIC_OP_COMP_SWAP ? "buf.compareValues[idx], " : "";
 
-       const tcu::StringTemplate shaderTemplateSrc(
+       const tcu::StringTemplate nonVertexShaderTemplateSrc(
                "int idx = atomicAdd(buf.index, 1);\n"
                "buf.outputValues[idx] = ${ATOMICOP}(buf.inoutValues[idx % (${N}/2)], ${COMPARE_ARG}buf.inputValues[idx]);\n");
 
+       const tcu::StringTemplate vertexShaderTemplateSrc(
+               "int idx = gl_VertexIndex;\n"
+               "if (atomicAdd(buf.invocationHitCount[idx], 1) == 0)\n"
+               "{\n"
+               "    buf.outputValues[idx] = ${ATOMICOP}(buf.inoutValues[idx % (${N}/2)], ${COMPARE_ARG}buf.inputValues[idx]);\n"
+               "}\n");
+
        m_shaderSpec.outputs.push_back(Symbol("outData", glu::VarType(glu::TYPE_UINT, glu::PRECISION_HIGHP)));
        m_shaderSpec.globalDeclarations = shaderTemplateGlobal.specialize(specializations);
-       m_shaderSpec.source = shaderTemplateSrc.specialize(specializations);
        m_shaderSpec.glslVersion = glu::GLSL_VERSION_450;
+       m_shaderSpec.source = m_shaderType == glu::SHADERTYPE_VERTEX ?
+               vertexShaderTemplateSrc.specialize(specializations) : nonVertexShaderTemplateSrc.specialize(specializations);
 }
 
 void addAtomicOperationTests (tcu::TestCaseGroup* atomicOperationTestsGroup)
index d1f54ff..dfe8fe9 100644 (file)
@@ -1694,11 +1694,12 @@ tcu::TestStatus AtomicCounterIndexingCaseInstance::iterate (void)
        }
 
        {
-               tcu::TestLog&                                   log                             = m_context.getTestContext().getLog();
-               tcu::TestStatus                                 testResult              = tcu::TestStatus::pass("Pass");
-               std::vector<int>                                numHits                 (numCounters, 0);       // Number of hits per counter.
-               std::vector<deUint32>                   counterValues   (numCounters);
-               std::vector<std::vector<bool> > counterMasks    (numCounters);
+               tcu::TestLog&                                             log                                           = m_context.getTestContext().getLog();
+               tcu::TestStatus                                           testResult                                    = tcu::TestStatus::pass("Pass");
+               std::vector<int>                                          numHits                                       (numCounters, 0);       // Number of hits per counter.
+               std::vector<deUint32>                             counterValues                         (numCounters);
+               std::vector<std::map<deUint32, int> > resultValueHitCountMaps   (numCounters);
+
 
                for (int opNdx = 0; opNdx < numOps; opNdx++)
                        numHits[m_opIndices[opNdx]] += 1;
@@ -1717,24 +1718,32 @@ tcu::TestStatus AtomicCounterIndexingCaseInstance::iterate (void)
                        const deUint32          refCount        = (deUint32)(numHits[counterNdx]*numInvocations);
                        const deUint32          resCount        = counterValues[counterNdx];
 
-                       if (refCount != resCount)
+                       bool foundInvalidCtrValue = false;
+
+                       if(resCount < refCount)
+                       {
+                               log << tcu::TestLog::Message << "ERROR: atomic counter " << counterNdx << " has value " << resCount
+                                       << ", expected value greater than or equal to " << refCount
+                                       << tcu::TestLog::EndMessage;
+
+                               foundInvalidCtrValue = true;
+                       }
+                       else if (refCount == 0 && resCount != 0)
                        {
                                log << tcu::TestLog::Message << "ERROR: atomic counter " << counterNdx << " has value " << resCount
                                        << ", expected " << refCount
                                        << tcu::TestLog::EndMessage;
 
+                               foundInvalidCtrValue = true;
+                       }
+
+                       if (foundInvalidCtrValue == true)
+                       {
                                if (testResult.getCode() == QP_TEST_RESULT_PASS)
                                        testResult = tcu::TestStatus::fail("Invalid atomic counter value");
                        }
                }
 
-               // Allocate bitmasks - one bit per each valid result value
-               for (int counterNdx = 0; counterNdx < numCounters; counterNdx++)
-               {
-                       const int       counterValue    = numHits[counterNdx]*numInvocations;
-                       counterMasks[counterNdx].resize(counterValue, false);
-               }
-
                // Verify result values from shaders
                for (int invocationNdx = 0; invocationNdx < numInvocations; invocationNdx++)
                {
@@ -1742,11 +1751,14 @@ tcu::TestStatus AtomicCounterIndexingCaseInstance::iterate (void)
                        {
                                const int               counterNdx      = m_opIndices[opNdx];
                                const deUint32  resValue        = outValues[opNdx*numInvocations + invocationNdx];
-                               const bool              rangeOk         = de::inBounds(resValue, 0u, (deUint32)counterMasks[counterNdx].size());
-                               const bool              notSeen         = rangeOk && !counterMasks[counterNdx][resValue];
-                               const bool              isOk            = rangeOk && notSeen;
+                               const bool              rangeOk         = de::inBounds(resValue, 0u, counterValues[counterNdx]);
+
+                               if (resultValueHitCountMaps[counterNdx].count(resValue) == 0)
+                                       resultValueHitCountMaps[counterNdx][resValue] = 1;
+                               else
+                                       resultValueHitCountMaps[counterNdx][resValue] += 1;
 
-                               if (!isOk)
+                               if (!rangeOk)
                                {
                                        log << tcu::TestLog::Message << "ERROR: at invocation " << invocationNdx
                                                << ", op " << opNdx << ": got invalid result value "
@@ -1756,21 +1768,23 @@ tcu::TestStatus AtomicCounterIndexingCaseInstance::iterate (void)
                                        if (testResult.getCode() == QP_TEST_RESULT_PASS)
                                                testResult = tcu::TestStatus::fail("Invalid result value");
                                }
-                               else
-                               {
-                                       // Mark as used - no other invocation should see this value from same counter.
-                                       counterMasks[counterNdx][resValue] = true;
-                               }
                        }
                }
 
-               if (testResult.getCode() == QP_TEST_RESULT_PASS)
+               for (int ctrIdx = 0; ctrIdx < numCounters; ctrIdx++)
                {
-                       // Consistency check - all masks should be 1 now
-                       for (int counterNdx = 0; counterNdx < numCounters; counterNdx++)
+                       std::map<deUint32, int>::iterator hitCountItr;
+                       for (hitCountItr = resultValueHitCountMaps[ctrIdx].begin(); hitCountItr != resultValueHitCountMaps[ctrIdx].end(); hitCountItr++)
                        {
-                               for (std::vector<bool>::const_iterator i = counterMasks[counterNdx].begin(); i != counterMasks[counterNdx].end(); i++)
-                                       TCU_CHECK_INTERNAL(*i);
+                               if(hitCountItr->second > 1)
+                               {
+                                       log << tcu::TestLog::Message << "ERROR: Duplicate result value from counter " << ctrIdx << "."
+                                               <<" Value " << hitCountItr->first << " found " << hitCountItr->second << " times."
+                                               << tcu::TestLog::EndMessage;
+
+                                       if (testResult.getCode() == QP_TEST_RESULT_PASS)
+                                               testResult = tcu::TestStatus::fail("Invalid result value");
+                               }
                        }
                }