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