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