Fix PIPELINE_STAGE_TOP_OF_PIPE_BIT usage in api tests
[platform/upstream/VK-GL-CTS.git] / modules / gles31 / functional / es31fAtomicCounterTests.cpp
1 /*-------------------------------------------------------------------------
2  * drawElements Quality Program OpenGL ES 3.1 Module
3  * -------------------------------------------------
4  *
5  * Copyright 2014 The Android Open Source Project
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  *
19  *//*!
20  * \file
21  * \brief Basic Compute Shader Tests.
22  *//*--------------------------------------------------------------------*/
23
24 #include "es31fAtomicCounterTests.hpp"
25
26 #include "gluShaderProgram.hpp"
27 #include "gluObjectWrapper.hpp"
28 #include "gluRenderContext.hpp"
29
30 #include "glwFunctions.hpp"
31 #include "glwEnums.hpp"
32
33 #include "tcuTestLog.hpp"
34
35 #include "deStringUtil.hpp"
36 #include "deRandom.hpp"
37 #include "deMemory.h"
38
39 #include <vector>
40 #include <string>
41
42 using namespace glw;
43 using tcu::TestLog;
44
45 using std::vector;
46 using std::string;
47
48 namespace deqp
49 {
50 namespace gles31
51 {
52 namespace Functional
53 {
54 namespace
55 {
56
57 class AtomicCounterTest : public TestCase
58 {
59 public:
60         enum Operation
61         {
62                 OPERATION_INC = (1<<0),
63                 OPERATION_DEC = (1<<1),
64                 OPERATION_GET = (1<<2)
65         };
66
67         enum OffsetType
68         {
69                 OFFSETTYPE_NONE = 0,
70                 OFFSETTYPE_BASIC,
71                 OFFSETTYPE_REVERSE,
72                 OFFSETTYPE_FIRST_AUTO,
73                 OFFSETTYPE_DEFAULT_AUTO,
74                 OFFSETTYPE_RESET_DEFAULT,
75                 OFFSETTYPE_INVALID,
76                 OFFSETTYPE_INVALID_OVERLAPPING,
77                 OFFSETTYPE_INVALID_DEFAULT
78         };
79
80         enum BindingType
81         {
82                 BINDINGTYPE_BASIC = 0,
83                 BINDINGTYPE_INVALID,
84                 BINDINGTYPE_INVALID_DEFAULT
85         };
86
87         struct TestSpec
88         {
89                 TestSpec (void)
90                         : atomicCounterCount    (0)
91                         , operations                    ((Operation)0)
92                         , callCount                             (0)
93                         , useBranches                   (false)
94                         , threadCount                   (0)
95                         , offsetType                    (OFFSETTYPE_NONE)
96                         , bindingType                   (BINDINGTYPE_BASIC)
97                 {
98                 }
99
100                 int                     atomicCounterCount;
101                 Operation       operations;
102                 int                     callCount;
103                 bool            useBranches;
104                 int                     threadCount;
105                 OffsetType      offsetType;
106                 BindingType     bindingType;
107         };
108
109                                                 AtomicCounterTest               (Context& context, const char* name, const char* description, const TestSpec& spec);
110                                                 ~AtomicCounterTest              (void);
111
112         void                            init                                            (void);
113         void                            deinit                                          (void);
114         IterateResult           iterate                                         (void);
115
116 private:
117         const TestSpec          m_spec;
118
119         bool                            checkAndLogCounterValues        (TestLog& log, const vector<deUint32>& counters) const;
120         bool                            checkAndLogCallValues           (TestLog& log, const vector<deUint32>& increments, const vector<deUint32>& decrements, const vector<deUint32>& preGets, const vector<deUint32>& postGets, const vector<deUint32>& gets) const;
121         void                            splitBuffer                                     (const vector<deUint32>& buffer, vector<deUint32>& increments, vector<deUint32>& decrements, vector<deUint32>& preGets, vector<deUint32>& postGets, vector<deUint32>& gets) const;
122         deUint32                        getInitialValue                         (void) const { return m_spec.callCount * m_spec.threadCount + 1; }
123
124         static string           generateShaderSource            (const TestSpec& spec);
125         static void                     getCountersValues                       (vector<deUint32>& counterValues, const vector<deUint32>& values, int ndx, int counterCount);
126         static bool                     checkRange                                      (TestLog& log, const vector<deUint32>& values, const vector<deUint32>& min, const vector<deUint32>& max);
127         static bool                     checkUniquenessAndLinearity     (TestLog& log, const vector<deUint32>& values);
128         static bool                     checkPath                                       (const vector<deUint32>& increments, const vector<deUint32>& decrements, int initialValue, const TestSpec& spec);
129
130         int                                     getOperationCount                       (void) const;
131
132         AtomicCounterTest&      operator=                                       (const AtomicCounterTest&);
133                                                 AtomicCounterTest                       (const AtomicCounterTest&);
134 };
135
136 int AtomicCounterTest::getOperationCount (void) const
137 {
138         int count = 0;
139
140         if (m_spec.operations & OPERATION_INC)
141                 count++;
142
143         if (m_spec.operations & OPERATION_DEC)
144                 count++;
145
146         if (m_spec.operations == OPERATION_GET)
147                 count++;
148         else if (m_spec.operations & OPERATION_GET)
149                 count += 2;
150
151         return count;
152 }
153
154 AtomicCounterTest::AtomicCounterTest (Context& context, const char* name, const char* description, const TestSpec& spec)
155         : TestCase      (context, name, description)
156         , m_spec        (spec)
157 {
158 }
159
160 AtomicCounterTest::~AtomicCounterTest (void)
161 {
162 }
163
164 void AtomicCounterTest::init (void)
165 {
166 }
167
168 void AtomicCounterTest::deinit (void)
169 {
170 }
171
172 string AtomicCounterTest::generateShaderSource (const TestSpec& spec)
173 {
174         std::ostringstream src;
175
176         src
177                 <<  "#version 310 es\n"
178                 << "layout (local_size_x = 1, local_size_y = 1, local_size_z = 1) in;\n";
179
180         {
181                 bool wroteLayout = false;
182
183                 switch (spec.bindingType)
184                 {
185                         case BINDINGTYPE_INVALID_DEFAULT:
186                                 src << "layout(binding=10000";
187                                 wroteLayout = true;
188                                 break;
189
190                         default:
191                                 // Do nothing
192                                 break;
193                 }
194
195                 switch (spec.offsetType)
196                 {
197                         case OFFSETTYPE_DEFAULT_AUTO:
198                                 if (!wroteLayout)
199                                         src << "layout(binding=1, ";
200                                 else
201                                         src << ", ";
202
203                                 src << "offset=4";
204                                 wroteLayout = true;
205                                 break;
206
207                         case OFFSETTYPE_RESET_DEFAULT:
208                                 DE_ASSERT(spec.atomicCounterCount > 2);
209
210                                 if (!wroteLayout)
211                                         src << "layout(binding=1, ";
212                                 else
213                                         src << ", ";
214
215                                 src << "offset=" << (4 * spec.atomicCounterCount/2);
216                                 wroteLayout = true;
217                                 break;
218
219                         case OFFSETTYPE_INVALID_DEFAULT:
220                                 if (!wroteLayout)
221                                         src << "layout(binding=1, ";
222                                 else
223                                         src << ", ";
224
225                                 src << "offset=1";
226                                 wroteLayout = true;
227                                 break;
228
229                         default:
230                                 // Do nothing
231                                 break;
232                 }
233
234                 if (wroteLayout)
235                         src << ") uniform atomic_uint;\n";
236         }
237
238         src
239         << "layout(binding = 1, std430) buffer Output {\n";
240
241         if ((spec.operations & OPERATION_GET) != 0 && spec.operations != OPERATION_GET)
242                 src << "        uint preGet[" << spec.threadCount * spec.atomicCounterCount * spec.callCount << "];\n";
243
244         if ((spec.operations & OPERATION_INC) != 0)
245                 src << "        uint increment[" << spec.threadCount * spec.atomicCounterCount * spec.callCount << "];\n";
246
247         if ((spec.operations & OPERATION_DEC) != 0)
248                 src << "        uint decrement[" << spec.threadCount * spec.atomicCounterCount * spec.callCount << "];\n";
249
250         if ((spec.operations & OPERATION_GET) != 0 && spec.operations != OPERATION_GET)
251                 src << "        uint postGet[" << spec.threadCount * spec.atomicCounterCount * spec.callCount << "];\n";
252
253         if (spec.operations == OPERATION_GET)
254                 src << "        uint get[" << spec.threadCount * spec.atomicCounterCount * spec.callCount << "];\n";
255
256         src << "} sb_in;\n\n";
257
258         for (int counterNdx = 0; counterNdx < spec.atomicCounterCount; counterNdx++)
259         {
260                 bool layoutStarted = false;
261
262                 if (spec.offsetType == OFFSETTYPE_RESET_DEFAULT && counterNdx == spec.atomicCounterCount/2)
263                         src << "layout(binding=1, offset=0) uniform atomic_uint;\n";
264
265                 switch (spec.bindingType)
266                 {
267                         case BINDINGTYPE_BASIC:
268                                 layoutStarted = true;
269                                 src << "layout(binding=1";
270                                 break;
271
272                         case BINDINGTYPE_INVALID:
273                                 layoutStarted = true;
274                                 src << "layout(binding=10000";
275                                 break;
276
277                         case BINDINGTYPE_INVALID_DEFAULT:
278                                 // Nothing
279                                 break;
280
281                         default:
282                                 DE_ASSERT(false);
283                 }
284
285                 switch (spec.offsetType)
286                 {
287                         case OFFSETTYPE_NONE:
288                                 if (layoutStarted)
289                                         src << ") ";
290
291                                 src << "uniform atomic_uint counter" << counterNdx << ";\n";
292
293                                 break;
294
295                         case OFFSETTYPE_BASIC:
296                                 if (!layoutStarted)
297                                         src << "layout(";
298                                 else
299                                         src << ", ";
300
301                                 src << "offset=" << (counterNdx * 4) << ") uniform atomic_uint counter" << counterNdx << ";\n";
302
303                                 break;
304
305                         case OFFSETTYPE_INVALID_DEFAULT:
306                                 if (layoutStarted)
307                                         src << ") ";
308
309                                 src << "uniform atomic_uint counter" << counterNdx << ";\n";
310
311                                 break;
312
313                         case OFFSETTYPE_INVALID:
314                                 if (!layoutStarted)
315                                         src << "layout(";
316                                 else
317                                         src << ", ";
318
319                                 src << "offset=" << (1 + counterNdx * 2) << ") uniform atomic_uint counter" << counterNdx << ";\n";
320
321                                 break;
322
323                         case OFFSETTYPE_INVALID_OVERLAPPING:
324                                 if (!layoutStarted)
325                                         src << "layout(";
326                                 else
327                                         src << ", ";
328
329                                 src << "offset=0) uniform atomic_uint counter" << counterNdx << ";\n";
330
331                                 break;
332
333                         case OFFSETTYPE_REVERSE:
334                                 if (!layoutStarted)
335                                         src << "layout(";
336                                 else
337                                         src << ", ";
338
339                                 src << "offset=" << (spec.atomicCounterCount - counterNdx - 1) * 4 << ") uniform atomic_uint counter" << (spec.atomicCounterCount - counterNdx - 1) << ";\n";
340
341                                 break;
342
343                         case OFFSETTYPE_FIRST_AUTO:
344                                 DE_ASSERT(spec.atomicCounterCount > 2);
345
346                                 if (counterNdx + 1 == spec.atomicCounterCount)
347                                 {
348                                         if (!layoutStarted)
349                                                 src << "layout(";
350                                         else
351                                                 src << ", ";
352
353                                         src << "offset=0) uniform atomic_uint counter0;\n";
354                                 }
355                                 else if (counterNdx == 0)
356                                 {
357                                         if (!layoutStarted)
358                                                 src << "layout(";
359                                         else
360                                                 src << ", ";
361
362                                         src << "offset=4) uniform atomic_uint counter1;\n";
363                                 }
364                                 else
365                                 {
366                                         if (layoutStarted)
367                                                 src << ") ";
368
369                                         src << "uniform atomic_uint counter" << (counterNdx + 1) << ";\n";
370                                 }
371
372                                 break;
373
374                         case OFFSETTYPE_DEFAULT_AUTO:
375                                 if (counterNdx + 1 == spec.atomicCounterCount)
376                                 {
377                                         if (!layoutStarted)
378                                                 src << "layout(";
379                                         else
380                                                 src << ", ";
381
382                                         src << "offset=0) uniform atomic_uint counter0;\n";
383                                 }
384                                 else
385                                 {
386                                         if (layoutStarted)
387                                                 src << ") ";
388
389                                         src << "uniform atomic_uint counter" << (counterNdx + 1) << ";\n";
390                                 }
391
392                                 break;
393
394                         case OFFSETTYPE_RESET_DEFAULT:
395                                 if (layoutStarted)
396                                         src << ") ";
397
398                                 if (counterNdx < spec.atomicCounterCount/2)
399                                         src << "uniform atomic_uint counter" << (counterNdx + spec.atomicCounterCount/2) << ";\n";
400                                 else
401                                         src << "uniform atomic_uint counter" << (counterNdx - spec.atomicCounterCount/2) << ";\n";
402
403                                 break;
404
405                         default:
406                                 DE_ASSERT(false);
407                 }
408         }
409
410         src
411         << "\n"
412         << "void main (void)\n"
413         << "{\n";
414
415         if (spec.callCount > 1)
416                 src << "\tfor (uint i = 0u; i < " << spec.callCount << "u; i++)\n";
417
418         src
419         << "\t{\n"
420         << "\t\tuint id = (gl_GlobalInvocationID.x";
421
422         if (spec.callCount > 1)
423                 src << " * "<< spec.callCount << "u";
424
425         if (spec.callCount > 1)
426                 src << " + i)";
427         else
428                 src << ")";
429
430         if  (spec.atomicCounterCount > 1)
431                 src << " * " << spec.atomicCounterCount << "u";
432
433         src << ";\n";
434
435         for (int counterNdx = 0; counterNdx < spec.atomicCounterCount; counterNdx++)
436         {
437                 if ((spec.operations & OPERATION_GET) != 0 && spec.operations != OPERATION_GET)
438                         src << "\t\tsb_in.preGet[id + " << counterNdx << "u] = atomicCounter(counter" << counterNdx << ");\n";
439
440                 if (spec.useBranches && ((spec.operations & (OPERATION_INC|OPERATION_DEC)) == (OPERATION_INC|OPERATION_DEC)))
441                 {
442                         src
443                         << "\t\tif (((gl_GlobalInvocationID.x" << (spec.callCount > 1 ? " + i" : "") << ") % 2u) == 0u)\n"
444                         << "\t\t{\n"
445                         << "\t\t\tsb_in.increment[id + " << counterNdx << "u] = atomicCounterIncrement(counter" << counterNdx << ");\n"
446                         << "\t\t\tsb_in.decrement[id + " << counterNdx << "u] = uint(-1);\n"
447                         << "\t\t}\n"
448                         << "\t\telse\n"
449                         << "\t\t{\n"
450                         << "\t\t\tsb_in.decrement[id + " << counterNdx << "u] = atomicCounterDecrement(counter" << counterNdx << ") + 1u;\n"
451                         << "\t\t\tsb_in.increment[id + " << counterNdx << "u] = uint(-1);\n"
452                         << "\t\t}\n";
453                 }
454                 else
455                 {
456                         if ((spec.operations & OPERATION_INC) != 0)
457                         {
458                                 if (spec.useBranches)
459                                 {
460                                         src
461                                         << "\t\tif (((gl_GlobalInvocationID.x" << (spec.callCount > 1 ? " + i" : "") << ") % 2u) == 0u)\n"
462                                         << "\t\t{\n"
463                                         << "\t\t\tsb_in.increment[id + " << counterNdx << "u] = atomicCounterIncrement(counter" << counterNdx << ");\n"
464                                         << "\t\t}\n"
465                                         << "\t\telse\n"
466                                         << "\t\t{\n"
467                                         << "\t\t\tsb_in.increment[id + " << counterNdx << "u] = uint(-1);\n"
468                                         << "\t\t}\n";
469
470                                 }
471                                 else
472                                         src << "\t\tsb_in.increment[id + " << counterNdx << "u] = atomicCounterIncrement(counter" << counterNdx << ");\n";
473                         }
474
475                         if ((spec.operations & OPERATION_DEC) != 0)
476                         {
477                                 if (spec.useBranches)
478                                 {
479                                         src
480                                         << "\t\tif (((gl_GlobalInvocationID.x" << (spec.callCount > 1 ? " + i" : "") << ") % 2u) == 0u)\n"
481                                         << "\t\t{\n"
482                                         << "\t\t\tsb_in.decrement[id + " << counterNdx << "u] = atomicCounterDecrement(counter" << counterNdx << ") + 1u;\n"
483                                         << "\t\t}\n"
484                                         << "\t\telse\n"
485                                         << "\t\t{\n"
486                                         << "\t\t\tsb_in.decrement[id + " << counterNdx << "u] = uint(-1);\n"
487                                         << "\t\t}\n";
488
489                                 }
490                                 else
491                                         src << "\t\tsb_in.decrement[id + " << counterNdx << "u] = atomicCounterDecrement(counter" << counterNdx << ") + 1u;\n";
492                         }
493                 }
494
495                 if ((spec.operations & OPERATION_GET) != 0 && spec.operations != OPERATION_GET)
496                         src << "\t\tsb_in.postGet[id + " << counterNdx << "u] = atomicCounter(counter" << counterNdx << ");\n";
497
498                 if ((spec.operations == OPERATION_GET) != 0)
499                 {
500                         if (spec.useBranches)
501                         {
502                                 src
503                                 << "\t\tif (((gl_GlobalInvocationID.x" << (spec.callCount > 1 ? " + i" : "") << ") % 2u) == 0u)\n"
504                                 << "\t\t{\n"
505                                 << "\t\t\tsb_in.get[id + " << counterNdx << "u] = atomicCounter(counter" << counterNdx << ");\n"
506                                 << "\t\t}\n"
507                                 << "\t\telse\n"
508                                 << "\t\t{\n"
509                                 << "\t\t\tsb_in.get[id + " << counterNdx << "u] = uint(-1);\n"
510                                 << "\t\t}\n";
511                         }
512                         else
513                                 src << "\t\tsb_in.get[id + " << counterNdx << "u] = atomicCounter(counter" << counterNdx << ");\n";
514                 }
515         }
516
517         src
518         << "\t}\n"
519         << "}\n";
520
521         return src.str();
522 }
523
524 bool AtomicCounterTest::checkAndLogCounterValues (TestLog& log, const vector<deUint32>& counters) const
525 {
526         tcu::ScopedLogSection   counterSection  (log, "Counter info", "Show initial value, current value and expected value of each counter.");
527         bool                                    isOk                    = true;
528
529         // Check that atomic counters have sensible results
530         for (int counterNdx = 0; counterNdx < (int)counters.size(); counterNdx++)
531         {
532                 const deUint32  value                   = counters[counterNdx];
533                 const deUint32  initialValue    = getInitialValue();
534                 deUint32                expectedValue   = (deUint32)-1;
535
536                 if ((m_spec.operations & OPERATION_INC) != 0 && (m_spec.operations & OPERATION_DEC) == 0)
537                         expectedValue = initialValue + (m_spec.useBranches ? m_spec.threadCount*m_spec.callCount - m_spec.threadCount*m_spec.callCount/2 : m_spec.threadCount*m_spec.callCount);
538
539                 if ((m_spec.operations & OPERATION_INC) == 0 && (m_spec.operations & OPERATION_DEC) != 0)
540                         expectedValue = initialValue - (m_spec.useBranches ? m_spec.threadCount*m_spec.callCount - m_spec.threadCount*m_spec.callCount/2 : m_spec.threadCount*m_spec.callCount);
541
542                 if ((m_spec.operations & OPERATION_INC) != 0 && (m_spec.operations & OPERATION_DEC) != 0)
543                         expectedValue = initialValue + (m_spec.useBranches ? m_spec.threadCount*m_spec.callCount - m_spec.threadCount*m_spec.callCount/2 : 0) - (m_spec.useBranches ? m_spec.threadCount*m_spec.callCount/2 : 0);
544
545                 if ((m_spec.operations & OPERATION_INC) == 0 && (m_spec.operations & OPERATION_DEC) == 0)
546                         expectedValue = initialValue;
547
548                 log << TestLog::Message << "atomic_uint counter" << counterNdx << " initial value: " << initialValue << ", value: " << value << ", expected: " << expectedValue << (value == expectedValue ? "" : ", failed!") << TestLog::EndMessage;
549
550                 if (value != expectedValue)
551                         isOk = false;
552         }
553
554         return isOk;
555 }
556
557 void AtomicCounterTest::splitBuffer (const vector<deUint32>& buffer, vector<deUint32>& increments, vector<deUint32>& decrements, vector<deUint32>& preGets, vector<deUint32>& postGets, vector<deUint32>& gets) const
558 {
559         const int bufferValueCount      = m_spec.callCount * m_spec.threadCount * m_spec.atomicCounterCount;
560
561         int firstPreGet                         = -1;
562         int firstPostGet                        = -1;
563         int     firstGet                                = -1;
564         int firstInc                            = -1;
565         int firstDec                            = -1;
566
567         increments.clear();
568         decrements.clear();
569         preGets.clear();
570         postGets.clear();
571         gets.clear();
572
573         if (m_spec.operations == OPERATION_GET)
574                 firstGet = 0;
575         else if (m_spec.operations == OPERATION_INC)
576                 firstInc = 0;
577         else if (m_spec.operations == OPERATION_DEC)
578                 firstDec = 0;
579         else if (m_spec.operations == (OPERATION_GET|OPERATION_INC))
580         {
581                 firstPreGet             = 0;
582                 firstInc                = bufferValueCount;
583                 firstPostGet    = bufferValueCount * 2;
584         }
585         else if (m_spec.operations == (OPERATION_GET|OPERATION_DEC))
586         {
587                 firstPreGet             = 0;
588                 firstDec                = bufferValueCount;
589                 firstPostGet    = bufferValueCount * 2;
590         }
591         else if (m_spec.operations == (OPERATION_GET|OPERATION_DEC|OPERATION_INC))
592         {
593                 firstPreGet             = 0;
594                 firstInc                = bufferValueCount;
595                 firstDec                = bufferValueCount * 2;
596                 firstPostGet    = bufferValueCount * 3;
597         }
598         else if (m_spec.operations == (OPERATION_DEC|OPERATION_INC))
599         {
600                 firstInc                = 0;
601                 firstDec                = bufferValueCount;
602         }
603         else
604                 DE_ASSERT(false);
605
606         for (int threadNdx = 0; threadNdx < m_spec.threadCount; threadNdx++)
607         {
608                 for (int callNdx = 0; callNdx < m_spec.callCount; callNdx++)
609                 {
610                         for (int counterNdx = 0; counterNdx < m_spec.atomicCounterCount; counterNdx++)
611                         {
612                                 const int id = ((threadNdx * m_spec.callCount) + callNdx) * m_spec.atomicCounterCount + counterNdx;
613
614                                 if (firstInc != -1)
615                                         increments.push_back(buffer[firstInc + id]);
616
617                                 if (firstDec != -1)
618                                         decrements.push_back(buffer[firstDec + id]);
619
620                                 if (firstPreGet != -1)
621                                         preGets.push_back(buffer[firstPreGet + id]);
622
623                                 if (firstPostGet != -1)
624                                         postGets.push_back(buffer[firstPostGet + id]);
625
626                                 if (firstGet != -1)
627                                         gets.push_back(buffer[firstGet + id]);
628                         }
629                 }
630         }
631 }
632
633 void AtomicCounterTest::getCountersValues (vector<deUint32>& counterValues, const vector<deUint32>& values, int ndx, int counterCount)
634 {
635         counterValues.resize(values.size()/counterCount, 0);
636
637         DE_ASSERT(values.size() % counterCount == 0);
638
639         for (int valueNdx = 0; valueNdx < (int)counterValues.size(); valueNdx++)
640                 counterValues[valueNdx] = values[valueNdx * counterCount + ndx];
641 }
642
643 bool AtomicCounterTest::checkRange (TestLog& log, const vector<deUint32>& values, const vector<deUint32>& min, const vector<deUint32>& max)
644 {
645         int failedCount = 0;
646
647         DE_ASSERT(values.size() == min.size());
648         DE_ASSERT(values.size() == max.size());
649
650         for (int valueNdx = 0; valueNdx < (int)values.size(); valueNdx++)
651         {
652                 if (values[valueNdx] != (deUint32)-1)
653                 {
654                         if (!deInRange32(values[valueNdx], min[valueNdx], max[valueNdx]))
655                         {
656                                 if (failedCount < 20)
657                                         log << TestLog::Message << "Value " << values[valueNdx] << " not in range [" << min[valueNdx] << ", " << max[valueNdx] << "]." << TestLog::EndMessage;
658                                 failedCount++;
659                         }
660                 }
661         }
662
663         if (failedCount > 20)
664                 log << TestLog::Message << "Number of values not in range: " << failedCount << ", displaying first 20 values." << TestLog::EndMessage;
665
666         return failedCount == 0;
667 }
668
669 bool AtomicCounterTest::checkUniquenessAndLinearity (TestLog& log, const vector<deUint32>& values)
670 {
671         vector<deUint32>        counts;
672         int                                     failedCount     = 0;
673         deUint32                        minValue        = (deUint32)-1;
674         deUint32                        maxValue        = 0;
675
676         DE_ASSERT(!values.empty());
677
678         for (int valueNdx = 0; valueNdx < (int)values.size(); valueNdx++)
679         {
680                 if (values[valueNdx] != (deUint32)-1)
681                 {
682                         minValue = std::min(minValue, values[valueNdx]);
683                         maxValue = std::max(maxValue, values[valueNdx]);
684                 }
685         }
686
687         counts.resize(maxValue - minValue + 1, 0);
688
689         for (int valueNdx = 0; valueNdx < (int)values.size(); valueNdx++)
690         {
691                 if (values[valueNdx] != (deUint32)-1)
692                         counts[values[valueNdx] - minValue]++;
693         }
694
695         for (int countNdx = 0; countNdx < (int)counts.size(); countNdx++)
696         {
697                 if (counts[countNdx] != 1)
698                 {
699                         if (failedCount < 20)
700                                 log << TestLog::Message << "Value " << (minValue + countNdx) << " is not unique. Returned " << counts[countNdx] << " times." << TestLog::EndMessage;
701
702                         failedCount++;
703                 }
704         }
705
706         if (failedCount > 20)
707                 log << TestLog::Message << "Number of values not unique: " << failedCount << ", displaying first 20 values." << TestLog::EndMessage;
708
709         return failedCount == 0;
710 }
711
712 bool AtomicCounterTest::checkPath (const vector<deUint32>& increments, const vector<deUint32>& decrements, int initialValue, const TestSpec& spec)
713 {
714         const deUint32          lastValue       = initialValue + (spec.useBranches ? spec.threadCount*spec.callCount - spec.threadCount*spec.callCount/2 : 0) - (spec.useBranches ? spec.threadCount*spec.callCount/2 : 0);
715         bool                            isOk            = true;
716
717         vector<deUint32>        incrementCounts;
718         vector<deUint32>        decrementCounts;
719
720         deUint32                        minValue = 0xFFFFFFFFu;
721         deUint32                        maxValue = 0;
722
723         for (int valueNdx = 0; valueNdx < (int)increments.size(); valueNdx++)
724         {
725                 if (increments[valueNdx] != (deUint32)-1)
726                 {
727                         minValue = std::min(minValue, increments[valueNdx]);
728                         maxValue = std::max(maxValue, increments[valueNdx]);
729                 }
730         }
731
732         for (int valueNdx = 0; valueNdx < (int)decrements.size(); valueNdx++)
733         {
734                 if (decrements[valueNdx] != (deUint32)-1)
735                 {
736                         minValue = std::min(minValue, decrements[valueNdx]);
737                         maxValue = std::max(maxValue, decrements[valueNdx]);
738                 }
739         }
740
741         minValue = std::min(minValue, (deUint32)initialValue);
742         maxValue = std::max(maxValue, (deUint32)initialValue);
743
744         incrementCounts.resize(maxValue - minValue + 1, 0);
745         decrementCounts.resize(maxValue - minValue + 1, 0);
746
747         for (int valueNdx = 0; valueNdx < (int)increments.size(); valueNdx++)
748         {
749                 if (increments[valueNdx] != (deUint32)-1)
750                         incrementCounts[increments[valueNdx] - minValue]++;
751         }
752
753         for (int valueNdx = 0; valueNdx < (int)decrements.size(); valueNdx++)
754         {
755                 if (decrements[valueNdx] != (deUint32)-1)
756                         decrementCounts[decrements[valueNdx] - minValue]++;
757         }
758
759         int pos = initialValue - minValue;
760
761         while (incrementCounts[pos] + decrementCounts[pos] != 0)
762         {
763                 if (incrementCounts[pos] > 0 && pos >= (int)(lastValue - minValue))
764                 {
765                         // If can increment and incrementation would move us away from result value, increment
766                         incrementCounts[pos]--;
767                         pos++;
768                 }
769                 else if (decrementCounts[pos] > 0)
770                 {
771                         // If can, decrement
772                         decrementCounts[pos]--;
773                         pos--;
774                 }
775                 else if (incrementCounts[pos] > 0)
776                 {
777                         // If increment moves closer to result value and can't decrement, increment
778                         incrementCounts[pos]--;
779                         pos++;
780                 }
781                 else
782                         DE_ASSERT(false);
783
784                 if (pos < 0 || pos >= (int)incrementCounts.size())
785                         break;
786         }
787
788         if (minValue + pos != lastValue)
789                 isOk = false;
790
791         for (int valueNdx = 0; valueNdx < (int)incrementCounts.size(); valueNdx++)
792         {
793                 if (incrementCounts[valueNdx] != 0)
794                         isOk = false;
795         }
796
797         for (int valueNdx = 0; valueNdx < (int)decrementCounts.size(); valueNdx++)
798         {
799                 if (decrementCounts[valueNdx] != 0)
800                         isOk = false;
801         }
802
803         return isOk;
804 }
805
806 bool AtomicCounterTest::checkAndLogCallValues (TestLog& log, const vector<deUint32>& increments, const vector<deUint32>& decrements, const vector<deUint32>& preGets, const vector<deUint32>& postGets, const vector<deUint32>& gets) const
807 {
808         bool isOk = true;
809
810         for (int counterNdx = 0; counterNdx < m_spec.atomicCounterCount; counterNdx++)
811         {
812                 vector<deUint32> counterIncrements;
813                 vector<deUint32> counterDecrements;
814                 vector<deUint32> counterPreGets;
815                 vector<deUint32> counterPostGets;
816                 vector<deUint32> counterGets;
817
818                 getCountersValues(counterIncrements,    increments,     counterNdx, m_spec.atomicCounterCount);
819                 getCountersValues(counterDecrements,    decrements,     counterNdx, m_spec.atomicCounterCount);
820                 getCountersValues(counterPreGets,               preGets,        counterNdx, m_spec.atomicCounterCount);
821                 getCountersValues(counterPostGets,              postGets,       counterNdx, m_spec.atomicCounterCount);
822                 getCountersValues(counterGets,                  gets,           counterNdx, m_spec.atomicCounterCount);
823
824                 if (m_spec.operations == OPERATION_GET)
825                 {
826                         tcu::ScopedLogSection valueCheck(log, ("counter" + de::toString(counterNdx) + " value check").c_str(), ("Check that counter" + de::toString(counterNdx) + " values haven't changed.").c_str());
827                         int changedValues = 0;
828
829                         for (int valueNdx = 0; valueNdx < (int)gets.size(); valueNdx++)
830                         {
831                                 if ((!m_spec.useBranches || gets[valueNdx] != (deUint32)-1) && gets[valueNdx] != getInitialValue())
832                                 {
833                                         if (changedValues < 20)
834                                                 log << TestLog::Message << "atomicCounter(counter" << counterNdx << ") returned " << gets[valueNdx] << " expected " << getInitialValue() << TestLog::EndMessage;
835                                         isOk = false;
836                                         changedValues++;
837                                 }
838                         }
839
840                         if (changedValues == 0)
841                                 log << TestLog::Message << "All values returned by atomicCounter(counter" << counterNdx << ") match initial value " << getInitialValue() <<  "." << TestLog::EndMessage;
842                         else if (changedValues > 20)
843                                 log << TestLog::Message << "Total number of invalid values returned by atomicCounter(counter" << counterNdx << ") " << changedValues << " displaying first 20 values." <<  TestLog::EndMessage;
844                 }
845                 else if ((m_spec.operations & (OPERATION_INC|OPERATION_DEC)) == (OPERATION_INC|OPERATION_DEC))
846                 {
847                         tcu::ScopedLogSection valueCheck(log, ("counter" + de::toString(counterNdx) + " path check").c_str(), ("Check that there is order in which counter" + de::toString(counterNdx) + " increments and decrements could have happened.").c_str());
848                         if (!checkPath(counterIncrements, counterDecrements, getInitialValue(), m_spec))
849                         {
850                                 isOk = false;
851                                 log << TestLog::Message << "No possible order of calls to atomicCounterIncrement(counter" << counterNdx << ") and atomicCounterDecrement(counter" << counterNdx << ") found." << TestLog::EndMessage;
852                         }
853                         else
854                                 log << TestLog::Message << "Found possible order of calls to atomicCounterIncrement(counter" << counterNdx << ") and atomicCounterDecrement(counter" << counterNdx << ")." << TestLog::EndMessage;
855                 }
856                 else if ((m_spec.operations & OPERATION_INC) != 0)
857                 {
858                         {
859                                 tcu::ScopedLogSection uniquenesCheck(log, ("counter" + de::toString(counterNdx) + " check uniqueness and linearity").c_str(), ("Check that counter" + de::toString(counterNdx) + " returned only unique and linear values.").c_str());
860
861                                 if (!checkUniquenessAndLinearity(log, counterIncrements))
862                                 {
863                                         isOk = false;
864                                         log << TestLog::Message << "atomicCounterIncrement(counter" << counterNdx << ") returned non unique values." << TestLog::EndMessage;
865                                 }
866                                 else
867                                         log << TestLog::Message << "atomicCounterIncrement(counter" << counterNdx << ") returned only unique values." << TestLog::EndMessage;
868                         }
869
870                         if (isOk && ((m_spec.operations & OPERATION_GET) != 0))
871                         {
872                                 tcu::ScopedLogSection uniquenesCheck(log, ("counter" + de::toString(counterNdx) + " check range").c_str(), ("Check that counter" + de::toString(counterNdx) + " returned only values values between previous and next atomicCounter(counter" + de::toString(counterNdx) + ").").c_str());
873
874                                 if (!checkRange(log, counterIncrements, counterPreGets, counterPostGets))
875                                 {
876                                         isOk = false;
877                                         log << TestLog::Message << "atomicCounterIncrement(counter" << counterNdx << ") returned value that is not between previous and next call to atomicCounter(counter" << counterNdx << ")." << TestLog::EndMessage;
878                                 }
879                                 else
880                                         log << TestLog::Message << "atomicCounterIncrement(counter" << counterNdx << ") returned only values between previous and next call to atomicCounter(counter" << counterNdx << ")." << TestLog::EndMessage;
881                         }
882                 }
883                 else if ((m_spec.operations & OPERATION_DEC) != 0)
884                 {
885                         {
886                                 tcu::ScopedLogSection uniquenesCheck(log, ("counter" + de::toString(counterNdx) + " check uniqueness and linearity").c_str(), ("Check that counter" + de::toString(counterNdx) + " returned only unique and linear values.").c_str());
887
888                                 if (!checkUniquenessAndLinearity(log, counterDecrements))
889                                 {
890                                         isOk = false;
891                                         log << TestLog::Message << "atomicCounterDecrement(counter" << counterNdx << ") returned non unique values." << TestLog::EndMessage;
892                                 }
893                                 else
894                                         log << TestLog::Message << "atomicCounterDecrement(counter" << counterNdx << ") returned only unique values." << TestLog::EndMessage;
895                         }
896
897                         if (isOk && ((m_spec.operations & OPERATION_GET) != 0))
898                         {
899                                 tcu::ScopedLogSection uniquenesCheck(log, ("counter" + de::toString(counterNdx) + " check range").c_str(), ("Check that counter" + de::toString(counterNdx) + " returned only values values between previous and next atomicCounter(counter" + de::toString(counterNdx) + ".").c_str());
900
901                                 if (!checkRange(log, counterDecrements, counterPostGets, counterPreGets))
902                                 {
903                                         isOk = false;
904                                         log << TestLog::Message << "atomicCounterDecrement(counter" << counterNdx << ") returned value that is not between previous and next call to atomicCounter(counter" << counterNdx << ")." << TestLog::EndMessage;
905                                 }
906                                 else
907                                         log << TestLog::Message << "atomicCounterDecrement(counter" << counterNdx << ") returned only values between previous and next call to atomicCounter(counter" << counterNdx << ")." << TestLog::EndMessage;
908                         }
909                 }
910         }
911
912         return isOk;
913 }
914
915 TestCase::IterateResult AtomicCounterTest::iterate (void)
916 {
917         const glw::Functions&           gl                                      = m_context.getRenderContext().getFunctions();
918         TestLog&                                        log                                     = m_testCtx.getLog();
919         const glu::Buffer                       counterBuffer           (m_context.getRenderContext());
920         const glu::Buffer                       outputBuffer            (m_context.getRenderContext());
921         const glu::ShaderProgram        program                         (m_context.getRenderContext(), glu::ProgramSources() << glu::ShaderSource(glu::SHADERTYPE_COMPUTE, generateShaderSource(m_spec)));
922
923         const deInt32                           counterBufferSize       = m_spec.atomicCounterCount * 4;
924         const deInt32                           ssoSize                         = m_spec.atomicCounterCount * m_spec.callCount * m_spec.threadCount * 4 * getOperationCount();
925
926         log << program;
927
928         if (m_spec.offsetType == OFFSETTYPE_INVALID || m_spec.offsetType == OFFSETTYPE_INVALID_DEFAULT || m_spec.bindingType == BINDINGTYPE_INVALID || m_spec.bindingType == BINDINGTYPE_INVALID_DEFAULT || m_spec.offsetType == OFFSETTYPE_INVALID_OVERLAPPING)
929         {
930                 if (program.isOk())
931                 {
932                         log << TestLog::Message << "Expected program to fail, but compilation passed." << TestLog::EndMessage;
933                         m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Compile succeeded");
934                         return STOP;
935                 }
936                 else
937                 {
938                         log << TestLog::Message << "Compilation failed as expected." << TestLog::EndMessage;
939                         m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Compile failed");
940                         return STOP;
941                 }
942         }
943         else if (!program.isOk())
944         {
945                 log << TestLog::Message << "Compile failed." << TestLog::EndMessage;
946                 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Compile failed");
947                 return STOP;
948         }
949
950         gl.useProgram(program.getProgram());
951         GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram()");
952
953         // Create output buffer
954         gl.bindBuffer(GL_SHADER_STORAGE_BUFFER, *outputBuffer);
955         gl.bufferData(GL_SHADER_STORAGE_BUFFER, ssoSize, NULL, GL_STATIC_DRAW);
956         GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to create output buffer");
957
958         // Create atomic counter buffer
959         {
960                 vector<deUint32> data(m_spec.atomicCounterCount, getInitialValue());
961                 gl.bindBuffer(GL_SHADER_STORAGE_BUFFER, *counterBuffer);
962                 gl.bufferData(GL_SHADER_STORAGE_BUFFER, counterBufferSize, &(data[0]), GL_STATIC_DRAW);
963                 GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to create buffer for atomic counters");
964         }
965
966         // Bind output buffer
967         gl.bindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, *outputBuffer);
968         GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to setup output buffer");
969
970         // Bind atomic counter buffer
971         gl.bindBufferBase(GL_ATOMIC_COUNTER_BUFFER, 1, *counterBuffer);
972         GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to setup atomic counter buffer");
973
974         // Dispath compute
975         gl.dispatchCompute(m_spec.threadCount, 1, 1);
976         GLU_EXPECT_NO_ERROR(gl.getError(), "glDispatchCompute()");
977
978         gl.finish();
979         GLU_EXPECT_NO_ERROR(gl.getError(), "glFinish()");
980
981         vector<deUint32> output(ssoSize/4, 0);
982         vector<deUint32> counters(m_spec.atomicCounterCount, 0);
983
984         // Read back output buffer
985         {
986                 gl.bindBuffer(GL_SHADER_STORAGE_BUFFER, *outputBuffer);
987                 GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer()");
988
989                 void* ptr = gl.mapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, (GLsizeiptr)(output.size() * sizeof(deUint32)), GL_MAP_READ_BIT);
990                 GLU_EXPECT_NO_ERROR(gl.getError(), "glMapBufferRange()");
991
992                 deMemcpy(&(output[0]), ptr, (int)output.size() * sizeof(deUint32));
993
994                 if (!gl.unmapBuffer(GL_SHADER_STORAGE_BUFFER))
995                 {
996                         GLU_EXPECT_NO_ERROR(gl.getError(), "glUnmapBuffer()");
997                         TCU_CHECK_MSG(false, "Mapped buffer corrupted");
998                 }
999
1000                 gl.bindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
1001                 GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer()");
1002         }
1003
1004         // Read back counter buffer
1005         {
1006                 gl.bindBuffer(GL_SHADER_STORAGE_BUFFER, *counterBuffer);
1007                 GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer()");
1008
1009                 void* ptr = gl.mapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, (GLsizeiptr)(counters.size() * sizeof(deUint32)), GL_MAP_READ_BIT);
1010                 GLU_EXPECT_NO_ERROR(gl.getError(), "glMapBufferRange()");
1011
1012                 deMemcpy(&(counters[0]), ptr, (int)counters.size() * sizeof(deUint32));
1013
1014                 if (!gl.unmapBuffer(GL_SHADER_STORAGE_BUFFER))
1015                 {
1016                         GLU_EXPECT_NO_ERROR(gl.getError(), "glUnmapBuffer()");
1017                         TCU_CHECK_MSG(false, "Mapped buffer corrupted");
1018                 }
1019
1020                 gl.bindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
1021                 GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer()");
1022         }
1023
1024         bool isOk = true;
1025
1026         if (!checkAndLogCounterValues(log, counters))
1027                 isOk = false;
1028
1029         {
1030                 vector<deUint32> increments;
1031                 vector<deUint32> decrements;
1032                 vector<deUint32> preGets;
1033                 vector<deUint32> postGets;
1034                 vector<deUint32> gets;
1035
1036                 splitBuffer(output, increments, decrements, preGets, postGets, gets);
1037
1038                 if (!checkAndLogCallValues(log, increments, decrements, preGets, postGets, gets))
1039                         isOk = false;
1040         }
1041
1042         if (isOk)
1043                 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
1044         else
1045                 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
1046
1047         return STOP;
1048 }
1049
1050 string specToTestName (const AtomicCounterTest::TestSpec& spec)
1051 {
1052         std::ostringstream stream;
1053
1054         stream << spec.atomicCounterCount       << (spec.atomicCounterCount == 1 ? "_counter" : "_counters");
1055         stream << "_" << spec.callCount         << (spec.callCount == 1 ? "_call" : "_calls");
1056         stream << "_" << spec.threadCount       << (spec.threadCount == 1 ? "_thread" : "_threads");
1057
1058         return stream.str();
1059 }
1060
1061 string specToTestDescription (const AtomicCounterTest::TestSpec& spec)
1062 {
1063         std::ostringstream      stream;
1064         bool                            firstOperation = 0;
1065
1066         stream
1067         << "Test ";
1068
1069         if ((spec.operations & AtomicCounterTest::OPERATION_GET) != 0)
1070         {
1071                 stream << "atomicCounter()";
1072                 firstOperation = false;
1073         }
1074
1075         if ((spec.operations & AtomicCounterTest::OPERATION_INC) != 0)
1076         {
1077                 if (!firstOperation)
1078                         stream << ", ";
1079
1080                 stream << " atomicCounterIncrement()";
1081                 firstOperation = false;
1082         }
1083
1084         if ((spec.operations & AtomicCounterTest::OPERATION_DEC) != 0)
1085         {
1086                 if (!firstOperation)
1087                         stream << ", ";
1088
1089                 stream << " atomicCounterDecrement()";
1090                 firstOperation = false;
1091         }
1092
1093         stream << " calls with ";
1094
1095         if (spec.useBranches)
1096                 stream << " branches, ";
1097
1098         stream << spec.atomicCounterCount << " atomic counters, " << spec.callCount << " calls and " << spec.threadCount << " threads.";
1099
1100         return stream.str();
1101 }
1102
1103 string operationToName (const AtomicCounterTest::Operation& operations, bool useBranch)
1104 {
1105         std::ostringstream      stream;
1106         bool                            first = true;
1107
1108         if ((operations & AtomicCounterTest::OPERATION_GET) != 0)
1109         {
1110                 stream << "get";
1111                 first = false;
1112         }
1113
1114         if ((operations & AtomicCounterTest::OPERATION_INC) != 0)
1115         {
1116                 if (!first)
1117                         stream << "_";
1118
1119                 stream << "inc";
1120                 first = false;
1121         }
1122
1123         if ((operations & AtomicCounterTest::OPERATION_DEC) != 0)
1124         {
1125                 if (!first)
1126                         stream << "_";
1127
1128                 stream << "dec";
1129                 first = false;
1130         }
1131
1132         if (useBranch)
1133                 stream << "_branch";
1134
1135         return stream.str();
1136 }
1137
1138 string operationToDescription (const AtomicCounterTest::Operation& operations, bool useBranch)
1139 {
1140         std::ostringstream      stream;
1141         bool                            firstOperation = 0;
1142
1143         stream
1144         << "Test ";
1145
1146         if ((operations & AtomicCounterTest::OPERATION_GET) != 0)
1147         {
1148                 stream << "atomicCounter()";
1149                 firstOperation = false;
1150         }
1151
1152         if ((operations & AtomicCounterTest::OPERATION_INC) != 0)
1153         {
1154                 if (!firstOperation)
1155                         stream << ", ";
1156
1157                 stream << " atomicCounterIncrement()";
1158                 firstOperation = false;
1159         }
1160
1161         if ((operations & AtomicCounterTest::OPERATION_DEC) != 0)
1162         {
1163                 if (!firstOperation)
1164                         stream << ", ";
1165
1166                 stream << " atomicCounterDecrement()";
1167                 firstOperation = false;
1168         }
1169
1170
1171         if (useBranch)
1172                 stream << " calls with branches.";
1173         else
1174                 stream << ".";
1175
1176         return stream.str();
1177 }
1178
1179 string layoutTypesToName (const AtomicCounterTest::BindingType& bindingType, const AtomicCounterTest::OffsetType& offsetType)
1180 {
1181         std::ostringstream      stream;
1182
1183         switch (bindingType)
1184         {
1185                 case AtomicCounterTest::BINDINGTYPE_BASIC:
1186                         // Nothing
1187                         break;
1188
1189                 case AtomicCounterTest::BINDINGTYPE_INVALID:
1190                         stream << "invalid_binding";
1191                         break;
1192
1193                 default:
1194                         DE_ASSERT(false);
1195         }
1196
1197         if (bindingType != AtomicCounterTest::BINDINGTYPE_BASIC && offsetType != AtomicCounterTest::OFFSETTYPE_NONE)
1198                 stream << "_";
1199
1200         switch (offsetType)
1201         {
1202                 case AtomicCounterTest::OFFSETTYPE_BASIC:
1203                         stream << "basic_offset";
1204                         break;
1205
1206                 case AtomicCounterTest::OFFSETTYPE_REVERSE:
1207                         stream << "reverse_offset";
1208                         break;
1209
1210                 case AtomicCounterTest::OFFSETTYPE_INVALID:
1211                         stream << "invalid_offset";
1212                         break;
1213
1214                 case AtomicCounterTest::OFFSETTYPE_FIRST_AUTO:
1215                         stream << "first_offset_set";
1216                         break;
1217
1218                 case AtomicCounterTest::OFFSETTYPE_DEFAULT_AUTO:
1219                         stream << "default_offset_set";
1220                         break;
1221
1222                 case AtomicCounterTest::OFFSETTYPE_RESET_DEFAULT:
1223                         stream << "reset_default_offset";
1224                         break;
1225
1226                 case AtomicCounterTest::OFFSETTYPE_NONE:
1227                         // Do nothing
1228                         break;
1229
1230                 default:
1231                         DE_ASSERT(false);
1232         }
1233
1234         return stream.str();
1235 }
1236
1237 string layoutTypesToDesc (const AtomicCounterTest::BindingType& bindingType, const AtomicCounterTest::OffsetType& offsetType)
1238 {
1239         std::ostringstream      stream;
1240
1241         switch (bindingType)
1242         {
1243                 case AtomicCounterTest::BINDINGTYPE_BASIC:
1244                         stream << "Test using atomic counters with explicit layout bindings and";
1245                         break;
1246
1247                 case AtomicCounterTest::BINDINGTYPE_INVALID:
1248                         stream << "Test using atomic counters with invalid explicit layout bindings and";
1249                         break;
1250
1251                 case AtomicCounterTest::BINDINGTYPE_INVALID_DEFAULT:
1252                         stream << "Test using atomic counters with invalid default layout binding and";
1253                         break;
1254
1255                 default:
1256                         DE_ASSERT(false);
1257         }
1258
1259         switch (offsetType)
1260         {
1261                 case AtomicCounterTest::OFFSETTYPE_NONE:
1262                         stream << " no explicit offsets.";
1263                         break;
1264
1265                 case AtomicCounterTest::OFFSETTYPE_BASIC:
1266                         stream << "explicit continuos offsets.";
1267                         break;
1268
1269                 case AtomicCounterTest::OFFSETTYPE_REVERSE:
1270                         stream << "reversed explicit offsets.";
1271                         break;
1272
1273                 case AtomicCounterTest::OFFSETTYPE_INVALID:
1274                         stream << "invalid explicit offsets.";
1275                         break;
1276
1277                 case AtomicCounterTest::OFFSETTYPE_FIRST_AUTO:
1278                         stream << "only first counter with explicit offset.";
1279                         break;
1280
1281                 case AtomicCounterTest::OFFSETTYPE_DEFAULT_AUTO:
1282                         stream << "default offset.";
1283                         break;
1284
1285                 case AtomicCounterTest::OFFSETTYPE_RESET_DEFAULT:
1286                         stream << "default offset specified twice.";
1287                         break;
1288
1289                 default:
1290                         DE_ASSERT(false);
1291         }
1292
1293         return stream.str();
1294 }
1295
1296 } // Anonymous
1297
1298 AtomicCounterTests::AtomicCounterTests (Context& context)
1299         : TestCaseGroup(context, "atomic_counter", "Atomic counter tests")
1300 {
1301         // Runtime use tests
1302         {
1303                 const int counterCounts[] =
1304                 {
1305                         1, 4, 8
1306                 };
1307
1308                 const int callCounts[] =
1309                 {
1310                         1, 5, 100
1311                 };
1312
1313                 const int threadCounts[] =
1314                 {
1315                         1, 10, 5000
1316                 };
1317
1318                 const AtomicCounterTest::Operation operations[] =
1319                 {
1320                         AtomicCounterTest::OPERATION_GET,
1321                         AtomicCounterTest::OPERATION_INC,
1322                         AtomicCounterTest::OPERATION_DEC,
1323
1324                         (AtomicCounterTest::Operation)(AtomicCounterTest::OPERATION_INC|AtomicCounterTest::OPERATION_GET),
1325                         (AtomicCounterTest::Operation)(AtomicCounterTest::OPERATION_DEC|AtomicCounterTest::OPERATION_GET),
1326
1327                         (AtomicCounterTest::Operation)(AtomicCounterTest::OPERATION_INC|AtomicCounterTest::OPERATION_DEC),
1328                         (AtomicCounterTest::Operation)(AtomicCounterTest::OPERATION_INC|AtomicCounterTest::OPERATION_DEC|AtomicCounterTest::OPERATION_GET)
1329                 };
1330
1331                 for (int operationNdx = 0; operationNdx < DE_LENGTH_OF_ARRAY(operations); operationNdx++)
1332                 {
1333                         const AtomicCounterTest::Operation operation = operations[operationNdx];
1334
1335                         for (int branch = 0; branch < 2; branch++)
1336                         {
1337                                 const bool useBranch = (branch == 1);
1338
1339                                 TestCaseGroup* operationGroup = new TestCaseGroup(m_context, operationToName(operation, useBranch).c_str(), operationToDescription(operation, useBranch).c_str());
1340
1341                                 for (int counterCountNdx = 0; counterCountNdx < DE_LENGTH_OF_ARRAY(counterCounts); counterCountNdx++)
1342                                 {
1343                                         const int counterCount = counterCounts[counterCountNdx];
1344
1345                                         for (int callCountNdx = 0; callCountNdx < DE_LENGTH_OF_ARRAY(callCounts); callCountNdx++)
1346                                         {
1347                                                 const int callCount = callCounts[callCountNdx];
1348
1349                                                 for (int threadCountNdx = 0; threadCountNdx < DE_LENGTH_OF_ARRAY(threadCounts); threadCountNdx++)
1350                                                 {
1351                                                         const int threadCount = threadCounts[threadCountNdx];
1352
1353                                                         if (threadCount * callCount * counterCount > 10000)
1354                                                                 continue;
1355
1356                                                         if (useBranch && threadCount * callCount == 1)
1357                                                                 continue;
1358
1359                                                         AtomicCounterTest::TestSpec spec;
1360
1361                                                         spec.atomicCounterCount = counterCount;
1362                                                         spec.operations                 = operation;
1363                                                         spec.callCount                  = callCount;
1364                                                         spec.useBranches                = useBranch;
1365                                                         spec.threadCount                = threadCount;
1366                                                         spec.bindingType                = AtomicCounterTest::BINDINGTYPE_BASIC;
1367                                                         spec.offsetType                 = AtomicCounterTest::OFFSETTYPE_NONE;
1368
1369                                                         operationGroup->addChild(new AtomicCounterTest(m_context, specToTestName(spec).c_str(), specToTestDescription(spec).c_str(), spec));
1370                                                 }
1371                                         }
1372                                 }
1373
1374                                 addChild(operationGroup);
1375                         }
1376                 }
1377         }
1378
1379         {
1380                 TestCaseGroup* layoutGroup = new TestCaseGroup(m_context, "layout", "Layout qualifier tests.");
1381
1382                 const int counterCounts[]       = { 1, 8 };
1383                 const int callCounts[]          = { 1, 5 };
1384                 const int threadCounts[]        = { 1, 1000 };
1385
1386                 const AtomicCounterTest::Operation operations[] =
1387                 {
1388                         (AtomicCounterTest::Operation)(AtomicCounterTest::OPERATION_INC|AtomicCounterTest::OPERATION_GET),
1389                         (AtomicCounterTest::Operation)(AtomicCounterTest::OPERATION_DEC|AtomicCounterTest::OPERATION_GET),
1390                         (AtomicCounterTest::Operation)(AtomicCounterTest::OPERATION_INC|AtomicCounterTest::OPERATION_DEC)
1391                 };
1392
1393                 const AtomicCounterTest::OffsetType offsetTypes[] =
1394                 {
1395                         AtomicCounterTest::OFFSETTYPE_REVERSE,
1396                         AtomicCounterTest::OFFSETTYPE_FIRST_AUTO,
1397                         AtomicCounterTest::OFFSETTYPE_DEFAULT_AUTO,
1398                         AtomicCounterTest::OFFSETTYPE_RESET_DEFAULT
1399                 };
1400
1401                 for (int offsetTypeNdx = 0; offsetTypeNdx < DE_LENGTH_OF_ARRAY(offsetTypes); offsetTypeNdx++)
1402                 {
1403                         const AtomicCounterTest::OffsetType offsetType = offsetTypes[offsetTypeNdx];
1404
1405                         TestCaseGroup* layoutQualifierGroup = new TestCaseGroup(m_context, layoutTypesToName(AtomicCounterTest::BINDINGTYPE_BASIC, offsetType).c_str(), layoutTypesToDesc(AtomicCounterTest::BINDINGTYPE_BASIC, offsetType).c_str());
1406
1407                         for (int operationNdx = 0; operationNdx < DE_LENGTH_OF_ARRAY(operations); operationNdx++)
1408                         {
1409                                 const AtomicCounterTest::Operation operation = operations[operationNdx];
1410
1411                                 TestCaseGroup* operationGroup = new TestCaseGroup(m_context, operationToName(operation, false).c_str(), operationToDescription(operation, false).c_str());
1412
1413                                 for (int counterCountNdx = 0; counterCountNdx < DE_LENGTH_OF_ARRAY(counterCounts); counterCountNdx++)
1414                                 {
1415                                         const int counterCount = counterCounts[counterCountNdx];
1416
1417                                         if (offsetType == AtomicCounterTest::OFFSETTYPE_FIRST_AUTO && counterCount < 3)
1418                                                 continue;
1419
1420                                         if (offsetType == AtomicCounterTest::OFFSETTYPE_DEFAULT_AUTO && counterCount < 2)
1421                                                 continue;
1422
1423                                         if (offsetType == AtomicCounterTest::OFFSETTYPE_RESET_DEFAULT && counterCount < 2)
1424                                                 continue;
1425
1426                                         if (offsetType == AtomicCounterTest::OFFSETTYPE_REVERSE && counterCount < 2)
1427                                                 continue;
1428
1429                                         for (int callCountNdx = 0; callCountNdx < DE_LENGTH_OF_ARRAY(callCounts); callCountNdx++)
1430                                         {
1431                                                 const int callCount = callCounts[callCountNdx];
1432
1433                                                 for (int threadCountNdx = 0; threadCountNdx < DE_LENGTH_OF_ARRAY(threadCounts); threadCountNdx++)
1434                                                 {
1435                                                         const int threadCount = threadCounts[threadCountNdx];
1436
1437                                                         AtomicCounterTest::TestSpec spec;
1438
1439                                                         spec.atomicCounterCount = counterCount;
1440                                                         spec.operations                 = operation;
1441                                                         spec.callCount                  = callCount;
1442                                                         spec.useBranches                = false;
1443                                                         spec.threadCount                = threadCount;
1444                                                         spec.bindingType                = AtomicCounterTest::BINDINGTYPE_BASIC;
1445                                                         spec.offsetType                 = offsetType;
1446
1447                                                         operationGroup->addChild(new AtomicCounterTest(m_context, specToTestName(spec).c_str(), specToTestDescription(spec).c_str(), spec));
1448                                                 }
1449                                         }
1450                                 }
1451                                 layoutQualifierGroup->addChild(operationGroup);
1452                         }
1453                         layoutGroup->addChild(layoutQualifierGroup);
1454                 }
1455
1456                 {
1457                         TestCaseGroup* invalidGroup = new TestCaseGroup(m_context, "invalid", "Test invalid layouts");
1458
1459                         {
1460                                 AtomicCounterTest::TestSpec spec;
1461
1462                                 spec.atomicCounterCount = 1;
1463                                 spec.operations                 = AtomicCounterTest::OPERATION_INC;
1464                                 spec.callCount                  = 1;
1465                                 spec.useBranches                = false;
1466                                 spec.threadCount                = 1;
1467                                 spec.bindingType                = AtomicCounterTest::BINDINGTYPE_INVALID;
1468                                 spec.offsetType                 = AtomicCounterTest::OFFSETTYPE_NONE;
1469
1470                                 invalidGroup->addChild(new AtomicCounterTest(m_context, "invalid_binding", "Test layout qualifiers with invalid binding.", spec));
1471                         }
1472
1473                         {
1474                                 AtomicCounterTest::TestSpec spec;
1475
1476                                 spec.atomicCounterCount = 1;
1477                                 spec.operations                 = AtomicCounterTest::OPERATION_INC;
1478                                 spec.callCount                  = 1;
1479                                 spec.useBranches                = false;
1480                                 spec.threadCount                = 1;
1481                                 spec.bindingType                = AtomicCounterTest::BINDINGTYPE_INVALID_DEFAULT;
1482                                 spec.offsetType                 = AtomicCounterTest::OFFSETTYPE_NONE;
1483
1484                                 invalidGroup->addChild(new AtomicCounterTest(m_context, "invalid_default_binding", "Test layout qualifiers with invalid default binding.", spec));
1485                         }
1486
1487                         {
1488                                 AtomicCounterTest::TestSpec spec;
1489
1490                                 spec.atomicCounterCount = 1;
1491                                 spec.operations                 = AtomicCounterTest::OPERATION_INC;
1492                                 spec.callCount                  = 1;
1493                                 spec.useBranches                = false;
1494                                 spec.threadCount                = 1;
1495                                 spec.bindingType                = AtomicCounterTest::BINDINGTYPE_BASIC;
1496                                 spec.offsetType                 = AtomicCounterTest::OFFSETTYPE_INVALID;
1497
1498                                 invalidGroup->addChild(new AtomicCounterTest(m_context, "invalid_offset_align", "Test layout qualifiers with invalid alignment offset.", spec));
1499                         }
1500
1501                         {
1502                                 AtomicCounterTest::TestSpec spec;
1503
1504                                 spec.atomicCounterCount = 2;
1505                                 spec.operations                 = AtomicCounterTest::OPERATION_INC;
1506                                 spec.callCount                  = 1;
1507                                 spec.useBranches                = false;
1508                                 spec.threadCount                = 1;
1509                                 spec.bindingType                = AtomicCounterTest::BINDINGTYPE_BASIC;
1510                                 spec.offsetType                 = AtomicCounterTest::OFFSETTYPE_INVALID_OVERLAPPING;
1511
1512                                 invalidGroup->addChild(new AtomicCounterTest(m_context, "invalid_offset_overlap", "Test layout qualifiers with invalid overlapping offset.", spec));
1513                         }
1514
1515                         {
1516                                 AtomicCounterTest::TestSpec spec;
1517
1518                                 spec.atomicCounterCount = 1;
1519                                 spec.operations                 = AtomicCounterTest::OPERATION_INC;
1520                                 spec.callCount                  = 1;
1521                                 spec.useBranches                = false;
1522                                 spec.threadCount                = 1;
1523                                 spec.bindingType                = AtomicCounterTest::BINDINGTYPE_BASIC;
1524                                 spec.offsetType                 = AtomicCounterTest::OFFSETTYPE_INVALID_DEFAULT;
1525
1526                                 invalidGroup->addChild(new AtomicCounterTest(m_context, "invalid_default_offset", "Test layout qualifiers with invalid default offset.", spec));
1527                         }
1528
1529                         layoutGroup->addChild(invalidGroup);
1530                 }
1531
1532                 addChild(layoutGroup);
1533         }
1534 }
1535
1536 AtomicCounterTests::~AtomicCounterTests (void)
1537 {
1538 }
1539
1540 void AtomicCounterTests::init (void)
1541 {
1542 }
1543
1544 } // Functional
1545 } // gles31
1546 } // deqp