xref: /aosp_15_r20/external/deqp/modules/gles31/functional/es31fShaderAtomicOpTests.cpp (revision 35238bce31c2a825756842865a792f8cf7f89930)
1*35238bceSAndroid Build Coastguard Worker /*-------------------------------------------------------------------------
2*35238bceSAndroid Build Coastguard Worker  * drawElements Quality Program OpenGL ES 3.1 Module
3*35238bceSAndroid Build Coastguard Worker  * -------------------------------------------------
4*35238bceSAndroid Build Coastguard Worker  *
5*35238bceSAndroid Build Coastguard Worker  * Copyright 2014 The Android Open Source Project
6*35238bceSAndroid Build Coastguard Worker  *
7*35238bceSAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
8*35238bceSAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
9*35238bceSAndroid Build Coastguard Worker  * You may obtain a copy of the License at
10*35238bceSAndroid Build Coastguard Worker  *
11*35238bceSAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
12*35238bceSAndroid Build Coastguard Worker  *
13*35238bceSAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
14*35238bceSAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
15*35238bceSAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16*35238bceSAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
17*35238bceSAndroid Build Coastguard Worker  * limitations under the License.
18*35238bceSAndroid Build Coastguard Worker  *
19*35238bceSAndroid Build Coastguard Worker  *//*!
20*35238bceSAndroid Build Coastguard Worker  * \file
21*35238bceSAndroid Build Coastguard Worker  * \brief Shader atomic operation tests.
22*35238bceSAndroid Build Coastguard Worker  *//*--------------------------------------------------------------------*/
23*35238bceSAndroid Build Coastguard Worker 
24*35238bceSAndroid Build Coastguard Worker #include "es31fShaderAtomicOpTests.hpp"
25*35238bceSAndroid Build Coastguard Worker #include "gluShaderProgram.hpp"
26*35238bceSAndroid Build Coastguard Worker #include "gluShaderUtil.hpp"
27*35238bceSAndroid Build Coastguard Worker #include "gluRenderContext.hpp"
28*35238bceSAndroid Build Coastguard Worker #include "gluObjectWrapper.hpp"
29*35238bceSAndroid Build Coastguard Worker #include "gluProgramInterfaceQuery.hpp"
30*35238bceSAndroid Build Coastguard Worker #include "tcuVector.hpp"
31*35238bceSAndroid Build Coastguard Worker #include "tcuTestLog.hpp"
32*35238bceSAndroid Build Coastguard Worker #include "tcuVectorUtil.hpp"
33*35238bceSAndroid Build Coastguard Worker #include "tcuFormatUtil.hpp"
34*35238bceSAndroid Build Coastguard Worker #include "deStringUtil.hpp"
35*35238bceSAndroid Build Coastguard Worker #include "deRandom.hpp"
36*35238bceSAndroid Build Coastguard Worker #include "glwFunctions.hpp"
37*35238bceSAndroid Build Coastguard Worker #include "glwEnums.hpp"
38*35238bceSAndroid Build Coastguard Worker 
39*35238bceSAndroid Build Coastguard Worker #include <algorithm>
40*35238bceSAndroid Build Coastguard Worker #include <set>
41*35238bceSAndroid Build Coastguard Worker 
42*35238bceSAndroid Build Coastguard Worker namespace deqp
43*35238bceSAndroid Build Coastguard Worker {
44*35238bceSAndroid Build Coastguard Worker namespace gles31
45*35238bceSAndroid Build Coastguard Worker {
46*35238bceSAndroid Build Coastguard Worker namespace Functional
47*35238bceSAndroid Build Coastguard Worker {
48*35238bceSAndroid Build Coastguard Worker 
49*35238bceSAndroid Build Coastguard Worker using std::set;
50*35238bceSAndroid Build Coastguard Worker using std::string;
51*35238bceSAndroid Build Coastguard Worker using std::vector;
52*35238bceSAndroid Build Coastguard Worker using tcu::TestLog;
53*35238bceSAndroid Build Coastguard Worker using tcu::UVec3;
54*35238bceSAndroid Build Coastguard Worker using namespace glu;
55*35238bceSAndroid Build Coastguard Worker 
56*35238bceSAndroid Build Coastguard Worker template <typename T, int Size>
product(const tcu::Vector<T,Size> & v)57*35238bceSAndroid Build Coastguard Worker static inline T product(const tcu::Vector<T, Size> &v)
58*35238bceSAndroid Build Coastguard Worker {
59*35238bceSAndroid Build Coastguard Worker     T res = v[0];
60*35238bceSAndroid Build Coastguard Worker     for (int ndx = 1; ndx < Size; ndx++)
61*35238bceSAndroid Build Coastguard Worker         res *= v[ndx];
62*35238bceSAndroid Build Coastguard Worker     return res;
63*35238bceSAndroid Build Coastguard Worker }
64*35238bceSAndroid Build Coastguard Worker 
65*35238bceSAndroid Build Coastguard Worker class ShaderAtomicOpCase : public TestCase
66*35238bceSAndroid Build Coastguard Worker {
67*35238bceSAndroid Build Coastguard Worker public:
68*35238bceSAndroid Build Coastguard Worker     ShaderAtomicOpCase(Context &context, const char *name, const char *funcName, AtomicOperandType operandType,
69*35238bceSAndroid Build Coastguard Worker                        DataType type, Precision precision, const UVec3 &workGroupSize);
70*35238bceSAndroid Build Coastguard Worker     ~ShaderAtomicOpCase(void);
71*35238bceSAndroid Build Coastguard Worker 
72*35238bceSAndroid Build Coastguard Worker     void init(void);
73*35238bceSAndroid Build Coastguard Worker     void deinit(void);
74*35238bceSAndroid Build Coastguard Worker     IterateResult iterate(void);
75*35238bceSAndroid Build Coastguard Worker 
76*35238bceSAndroid Build Coastguard Worker protected:
77*35238bceSAndroid Build Coastguard Worker     virtual void getInputs(int numValues, int stride, void *inputs) const = 0;
78*35238bceSAndroid Build Coastguard Worker     virtual bool verify(int numValues, int inputStride, const void *inputs, int outputStride, const void *outputs,
79*35238bceSAndroid Build Coastguard Worker                         int groupStride, const void *groupOutputs) const  = 0;
80*35238bceSAndroid Build Coastguard Worker 
81*35238bceSAndroid Build Coastguard Worker     const string m_funcName;
82*35238bceSAndroid Build Coastguard Worker     const AtomicOperandType m_operandType;
83*35238bceSAndroid Build Coastguard Worker     const DataType m_type;
84*35238bceSAndroid Build Coastguard Worker     const Precision m_precision;
85*35238bceSAndroid Build Coastguard Worker 
86*35238bceSAndroid Build Coastguard Worker     const UVec3 m_workGroupSize;
87*35238bceSAndroid Build Coastguard Worker     const UVec3 m_numWorkGroups;
88*35238bceSAndroid Build Coastguard Worker 
89*35238bceSAndroid Build Coastguard Worker     uint32_t m_initialValue;
90*35238bceSAndroid Build Coastguard Worker 
91*35238bceSAndroid Build Coastguard Worker private:
92*35238bceSAndroid Build Coastguard Worker     ShaderAtomicOpCase(const ShaderAtomicOpCase &other);
93*35238bceSAndroid Build Coastguard Worker     ShaderAtomicOpCase &operator=(const ShaderAtomicOpCase &other);
94*35238bceSAndroid Build Coastguard Worker 
95*35238bceSAndroid Build Coastguard Worker     ShaderProgram *m_program;
96*35238bceSAndroid Build Coastguard Worker };
97*35238bceSAndroid Build Coastguard Worker 
ShaderAtomicOpCase(Context & context,const char * name,const char * funcName,AtomicOperandType operandType,DataType type,Precision precision,const UVec3 & workGroupSize)98*35238bceSAndroid Build Coastguard Worker ShaderAtomicOpCase::ShaderAtomicOpCase(Context &context, const char *name, const char *funcName,
99*35238bceSAndroid Build Coastguard Worker                                        AtomicOperandType operandType, DataType type, Precision precision,
100*35238bceSAndroid Build Coastguard Worker                                        const UVec3 &workGroupSize)
101*35238bceSAndroid Build Coastguard Worker     : TestCase(context, name, funcName)
102*35238bceSAndroid Build Coastguard Worker     , m_funcName(funcName)
103*35238bceSAndroid Build Coastguard Worker     , m_operandType(operandType)
104*35238bceSAndroid Build Coastguard Worker     , m_type(type)
105*35238bceSAndroid Build Coastguard Worker     , m_precision(precision)
106*35238bceSAndroid Build Coastguard Worker     , m_workGroupSize(workGroupSize)
107*35238bceSAndroid Build Coastguard Worker     , m_numWorkGroups(4, 4, 4)
108*35238bceSAndroid Build Coastguard Worker     , m_initialValue(0)
109*35238bceSAndroid Build Coastguard Worker     , m_program(DE_NULL)
110*35238bceSAndroid Build Coastguard Worker {
111*35238bceSAndroid Build Coastguard Worker }
112*35238bceSAndroid Build Coastguard Worker 
~ShaderAtomicOpCase(void)113*35238bceSAndroid Build Coastguard Worker ShaderAtomicOpCase::~ShaderAtomicOpCase(void)
114*35238bceSAndroid Build Coastguard Worker {
115*35238bceSAndroid Build Coastguard Worker     ShaderAtomicOpCase::deinit();
116*35238bceSAndroid Build Coastguard Worker }
117*35238bceSAndroid Build Coastguard Worker 
init(void)118*35238bceSAndroid Build Coastguard Worker void ShaderAtomicOpCase::init(void)
119*35238bceSAndroid Build Coastguard Worker {
120*35238bceSAndroid Build Coastguard Worker     const bool isSSBO    = m_operandType == ATOMIC_OPERAND_BUFFER_VARIABLE;
121*35238bceSAndroid Build Coastguard Worker     const char *precName = getPrecisionName(m_precision);
122*35238bceSAndroid Build Coastguard Worker     const char *typeName = getDataTypeName(m_type);
123*35238bceSAndroid Build Coastguard Worker 
124*35238bceSAndroid Build Coastguard Worker     const DataType outType  = isSSBO ? m_type : glu::TYPE_UINT;
125*35238bceSAndroid Build Coastguard Worker     const char *outTypeName = getDataTypeName(outType);
126*35238bceSAndroid Build Coastguard Worker 
127*35238bceSAndroid Build Coastguard Worker     const uint32_t numValues = product(m_workGroupSize) * product(m_numWorkGroups);
128*35238bceSAndroid Build Coastguard Worker     std::ostringstream src;
129*35238bceSAndroid Build Coastguard Worker 
130*35238bceSAndroid Build Coastguard Worker     src << glu::getGLSLVersionDeclaration(getContextTypeGLSLVersion(m_context.getRenderContext().getType())) << "\n"
131*35238bceSAndroid Build Coastguard Worker         << "layout(local_size_x = " << m_workGroupSize.x() << ", local_size_y = " << m_workGroupSize.y()
132*35238bceSAndroid Build Coastguard Worker         << ", local_size_z = " << m_workGroupSize.z() << ") in;\n"
133*35238bceSAndroid Build Coastguard Worker         << "layout(binding = 0) buffer InOut\n"
134*35238bceSAndroid Build Coastguard Worker         << "{\n"
135*35238bceSAndroid Build Coastguard Worker         << "    " << precName << " " << typeName << " inputValues[" << numValues << "];\n"
136*35238bceSAndroid Build Coastguard Worker         << "    " << precName << " " << outTypeName << " outputValues[" << numValues << "];\n"
137*35238bceSAndroid Build Coastguard Worker         << "    " << (isSSBO ? "coherent " : "") << precName << " " << outTypeName << " groupValues["
138*35238bceSAndroid Build Coastguard Worker         << product(m_numWorkGroups) << "];\n"
139*35238bceSAndroid Build Coastguard Worker         << "} sb_inout;\n";
140*35238bceSAndroid Build Coastguard Worker 
141*35238bceSAndroid Build Coastguard Worker     if (!isSSBO)
142*35238bceSAndroid Build Coastguard Worker         src << "shared " << precName << " " << typeName << " s_var;\n";
143*35238bceSAndroid Build Coastguard Worker 
144*35238bceSAndroid Build Coastguard Worker     src << "\n"
145*35238bceSAndroid Build Coastguard Worker         << "void main (void)\n"
146*35238bceSAndroid Build Coastguard Worker         << "{\n"
147*35238bceSAndroid Build Coastguard Worker         << "    uint localSize  = gl_WorkGroupSize.x*gl_WorkGroupSize.y*gl_WorkGroupSize.z;\n"
148*35238bceSAndroid Build Coastguard Worker         << "    uint globalNdx  = gl_NumWorkGroups.x*gl_NumWorkGroups.y*gl_WorkGroupID.z + "
149*35238bceSAndroid Build Coastguard Worker            "gl_NumWorkGroups.x*gl_WorkGroupID.y + gl_WorkGroupID.x;\n"
150*35238bceSAndroid Build Coastguard Worker         << "    uint globalOffs = localSize*globalNdx;\n"
151*35238bceSAndroid Build Coastguard Worker         << "    uint offset     = globalOffs + gl_LocalInvocationIndex;\n"
152*35238bceSAndroid Build Coastguard Worker         << "\n";
153*35238bceSAndroid Build Coastguard Worker 
154*35238bceSAndroid Build Coastguard Worker     if (isSSBO)
155*35238bceSAndroid Build Coastguard Worker     {
156*35238bceSAndroid Build Coastguard Worker         DE_ASSERT(outType == m_type);
157*35238bceSAndroid Build Coastguard Worker         src << "    sb_inout.outputValues[offset] = " << m_funcName
158*35238bceSAndroid Build Coastguard Worker             << "(sb_inout.groupValues[globalNdx], sb_inout.inputValues[offset]);\n";
159*35238bceSAndroid Build Coastguard Worker     }
160*35238bceSAndroid Build Coastguard Worker     else
161*35238bceSAndroid Build Coastguard Worker     {
162*35238bceSAndroid Build Coastguard Worker         const string castBeg      = outType != m_type ? (string(outTypeName) + "(") : string("");
163*35238bceSAndroid Build Coastguard Worker         const char *const castEnd = outType != m_type ? ")" : "";
164*35238bceSAndroid Build Coastguard Worker 
165*35238bceSAndroid Build Coastguard Worker         src << "    if (gl_LocalInvocationIndex == 0u)\n"
166*35238bceSAndroid Build Coastguard Worker             << "        s_var = " << typeName << "(" << tcu::toHex(m_initialValue) << "u);\n"
167*35238bceSAndroid Build Coastguard Worker             << "    barrier();\n"
168*35238bceSAndroid Build Coastguard Worker             << "    " << precName << " " << typeName << " res = " << m_funcName
169*35238bceSAndroid Build Coastguard Worker             << "(s_var, sb_inout.inputValues[offset]);\n"
170*35238bceSAndroid Build Coastguard Worker             << "    sb_inout.outputValues[offset] = " << castBeg << "res" << castEnd << ";\n"
171*35238bceSAndroid Build Coastguard Worker             << "    barrier();\n"
172*35238bceSAndroid Build Coastguard Worker             << "    if (gl_LocalInvocationIndex == 0u)\n"
173*35238bceSAndroid Build Coastguard Worker             << "        sb_inout.groupValues[globalNdx] = " << castBeg << "s_var" << castEnd << ";\n";
174*35238bceSAndroid Build Coastguard Worker     }
175*35238bceSAndroid Build Coastguard Worker 
176*35238bceSAndroid Build Coastguard Worker     src << "}\n";
177*35238bceSAndroid Build Coastguard Worker 
178*35238bceSAndroid Build Coastguard Worker     DE_ASSERT(!m_program);
179*35238bceSAndroid Build Coastguard Worker     m_program = new ShaderProgram(m_context.getRenderContext(), ProgramSources() << ComputeSource(src.str()));
180*35238bceSAndroid Build Coastguard Worker 
181*35238bceSAndroid Build Coastguard Worker     m_testCtx.getLog() << *m_program;
182*35238bceSAndroid Build Coastguard Worker 
183*35238bceSAndroid Build Coastguard Worker     if (!m_program->isOk())
184*35238bceSAndroid Build Coastguard Worker     {
185*35238bceSAndroid Build Coastguard Worker         delete m_program;
186*35238bceSAndroid Build Coastguard Worker         m_program = DE_NULL;
187*35238bceSAndroid Build Coastguard Worker         throw tcu::TestError("Compile failed");
188*35238bceSAndroid Build Coastguard Worker     }
189*35238bceSAndroid Build Coastguard Worker }
190*35238bceSAndroid Build Coastguard Worker 
deinit(void)191*35238bceSAndroid Build Coastguard Worker void ShaderAtomicOpCase::deinit(void)
192*35238bceSAndroid Build Coastguard Worker {
193*35238bceSAndroid Build Coastguard Worker     delete m_program;
194*35238bceSAndroid Build Coastguard Worker     m_program = DE_NULL;
195*35238bceSAndroid Build Coastguard Worker }
196*35238bceSAndroid Build Coastguard Worker 
iterate(void)197*35238bceSAndroid Build Coastguard Worker ShaderAtomicOpCase::IterateResult ShaderAtomicOpCase::iterate(void)
198*35238bceSAndroid Build Coastguard Worker {
199*35238bceSAndroid Build Coastguard Worker     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
200*35238bceSAndroid Build Coastguard Worker     const uint32_t program   = m_program->getProgram();
201*35238bceSAndroid Build Coastguard Worker     const Buffer inoutBuffer(m_context.getRenderContext());
202*35238bceSAndroid Build Coastguard Worker     const uint32_t blockNdx            = gl.getProgramResourceIndex(program, GL_SHADER_STORAGE_BLOCK, "InOut");
203*35238bceSAndroid Build Coastguard Worker     const InterfaceBlockInfo blockInfo = getProgramInterfaceBlockInfo(gl, program, GL_SHADER_STORAGE_BLOCK, blockNdx);
204*35238bceSAndroid Build Coastguard Worker     const uint32_t inVarNdx = gl.getProgramResourceIndex(program, GL_BUFFER_VARIABLE, "InOut.inputValues[0]");
205*35238bceSAndroid Build Coastguard Worker     const InterfaceVariableInfo inVarInfo = getProgramInterfaceVariableInfo(gl, program, GL_BUFFER_VARIABLE, inVarNdx);
206*35238bceSAndroid Build Coastguard Worker     const uint32_t outVarNdx = gl.getProgramResourceIndex(program, GL_BUFFER_VARIABLE, "InOut.outputValues[0]");
207*35238bceSAndroid Build Coastguard Worker     const InterfaceVariableInfo outVarInfo =
208*35238bceSAndroid Build Coastguard Worker         getProgramInterfaceVariableInfo(gl, program, GL_BUFFER_VARIABLE, outVarNdx);
209*35238bceSAndroid Build Coastguard Worker     const uint32_t groupVarNdx = gl.getProgramResourceIndex(program, GL_BUFFER_VARIABLE, "InOut.groupValues[0]");
210*35238bceSAndroid Build Coastguard Worker     const InterfaceVariableInfo groupVarInfo =
211*35238bceSAndroid Build Coastguard Worker         getProgramInterfaceVariableInfo(gl, program, GL_BUFFER_VARIABLE, groupVarNdx);
212*35238bceSAndroid Build Coastguard Worker     const uint32_t numValues = product(m_workGroupSize) * product(m_numWorkGroups);
213*35238bceSAndroid Build Coastguard Worker 
214*35238bceSAndroid Build Coastguard Worker     TCU_CHECK(inVarInfo.arraySize == numValues && outVarInfo.arraySize == numValues &&
215*35238bceSAndroid Build Coastguard Worker               groupVarInfo.arraySize == product(m_numWorkGroups));
216*35238bceSAndroid Build Coastguard Worker 
217*35238bceSAndroid Build Coastguard Worker     gl.useProgram(program);
218*35238bceSAndroid Build Coastguard Worker 
219*35238bceSAndroid Build Coastguard Worker     // Setup buffer.
220*35238bceSAndroid Build Coastguard Worker     {
221*35238bceSAndroid Build Coastguard Worker         vector<uint8_t> bufData(blockInfo.dataSize);
222*35238bceSAndroid Build Coastguard Worker         std::fill(bufData.begin(), bufData.end(), 0);
223*35238bceSAndroid Build Coastguard Worker 
224*35238bceSAndroid Build Coastguard Worker         getInputs((int)numValues, (int)inVarInfo.arrayStride, &bufData[0] + inVarInfo.offset);
225*35238bceSAndroid Build Coastguard Worker 
226*35238bceSAndroid Build Coastguard Worker         if (m_operandType == ATOMIC_OPERAND_BUFFER_VARIABLE)
227*35238bceSAndroid Build Coastguard Worker         {
228*35238bceSAndroid Build Coastguard Worker             for (uint32_t valNdx = 0; valNdx < product(m_numWorkGroups); valNdx++)
229*35238bceSAndroid Build Coastguard Worker                 *(uint32_t *)(&bufData[0] + groupVarInfo.offset + groupVarInfo.arrayStride * valNdx) = m_initialValue;
230*35238bceSAndroid Build Coastguard Worker         }
231*35238bceSAndroid Build Coastguard Worker 
232*35238bceSAndroid Build Coastguard Worker         gl.bindBuffer(GL_SHADER_STORAGE_BUFFER, *inoutBuffer);
233*35238bceSAndroid Build Coastguard Worker         gl.bufferData(GL_SHADER_STORAGE_BUFFER, blockInfo.dataSize, &bufData[0], GL_STATIC_READ);
234*35238bceSAndroid Build Coastguard Worker         gl.bindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, *inoutBuffer);
235*35238bceSAndroid Build Coastguard Worker         GLU_EXPECT_NO_ERROR(gl.getError(), "Output buffer setup failed");
236*35238bceSAndroid Build Coastguard Worker     }
237*35238bceSAndroid Build Coastguard Worker 
238*35238bceSAndroid Build Coastguard Worker     gl.dispatchCompute(m_numWorkGroups.x(), m_numWorkGroups.y(), m_numWorkGroups.z());
239*35238bceSAndroid Build Coastguard Worker 
240*35238bceSAndroid Build Coastguard Worker     // Read back and compare
241*35238bceSAndroid Build Coastguard Worker     {
242*35238bceSAndroid Build Coastguard Worker         const void *resPtr = gl.mapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, blockInfo.dataSize, GL_MAP_READ_BIT);
243*35238bceSAndroid Build Coastguard Worker         bool isOk          = true;
244*35238bceSAndroid Build Coastguard Worker 
245*35238bceSAndroid Build Coastguard Worker         GLU_EXPECT_NO_ERROR(gl.getError(), "glMapBufferRange()");
246*35238bceSAndroid Build Coastguard Worker         TCU_CHECK(resPtr);
247*35238bceSAndroid Build Coastguard Worker 
248*35238bceSAndroid Build Coastguard Worker         isOk = verify((int)numValues, (int)inVarInfo.arrayStride, (const uint8_t *)resPtr + inVarInfo.offset,
249*35238bceSAndroid Build Coastguard Worker                       (int)outVarInfo.arrayStride, (const uint8_t *)resPtr + outVarInfo.offset,
250*35238bceSAndroid Build Coastguard Worker                       (int)groupVarInfo.arrayStride, (const uint8_t *)resPtr + groupVarInfo.offset);
251*35238bceSAndroid Build Coastguard Worker 
252*35238bceSAndroid Build Coastguard Worker         gl.unmapBuffer(GL_SHADER_STORAGE_BUFFER);
253*35238bceSAndroid Build Coastguard Worker         GLU_EXPECT_NO_ERROR(gl.getError(), "glUnmapBuffer()");
254*35238bceSAndroid Build Coastguard Worker 
255*35238bceSAndroid Build Coastguard Worker         m_testCtx.setTestResult(isOk ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL, isOk ? "Pass" : "Comparison failed");
256*35238bceSAndroid Build Coastguard Worker     }
257*35238bceSAndroid Build Coastguard Worker 
258*35238bceSAndroid Build Coastguard Worker     return STOP;
259*35238bceSAndroid Build Coastguard Worker }
260*35238bceSAndroid Build Coastguard Worker 
261*35238bceSAndroid Build Coastguard Worker class ShaderAtomicAddCase : public ShaderAtomicOpCase
262*35238bceSAndroid Build Coastguard Worker {
263*35238bceSAndroid Build Coastguard Worker public:
ShaderAtomicAddCase(Context & context,const char * name,AtomicOperandType operandType,DataType type,Precision precision)264*35238bceSAndroid Build Coastguard Worker     ShaderAtomicAddCase(Context &context, const char *name, AtomicOperandType operandType, DataType type,
265*35238bceSAndroid Build Coastguard Worker                         Precision precision)
266*35238bceSAndroid Build Coastguard Worker         : ShaderAtomicOpCase(context, name, "atomicAdd", operandType, type, precision, UVec3(3, 2, 1))
267*35238bceSAndroid Build Coastguard Worker     {
268*35238bceSAndroid Build Coastguard Worker         m_initialValue = 1;
269*35238bceSAndroid Build Coastguard Worker     }
270*35238bceSAndroid Build Coastguard Worker 
271*35238bceSAndroid Build Coastguard Worker protected:
getInputs(int numValues,int stride,void * inputs) const272*35238bceSAndroid Build Coastguard Worker     void getInputs(int numValues, int stride, void *inputs) const
273*35238bceSAndroid Build Coastguard Worker     {
274*35238bceSAndroid Build Coastguard Worker         de::Random rnd(deStringHash(getName()));
275*35238bceSAndroid Build Coastguard Worker         const int maxVal = m_precision == PRECISION_LOWP ? 2 : 32;
276*35238bceSAndroid Build Coastguard Worker         const int minVal = 1;
277*35238bceSAndroid Build Coastguard Worker 
278*35238bceSAndroid Build Coastguard Worker         // \todo [2013-09-04 pyry] Negative values!
279*35238bceSAndroid Build Coastguard Worker 
280*35238bceSAndroid Build Coastguard Worker         for (int valNdx = 0; valNdx < numValues; valNdx++)
281*35238bceSAndroid Build Coastguard Worker             *(int *)((uint8_t *)inputs + stride * valNdx) = rnd.getInt(minVal, maxVal);
282*35238bceSAndroid Build Coastguard Worker     }
283*35238bceSAndroid Build Coastguard Worker 
verify(int numValues,int inputStride,const void * inputs,int outputStride,const void * outputs,int groupStride,const void * groupOutputs) const284*35238bceSAndroid Build Coastguard Worker     bool verify(int numValues, int inputStride, const void *inputs, int outputStride, const void *outputs,
285*35238bceSAndroid Build Coastguard Worker                 int groupStride, const void *groupOutputs) const
286*35238bceSAndroid Build Coastguard Worker     {
287*35238bceSAndroid Build Coastguard Worker         const int workGroupSize = (int)product(m_workGroupSize);
288*35238bceSAndroid Build Coastguard Worker         const int numWorkGroups = numValues / workGroupSize;
289*35238bceSAndroid Build Coastguard Worker 
290*35238bceSAndroid Build Coastguard Worker         for (int groupNdx = 0; groupNdx < numWorkGroups; groupNdx++)
291*35238bceSAndroid Build Coastguard Worker         {
292*35238bceSAndroid Build Coastguard Worker             const int groupOffset = groupNdx * workGroupSize;
293*35238bceSAndroid Build Coastguard Worker             const int groupOutput = *(const int32_t *)((const uint8_t *)groupOutputs + groupNdx * groupStride);
294*35238bceSAndroid Build Coastguard Worker             set<int> outValues;
295*35238bceSAndroid Build Coastguard Worker             bool maxFound = false;
296*35238bceSAndroid Build Coastguard Worker             int valueSum  = (int)m_initialValue;
297*35238bceSAndroid Build Coastguard Worker 
298*35238bceSAndroid Build Coastguard Worker             for (int localNdx = 0; localNdx < workGroupSize; localNdx++)
299*35238bceSAndroid Build Coastguard Worker             {
300*35238bceSAndroid Build Coastguard Worker                 const int inputValue =
301*35238bceSAndroid Build Coastguard Worker                     *(const int32_t *)((const uint8_t *)inputs + inputStride * (groupOffset + localNdx));
302*35238bceSAndroid Build Coastguard Worker                 valueSum += inputValue;
303*35238bceSAndroid Build Coastguard Worker             }
304*35238bceSAndroid Build Coastguard Worker 
305*35238bceSAndroid Build Coastguard Worker             if (groupOutput != valueSum)
306*35238bceSAndroid Build Coastguard Worker             {
307*35238bceSAndroid Build Coastguard Worker                 m_testCtx.getLog() << TestLog::Message << "ERROR: at group " << groupNdx << ": expected sum "
308*35238bceSAndroid Build Coastguard Worker                                    << valueSum << ", got " << groupOutput << TestLog::EndMessage;
309*35238bceSAndroid Build Coastguard Worker                 return false;
310*35238bceSAndroid Build Coastguard Worker             }
311*35238bceSAndroid Build Coastguard Worker 
312*35238bceSAndroid Build Coastguard Worker             for (int localNdx = 0; localNdx < workGroupSize; localNdx++)
313*35238bceSAndroid Build Coastguard Worker             {
314*35238bceSAndroid Build Coastguard Worker                 const int inputValue =
315*35238bceSAndroid Build Coastguard Worker                     *(const int32_t *)((const uint8_t *)inputs + inputStride * (groupOffset + localNdx));
316*35238bceSAndroid Build Coastguard Worker                 const int outputValue =
317*35238bceSAndroid Build Coastguard Worker                     *(const int32_t *)((const uint8_t *)outputs + outputStride * (groupOffset + localNdx));
318*35238bceSAndroid Build Coastguard Worker 
319*35238bceSAndroid Build Coastguard Worker                 if (!de::inRange(outputValue, (int)m_initialValue, valueSum - inputValue))
320*35238bceSAndroid Build Coastguard Worker                 {
321*35238bceSAndroid Build Coastguard Worker                     m_testCtx.getLog() << TestLog::Message << "ERROR: at group " << groupNdx << ", invocation "
322*35238bceSAndroid Build Coastguard Worker                                        << localNdx << ": expected value in range [" << m_initialValue << ", "
323*35238bceSAndroid Build Coastguard Worker                                        << (valueSum - inputValue) << "], got " << outputValue << TestLog::EndMessage;
324*35238bceSAndroid Build Coastguard Worker                     return false;
325*35238bceSAndroid Build Coastguard Worker                 }
326*35238bceSAndroid Build Coastguard Worker 
327*35238bceSAndroid Build Coastguard Worker                 if (outValues.find(outputValue) != outValues.end())
328*35238bceSAndroid Build Coastguard Worker                 {
329*35238bceSAndroid Build Coastguard Worker                     m_testCtx.getLog() << TestLog::Message << "ERROR: at group " << groupNdx << ", invocation "
330*35238bceSAndroid Build Coastguard Worker                                        << localNdx << ": found duplicate value " << outputValue << TestLog::EndMessage;
331*35238bceSAndroid Build Coastguard Worker                     return false;
332*35238bceSAndroid Build Coastguard Worker                 }
333*35238bceSAndroid Build Coastguard Worker 
334*35238bceSAndroid Build Coastguard Worker                 outValues.insert(outputValue);
335*35238bceSAndroid Build Coastguard Worker                 if (outputValue == valueSum - inputValue)
336*35238bceSAndroid Build Coastguard Worker                     maxFound = true;
337*35238bceSAndroid Build Coastguard Worker             }
338*35238bceSAndroid Build Coastguard Worker 
339*35238bceSAndroid Build Coastguard Worker             if (!maxFound)
340*35238bceSAndroid Build Coastguard Worker             {
341*35238bceSAndroid Build Coastguard Worker                 m_testCtx.getLog() << TestLog::Message << "ERROR: could not find maximum expected value from group "
342*35238bceSAndroid Build Coastguard Worker                                    << groupNdx << TestLog::EndMessage;
343*35238bceSAndroid Build Coastguard Worker                 return false;
344*35238bceSAndroid Build Coastguard Worker             }
345*35238bceSAndroid Build Coastguard Worker 
346*35238bceSAndroid Build Coastguard Worker             if (outValues.find((int)m_initialValue) == outValues.end())
347*35238bceSAndroid Build Coastguard Worker             {
348*35238bceSAndroid Build Coastguard Worker                 m_testCtx.getLog() << TestLog::Message << "ERROR: could not find initial value from group " << groupNdx
349*35238bceSAndroid Build Coastguard Worker                                    << TestLog::EndMessage;
350*35238bceSAndroid Build Coastguard Worker                 return false;
351*35238bceSAndroid Build Coastguard Worker             }
352*35238bceSAndroid Build Coastguard Worker         }
353*35238bceSAndroid Build Coastguard Worker 
354*35238bceSAndroid Build Coastguard Worker         return true;
355*35238bceSAndroid Build Coastguard Worker     }
356*35238bceSAndroid Build Coastguard Worker };
357*35238bceSAndroid Build Coastguard Worker 
getPrecisionNumIntegerBits(glu::Precision precision)358*35238bceSAndroid Build Coastguard Worker static int getPrecisionNumIntegerBits(glu::Precision precision)
359*35238bceSAndroid Build Coastguard Worker {
360*35238bceSAndroid Build Coastguard Worker     switch (precision)
361*35238bceSAndroid Build Coastguard Worker     {
362*35238bceSAndroid Build Coastguard Worker     case glu::PRECISION_HIGHP:
363*35238bceSAndroid Build Coastguard Worker         return 32;
364*35238bceSAndroid Build Coastguard Worker     case glu::PRECISION_MEDIUMP:
365*35238bceSAndroid Build Coastguard Worker         return 16;
366*35238bceSAndroid Build Coastguard Worker     case glu::PRECISION_LOWP:
367*35238bceSAndroid Build Coastguard Worker         return 9;
368*35238bceSAndroid Build Coastguard Worker     default:
369*35238bceSAndroid Build Coastguard Worker         DE_ASSERT(false);
370*35238bceSAndroid Build Coastguard Worker         return 0;
371*35238bceSAndroid Build Coastguard Worker     }
372*35238bceSAndroid Build Coastguard Worker }
373*35238bceSAndroid Build Coastguard Worker 
getPrecisionMask(int numPreciseBits)374*35238bceSAndroid Build Coastguard Worker static uint32_t getPrecisionMask(int numPreciseBits)
375*35238bceSAndroid Build Coastguard Worker {
376*35238bceSAndroid Build Coastguard Worker     // \note: bit shift with larger or equal than var length is undefined, use 64 bit ints
377*35238bceSAndroid Build Coastguard Worker     return (uint32_t)((((uint64_t)1u) << numPreciseBits) - 1);
378*35238bceSAndroid Build Coastguard Worker }
379*35238bceSAndroid Build Coastguard Worker 
intEqualsAfterUintCast(int32_t value,uint32_t casted,glu::Precision precision)380*35238bceSAndroid Build Coastguard Worker static bool intEqualsAfterUintCast(int32_t value, uint32_t casted, glu::Precision precision)
381*35238bceSAndroid Build Coastguard Worker {
382*35238bceSAndroid Build Coastguard Worker     // Bit format of 'casted' = [ uint -> highp uint promotion bits (0) ] [ sign extend bits (s) ] [ value bits ]
383*35238bceSAndroid Build Coastguard Worker     //                                                                                             |--min len---|
384*35238bceSAndroid Build Coastguard Worker     //                                                                    |---------------signed length---------|
385*35238bceSAndroid Build Coastguard Worker     //                          |-------------------------------- highp uint length ----------------------------|
386*35238bceSAndroid Build Coastguard Worker 
387*35238bceSAndroid Build Coastguard Worker     const uint32_t reference   = (uint32_t)value;
388*35238bceSAndroid Build Coastguard Worker     const int signBitOn        = value < 0;
389*35238bceSAndroid Build Coastguard Worker     const int numPreciseBits   = getPrecisionNumIntegerBits(precision);
390*35238bceSAndroid Build Coastguard Worker     const uint32_t preciseMask = getPrecisionMask(numPreciseBits);
391*35238bceSAndroid Build Coastguard Worker 
392*35238bceSAndroid Build Coastguard Worker     // Lowest N bits must match, N = minimum precision
393*35238bceSAndroid Build Coastguard Worker     if ((reference & preciseMask) != (casted & preciseMask))
394*35238bceSAndroid Build Coastguard Worker         return false;
395*35238bceSAndroid Build Coastguard Worker 
396*35238bceSAndroid Build Coastguard Worker     // Other lowest bits must match the sign and the remaining (topmost) if any must be 0
397*35238bceSAndroid Build Coastguard Worker     for (int signedIntegerLength = numPreciseBits; signedIntegerLength <= 32; ++signedIntegerLength)
398*35238bceSAndroid Build Coastguard Worker     {
399*35238bceSAndroid Build Coastguard Worker         const uint32_t signBits = (signBitOn) ? (getPrecisionMask(signedIntegerLength)) : (0u);
400*35238bceSAndroid Build Coastguard Worker 
401*35238bceSAndroid Build Coastguard Worker         if ((signBits & ~preciseMask) == (casted & ~preciseMask))
402*35238bceSAndroid Build Coastguard Worker             return true;
403*35238bceSAndroid Build Coastguard Worker     }
404*35238bceSAndroid Build Coastguard Worker     return false;
405*35238bceSAndroid Build Coastguard Worker }
406*35238bceSAndroid Build Coastguard Worker 
containsAfterUintCast(const std::set<int32_t> & haystack,uint32_t needle,glu::Precision precision)407*35238bceSAndroid Build Coastguard Worker static bool containsAfterUintCast(const std::set<int32_t> &haystack, uint32_t needle, glu::Precision precision)
408*35238bceSAndroid Build Coastguard Worker {
409*35238bceSAndroid Build Coastguard Worker     for (std::set<int32_t>::const_iterator it = haystack.begin(); it != haystack.end(); ++it)
410*35238bceSAndroid Build Coastguard Worker         if (intEqualsAfterUintCast(*it, needle, precision))
411*35238bceSAndroid Build Coastguard Worker             return true;
412*35238bceSAndroid Build Coastguard Worker     return false;
413*35238bceSAndroid Build Coastguard Worker }
414*35238bceSAndroid Build Coastguard Worker 
containsAfterUintCast(const std::set<uint32_t> & haystack,int32_t needle,glu::Precision precision)415*35238bceSAndroid Build Coastguard Worker static bool containsAfterUintCast(const std::set<uint32_t> &haystack, int32_t needle, glu::Precision precision)
416*35238bceSAndroid Build Coastguard Worker {
417*35238bceSAndroid Build Coastguard Worker     for (std::set<uint32_t>::const_iterator it = haystack.begin(); it != haystack.end(); ++it)
418*35238bceSAndroid Build Coastguard Worker         if (intEqualsAfterUintCast(needle, *it, precision))
419*35238bceSAndroid Build Coastguard Worker             return true;
420*35238bceSAndroid Build Coastguard Worker     return false;
421*35238bceSAndroid Build Coastguard Worker }
422*35238bceSAndroid Build Coastguard Worker 
423*35238bceSAndroid Build Coastguard Worker class ShaderAtomicMinCase : public ShaderAtomicOpCase
424*35238bceSAndroid Build Coastguard Worker {
425*35238bceSAndroid Build Coastguard Worker public:
ShaderAtomicMinCase(Context & context,const char * name,AtomicOperandType operandType,DataType type,Precision precision)426*35238bceSAndroid Build Coastguard Worker     ShaderAtomicMinCase(Context &context, const char *name, AtomicOperandType operandType, DataType type,
427*35238bceSAndroid Build Coastguard Worker                         Precision precision)
428*35238bceSAndroid Build Coastguard Worker         : ShaderAtomicOpCase(context, name, "atomicMin", operandType, type, precision, UVec3(3, 2, 1))
429*35238bceSAndroid Build Coastguard Worker     {
430*35238bceSAndroid Build Coastguard Worker         m_initialValue = m_precision == PRECISION_LOWP ? 100 : 1000;
431*35238bceSAndroid Build Coastguard Worker     }
432*35238bceSAndroid Build Coastguard Worker 
433*35238bceSAndroid Build Coastguard Worker protected:
getInputs(int numValues,int stride,void * inputs) const434*35238bceSAndroid Build Coastguard Worker     void getInputs(int numValues, int stride, void *inputs) const
435*35238bceSAndroid Build Coastguard Worker     {
436*35238bceSAndroid Build Coastguard Worker         de::Random rnd(deStringHash(getName()));
437*35238bceSAndroid Build Coastguard Worker         const bool isSigned = m_type == TYPE_INT;
438*35238bceSAndroid Build Coastguard Worker         const int maxVal    = m_precision == PRECISION_LOWP ? 100 : 1000;
439*35238bceSAndroid Build Coastguard Worker         const int minVal    = isSigned ? -maxVal : 0;
440*35238bceSAndroid Build Coastguard Worker 
441*35238bceSAndroid Build Coastguard Worker         for (int valNdx = 0; valNdx < numValues; valNdx++)
442*35238bceSAndroid Build Coastguard Worker             *(int *)((uint8_t *)inputs + stride * valNdx) = rnd.getInt(minVal, maxVal);
443*35238bceSAndroid Build Coastguard Worker     }
444*35238bceSAndroid Build Coastguard Worker 
verify(int numValues,int inputStride,const void * inputs,int outputStride,const void * outputs,int groupStride,const void * groupOutputs) const445*35238bceSAndroid Build Coastguard Worker     bool verify(int numValues, int inputStride, const void *inputs, int outputStride, const void *outputs,
446*35238bceSAndroid Build Coastguard Worker                 int groupStride, const void *groupOutputs) const
447*35238bceSAndroid Build Coastguard Worker     {
448*35238bceSAndroid Build Coastguard Worker         const int workGroupSize = (int)product(m_workGroupSize);
449*35238bceSAndroid Build Coastguard Worker         const int numWorkGroups = numValues / workGroupSize;
450*35238bceSAndroid Build Coastguard Worker         bool anyError           = false;
451*35238bceSAndroid Build Coastguard Worker 
452*35238bceSAndroid Build Coastguard Worker         for (int groupNdx = 0; groupNdx < numWorkGroups; groupNdx++)
453*35238bceSAndroid Build Coastguard Worker         {
454*35238bceSAndroid Build Coastguard Worker             const int groupOffset      = groupNdx * workGroupSize;
455*35238bceSAndroid Build Coastguard Worker             const uint32_t groupOutput = *(const uint32_t *)((const uint8_t *)groupOutputs + groupNdx * groupStride);
456*35238bceSAndroid Build Coastguard Worker             set<int32_t> inValues;
457*35238bceSAndroid Build Coastguard Worker             set<uint32_t> outValues;
458*35238bceSAndroid Build Coastguard Worker             int minValue = (int)m_initialValue;
459*35238bceSAndroid Build Coastguard Worker 
460*35238bceSAndroid Build Coastguard Worker             for (int localNdx = 0; localNdx < workGroupSize; localNdx++)
461*35238bceSAndroid Build Coastguard Worker             {
462*35238bceSAndroid Build Coastguard Worker                 const int32_t inputValue =
463*35238bceSAndroid Build Coastguard Worker                     *(const int32_t *)((const uint8_t *)inputs + inputStride * (groupOffset + localNdx));
464*35238bceSAndroid Build Coastguard Worker                 inValues.insert(inputValue);
465*35238bceSAndroid Build Coastguard Worker                 minValue = de::min(inputValue, minValue);
466*35238bceSAndroid Build Coastguard Worker             }
467*35238bceSAndroid Build Coastguard Worker 
468*35238bceSAndroid Build Coastguard Worker             if (!intEqualsAfterUintCast(minValue, groupOutput, m_precision))
469*35238bceSAndroid Build Coastguard Worker             {
470*35238bceSAndroid Build Coastguard Worker                 m_testCtx.getLog() << TestLog::Message << "ERROR: at group " << groupNdx << ": expected minimum "
471*35238bceSAndroid Build Coastguard Worker                                    << minValue << " (" << tcu::Format::Hex<8>((uint32_t)minValue) << ")"
472*35238bceSAndroid Build Coastguard Worker                                    << ", got " << groupOutput << " (" << tcu::Format::Hex<8>(groupOutput) << ")"
473*35238bceSAndroid Build Coastguard Worker                                    << TestLog::EndMessage;
474*35238bceSAndroid Build Coastguard Worker                 anyError = true;
475*35238bceSAndroid Build Coastguard Worker             }
476*35238bceSAndroid Build Coastguard Worker 
477*35238bceSAndroid Build Coastguard Worker             for (int localNdx = 0; localNdx < workGroupSize; localNdx++)
478*35238bceSAndroid Build Coastguard Worker             {
479*35238bceSAndroid Build Coastguard Worker                 const uint32_t outputValue =
480*35238bceSAndroid Build Coastguard Worker                     *(const uint32_t *)((const uint8_t *)outputs + outputStride * (groupOffset + localNdx));
481*35238bceSAndroid Build Coastguard Worker 
482*35238bceSAndroid Build Coastguard Worker                 if (!containsAfterUintCast(inValues, outputValue, m_precision) &&
483*35238bceSAndroid Build Coastguard Worker                     !intEqualsAfterUintCast((int32_t)m_initialValue, outputValue, m_precision))
484*35238bceSAndroid Build Coastguard Worker                 {
485*35238bceSAndroid Build Coastguard Worker                     m_testCtx.getLog() << TestLog::Message << "ERROR: at group " << groupNdx << ", invocation "
486*35238bceSAndroid Build Coastguard Worker                                        << localNdx << ": found unexpected value " << outputValue << " ("
487*35238bceSAndroid Build Coastguard Worker                                        << tcu::Format::Hex<8>(outputValue) << ")" << TestLog::EndMessage;
488*35238bceSAndroid Build Coastguard Worker                     anyError = true;
489*35238bceSAndroid Build Coastguard Worker                 }
490*35238bceSAndroid Build Coastguard Worker 
491*35238bceSAndroid Build Coastguard Worker                 outValues.insert(outputValue);
492*35238bceSAndroid Build Coastguard Worker             }
493*35238bceSAndroid Build Coastguard Worker 
494*35238bceSAndroid Build Coastguard Worker             if (!containsAfterUintCast(outValues, (int)m_initialValue, m_precision))
495*35238bceSAndroid Build Coastguard Worker             {
496*35238bceSAndroid Build Coastguard Worker                 m_testCtx.getLog() << TestLog::Message << "ERROR: could not find initial value from group " << groupNdx
497*35238bceSAndroid Build Coastguard Worker                                    << TestLog::EndMessage;
498*35238bceSAndroid Build Coastguard Worker                 anyError = true;
499*35238bceSAndroid Build Coastguard Worker             }
500*35238bceSAndroid Build Coastguard Worker         }
501*35238bceSAndroid Build Coastguard Worker 
502*35238bceSAndroid Build Coastguard Worker         return !anyError;
503*35238bceSAndroid Build Coastguard Worker     }
504*35238bceSAndroid Build Coastguard Worker };
505*35238bceSAndroid Build Coastguard Worker 
506*35238bceSAndroid Build Coastguard Worker class ShaderAtomicMaxCase : public ShaderAtomicOpCase
507*35238bceSAndroid Build Coastguard Worker {
508*35238bceSAndroid Build Coastguard Worker public:
ShaderAtomicMaxCase(Context & context,const char * name,AtomicOperandType operandType,DataType type,Precision precision)509*35238bceSAndroid Build Coastguard Worker     ShaderAtomicMaxCase(Context &context, const char *name, AtomicOperandType operandType, DataType type,
510*35238bceSAndroid Build Coastguard Worker                         Precision precision)
511*35238bceSAndroid Build Coastguard Worker         : ShaderAtomicOpCase(context, name, "atomicMax", operandType, type, precision, UVec3(3, 2, 1))
512*35238bceSAndroid Build Coastguard Worker     {
513*35238bceSAndroid Build Coastguard Worker         const bool isSigned = m_type == TYPE_INT;
514*35238bceSAndroid Build Coastguard Worker         m_initialValue      = isSigned ? (m_precision == PRECISION_LOWP ? -100 : -1000) : 0;
515*35238bceSAndroid Build Coastguard Worker     }
516*35238bceSAndroid Build Coastguard Worker 
517*35238bceSAndroid Build Coastguard Worker protected:
getInputs(int numValues,int stride,void * inputs) const518*35238bceSAndroid Build Coastguard Worker     void getInputs(int numValues, int stride, void *inputs) const
519*35238bceSAndroid Build Coastguard Worker     {
520*35238bceSAndroid Build Coastguard Worker         de::Random rnd(deStringHash(getName()));
521*35238bceSAndroid Build Coastguard Worker         const bool isSigned = m_type == TYPE_INT;
522*35238bceSAndroid Build Coastguard Worker         const int maxVal    = m_precision == PRECISION_LOWP ? 100 : 1000;
523*35238bceSAndroid Build Coastguard Worker         const int minVal    = isSigned ? -maxVal : 0;
524*35238bceSAndroid Build Coastguard Worker 
525*35238bceSAndroid Build Coastguard Worker         for (int valNdx = 0; valNdx < numValues; valNdx++)
526*35238bceSAndroid Build Coastguard Worker             *(int *)((uint8_t *)inputs + stride * valNdx) = rnd.getInt(minVal, maxVal);
527*35238bceSAndroid Build Coastguard Worker     }
528*35238bceSAndroid Build Coastguard Worker 
verify(int numValues,int inputStride,const void * inputs,int outputStride,const void * outputs,int groupStride,const void * groupOutputs) const529*35238bceSAndroid Build Coastguard Worker     bool verify(int numValues, int inputStride, const void *inputs, int outputStride, const void *outputs,
530*35238bceSAndroid Build Coastguard Worker                 int groupStride, const void *groupOutputs) const
531*35238bceSAndroid Build Coastguard Worker     {
532*35238bceSAndroid Build Coastguard Worker         const int workGroupSize = (int)product(m_workGroupSize);
533*35238bceSAndroid Build Coastguard Worker         const int numWorkGroups = numValues / workGroupSize;
534*35238bceSAndroid Build Coastguard Worker         bool anyError           = false;
535*35238bceSAndroid Build Coastguard Worker 
536*35238bceSAndroid Build Coastguard Worker         for (int groupNdx = 0; groupNdx < numWorkGroups; groupNdx++)
537*35238bceSAndroid Build Coastguard Worker         {
538*35238bceSAndroid Build Coastguard Worker             const int groupOffset      = groupNdx * workGroupSize;
539*35238bceSAndroid Build Coastguard Worker             const uint32_t groupOutput = *(const uint32_t *)((const uint8_t *)groupOutputs + groupNdx * groupStride);
540*35238bceSAndroid Build Coastguard Worker             set<int> inValues;
541*35238bceSAndroid Build Coastguard Worker             set<uint32_t> outValues;
542*35238bceSAndroid Build Coastguard Worker             int maxValue = (int)m_initialValue;
543*35238bceSAndroid Build Coastguard Worker 
544*35238bceSAndroid Build Coastguard Worker             for (int localNdx = 0; localNdx < workGroupSize; localNdx++)
545*35238bceSAndroid Build Coastguard Worker             {
546*35238bceSAndroid Build Coastguard Worker                 const int32_t inputValue =
547*35238bceSAndroid Build Coastguard Worker                     *(const int32_t *)((const uint8_t *)inputs + inputStride * (groupOffset + localNdx));
548*35238bceSAndroid Build Coastguard Worker                 inValues.insert(inputValue);
549*35238bceSAndroid Build Coastguard Worker                 maxValue = de::max(maxValue, inputValue);
550*35238bceSAndroid Build Coastguard Worker             }
551*35238bceSAndroid Build Coastguard Worker 
552*35238bceSAndroid Build Coastguard Worker             if (!intEqualsAfterUintCast(maxValue, groupOutput, m_precision))
553*35238bceSAndroid Build Coastguard Worker             {
554*35238bceSAndroid Build Coastguard Worker                 m_testCtx.getLog() << TestLog::Message << "ERROR: at group " << groupNdx << ": expected maximum "
555*35238bceSAndroid Build Coastguard Worker                                    << maxValue << " (" << tcu::Format::Hex<8>((uint32_t)maxValue) << ")"
556*35238bceSAndroid Build Coastguard Worker                                    << ", got " << groupOutput << " (" << tcu::Format::Hex<8>(groupOutput) << ")"
557*35238bceSAndroid Build Coastguard Worker                                    << TestLog::EndMessage;
558*35238bceSAndroid Build Coastguard Worker                 anyError = true;
559*35238bceSAndroid Build Coastguard Worker             }
560*35238bceSAndroid Build Coastguard Worker 
561*35238bceSAndroid Build Coastguard Worker             for (int localNdx = 0; localNdx < workGroupSize; localNdx++)
562*35238bceSAndroid Build Coastguard Worker             {
563*35238bceSAndroid Build Coastguard Worker                 const uint32_t outputValue =
564*35238bceSAndroid Build Coastguard Worker                     *(const uint32_t *)((const uint8_t *)outputs + outputStride * (groupOffset + localNdx));
565*35238bceSAndroid Build Coastguard Worker 
566*35238bceSAndroid Build Coastguard Worker                 if (!containsAfterUintCast(inValues, outputValue, m_precision) &&
567*35238bceSAndroid Build Coastguard Worker                     !intEqualsAfterUintCast((int32_t)m_initialValue, outputValue, m_precision))
568*35238bceSAndroid Build Coastguard Worker                 {
569*35238bceSAndroid Build Coastguard Worker                     m_testCtx.getLog() << TestLog::Message << "ERROR: at group " << groupNdx << ", invocation "
570*35238bceSAndroid Build Coastguard Worker                                        << localNdx << ": found unexpected value " << outputValue << " ("
571*35238bceSAndroid Build Coastguard Worker                                        << tcu::Format::Hex<8>(outputValue) << ")" << TestLog::EndMessage;
572*35238bceSAndroid Build Coastguard Worker                     anyError = true;
573*35238bceSAndroid Build Coastguard Worker                 }
574*35238bceSAndroid Build Coastguard Worker 
575*35238bceSAndroid Build Coastguard Worker                 outValues.insert(outputValue);
576*35238bceSAndroid Build Coastguard Worker             }
577*35238bceSAndroid Build Coastguard Worker 
578*35238bceSAndroid Build Coastguard Worker             if (!containsAfterUintCast(outValues, (int)m_initialValue, m_precision))
579*35238bceSAndroid Build Coastguard Worker             {
580*35238bceSAndroid Build Coastguard Worker                 m_testCtx.getLog() << TestLog::Message << "ERROR: could not find initial value from group " << groupNdx
581*35238bceSAndroid Build Coastguard Worker                                    << TestLog::EndMessage;
582*35238bceSAndroid Build Coastguard Worker                 anyError = true;
583*35238bceSAndroid Build Coastguard Worker             }
584*35238bceSAndroid Build Coastguard Worker         }
585*35238bceSAndroid Build Coastguard Worker 
586*35238bceSAndroid Build Coastguard Worker         return !anyError;
587*35238bceSAndroid Build Coastguard Worker     }
588*35238bceSAndroid Build Coastguard Worker };
589*35238bceSAndroid Build Coastguard Worker 
590*35238bceSAndroid Build Coastguard Worker class ShaderAtomicAndCase : public ShaderAtomicOpCase
591*35238bceSAndroid Build Coastguard Worker {
592*35238bceSAndroid Build Coastguard Worker public:
ShaderAtomicAndCase(Context & context,const char * name,AtomicOperandType operandType,DataType type,Precision precision)593*35238bceSAndroid Build Coastguard Worker     ShaderAtomicAndCase(Context &context, const char *name, AtomicOperandType operandType, DataType type,
594*35238bceSAndroid Build Coastguard Worker                         Precision precision)
595*35238bceSAndroid Build Coastguard Worker         : ShaderAtomicOpCase(context, name, "atomicAnd", operandType, type, precision, UVec3(3, 2, 1))
596*35238bceSAndroid Build Coastguard Worker     {
597*35238bceSAndroid Build Coastguard Worker         const int numBits        = m_precision == PRECISION_HIGHP ? 32 : m_precision == PRECISION_MEDIUMP ? 16 : 8;
598*35238bceSAndroid Build Coastguard Worker         const uint32_t valueMask = numBits == 32 ? ~0u : (1u << numBits) - 1u;
599*35238bceSAndroid Build Coastguard Worker         m_initialValue = ~((1u << (numBits - 1u)) | 1u) & valueMask; // All bits except lowest and highest set.
600*35238bceSAndroid Build Coastguard Worker     }
601*35238bceSAndroid Build Coastguard Worker 
602*35238bceSAndroid Build Coastguard Worker protected:
getInputs(int numValues,int stride,void * inputs) const603*35238bceSAndroid Build Coastguard Worker     void getInputs(int numValues, int stride, void *inputs) const
604*35238bceSAndroid Build Coastguard Worker     {
605*35238bceSAndroid Build Coastguard Worker         de::Random rnd(deStringHash(getName()));
606*35238bceSAndroid Build Coastguard Worker         const int workGroupSize  = (int)product(m_workGroupSize);
607*35238bceSAndroid Build Coastguard Worker         const int numWorkGroups  = numValues / workGroupSize;
608*35238bceSAndroid Build Coastguard Worker         const int numBits        = m_precision == PRECISION_HIGHP ? 32 : m_precision == PRECISION_MEDIUMP ? 16 : 8;
609*35238bceSAndroid Build Coastguard Worker         const uint32_t valueMask = numBits == 32 ? ~0u : (1u << numBits) - 1u;
610*35238bceSAndroid Build Coastguard Worker 
611*35238bceSAndroid Build Coastguard Worker         for (int groupNdx = 0; groupNdx < numWorkGroups; groupNdx++)
612*35238bceSAndroid Build Coastguard Worker         {
613*35238bceSAndroid Build Coastguard Worker             const int groupOffset    = groupNdx * workGroupSize;
614*35238bceSAndroid Build Coastguard Worker             const uint32_t groupMask = 1 << rnd.getInt(0, numBits - 2); // One bit is always set.
615*35238bceSAndroid Build Coastguard Worker 
616*35238bceSAndroid Build Coastguard Worker             for (int localNdx = 0; localNdx < workGroupSize; localNdx++)
617*35238bceSAndroid Build Coastguard Worker                 *(uint32_t *)((uint8_t *)inputs + stride * (groupOffset + localNdx)) =
618*35238bceSAndroid Build Coastguard Worker                     (rnd.getUint32() & valueMask) | groupMask;
619*35238bceSAndroid Build Coastguard Worker         }
620*35238bceSAndroid Build Coastguard Worker     }
621*35238bceSAndroid Build Coastguard Worker 
verify(int numValues,int inputStride,const void * inputs,int outputStride,const void * outputs,int groupStride,const void * groupOutputs) const622*35238bceSAndroid Build Coastguard Worker     bool verify(int numValues, int inputStride, const void *inputs, int outputStride, const void *outputs,
623*35238bceSAndroid Build Coastguard Worker                 int groupStride, const void *groupOutputs) const
624*35238bceSAndroid Build Coastguard Worker     {
625*35238bceSAndroid Build Coastguard Worker         const int workGroupSize    = (int)product(m_workGroupSize);
626*35238bceSAndroid Build Coastguard Worker         const int numWorkGroups    = numValues / workGroupSize;
627*35238bceSAndroid Build Coastguard Worker         const int numBits          = m_precision == PRECISION_HIGHP ? 32 : m_precision == PRECISION_MEDIUMP ? 16 : 8;
628*35238bceSAndroid Build Coastguard Worker         const uint32_t compareMask = (m_type == TYPE_UINT || numBits == 32) ? ~0u : (1u << numBits) - 1u;
629*35238bceSAndroid Build Coastguard Worker 
630*35238bceSAndroid Build Coastguard Worker         for (int groupNdx = 0; groupNdx < numWorkGroups; groupNdx++)
631*35238bceSAndroid Build Coastguard Worker         {
632*35238bceSAndroid Build Coastguard Worker             const int groupOffset      = groupNdx * workGroupSize;
633*35238bceSAndroid Build Coastguard Worker             const uint32_t groupOutput = *(const uint32_t *)((const uint8_t *)groupOutputs + groupNdx * groupStride);
634*35238bceSAndroid Build Coastguard Worker             uint32_t expectedValue     = m_initialValue;
635*35238bceSAndroid Build Coastguard Worker 
636*35238bceSAndroid Build Coastguard Worker             for (int localNdx = 0; localNdx < workGroupSize; localNdx++)
637*35238bceSAndroid Build Coastguard Worker             {
638*35238bceSAndroid Build Coastguard Worker                 const uint32_t inputValue =
639*35238bceSAndroid Build Coastguard Worker                     *(const uint32_t *)((const uint8_t *)inputs + inputStride * (groupOffset + localNdx));
640*35238bceSAndroid Build Coastguard Worker                 expectedValue &= inputValue;
641*35238bceSAndroid Build Coastguard Worker             }
642*35238bceSAndroid Build Coastguard Worker 
643*35238bceSAndroid Build Coastguard Worker             if ((groupOutput & compareMask) != (expectedValue & compareMask))
644*35238bceSAndroid Build Coastguard Worker             {
645*35238bceSAndroid Build Coastguard Worker                 m_testCtx.getLog() << TestLog::Message << "ERROR: at group " << groupNdx << ": expected "
646*35238bceSAndroid Build Coastguard Worker                                    << tcu::toHex(expectedValue) << ", got " << tcu::toHex(groupOutput)
647*35238bceSAndroid Build Coastguard Worker                                    << TestLog::EndMessage;
648*35238bceSAndroid Build Coastguard Worker                 return false;
649*35238bceSAndroid Build Coastguard Worker             }
650*35238bceSAndroid Build Coastguard Worker 
651*35238bceSAndroid Build Coastguard Worker             for (int localNdx = 0; localNdx < workGroupSize; localNdx++)
652*35238bceSAndroid Build Coastguard Worker             {
653*35238bceSAndroid Build Coastguard Worker                 const uint32_t outputValue =
654*35238bceSAndroid Build Coastguard Worker                     *(const uint32_t *)((const uint8_t *)outputs + outputStride * (groupOffset + localNdx));
655*35238bceSAndroid Build Coastguard Worker 
656*35238bceSAndroid Build Coastguard Worker                 if ((compareMask & (outputValue & ~m_initialValue)) != 0)
657*35238bceSAndroid Build Coastguard Worker                 {
658*35238bceSAndroid Build Coastguard Worker                     m_testCtx.getLog() << TestLog::Message << "ERROR: at group " << groupNdx << ", invocation "
659*35238bceSAndroid Build Coastguard Worker                                        << localNdx << ": found unexpected value " << tcu::toHex(outputValue)
660*35238bceSAndroid Build Coastguard Worker                                        << TestLog::EndMessage;
661*35238bceSAndroid Build Coastguard Worker                     return false;
662*35238bceSAndroid Build Coastguard Worker                 }
663*35238bceSAndroid Build Coastguard Worker             }
664*35238bceSAndroid Build Coastguard Worker         }
665*35238bceSAndroid Build Coastguard Worker 
666*35238bceSAndroid Build Coastguard Worker         return true;
667*35238bceSAndroid Build Coastguard Worker     }
668*35238bceSAndroid Build Coastguard Worker };
669*35238bceSAndroid Build Coastguard Worker 
670*35238bceSAndroid Build Coastguard Worker class ShaderAtomicOrCase : public ShaderAtomicOpCase
671*35238bceSAndroid Build Coastguard Worker {
672*35238bceSAndroid Build Coastguard Worker public:
ShaderAtomicOrCase(Context & context,const char * name,AtomicOperandType operandType,DataType type,Precision precision)673*35238bceSAndroid Build Coastguard Worker     ShaderAtomicOrCase(Context &context, const char *name, AtomicOperandType operandType, DataType type,
674*35238bceSAndroid Build Coastguard Worker                        Precision precision)
675*35238bceSAndroid Build Coastguard Worker         : ShaderAtomicOpCase(context, name, "atomicOr", operandType, type, precision, UVec3(3, 2, 1))
676*35238bceSAndroid Build Coastguard Worker     {
677*35238bceSAndroid Build Coastguard Worker         m_initialValue = 1u; // Lowest bit set.
678*35238bceSAndroid Build Coastguard Worker     }
679*35238bceSAndroid Build Coastguard Worker 
680*35238bceSAndroid Build Coastguard Worker protected:
getInputs(int numValues,int stride,void * inputs) const681*35238bceSAndroid Build Coastguard Worker     void getInputs(int numValues, int stride, void *inputs) const
682*35238bceSAndroid Build Coastguard Worker     {
683*35238bceSAndroid Build Coastguard Worker         de::Random rnd(deStringHash(getName()));
684*35238bceSAndroid Build Coastguard Worker         const int workGroupSize = (int)product(m_workGroupSize);
685*35238bceSAndroid Build Coastguard Worker         const int numWorkGroups = numValues / workGroupSize;
686*35238bceSAndroid Build Coastguard Worker         const int numBits       = m_precision == PRECISION_HIGHP ? 32 : m_precision == PRECISION_MEDIUMP ? 16 : 8;
687*35238bceSAndroid Build Coastguard Worker 
688*35238bceSAndroid Build Coastguard Worker         for (int groupNdx = 0; groupNdx < numWorkGroups; groupNdx++)
689*35238bceSAndroid Build Coastguard Worker         {
690*35238bceSAndroid Build Coastguard Worker             const int groupOffset = groupNdx * workGroupSize;
691*35238bceSAndroid Build Coastguard Worker 
692*35238bceSAndroid Build Coastguard Worker             for (int localNdx = 0; localNdx < workGroupSize; localNdx++)
693*35238bceSAndroid Build Coastguard Worker                 *(uint32_t *)((uint8_t *)inputs + stride * (groupOffset + localNdx)) = 1u << rnd.getInt(0, numBits - 1);
694*35238bceSAndroid Build Coastguard Worker         }
695*35238bceSAndroid Build Coastguard Worker     }
696*35238bceSAndroid Build Coastguard Worker 
verify(int numValues,int inputStride,const void * inputs,int outputStride,const void * outputs,int groupStride,const void * groupOutputs) const697*35238bceSAndroid Build Coastguard Worker     bool verify(int numValues, int inputStride, const void *inputs, int outputStride, const void *outputs,
698*35238bceSAndroid Build Coastguard Worker                 int groupStride, const void *groupOutputs) const
699*35238bceSAndroid Build Coastguard Worker     {
700*35238bceSAndroid Build Coastguard Worker         const int workGroupSize    = (int)product(m_workGroupSize);
701*35238bceSAndroid Build Coastguard Worker         const int numWorkGroups    = numValues / workGroupSize;
702*35238bceSAndroid Build Coastguard Worker         const int numBits          = m_precision == PRECISION_HIGHP ? 32 : m_precision == PRECISION_MEDIUMP ? 16 : 8;
703*35238bceSAndroid Build Coastguard Worker         const uint32_t compareMask = (m_type == TYPE_UINT || numBits == 32) ? ~0u : (1u << numBits) - 1u;
704*35238bceSAndroid Build Coastguard Worker 
705*35238bceSAndroid Build Coastguard Worker         for (int groupNdx = 0; groupNdx < numWorkGroups; groupNdx++)
706*35238bceSAndroid Build Coastguard Worker         {
707*35238bceSAndroid Build Coastguard Worker             const int groupOffset      = groupNdx * workGroupSize;
708*35238bceSAndroid Build Coastguard Worker             const uint32_t groupOutput = *(const uint32_t *)((const uint8_t *)groupOutputs + groupNdx * groupStride);
709*35238bceSAndroid Build Coastguard Worker             uint32_t expectedValue     = m_initialValue;
710*35238bceSAndroid Build Coastguard Worker 
711*35238bceSAndroid Build Coastguard Worker             for (int localNdx = 0; localNdx < workGroupSize; localNdx++)
712*35238bceSAndroid Build Coastguard Worker             {
713*35238bceSAndroid Build Coastguard Worker                 const uint32_t inputValue =
714*35238bceSAndroid Build Coastguard Worker                     *(const uint32_t *)((const uint8_t *)inputs + inputStride * (groupOffset + localNdx));
715*35238bceSAndroid Build Coastguard Worker                 expectedValue |= inputValue;
716*35238bceSAndroid Build Coastguard Worker             }
717*35238bceSAndroid Build Coastguard Worker 
718*35238bceSAndroid Build Coastguard Worker             if ((groupOutput & compareMask) != (expectedValue & compareMask))
719*35238bceSAndroid Build Coastguard Worker             {
720*35238bceSAndroid Build Coastguard Worker                 m_testCtx.getLog() << TestLog::Message << "ERROR: at group " << groupNdx << ": expected "
721*35238bceSAndroid Build Coastguard Worker                                    << tcu::toHex(expectedValue) << ", got " << tcu::toHex(groupOutput)
722*35238bceSAndroid Build Coastguard Worker                                    << TestLog::EndMessage;
723*35238bceSAndroid Build Coastguard Worker                 return false;
724*35238bceSAndroid Build Coastguard Worker             }
725*35238bceSAndroid Build Coastguard Worker 
726*35238bceSAndroid Build Coastguard Worker             for (int localNdx = 0; localNdx < workGroupSize; localNdx++)
727*35238bceSAndroid Build Coastguard Worker             {
728*35238bceSAndroid Build Coastguard Worker                 const uint32_t outputValue =
729*35238bceSAndroid Build Coastguard Worker                     *(const uint32_t *)((const uint8_t *)outputs + outputStride * (groupOffset + localNdx));
730*35238bceSAndroid Build Coastguard Worker 
731*35238bceSAndroid Build Coastguard Worker                 if ((compareMask & (outputValue & m_initialValue)) == 0)
732*35238bceSAndroid Build Coastguard Worker                 {
733*35238bceSAndroid Build Coastguard Worker                     m_testCtx.getLog() << TestLog::Message << "ERROR: at group " << groupNdx << ", invocation "
734*35238bceSAndroid Build Coastguard Worker                                        << localNdx << ": found unexpected value " << tcu::toHex(outputValue)
735*35238bceSAndroid Build Coastguard Worker                                        << TestLog::EndMessage;
736*35238bceSAndroid Build Coastguard Worker                     return false;
737*35238bceSAndroid Build Coastguard Worker                 }
738*35238bceSAndroid Build Coastguard Worker             }
739*35238bceSAndroid Build Coastguard Worker         }
740*35238bceSAndroid Build Coastguard Worker 
741*35238bceSAndroid Build Coastguard Worker         return true;
742*35238bceSAndroid Build Coastguard Worker     }
743*35238bceSAndroid Build Coastguard Worker };
744*35238bceSAndroid Build Coastguard Worker 
745*35238bceSAndroid Build Coastguard Worker class ShaderAtomicXorCase : public ShaderAtomicOpCase
746*35238bceSAndroid Build Coastguard Worker {
747*35238bceSAndroid Build Coastguard Worker public:
ShaderAtomicXorCase(Context & context,const char * name,AtomicOperandType operandType,DataType type,Precision precision)748*35238bceSAndroid Build Coastguard Worker     ShaderAtomicXorCase(Context &context, const char *name, AtomicOperandType operandType, DataType type,
749*35238bceSAndroid Build Coastguard Worker                         Precision precision)
750*35238bceSAndroid Build Coastguard Worker         : ShaderAtomicOpCase(context, name, "atomicXor", operandType, type, precision, UVec3(3, 2, 1))
751*35238bceSAndroid Build Coastguard Worker     {
752*35238bceSAndroid Build Coastguard Worker         m_initialValue = 0;
753*35238bceSAndroid Build Coastguard Worker     }
754*35238bceSAndroid Build Coastguard Worker 
755*35238bceSAndroid Build Coastguard Worker protected:
getInputs(int numValues,int stride,void * inputs) const756*35238bceSAndroid Build Coastguard Worker     void getInputs(int numValues, int stride, void *inputs) const
757*35238bceSAndroid Build Coastguard Worker     {
758*35238bceSAndroid Build Coastguard Worker         de::Random rnd(deStringHash(getName()));
759*35238bceSAndroid Build Coastguard Worker         const int workGroupSize = (int)product(m_workGroupSize);
760*35238bceSAndroid Build Coastguard Worker         const int numWorkGroups = numValues / workGroupSize;
761*35238bceSAndroid Build Coastguard Worker 
762*35238bceSAndroid Build Coastguard Worker         for (int groupNdx = 0; groupNdx < numWorkGroups; groupNdx++)
763*35238bceSAndroid Build Coastguard Worker         {
764*35238bceSAndroid Build Coastguard Worker             const int groupOffset = groupNdx * workGroupSize;
765*35238bceSAndroid Build Coastguard Worker 
766*35238bceSAndroid Build Coastguard Worker             // First uses random bit-pattern.
767*35238bceSAndroid Build Coastguard Worker             *(uint32_t *)((uint8_t *)inputs + stride * (groupOffset)) = rnd.getUint32();
768*35238bceSAndroid Build Coastguard Worker 
769*35238bceSAndroid Build Coastguard Worker             // Rest have either all or no bits set.
770*35238bceSAndroid Build Coastguard Worker             for (int localNdx = 1; localNdx < workGroupSize; localNdx++)
771*35238bceSAndroid Build Coastguard Worker                 *(uint32_t *)((uint8_t *)inputs + stride * (groupOffset + localNdx)) = rnd.getBool() ? ~0u : 0u;
772*35238bceSAndroid Build Coastguard Worker         }
773*35238bceSAndroid Build Coastguard Worker     }
774*35238bceSAndroid Build Coastguard Worker 
verify(int numValues,int inputStride,const void * inputs,int outputStride,const void * outputs,int groupStride,const void * groupOutputs) const775*35238bceSAndroid Build Coastguard Worker     bool verify(int numValues, int inputStride, const void *inputs, int outputStride, const void *outputs,
776*35238bceSAndroid Build Coastguard Worker                 int groupStride, const void *groupOutputs) const
777*35238bceSAndroid Build Coastguard Worker     {
778*35238bceSAndroid Build Coastguard Worker         const int workGroupSize    = (int)product(m_workGroupSize);
779*35238bceSAndroid Build Coastguard Worker         const int numWorkGroups    = numValues / workGroupSize;
780*35238bceSAndroid Build Coastguard Worker         const int numBits          = m_precision == PRECISION_HIGHP ? 32 : m_precision == PRECISION_MEDIUMP ? 16 : 8;
781*35238bceSAndroid Build Coastguard Worker         const uint32_t compareMask = numBits == 32 ? ~0u : (1u << numBits) - 1u;
782*35238bceSAndroid Build Coastguard Worker 
783*35238bceSAndroid Build Coastguard Worker         for (int groupNdx = 0; groupNdx < numWorkGroups; groupNdx++)
784*35238bceSAndroid Build Coastguard Worker         {
785*35238bceSAndroid Build Coastguard Worker             const int groupOffset      = groupNdx * workGroupSize;
786*35238bceSAndroid Build Coastguard Worker             const uint32_t groupOutput = *(const uint32_t *)((const uint8_t *)groupOutputs + groupNdx * groupStride);
787*35238bceSAndroid Build Coastguard Worker             const uint32_t randomValue = *(const int32_t *)((const uint8_t *)inputs + inputStride * groupOffset);
788*35238bceSAndroid Build Coastguard Worker             const uint32_t expected0   = randomValue ^ 0u;
789*35238bceSAndroid Build Coastguard Worker             const uint32_t expected1   = randomValue ^ ~0u;
790*35238bceSAndroid Build Coastguard Worker             int numXorZeros            = (m_initialValue == 0) ? 1 : 0;
791*35238bceSAndroid Build Coastguard Worker 
792*35238bceSAndroid Build Coastguard Worker             for (int localNdx = 1; localNdx < workGroupSize; localNdx++)
793*35238bceSAndroid Build Coastguard Worker             {
794*35238bceSAndroid Build Coastguard Worker                 const uint32_t inputValue =
795*35238bceSAndroid Build Coastguard Worker                     *(const uint32_t *)((const uint8_t *)inputs + inputStride * (groupOffset + localNdx));
796*35238bceSAndroid Build Coastguard Worker                 if (inputValue == 0)
797*35238bceSAndroid Build Coastguard Worker                     numXorZeros += 1;
798*35238bceSAndroid Build Coastguard Worker             }
799*35238bceSAndroid Build Coastguard Worker 
800*35238bceSAndroid Build Coastguard Worker             const uint32_t expected = (numXorZeros % 2 == 0) ? expected0 : expected1;
801*35238bceSAndroid Build Coastguard Worker 
802*35238bceSAndroid Build Coastguard Worker             if ((groupOutput & compareMask) != (expected & compareMask))
803*35238bceSAndroid Build Coastguard Worker             {
804*35238bceSAndroid Build Coastguard Worker                 m_testCtx.getLog() << TestLog::Message << "ERROR: at group " << groupNdx << ": expected "
805*35238bceSAndroid Build Coastguard Worker                                    << tcu::toHex(expected0) << " or " << tcu::toHex(expected1) << " (compare mask "
806*35238bceSAndroid Build Coastguard Worker                                    << tcu::toHex(compareMask) << "), got " << tcu::toHex(groupOutput)
807*35238bceSAndroid Build Coastguard Worker                                    << TestLog::EndMessage;
808*35238bceSAndroid Build Coastguard Worker                 return false;
809*35238bceSAndroid Build Coastguard Worker             }
810*35238bceSAndroid Build Coastguard Worker 
811*35238bceSAndroid Build Coastguard Worker             for (int localNdx = 0; localNdx < workGroupSize; localNdx++)
812*35238bceSAndroid Build Coastguard Worker             {
813*35238bceSAndroid Build Coastguard Worker                 const uint32_t outputValue =
814*35238bceSAndroid Build Coastguard Worker                     *(const uint32_t *)((const uint8_t *)outputs + outputStride * (groupOffset + localNdx));
815*35238bceSAndroid Build Coastguard Worker 
816*35238bceSAndroid Build Coastguard Worker                 if ((outputValue & compareMask) != 0 && (outputValue & compareMask) != compareMask &&
817*35238bceSAndroid Build Coastguard Worker                     (outputValue & compareMask) != (expected0 & compareMask) &&
818*35238bceSAndroid Build Coastguard Worker                     (outputValue & compareMask) != (expected1 & compareMask))
819*35238bceSAndroid Build Coastguard Worker                 {
820*35238bceSAndroid Build Coastguard Worker                     m_testCtx.getLog() << TestLog::Message << "ERROR: at group " << groupNdx << ", invocation "
821*35238bceSAndroid Build Coastguard Worker                                        << localNdx << ": found unexpected value " << tcu::toHex(outputValue)
822*35238bceSAndroid Build Coastguard Worker                                        << TestLog::EndMessage;
823*35238bceSAndroid Build Coastguard Worker                     return false;
824*35238bceSAndroid Build Coastguard Worker                 }
825*35238bceSAndroid Build Coastguard Worker             }
826*35238bceSAndroid Build Coastguard Worker         }
827*35238bceSAndroid Build Coastguard Worker 
828*35238bceSAndroid Build Coastguard Worker         return true;
829*35238bceSAndroid Build Coastguard Worker     }
830*35238bceSAndroid Build Coastguard Worker };
831*35238bceSAndroid Build Coastguard Worker 
832*35238bceSAndroid Build Coastguard Worker class ShaderAtomicExchangeCase : public ShaderAtomicOpCase
833*35238bceSAndroid Build Coastguard Worker {
834*35238bceSAndroid Build Coastguard Worker public:
ShaderAtomicExchangeCase(Context & context,const char * name,AtomicOperandType operandType,DataType type,Precision precision)835*35238bceSAndroid Build Coastguard Worker     ShaderAtomicExchangeCase(Context &context, const char *name, AtomicOperandType operandType, DataType type,
836*35238bceSAndroid Build Coastguard Worker                              Precision precision)
837*35238bceSAndroid Build Coastguard Worker         : ShaderAtomicOpCase(context, name, "atomicExchange", operandType, type, precision, UVec3(3, 2, 1))
838*35238bceSAndroid Build Coastguard Worker     {
839*35238bceSAndroid Build Coastguard Worker         m_initialValue = 0;
840*35238bceSAndroid Build Coastguard Worker     }
841*35238bceSAndroid Build Coastguard Worker 
842*35238bceSAndroid Build Coastguard Worker protected:
getInputs(int numValues,int stride,void * inputs) const843*35238bceSAndroid Build Coastguard Worker     void getInputs(int numValues, int stride, void *inputs) const
844*35238bceSAndroid Build Coastguard Worker     {
845*35238bceSAndroid Build Coastguard Worker         const int workGroupSize = (int)product(m_workGroupSize);
846*35238bceSAndroid Build Coastguard Worker         const int numWorkGroups = numValues / workGroupSize;
847*35238bceSAndroid Build Coastguard Worker 
848*35238bceSAndroid Build Coastguard Worker         for (int groupNdx = 0; groupNdx < numWorkGroups; groupNdx++)
849*35238bceSAndroid Build Coastguard Worker         {
850*35238bceSAndroid Build Coastguard Worker             const int groupOffset = groupNdx * workGroupSize;
851*35238bceSAndroid Build Coastguard Worker 
852*35238bceSAndroid Build Coastguard Worker             for (int localNdx = 0; localNdx < workGroupSize; localNdx++)
853*35238bceSAndroid Build Coastguard Worker                 *(int *)((uint8_t *)inputs + stride * (groupOffset + localNdx)) = localNdx + 1;
854*35238bceSAndroid Build Coastguard Worker         }
855*35238bceSAndroid Build Coastguard Worker     }
856*35238bceSAndroid Build Coastguard Worker 
verify(int numValues,int inputStride,const void * inputs,int outputStride,const void * outputs,int groupStride,const void * groupOutputs) const857*35238bceSAndroid Build Coastguard Worker     bool verify(int numValues, int inputStride, const void *inputs, int outputStride, const void *outputs,
858*35238bceSAndroid Build Coastguard Worker                 int groupStride, const void *groupOutputs) const
859*35238bceSAndroid Build Coastguard Worker     {
860*35238bceSAndroid Build Coastguard Worker         const int workGroupSize = (int)product(m_workGroupSize);
861*35238bceSAndroid Build Coastguard Worker         const int numWorkGroups = numValues / workGroupSize;
862*35238bceSAndroid Build Coastguard Worker 
863*35238bceSAndroid Build Coastguard Worker         DE_UNREF(inputStride && inputs);
864*35238bceSAndroid Build Coastguard Worker 
865*35238bceSAndroid Build Coastguard Worker         for (int groupNdx = 0; groupNdx < numWorkGroups; groupNdx++)
866*35238bceSAndroid Build Coastguard Worker         {
867*35238bceSAndroid Build Coastguard Worker             const int groupOffset = groupNdx * workGroupSize;
868*35238bceSAndroid Build Coastguard Worker             const int groupOutput = *(const int32_t *)((const uint8_t *)groupOutputs + groupNdx * groupStride);
869*35238bceSAndroid Build Coastguard Worker             set<int> usedValues;
870*35238bceSAndroid Build Coastguard Worker 
871*35238bceSAndroid Build Coastguard Worker             for (int localNdx = 0; localNdx < workGroupSize; localNdx++)
872*35238bceSAndroid Build Coastguard Worker             {
873*35238bceSAndroid Build Coastguard Worker                 const int outputValue =
874*35238bceSAndroid Build Coastguard Worker                     *(const int32_t *)((const uint8_t *)outputs + outputStride * (groupOffset + localNdx));
875*35238bceSAndroid Build Coastguard Worker 
876*35238bceSAndroid Build Coastguard Worker                 if (!de::inRange(outputValue, 0, workGroupSize) || usedValues.find(outputValue) != usedValues.end())
877*35238bceSAndroid Build Coastguard Worker                 {
878*35238bceSAndroid Build Coastguard Worker                     m_testCtx.getLog() << TestLog::Message << "ERROR: at group " << groupNdx << ", invocation "
879*35238bceSAndroid Build Coastguard Worker                                        << localNdx << ": found unexpected value " << outputValue << TestLog::EndMessage;
880*35238bceSAndroid Build Coastguard Worker                     return false;
881*35238bceSAndroid Build Coastguard Worker                 }
882*35238bceSAndroid Build Coastguard Worker                 usedValues.insert(outputValue);
883*35238bceSAndroid Build Coastguard Worker             }
884*35238bceSAndroid Build Coastguard Worker 
885*35238bceSAndroid Build Coastguard Worker             if (!de::inRange(groupOutput, 0, workGroupSize) || usedValues.find(groupOutput) != usedValues.end())
886*35238bceSAndroid Build Coastguard Worker             {
887*35238bceSAndroid Build Coastguard Worker                 m_testCtx.getLog() << TestLog::Message << "ERROR: at group " << groupNdx << ": unexpected final value"
888*35238bceSAndroid Build Coastguard Worker                                    << groupOutput << TestLog::EndMessage;
889*35238bceSAndroid Build Coastguard Worker                 return false;
890*35238bceSAndroid Build Coastguard Worker             }
891*35238bceSAndroid Build Coastguard Worker         }
892*35238bceSAndroid Build Coastguard Worker 
893*35238bceSAndroid Build Coastguard Worker         return true;
894*35238bceSAndroid Build Coastguard Worker     }
895*35238bceSAndroid Build Coastguard Worker };
896*35238bceSAndroid Build Coastguard Worker 
897*35238bceSAndroid Build Coastguard Worker class ShaderAtomicCompSwapCase : public TestCase
898*35238bceSAndroid Build Coastguard Worker {
899*35238bceSAndroid Build Coastguard Worker public:
900*35238bceSAndroid Build Coastguard Worker     ShaderAtomicCompSwapCase(Context &context, const char *name, AtomicOperandType operandType, DataType type,
901*35238bceSAndroid Build Coastguard Worker                              Precision precision);
902*35238bceSAndroid Build Coastguard Worker     ~ShaderAtomicCompSwapCase(void);
903*35238bceSAndroid Build Coastguard Worker 
904*35238bceSAndroid Build Coastguard Worker     void init(void);
905*35238bceSAndroid Build Coastguard Worker     void deinit(void);
906*35238bceSAndroid Build Coastguard Worker     IterateResult iterate(void);
907*35238bceSAndroid Build Coastguard Worker 
908*35238bceSAndroid Build Coastguard Worker protected:
909*35238bceSAndroid Build Coastguard Worker private:
910*35238bceSAndroid Build Coastguard Worker     ShaderAtomicCompSwapCase(const ShaderAtomicCompSwapCase &other);
911*35238bceSAndroid Build Coastguard Worker     ShaderAtomicCompSwapCase &operator=(const ShaderAtomicCompSwapCase &other);
912*35238bceSAndroid Build Coastguard Worker 
913*35238bceSAndroid Build Coastguard Worker     const AtomicOperandType m_operandType;
914*35238bceSAndroid Build Coastguard Worker     const DataType m_type;
915*35238bceSAndroid Build Coastguard Worker     const Precision m_precision;
916*35238bceSAndroid Build Coastguard Worker 
917*35238bceSAndroid Build Coastguard Worker     const UVec3 m_workGroupSize;
918*35238bceSAndroid Build Coastguard Worker     const UVec3 m_numWorkGroups;
919*35238bceSAndroid Build Coastguard Worker 
920*35238bceSAndroid Build Coastguard Worker     ShaderProgram *m_program;
921*35238bceSAndroid Build Coastguard Worker };
922*35238bceSAndroid Build Coastguard Worker 
ShaderAtomicCompSwapCase(Context & context,const char * name,AtomicOperandType operandType,DataType type,Precision precision)923*35238bceSAndroid Build Coastguard Worker ShaderAtomicCompSwapCase::ShaderAtomicCompSwapCase(Context &context, const char *name, AtomicOperandType operandType,
924*35238bceSAndroid Build Coastguard Worker                                                    DataType type, Precision precision)
925*35238bceSAndroid Build Coastguard Worker     : TestCase(context, name, "atomicCompSwap() Test")
926*35238bceSAndroid Build Coastguard Worker     , m_operandType(operandType)
927*35238bceSAndroid Build Coastguard Worker     , m_type(type)
928*35238bceSAndroid Build Coastguard Worker     , m_precision(precision)
929*35238bceSAndroid Build Coastguard Worker     , m_workGroupSize(3, 2, 1)
930*35238bceSAndroid Build Coastguard Worker     , m_numWorkGroups(4, 4, 4)
931*35238bceSAndroid Build Coastguard Worker     , m_program(DE_NULL)
932*35238bceSAndroid Build Coastguard Worker {
933*35238bceSAndroid Build Coastguard Worker }
934*35238bceSAndroid Build Coastguard Worker 
~ShaderAtomicCompSwapCase(void)935*35238bceSAndroid Build Coastguard Worker ShaderAtomicCompSwapCase::~ShaderAtomicCompSwapCase(void)
936*35238bceSAndroid Build Coastguard Worker {
937*35238bceSAndroid Build Coastguard Worker     ShaderAtomicCompSwapCase::deinit();
938*35238bceSAndroid Build Coastguard Worker }
939*35238bceSAndroid Build Coastguard Worker 
init(void)940*35238bceSAndroid Build Coastguard Worker void ShaderAtomicCompSwapCase::init(void)
941*35238bceSAndroid Build Coastguard Worker {
942*35238bceSAndroid Build Coastguard Worker     const bool isSSBO        = m_operandType == ATOMIC_OPERAND_BUFFER_VARIABLE;
943*35238bceSAndroid Build Coastguard Worker     const char *precName     = getPrecisionName(m_precision);
944*35238bceSAndroid Build Coastguard Worker     const char *typeName     = getDataTypeName(m_type);
945*35238bceSAndroid Build Coastguard Worker     const uint32_t numValues = product(m_workGroupSize) * product(m_numWorkGroups);
946*35238bceSAndroid Build Coastguard Worker     std::ostringstream src;
947*35238bceSAndroid Build Coastguard Worker 
948*35238bceSAndroid Build Coastguard Worker     src << "#version 310 es\n"
949*35238bceSAndroid Build Coastguard Worker         << "layout(local_size_x = " << m_workGroupSize.x() << ", local_size_y = " << m_workGroupSize.y()
950*35238bceSAndroid Build Coastguard Worker         << ", local_size_z = " << m_workGroupSize.z() << ") in;\n"
951*35238bceSAndroid Build Coastguard Worker         << "layout(binding = 0) buffer InOut\n"
952*35238bceSAndroid Build Coastguard Worker         << "{\n"
953*35238bceSAndroid Build Coastguard Worker         << "    " << precName << " " << typeName << " compareValues[" << numValues << "];\n"
954*35238bceSAndroid Build Coastguard Worker         << "    " << precName << " " << typeName << " exchangeValues[" << numValues << "];\n"
955*35238bceSAndroid Build Coastguard Worker         << "    " << precName << " " << typeName << " outputValues[" << numValues << "];\n"
956*35238bceSAndroid Build Coastguard Worker         << "    " << (isSSBO ? "coherent " : "") << precName << " " << typeName << " groupValues["
957*35238bceSAndroid Build Coastguard Worker         << product(m_numWorkGroups) << "];\n"
958*35238bceSAndroid Build Coastguard Worker         << "} sb_inout;\n";
959*35238bceSAndroid Build Coastguard Worker 
960*35238bceSAndroid Build Coastguard Worker     if (!isSSBO)
961*35238bceSAndroid Build Coastguard Worker         src << "shared " << precName << " " << typeName << " s_var;\n";
962*35238bceSAndroid Build Coastguard Worker 
963*35238bceSAndroid Build Coastguard Worker     src << "\n"
964*35238bceSAndroid Build Coastguard Worker         << "void main (void)\n"
965*35238bceSAndroid Build Coastguard Worker         << "{\n"
966*35238bceSAndroid Build Coastguard Worker         << "    uint localSize  = gl_WorkGroupSize.x*gl_WorkGroupSize.y*gl_WorkGroupSize.z;\n"
967*35238bceSAndroid Build Coastguard Worker         << "    uint globalNdx  = gl_NumWorkGroups.x*gl_NumWorkGroups.y*gl_WorkGroupID.z + "
968*35238bceSAndroid Build Coastguard Worker            "gl_NumWorkGroups.x*gl_WorkGroupID.y + gl_WorkGroupID.x;\n"
969*35238bceSAndroid Build Coastguard Worker         << "    uint globalOffs = localSize*globalNdx;\n"
970*35238bceSAndroid Build Coastguard Worker         << "    uint offset     = globalOffs + gl_LocalInvocationIndex;\n"
971*35238bceSAndroid Build Coastguard Worker         << "\n";
972*35238bceSAndroid Build Coastguard Worker 
973*35238bceSAndroid Build Coastguard Worker     if (!isSSBO)
974*35238bceSAndroid Build Coastguard Worker     {
975*35238bceSAndroid Build Coastguard Worker         src << "    if (gl_LocalInvocationIndex == 0u)\n"
976*35238bceSAndroid Build Coastguard Worker             << "        s_var = " << typeName << "(" << 0 << ");\n"
977*35238bceSAndroid Build Coastguard Worker             << "\n";
978*35238bceSAndroid Build Coastguard Worker     }
979*35238bceSAndroid Build Coastguard Worker 
980*35238bceSAndroid Build Coastguard Worker     src << "    " << precName << " " << typeName << " compare = sb_inout.compareValues[offset];\n"
981*35238bceSAndroid Build Coastguard Worker         << "    " << precName << " " << typeName << " exchange = sb_inout.exchangeValues[offset];\n"
982*35238bceSAndroid Build Coastguard Worker         << "    " << precName << " " << typeName << " result;\n"
983*35238bceSAndroid Build Coastguard Worker         << "    bool swapDone = false;\n"
984*35238bceSAndroid Build Coastguard Worker         << "\n"
985*35238bceSAndroid Build Coastguard Worker         << "    for (uint ndx = 0u; ndx < localSize; ndx++)\n"
986*35238bceSAndroid Build Coastguard Worker         << "    {\n"
987*35238bceSAndroid Build Coastguard Worker         << "        barrier();\n"
988*35238bceSAndroid Build Coastguard Worker         << "        if (!swapDone)\n"
989*35238bceSAndroid Build Coastguard Worker         << "        {\n"
990*35238bceSAndroid Build Coastguard Worker         << "            result = atomicCompSwap(" << (isSSBO ? "sb_inout.groupValues[globalNdx]" : "s_var")
991*35238bceSAndroid Build Coastguard Worker         << ", compare, exchange);\n"
992*35238bceSAndroid Build Coastguard Worker         << "            if (result == compare)\n"
993*35238bceSAndroid Build Coastguard Worker         << "                swapDone = true;\n"
994*35238bceSAndroid Build Coastguard Worker         << "        }\n"
995*35238bceSAndroid Build Coastguard Worker         << "    }\n"
996*35238bceSAndroid Build Coastguard Worker         << "\n"
997*35238bceSAndroid Build Coastguard Worker         << "    sb_inout.outputValues[offset] = result;\n";
998*35238bceSAndroid Build Coastguard Worker 
999*35238bceSAndroid Build Coastguard Worker     if (!isSSBO)
1000*35238bceSAndroid Build Coastguard Worker     {
1001*35238bceSAndroid Build Coastguard Worker         src << "    barrier();\n"
1002*35238bceSAndroid Build Coastguard Worker             << "    if (gl_LocalInvocationIndex == 0u)\n"
1003*35238bceSAndroid Build Coastguard Worker             << "        sb_inout.groupValues[globalNdx] = s_var;\n";
1004*35238bceSAndroid Build Coastguard Worker     }
1005*35238bceSAndroid Build Coastguard Worker 
1006*35238bceSAndroid Build Coastguard Worker     src << "}\n";
1007*35238bceSAndroid Build Coastguard Worker 
1008*35238bceSAndroid Build Coastguard Worker     DE_ASSERT(!m_program);
1009*35238bceSAndroid Build Coastguard Worker     m_program = new ShaderProgram(m_context.getRenderContext(), ProgramSources() << ComputeSource(src.str()));
1010*35238bceSAndroid Build Coastguard Worker 
1011*35238bceSAndroid Build Coastguard Worker     m_testCtx.getLog() << *m_program;
1012*35238bceSAndroid Build Coastguard Worker 
1013*35238bceSAndroid Build Coastguard Worker     if (!m_program->isOk())
1014*35238bceSAndroid Build Coastguard Worker     {
1015*35238bceSAndroid Build Coastguard Worker         delete m_program;
1016*35238bceSAndroid Build Coastguard Worker         m_program = DE_NULL;
1017*35238bceSAndroid Build Coastguard Worker         throw tcu::TestError("Compile failed");
1018*35238bceSAndroid Build Coastguard Worker     }
1019*35238bceSAndroid Build Coastguard Worker }
1020*35238bceSAndroid Build Coastguard Worker 
deinit(void)1021*35238bceSAndroid Build Coastguard Worker void ShaderAtomicCompSwapCase::deinit(void)
1022*35238bceSAndroid Build Coastguard Worker {
1023*35238bceSAndroid Build Coastguard Worker     delete m_program;
1024*35238bceSAndroid Build Coastguard Worker     m_program = DE_NULL;
1025*35238bceSAndroid Build Coastguard Worker }
1026*35238bceSAndroid Build Coastguard Worker 
iterate(void)1027*35238bceSAndroid Build Coastguard Worker ShaderAtomicOpCase::IterateResult ShaderAtomicCompSwapCase::iterate(void)
1028*35238bceSAndroid Build Coastguard Worker {
1029*35238bceSAndroid Build Coastguard Worker     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
1030*35238bceSAndroid Build Coastguard Worker     const uint32_t program   = m_program->getProgram();
1031*35238bceSAndroid Build Coastguard Worker     const Buffer inoutBuffer(m_context.getRenderContext());
1032*35238bceSAndroid Build Coastguard Worker     const uint32_t blockNdx            = gl.getProgramResourceIndex(program, GL_SHADER_STORAGE_BLOCK, "InOut");
1033*35238bceSAndroid Build Coastguard Worker     const InterfaceBlockInfo blockInfo = getProgramInterfaceBlockInfo(gl, program, GL_SHADER_STORAGE_BLOCK, blockNdx);
1034*35238bceSAndroid Build Coastguard Worker     const uint32_t cmpVarNdx = gl.getProgramResourceIndex(program, GL_BUFFER_VARIABLE, "InOut.compareValues[0]");
1035*35238bceSAndroid Build Coastguard Worker     const InterfaceVariableInfo cmpVarInfo =
1036*35238bceSAndroid Build Coastguard Worker         getProgramInterfaceVariableInfo(gl, program, GL_BUFFER_VARIABLE, cmpVarNdx);
1037*35238bceSAndroid Build Coastguard Worker     const uint32_t exhVarNdx = gl.getProgramResourceIndex(program, GL_BUFFER_VARIABLE, "InOut.exchangeValues[0]");
1038*35238bceSAndroid Build Coastguard Worker     const InterfaceVariableInfo exhVarInfo =
1039*35238bceSAndroid Build Coastguard Worker         getProgramInterfaceVariableInfo(gl, program, GL_BUFFER_VARIABLE, exhVarNdx);
1040*35238bceSAndroid Build Coastguard Worker     const uint32_t outVarNdx = gl.getProgramResourceIndex(program, GL_BUFFER_VARIABLE, "InOut.outputValues[0]");
1041*35238bceSAndroid Build Coastguard Worker     const InterfaceVariableInfo outVarInfo =
1042*35238bceSAndroid Build Coastguard Worker         getProgramInterfaceVariableInfo(gl, program, GL_BUFFER_VARIABLE, outVarNdx);
1043*35238bceSAndroid Build Coastguard Worker     const uint32_t groupVarNdx = gl.getProgramResourceIndex(program, GL_BUFFER_VARIABLE, "InOut.groupValues[0]");
1044*35238bceSAndroid Build Coastguard Worker     const InterfaceVariableInfo groupVarInfo =
1045*35238bceSAndroid Build Coastguard Worker         getProgramInterfaceVariableInfo(gl, program, GL_BUFFER_VARIABLE, groupVarNdx);
1046*35238bceSAndroid Build Coastguard Worker     const uint32_t numValues = product(m_workGroupSize) * product(m_numWorkGroups);
1047*35238bceSAndroid Build Coastguard Worker 
1048*35238bceSAndroid Build Coastguard Worker     TCU_CHECK(cmpVarInfo.arraySize == numValues && exhVarInfo.arraySize == numValues &&
1049*35238bceSAndroid Build Coastguard Worker               outVarInfo.arraySize == numValues && groupVarInfo.arraySize == product(m_numWorkGroups));
1050*35238bceSAndroid Build Coastguard Worker 
1051*35238bceSAndroid Build Coastguard Worker     gl.useProgram(program);
1052*35238bceSAndroid Build Coastguard Worker 
1053*35238bceSAndroid Build Coastguard Worker     // \todo [2013-09-05 pyry] Use randomized input values!
1054*35238bceSAndroid Build Coastguard Worker 
1055*35238bceSAndroid Build Coastguard Worker     // Setup buffer.
1056*35238bceSAndroid Build Coastguard Worker     {
1057*35238bceSAndroid Build Coastguard Worker         const uint32_t workGroupSize = product(m_workGroupSize);
1058*35238bceSAndroid Build Coastguard Worker         vector<uint8_t> bufData(blockInfo.dataSize);
1059*35238bceSAndroid Build Coastguard Worker 
1060*35238bceSAndroid Build Coastguard Worker         std::fill(bufData.begin(), bufData.end(), 0);
1061*35238bceSAndroid Build Coastguard Worker 
1062*35238bceSAndroid Build Coastguard Worker         for (uint32_t ndx = 0; ndx < numValues; ndx++)
1063*35238bceSAndroid Build Coastguard Worker             *(uint32_t *)(&bufData[0] + cmpVarInfo.offset + cmpVarInfo.arrayStride * ndx) = ndx % workGroupSize;
1064*35238bceSAndroid Build Coastguard Worker 
1065*35238bceSAndroid Build Coastguard Worker         for (uint32_t ndx = 0; ndx < numValues; ndx++)
1066*35238bceSAndroid Build Coastguard Worker             *(uint32_t *)(&bufData[0] + exhVarInfo.offset + exhVarInfo.arrayStride * ndx) = (ndx % workGroupSize) + 1;
1067*35238bceSAndroid Build Coastguard Worker 
1068*35238bceSAndroid Build Coastguard Worker         gl.bindBuffer(GL_SHADER_STORAGE_BUFFER, *inoutBuffer);
1069*35238bceSAndroid Build Coastguard Worker         gl.bufferData(GL_SHADER_STORAGE_BUFFER, blockInfo.dataSize, &bufData[0], GL_STATIC_READ);
1070*35238bceSAndroid Build Coastguard Worker         gl.bindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, *inoutBuffer);
1071*35238bceSAndroid Build Coastguard Worker         GLU_EXPECT_NO_ERROR(gl.getError(), "Output buffer setup failed");
1072*35238bceSAndroid Build Coastguard Worker     }
1073*35238bceSAndroid Build Coastguard Worker 
1074*35238bceSAndroid Build Coastguard Worker     gl.dispatchCompute(m_numWorkGroups.x(), m_numWorkGroups.y(), m_numWorkGroups.z());
1075*35238bceSAndroid Build Coastguard Worker 
1076*35238bceSAndroid Build Coastguard Worker     // Read back and compare
1077*35238bceSAndroid Build Coastguard Worker     {
1078*35238bceSAndroid Build Coastguard Worker         const void *resPtr      = gl.mapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, blockInfo.dataSize, GL_MAP_READ_BIT);
1079*35238bceSAndroid Build Coastguard Worker         const int numWorkGroups = (int)product(m_numWorkGroups);
1080*35238bceSAndroid Build Coastguard Worker         const int workGroupSize = (int)product(m_workGroupSize);
1081*35238bceSAndroid Build Coastguard Worker         bool isOk               = true;
1082*35238bceSAndroid Build Coastguard Worker 
1083*35238bceSAndroid Build Coastguard Worker         GLU_EXPECT_NO_ERROR(gl.getError(), "glMapBufferRange()");
1084*35238bceSAndroid Build Coastguard Worker         TCU_CHECK(resPtr);
1085*35238bceSAndroid Build Coastguard Worker 
1086*35238bceSAndroid Build Coastguard Worker         for (int groupNdx = 0; groupNdx < numWorkGroups; groupNdx++)
1087*35238bceSAndroid Build Coastguard Worker         {
1088*35238bceSAndroid Build Coastguard Worker             const int groupOffset = groupNdx * workGroupSize;
1089*35238bceSAndroid Build Coastguard Worker             const int groupOutput =
1090*35238bceSAndroid Build Coastguard Worker                 *(const int32_t *)((const uint8_t *)resPtr + groupVarInfo.offset + groupNdx * groupVarInfo.arrayStride);
1091*35238bceSAndroid Build Coastguard Worker 
1092*35238bceSAndroid Build Coastguard Worker             for (int localNdx = 0; localNdx < workGroupSize; localNdx++)
1093*35238bceSAndroid Build Coastguard Worker             {
1094*35238bceSAndroid Build Coastguard Worker                 const int refValue    = localNdx;
1095*35238bceSAndroid Build Coastguard Worker                 const int outputValue = *(const int32_t *)((const uint8_t *)resPtr + outVarInfo.offset +
1096*35238bceSAndroid Build Coastguard Worker                                                            outVarInfo.arrayStride * (groupOffset + localNdx));
1097*35238bceSAndroid Build Coastguard Worker 
1098*35238bceSAndroid Build Coastguard Worker                 if (outputValue != refValue)
1099*35238bceSAndroid Build Coastguard Worker                 {
1100*35238bceSAndroid Build Coastguard Worker                     m_testCtx.getLog() << TestLog::Message << "ERROR: at group " << groupNdx << ", invocation "
1101*35238bceSAndroid Build Coastguard Worker                                        << localNdx << ": expected " << refValue << ", got " << outputValue
1102*35238bceSAndroid Build Coastguard Worker                                        << TestLog::EndMessage;
1103*35238bceSAndroid Build Coastguard Worker                     isOk = false;
1104*35238bceSAndroid Build Coastguard Worker                     break;
1105*35238bceSAndroid Build Coastguard Worker                 }
1106*35238bceSAndroid Build Coastguard Worker             }
1107*35238bceSAndroid Build Coastguard Worker 
1108*35238bceSAndroid Build Coastguard Worker             if (groupOutput != workGroupSize)
1109*35238bceSAndroid Build Coastguard Worker             {
1110*35238bceSAndroid Build Coastguard Worker                 m_testCtx.getLog() << TestLog::Message << "ERROR: at group " << groupNdx << ": expected"
1111*35238bceSAndroid Build Coastguard Worker                                    << workGroupSize << ", got " << groupOutput << TestLog::EndMessage;
1112*35238bceSAndroid Build Coastguard Worker                 isOk = false;
1113*35238bceSAndroid Build Coastguard Worker                 break;
1114*35238bceSAndroid Build Coastguard Worker             }
1115*35238bceSAndroid Build Coastguard Worker         }
1116*35238bceSAndroid Build Coastguard Worker 
1117*35238bceSAndroid Build Coastguard Worker         gl.unmapBuffer(GL_SHADER_STORAGE_BUFFER);
1118*35238bceSAndroid Build Coastguard Worker         GLU_EXPECT_NO_ERROR(gl.getError(), "glUnmapBuffer()");
1119*35238bceSAndroid Build Coastguard Worker 
1120*35238bceSAndroid Build Coastguard Worker         m_testCtx.setTestResult(isOk ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL, isOk ? "Pass" : "Comparison failed");
1121*35238bceSAndroid Build Coastguard Worker     }
1122*35238bceSAndroid Build Coastguard Worker 
1123*35238bceSAndroid Build Coastguard Worker     return STOP;
1124*35238bceSAndroid Build Coastguard Worker }
1125*35238bceSAndroid Build Coastguard Worker 
ShaderAtomicOpTests(Context & context,const char * name,AtomicOperandType operandType)1126*35238bceSAndroid Build Coastguard Worker ShaderAtomicOpTests::ShaderAtomicOpTests(Context &context, const char *name, AtomicOperandType operandType)
1127*35238bceSAndroid Build Coastguard Worker     : TestCaseGroup(context, name, "Atomic Operation Tests")
1128*35238bceSAndroid Build Coastguard Worker     , m_operandType(operandType)
1129*35238bceSAndroid Build Coastguard Worker {
1130*35238bceSAndroid Build Coastguard Worker }
1131*35238bceSAndroid Build Coastguard Worker 
~ShaderAtomicOpTests(void)1132*35238bceSAndroid Build Coastguard Worker ShaderAtomicOpTests::~ShaderAtomicOpTests(void)
1133*35238bceSAndroid Build Coastguard Worker {
1134*35238bceSAndroid Build Coastguard Worker }
1135*35238bceSAndroid Build Coastguard Worker 
1136*35238bceSAndroid Build Coastguard Worker template <typename T>
createAtomicOpGroup(Context & context,AtomicOperandType operandType,const char * groupName)1137*35238bceSAndroid Build Coastguard Worker static tcu::TestCaseGroup *createAtomicOpGroup(Context &context, AtomicOperandType operandType, const char *groupName)
1138*35238bceSAndroid Build Coastguard Worker {
1139*35238bceSAndroid Build Coastguard Worker     tcu::TestCaseGroup *const group =
1140*35238bceSAndroid Build Coastguard Worker         new tcu::TestCaseGroup(context.getTestContext(), groupName, (string("Atomic ") + groupName).c_str());
1141*35238bceSAndroid Build Coastguard Worker     try
1142*35238bceSAndroid Build Coastguard Worker     {
1143*35238bceSAndroid Build Coastguard Worker         for (int precNdx = 0; precNdx < PRECISION_LAST; precNdx++)
1144*35238bceSAndroid Build Coastguard Worker         {
1145*35238bceSAndroid Build Coastguard Worker             for (int typeNdx = 0; typeNdx < 2; typeNdx++)
1146*35238bceSAndroid Build Coastguard Worker             {
1147*35238bceSAndroid Build Coastguard Worker                 const Precision precision = Precision(precNdx);
1148*35238bceSAndroid Build Coastguard Worker                 const DataType type       = typeNdx > 0 ? TYPE_INT : TYPE_UINT;
1149*35238bceSAndroid Build Coastguard Worker                 const string caseName     = string(getPrecisionName(precision)) + "_" + getDataTypeName(type);
1150*35238bceSAndroid Build Coastguard Worker 
1151*35238bceSAndroid Build Coastguard Worker                 group->addChild(new T(context, caseName.c_str(), operandType, type, precision));
1152*35238bceSAndroid Build Coastguard Worker             }
1153*35238bceSAndroid Build Coastguard Worker         }
1154*35238bceSAndroid Build Coastguard Worker 
1155*35238bceSAndroid Build Coastguard Worker         return group;
1156*35238bceSAndroid Build Coastguard Worker     }
1157*35238bceSAndroid Build Coastguard Worker     catch (...)
1158*35238bceSAndroid Build Coastguard Worker     {
1159*35238bceSAndroid Build Coastguard Worker         delete group;
1160*35238bceSAndroid Build Coastguard Worker         throw;
1161*35238bceSAndroid Build Coastguard Worker     }
1162*35238bceSAndroid Build Coastguard Worker }
1163*35238bceSAndroid Build Coastguard Worker 
init(void)1164*35238bceSAndroid Build Coastguard Worker void ShaderAtomicOpTests::init(void)
1165*35238bceSAndroid Build Coastguard Worker {
1166*35238bceSAndroid Build Coastguard Worker     addChild(createAtomicOpGroup<ShaderAtomicAddCase>(m_context, m_operandType, "add"));
1167*35238bceSAndroid Build Coastguard Worker     addChild(createAtomicOpGroup<ShaderAtomicMinCase>(m_context, m_operandType, "min"));
1168*35238bceSAndroid Build Coastguard Worker     addChild(createAtomicOpGroup<ShaderAtomicMaxCase>(m_context, m_operandType, "max"));
1169*35238bceSAndroid Build Coastguard Worker     addChild(createAtomicOpGroup<ShaderAtomicAndCase>(m_context, m_operandType, "and"));
1170*35238bceSAndroid Build Coastguard Worker     addChild(createAtomicOpGroup<ShaderAtomicOrCase>(m_context, m_operandType, "or"));
1171*35238bceSAndroid Build Coastguard Worker     addChild(createAtomicOpGroup<ShaderAtomicXorCase>(m_context, m_operandType, "xor"));
1172*35238bceSAndroid Build Coastguard Worker     addChild(createAtomicOpGroup<ShaderAtomicExchangeCase>(m_context, m_operandType, "exchange"));
1173*35238bceSAndroid Build Coastguard Worker     addChild(createAtomicOpGroup<ShaderAtomicCompSwapCase>(m_context, m_operandType, "compswap"));
1174*35238bceSAndroid Build Coastguard Worker }
1175*35238bceSAndroid Build Coastguard Worker 
1176*35238bceSAndroid Build Coastguard Worker } // namespace Functional
1177*35238bceSAndroid Build Coastguard Worker } // namespace gles31
1178*35238bceSAndroid Build Coastguard Worker } // namespace deqp
1179