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 {
TestSpecdeqp::gles31::Functional::__anon5918c1d40111::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<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;
getInitialValue(void) const122 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
getOperationCount(void) const136 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
AtomicCounterTest(Context & context,const char * name,const char * description,const TestSpec & spec)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
~AtomicCounterTest(void)160 AtomicCounterTest::~AtomicCounterTest (void)
161 {
162 }
163
init(void)164 void AtomicCounterTest::init (void)
165 {
166 }
167
deinit(void)168 void AtomicCounterTest::deinit (void)
169 {
170 }
171
generateShaderSource(const TestSpec & spec)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
checkAndLogCounterValues(TestLog & log,const vector<deUint32> & counters) const524 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
splitBuffer(const vector<deUint32> & buffer,vector<deUint32> & increments,vector<deUint32> & decrements,vector<deUint32> & preGets,vector<deUint32> & postGets,vector<deUint32> & gets) const557 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
getCountersValues(vector<deUint32> & counterValues,const vector<deUint32> & values,int ndx,int counterCount)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
checkRange(TestLog & log,const vector<deUint32> & values,const vector<deUint32> & min,const vector<deUint32> & max)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
checkUniquenessAndLinearity(TestLog & log,const vector<deUint32> & values)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
checkPath(const vector<deUint32> & increments,const vector<deUint32> & decrements,int initialValue,const TestSpec & spec)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
checkAndLogCallValues(TestLog & log,const vector<deUint32> & increments,const vector<deUint32> & decrements,const vector<deUint32> & preGets,const vector<deUint32> & postGets,const vector<deUint32> & gets) const806 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
iterate(void)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
specToTestName(const AtomicCounterTest::TestSpec & spec)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
specToTestDescription(const AtomicCounterTest::TestSpec & spec)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
operationToName(const AtomicCounterTest::Operation & operations,bool useBranch)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
operationToDescription(const AtomicCounterTest::Operation & operations,bool useBranch)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
layoutTypesToName(const AtomicCounterTest::BindingType & bindingType,const AtomicCounterTest::OffsetType & offsetType)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
layoutTypesToDesc(const AtomicCounterTest::BindingType & bindingType,const AtomicCounterTest::OffsetType & offsetType)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
AtomicCounterTests(Context & context)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
~AtomicCounterTests(void)1536 AtomicCounterTests::~AtomicCounterTests (void)
1537 {
1538 }
1539
init(void)1540 void AtomicCounterTests::init (void)
1541 {
1542 }
1543
1544 } // Functional
1545 } // gles31
1546 } // deqp
1547