Home | History | Annotate | Download | only in functional
      1 /*-------------------------------------------------------------------------
      2  * drawElements Quality Program OpenGL ES 2.0 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 Buffer data upload tests.
     22  *//*--------------------------------------------------------------------*/
     23 
     24 #include "es2fBufferWriteTests.hpp"
     25 #include "es2fBufferTestUtil.hpp"
     26 #include "tcuTestLog.hpp"
     27 #include "gluStrUtil.hpp"
     28 #include "deMemory.h"
     29 #include "deString.h"
     30 #include "deRandom.hpp"
     31 #include "deStringUtil.hpp"
     32 #include "deMath.h"
     33 #include "glwEnums.hpp"
     34 #include "glwFunctions.hpp"
     35 
     36 #include <algorithm>
     37 #include <list>
     38 
     39 using std::set;
     40 using std::vector;
     41 using std::string;
     42 using tcu::TestLog;
     43 using tcu::IVec2;
     44 
     45 namespace deqp
     46 {
     47 namespace gles2
     48 {
     49 namespace Functional
     50 {
     51 
     52 using namespace BufferTestUtil;
     53 
     54 struct DataStoreSpec
     55 {
     56 	DataStoreSpec (void)
     57 		: target	(0)
     58 		, usage		(0)
     59 		, size		(0)
     60 	{
     61 	}
     62 
     63 	DataStoreSpec (deUint32 target_, deUint32 usage_, int size_)
     64 		: target	(target_)
     65 		, usage		(usage_)
     66 		, size		(size_)
     67 	{
     68 	}
     69 
     70 	deUint32	target;
     71 	deUint32	usage;
     72 	int			size;
     73 };
     74 
     75 struct DataStoreSpecVecBuilder
     76 {
     77 	std::vector<DataStoreSpec>& list;
     78 
     79 	DataStoreSpecVecBuilder (std::vector<DataStoreSpec>& list_)
     80 		: list(list_)
     81 	{
     82 	}
     83 
     84 	DataStoreSpecVecBuilder& operator<< (const DataStoreSpec& spec)
     85 	{
     86 		list.push_back(spec);
     87 		return *this;
     88 	}
     89 };
     90 
     91 struct RangeVecBuilder
     92 {
     93 	std::vector<tcu::IVec2>& list;
     94 
     95 	RangeVecBuilder (std::vector<tcu::IVec2>& list_)
     96 		: list(list_)
     97 	{
     98 	}
     99 
    100 	RangeVecBuilder& operator<< (const tcu::IVec2& vec)
    101 	{
    102 		list.push_back(vec);
    103 		return *this;
    104 	}
    105 };
    106 
    107 template<typename Iterator>
    108 static bool isRangeListValid (Iterator begin, Iterator end)
    109 {
    110 	if (begin != end)
    111 	{
    112 		// Fetch first.
    113 		tcu::IVec2 prev = *begin;
    114 		++begin;
    115 
    116 		for (; begin != end; ++begin)
    117 		{
    118 			tcu::IVec2 cur = *begin;
    119 			if (cur.x() <= prev.x() || cur.x() <= prev.x()+prev.y())
    120 				return false;
    121 			prev = cur;
    122 		}
    123 	}
    124 
    125 	return true;
    126 }
    127 
    128 inline bool rangesIntersect (const tcu::IVec2& a, const tcu::IVec2& b)
    129 {
    130 	return de::inRange(a.x(), b.x(), b.x()+b.y()) || de::inRange(a.x()+a.y(), b.x(), b.x()+b.y()) ||
    131 		   de::inRange(b.x(), a.x(), a.x()+a.y()) || de::inRange(b.x()+b.y(), a.x(), a.x()+a.y());
    132 }
    133 
    134 inline tcu::IVec2 unionRanges (const tcu::IVec2& a, const tcu::IVec2& b)
    135 {
    136 	DE_ASSERT(rangesIntersect(a, b));
    137 
    138 	int start	= de::min(a.x(), b.x());
    139 	int end		= de::max(a.x()+a.y(), b.x()+b.y());
    140 
    141 	return tcu::IVec2(start, end-start);
    142 }
    143 
    144 //! Updates range list (start, len) with a new range.
    145 std::vector<tcu::IVec2> addRangeToList (const std::vector<tcu::IVec2>& oldList, const tcu::IVec2& newRange)
    146 {
    147 	DE_ASSERT(newRange.y() > 0);
    148 
    149 	std::vector<tcu::IVec2>					newList;
    150 	std::vector<tcu::IVec2>::const_iterator	oldListIter	= oldList.begin();
    151 
    152 	// Append ranges that end before the new range.
    153 	for (; oldListIter != oldList.end() && oldListIter->x()+oldListIter->y() < newRange.x(); ++oldListIter)
    154 		newList.push_back(*oldListIter);
    155 
    156 	// Join any ranges that intersect new range
    157 	{
    158 		tcu::IVec2 curRange = newRange;
    159 		while (oldListIter != oldList.end() && rangesIntersect(curRange, *oldListIter))
    160 		{
    161 			curRange = unionRanges(curRange, *oldListIter);
    162 			++oldListIter;
    163 		}
    164 
    165 		newList.push_back(curRange);
    166 	}
    167 
    168 	// Append remaining ranges.
    169 	for (; oldListIter != oldList.end(); oldListIter++)
    170 		newList.push_back(*oldListIter);
    171 
    172 	DE_ASSERT(isRangeListValid(newList.begin(), newList.end()));
    173 
    174 	return newList;
    175 }
    176 
    177 class BasicBufferDataCase : public BufferCase
    178 {
    179 public:
    180 	BasicBufferDataCase (Context& context, const char* name, const char* desc, deUint32 target, deUint32 usage, int size, VerifyType verify)
    181 		: BufferCase	(context, name, desc)
    182 		, m_target		(target)
    183 		, m_usage		(usage)
    184 		, m_size		(size)
    185 		, m_verify		(verify)
    186 	{
    187 	}
    188 
    189 	IterateResult iterate (void)
    190 	{
    191 		const deUint32			dataSeed	= deStringHash(getName()) ^ 0x125;
    192 		BufferVerifier			verifier	(m_context, m_verify);
    193 		ReferenceBuffer			refBuf;
    194 		bool					isOk		= false;
    195 
    196 		refBuf.setSize(m_size);
    197 		fillWithRandomBytes(refBuf.getPtr(), m_size, dataSeed);
    198 
    199 		deUint32 buf = genBuffer();
    200 		glBindBuffer(m_target, buf);
    201 		glBufferData(m_target, m_size, refBuf.getPtr(), m_usage);
    202 
    203 		checkError();
    204 
    205 		isOk = verifier.verify(buf, refBuf.getPtr(), 0, m_size);
    206 
    207 		deleteBuffer(buf);
    208 
    209 		m_testCtx.setTestResult(isOk ? QP_TEST_RESULT_PASS	: QP_TEST_RESULT_FAIL,
    210 								isOk ? "Pass"				: "Buffer verification failed");
    211 		return STOP;
    212 	}
    213 
    214 private:
    215 	deUint32		m_target;
    216 	deUint32		m_usage;
    217 	int				m_size;
    218 	VerifyType		m_verify;
    219 };
    220 
    221 class RecreateBufferDataStoreCase : public BufferCase
    222 {
    223 public:
    224 	RecreateBufferDataStoreCase (Context& context, const char* name, const char* desc, const DataStoreSpec* specs, int numSpecs, VerifyType verify)
    225 		: BufferCase(context, name, desc)
    226 		, m_specs	(specs, specs+numSpecs)
    227 		, m_verify	(verify)
    228 	{
    229 	}
    230 
    231 	IterateResult iterate (void)
    232 	{
    233 		const deUint32			baseSeed	= deStringHash(getName()) ^ 0xbeef;
    234 		BufferVerifier			verifier	(m_context, m_verify);
    235 		ReferenceBuffer			refBuf;
    236 		const deUint32			buf			= genBuffer();
    237 
    238 		m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
    239 
    240 		for (vector<DataStoreSpec>::const_iterator spec = m_specs.begin(); spec != m_specs.end(); spec++)
    241 		{
    242 			bool iterOk = false;
    243 
    244 			refBuf.setSize(spec->size);
    245 			fillWithRandomBytes(refBuf.getPtr(), spec->size, baseSeed ^ deInt32Hash(spec->size+spec->target+spec->usage));
    246 
    247 			glBindBuffer(spec->target, buf);
    248 			glBufferData(spec->target, spec->size, refBuf.getPtr(), spec->usage);
    249 
    250 			checkError();
    251 
    252 			iterOk = verifier.verify(buf, refBuf.getPtr(), 0, spec->size);
    253 
    254 			if (!iterOk)
    255 			{
    256 				m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
    257 				break;
    258 			}
    259 		}
    260 
    261 		deleteBuffer(buf);
    262 		return STOP;
    263 	}
    264 
    265 private:
    266 	std::vector<DataStoreSpec>	m_specs;
    267 	VerifyType					m_verify;
    268 };
    269 
    270 class BasicBufferSubDataCase : public BufferCase
    271 {
    272 public:
    273 	BasicBufferSubDataCase (Context& context, const char* name, const char* desc, deUint32 target, deUint32 usage, int size, int subDataOffs, int subDataSize, VerifyType verify)
    274 		: BufferCase	(context, name, desc)
    275 		, m_target		(target)
    276 		, m_usage		(usage)
    277 		, m_size		(size)
    278 		, m_subDataOffs	(subDataOffs)
    279 		, m_subDataSize	(subDataSize)
    280 		, m_verify		(verify)
    281 	{
    282 		DE_ASSERT(de::inBounds(subDataOffs, 0, size) && de::inRange(subDataOffs+subDataSize, 0, size));
    283 	}
    284 
    285 	IterateResult iterate (void)
    286 	{
    287 		const deUint32			dataSeed	= deStringHash(getName());
    288 		BufferVerifier			verifier	(m_context, m_verify);
    289 		ReferenceBuffer			refBuf;
    290 		bool					isOk		= false;
    291 
    292 		refBuf.setSize(m_size);
    293 
    294 		deUint32 buf = genBuffer();
    295 		glBindBuffer(m_target, buf);
    296 
    297 		// Initialize with glBufferData()
    298 		fillWithRandomBytes(refBuf.getPtr(), m_size, dataSeed ^ 0x80354f);
    299 		glBufferData(m_target, m_size, refBuf.getPtr(), m_usage);
    300 		checkError();
    301 
    302 		// Re-specify part of buffer
    303 		fillWithRandomBytes(refBuf.getPtr()+m_subDataOffs, m_subDataSize, dataSeed ^ 0xfac425c);
    304 		glBufferSubData(m_target, m_subDataOffs, m_subDataSize, refBuf.getPtr()+m_subDataOffs);
    305 
    306 		isOk = verifier.verify(buf, refBuf.getPtr(), 0, m_size);
    307 
    308 		deleteBuffer(buf);
    309 
    310 		m_testCtx.setTestResult(isOk ? QP_TEST_RESULT_PASS	: QP_TEST_RESULT_FAIL,
    311 								isOk ? "Pass"				: "Buffer verification failed");
    312 		return STOP;
    313 	}
    314 
    315 private:
    316 	deUint32		m_target;
    317 	deUint32		m_usage;
    318 	int				m_size;
    319 	int				m_subDataOffs;
    320 	int				m_subDataSize;
    321 	VerifyType		m_verify;
    322 };
    323 
    324 class SubDataToUndefinedCase : public BufferCase
    325 {
    326 public:
    327 	SubDataToUndefinedCase (Context& context, const char* name, const char* desc, deUint32 target, deUint32 usage, int size, const tcu::IVec2* ranges, int numRanges, VerifyType verify)
    328 		: BufferCase	(context, name, desc)
    329 		, m_target		(target)
    330 		, m_usage		(usage)
    331 		, m_size		(size)
    332 		, m_ranges		(ranges, ranges+numRanges)
    333 		, m_verify		(verify)
    334 	{
    335 	}
    336 
    337 	IterateResult iterate (void)
    338 	{
    339 		const deUint32			dataSeed	= deStringHash(getName());
    340 		BufferVerifier			verifier	(m_context, m_verify);
    341 		ReferenceBuffer			refBuf;
    342 		bool					isOk		= true;
    343 		std::vector<tcu::IVec2>	definedRanges;
    344 
    345 		refBuf.setSize(m_size);
    346 
    347 		deUint32 buf = genBuffer();
    348 		glBindBuffer(m_target, buf);
    349 
    350 		// Initialize storage with glBufferData()
    351 		glBufferData(m_target, m_size, DE_NULL, m_usage);
    352 		checkError();
    353 
    354 		// Fill specified ranges with glBufferSubData()
    355 		for (vector<tcu::IVec2>::const_iterator range = m_ranges.begin(); range != m_ranges.end(); range++)
    356 		{
    357 			fillWithRandomBytes(refBuf.getPtr()+range->x(), range->y(), dataSeed ^ deInt32Hash(range->x()+range->y()));
    358 			glBufferSubData(m_target, range->x(), range->y(), refBuf.getPtr()+range->x());
    359 
    360 			// Mark range as defined
    361 			definedRanges = addRangeToList(definedRanges, *range);
    362 		}
    363 
    364 		// Verify defined parts
    365 		for (vector<tcu::IVec2>::const_iterator range = definedRanges.begin(); range != definedRanges.end(); range++)
    366 		{
    367 			if (!verifier.verify(buf, refBuf.getPtr(), range->x(), range->y()))
    368 				isOk = false;
    369 		}
    370 
    371 		deleteBuffer(buf);
    372 
    373 		m_testCtx.setTestResult(isOk ? QP_TEST_RESULT_PASS	: QP_TEST_RESULT_FAIL,
    374 								isOk ? "Pass"				: "Buffer verification failed");
    375 		return STOP;
    376 	}
    377 
    378 private:
    379 	deUint32				m_target;
    380 	deUint32				m_usage;
    381 	int						m_size;
    382 	std::vector<tcu::IVec2>	m_ranges;
    383 	VerifyType				m_verify;
    384 };
    385 
    386 class RandomBufferWriteCase : public BufferCase
    387 {
    388 public:
    389 	RandomBufferWriteCase (Context& context, const char* name, const char* desc, deUint32 seed)
    390 		: BufferCase(context, name, desc)
    391 		, m_seed		(seed)
    392 		, m_verifier	(DE_NULL)
    393 		, m_buffer		(0)
    394 		, m_curSize		(0)
    395 		, m_iterNdx		(0)
    396 	{
    397 	}
    398 
    399 	~RandomBufferWriteCase (void)
    400 	{
    401 		delete m_verifier;
    402 	}
    403 
    404 	void init (void)
    405 	{
    406 		BufferCase::init();
    407 
    408 		m_iterNdx	= 0;
    409 		m_buffer	= genBuffer();
    410 		m_curSize	= 0;
    411 		m_verifier	= new BufferVerifier(m_context, VERIFY_AS_VERTEX_ARRAY);
    412 
    413 		m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
    414 	}
    415 
    416 	void deinit (void)
    417 	{
    418 		deleteBuffer(m_buffer);
    419 		m_refBuffer.setSize(0);
    420 
    421 		delete m_verifier;
    422 		m_verifier = DE_NULL;
    423 
    424 		BufferCase::deinit();
    425 	}
    426 
    427 	IterateResult iterate (void)
    428 	{
    429 		// Parameters.
    430 		const int	numIterations				= 5;
    431 		const int	uploadsPerIteration			= 7;
    432 		const int	minSize						= 12;
    433 		const int	maxSize						= 32*1024;
    434 		const float	respecifyProbability		= 0.07f;
    435 		const float	respecifyDataProbability	= 0.2f;
    436 
    437 		static const deUint32 bufferTargets[] =
    438 		{
    439 			GL_ARRAY_BUFFER,
    440 			GL_ELEMENT_ARRAY_BUFFER
    441 		};
    442 
    443 		static const deUint32 usageHints[] =
    444 		{
    445 			GL_STREAM_DRAW,
    446 			GL_STATIC_DRAW,
    447 			GL_DYNAMIC_DRAW,
    448 		};
    449 
    450 		bool		iterOk					= true;
    451 		deUint32	curBoundTarget			= GL_NONE;
    452 		de::Random	rnd						(m_seed ^ deInt32Hash(m_iterNdx) ^ 0xacf92e);
    453 
    454 		m_testCtx.getLog() << TestLog::Section(string("Iteration") + de::toString(m_iterNdx+1), string("Iteration ") + de::toString(m_iterNdx+1) + " / " + de::toString(numIterations));
    455 
    456 		for (int uploadNdx = 0; uploadNdx < uploadsPerIteration; uploadNdx++)
    457 		{
    458 			const deUint32	target		= bufferTargets[rnd.getInt(0, DE_LENGTH_OF_ARRAY(bufferTargets)-1)];
    459 			const bool		respecify	= m_curSize == 0 || rnd.getFloat() < respecifyProbability;
    460 
    461 			if (target != curBoundTarget)
    462 			{
    463 				glBindBuffer(target, m_buffer);
    464 				curBoundTarget = target;
    465 			}
    466 
    467 			if (respecify)
    468 			{
    469 				const int		size			= rnd.getInt(minSize, maxSize);
    470 				const deUint32	hint			= usageHints[rnd.getInt(0, DE_LENGTH_OF_ARRAY(usageHints)-1)];
    471 				const bool		fillWithData	= rnd.getFloat() < respecifyDataProbability;
    472 
    473 				m_refBuffer.setSize(size);
    474 				if (fillWithData)
    475 					fillWithRandomBytes(m_refBuffer.getPtr(), size, rnd.getUint32());
    476 
    477 				glBufferData(target, size, fillWithData ? m_refBuffer.getPtr() : DE_NULL, hint);
    478 
    479 				m_validRanges.clear();
    480 				if (fillWithData)
    481 					m_validRanges.push_back(tcu::IVec2(0, size));
    482 
    483 				m_curSize = size;
    484 			}
    485 			else
    486 			{
    487 				// \note Non-uniform size distribution.
    488 				const int	size	= de::clamp(deRoundFloatToInt32((float)m_curSize * deFloatPow(rnd.getFloat(0.0f, 0.7f), 3.0f)), minSize, m_curSize);
    489 				const int	offset	= rnd.getInt(0, m_curSize-size);
    490 
    491 				fillWithRandomBytes(m_refBuffer.getPtr()+offset, size, rnd.getUint32());
    492 				glBufferSubData(target, offset, size, m_refBuffer.getPtr()+offset);
    493 
    494 				m_validRanges = addRangeToList(m_validRanges, tcu::IVec2(offset, size));
    495 			}
    496 		}
    497 
    498 		// Check error.
    499 		{
    500 			deUint32 err = glGetError();
    501 			if (err != GL_NO_ERROR)
    502 				throw tcu::TestError(string("Got ") + glu::getErrorStr(err).toString());
    503 		}
    504 
    505 		// Verify valid ranges.
    506 		for (vector<IVec2>::const_iterator range = m_validRanges.begin(); range != m_validRanges.end(); range++)
    507 		{
    508 			if (!m_verifier->verify(m_buffer, m_refBuffer.getPtr(), range->x(), range->y()))
    509 			{
    510 				m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Buffer verification failed");
    511 				iterOk = false;
    512 				break;
    513 			}
    514 		}
    515 
    516 		m_testCtx.getLog() << TestLog::EndSection;
    517 
    518 		DE_ASSERT(iterOk || m_testCtx.getTestResult() != QP_TEST_RESULT_PASS);
    519 
    520 		m_iterNdx += 1;
    521 		return (iterOk && m_iterNdx < numIterations) ? CONTINUE : STOP;
    522 	}
    523 
    524 private:
    525 	deUint32				m_seed;
    526 
    527 	BufferVerifier*			m_verifier;
    528 	deUint32				m_buffer;
    529 	ReferenceBuffer			m_refBuffer;
    530 	std::vector<tcu::IVec2>	m_validRanges;
    531 	int						m_curSize;
    532 	int						m_iterNdx;
    533 };
    534 
    535 BufferWriteTests::BufferWriteTests (Context& context)
    536 	: TestCaseGroup(context, "write", "Buffer data upload tests")
    537 {
    538 }
    539 
    540 BufferWriteTests::~BufferWriteTests (void)
    541 {
    542 }
    543 
    544 void BufferWriteTests::init (void)
    545 {
    546 	static const deUint32 bufferTargets[] =
    547 	{
    548 		GL_ARRAY_BUFFER,
    549 		GL_ELEMENT_ARRAY_BUFFER
    550 	};
    551 
    552 	static const deUint32 usageHints[] =
    553 	{
    554 		GL_STREAM_DRAW,
    555 		GL_STATIC_DRAW,
    556 		GL_DYNAMIC_DRAW
    557 	};
    558 
    559 	static const struct
    560 	{
    561 		const char*	name;
    562 		VerifyType	verify;
    563 	} verifyTypes[] =
    564 	{
    565 		{ "vertex_array",	VERIFY_AS_VERTEX_ARRAY	},
    566 		{ "index_array",	VERIFY_AS_INDEX_ARRAY	}
    567 	};
    568 
    569 	// .basic
    570 	{
    571 		tcu::TestCaseGroup* const basicGroup = new tcu::TestCaseGroup(m_testCtx, "basic", "Basic upload with glBufferData()");
    572 		addChild(basicGroup);
    573 
    574 		for (int targetNdx = 0; targetNdx < DE_LENGTH_OF_ARRAY(bufferTargets); targetNdx++)
    575 		{
    576 			for (int usageNdx = 0; usageNdx < DE_LENGTH_OF_ARRAY(usageHints); usageNdx++)
    577 			{
    578 				const deUint32		target	= bufferTargets[targetNdx];
    579 				const deUint32		usage	= usageHints[usageNdx];
    580 				const int			size	= 1020;
    581 				const VerifyType	verify	= VERIFY_AS_VERTEX_ARRAY;
    582 				const string		name	= string(getBufferTargetName(target)) + "_" + getUsageHintName(usage);
    583 
    584 				basicGroup->addChild(new BasicBufferDataCase(m_context, name.c_str(), "", target, usage, size, verify));
    585 			}
    586 		}
    587 	}
    588 
    589 	// .use
    590 	{
    591 		tcu::TestCaseGroup* const useGroup = new tcu::TestCaseGroup(m_testCtx, "use", "Buffer uses");
    592 		addChild(useGroup);
    593 
    594 		for (int verifyNdx = 0; verifyNdx < DE_LENGTH_OF_ARRAY(verifyTypes); verifyNdx++)
    595 		{
    596 			tcu::TestCaseGroup* const verifyGroup = new tcu::TestCaseGroup(m_testCtx, verifyTypes[verifyNdx].name, "");
    597 			useGroup->addChild(verifyGroup);
    598 
    599 			for (int targetNdx = 0; targetNdx < DE_LENGTH_OF_ARRAY(bufferTargets); targetNdx++)
    600 			{
    601 				const deUint32		target	= bufferTargets[targetNdx];
    602 				const deUint32		usage	= GL_STATIC_DRAW;
    603 				const int			size	= 763;
    604 				const VerifyType	verify	= verifyTypes[verifyNdx].verify;
    605 				const string		name	= getBufferTargetName(target);
    606 
    607 				verifyGroup->addChild(new BasicBufferDataCase(m_context, name.c_str(), "", target, usage, size, verify));
    608 			}
    609 		}
    610 	}
    611 
    612 	// .recreate_store
    613 	{
    614 		tcu::TestCaseGroup* const recreateStoreGroup = new tcu::TestCaseGroup(m_testCtx, "recreate_store", "Data store recreate using glBufferData()");
    615 		addChild(recreateStoreGroup);
    616 
    617 #define RECREATE_STORE_CASE(NAME, DESC, SPECLIST)																											\
    618 		do {																																				\
    619 			std::vector<DataStoreSpec> specs;																												\
    620 			DataStoreSpecVecBuilder builder(specs);																											\
    621 			builder SPECLIST;																																\
    622 			recreateStoreGroup->addChild(new RecreateBufferDataStoreCase(m_context, #NAME, DESC, &specs[0], (int)specs.size(), VERIFY_AS_VERTEX_ARRAY));	\
    623 		} while (deGetFalse())
    624 
    625 		RECREATE_STORE_CASE(identical_1, "Recreate with identical parameters",
    626 			<< DataStoreSpec(GL_ARRAY_BUFFER, GL_STATIC_DRAW, 996)
    627 			<< DataStoreSpec(GL_ARRAY_BUFFER, GL_STATIC_DRAW, 996)
    628 			<< DataStoreSpec(GL_ARRAY_BUFFER, GL_STATIC_DRAW, 996));
    629 
    630 		RECREATE_STORE_CASE(identical_2, "Recreate with identical parameters",
    631 			<< DataStoreSpec(GL_ELEMENT_ARRAY_BUFFER, GL_STATIC_DRAW, 72)
    632 			<< DataStoreSpec(GL_ELEMENT_ARRAY_BUFFER, GL_STATIC_DRAW, 72)
    633 			<< DataStoreSpec(GL_ELEMENT_ARRAY_BUFFER, GL_STATIC_DRAW, 72));
    634 
    635 		RECREATE_STORE_CASE(different_target_1, "Recreate with different target",
    636 			<< DataStoreSpec(GL_ARRAY_BUFFER,				GL_STATIC_DRAW, 504)
    637 			<< DataStoreSpec(GL_ELEMENT_ARRAY_BUFFER,		GL_STATIC_DRAW, 504));
    638 
    639 		RECREATE_STORE_CASE(different_target_2, "Recreate with different target",
    640 			<< DataStoreSpec(GL_ELEMENT_ARRAY_BUFFER,		GL_STATIC_DRAW, 716)
    641 			<< DataStoreSpec(GL_ARRAY_BUFFER,				GL_STATIC_DRAW, 716)
    642 			<< DataStoreSpec(GL_ELEMENT_ARRAY_BUFFER,		GL_STATIC_DRAW, 716));
    643 
    644 		RECREATE_STORE_CASE(different_usage, "Recreate with different usage",
    645 			<< DataStoreSpec(GL_ARRAY_BUFFER, GL_STREAM_DRAW,	1644)
    646 			<< DataStoreSpec(GL_ARRAY_BUFFER, GL_DYNAMIC_DRAW,	1644)
    647 			<< DataStoreSpec(GL_ARRAY_BUFFER, GL_STATIC_DRAW,	1644)
    648 			<< DataStoreSpec(GL_ARRAY_BUFFER, GL_STREAM_DRAW,	1644));
    649 
    650 		RECREATE_STORE_CASE(different_size, "Recreate with different size",
    651 			<< DataStoreSpec(GL_ARRAY_BUFFER, GL_STREAM_DRAW,	1024)
    652 			<< DataStoreSpec(GL_ARRAY_BUFFER, GL_STREAM_DRAW,	12)
    653 			<< DataStoreSpec(GL_ARRAY_BUFFER, GL_STREAM_DRAW,	3327)
    654 			<< DataStoreSpec(GL_ARRAY_BUFFER, GL_STREAM_DRAW,	92)
    655 			<< DataStoreSpec(GL_ARRAY_BUFFER, GL_STREAM_DRAW,	12379)
    656 			<< DataStoreSpec(GL_ARRAY_BUFFER, GL_STREAM_DRAW,	571));
    657 
    658 #undef RECREATE_STORE_CASE
    659 
    660 		// Random cases.
    661 		{
    662 			const int			numRandomCases		= 4;
    663 			const int			numUploadsPerCase	= 10;
    664 			const int			minSize				= 12;
    665 			const int			maxSize				= 65536;
    666 			const VerifyType	verify				= VERIFY_AS_VERTEX_ARRAY;
    667 			de::Random			rnd					(23921);
    668 
    669 			for (int caseNdx = 0; caseNdx < numRandomCases; caseNdx++)
    670 			{
    671 				vector<DataStoreSpec> specs(numUploadsPerCase);
    672 
    673 				for (vector<DataStoreSpec>::iterator spec = specs.begin(); spec != specs.end(); spec++)
    674 				{
    675 					spec->target	= bufferTargets[rnd.getInt(0, DE_LENGTH_OF_ARRAY(bufferTargets)-1)];
    676 					spec->usage		= usageHints[rnd.getInt(0, DE_LENGTH_OF_ARRAY(usageHints)-1)];
    677 					spec->size		= rnd.getInt(minSize, maxSize);
    678 				}
    679 
    680 				recreateStoreGroup->addChild(new RecreateBufferDataStoreCase(m_context, (string("random_") + de::toString(caseNdx+1)).c_str(), "", &specs[0], (int)specs.size(), verify));
    681 			}
    682 		}
    683 	}
    684 
    685 	// .basic_subdata
    686 	{
    687 		tcu::TestCaseGroup* const basicGroup = new tcu::TestCaseGroup(m_testCtx, "basic_subdata", "Basic glBufferSubData() usage");
    688 		addChild(basicGroup);
    689 
    690 		for (int targetNdx = 0; targetNdx < DE_LENGTH_OF_ARRAY(bufferTargets); targetNdx++)
    691 		{
    692 			for (int usageNdx = 0; usageNdx < DE_LENGTH_OF_ARRAY(usageHints); usageNdx++)
    693 			{
    694 				const deUint32		target	= bufferTargets[targetNdx];
    695 				const deUint32		usage	= usageHints[usageNdx];
    696 				const int			size	= 1020;
    697 				const VerifyType	verify	= VERIFY_AS_VERTEX_ARRAY;
    698 				const string		name	= string(getBufferTargetName(target)) + "_" + getUsageHintName(usage);
    699 
    700 				basicGroup->addChild(new BasicBufferDataCase(m_context, name.c_str(), "", target, usage, size, verify));
    701 			}
    702 		}
    703 	}
    704 
    705 	// .partial_specify
    706 	{
    707 		tcu::TestCaseGroup* const partialSpecifyGroup = new tcu::TestCaseGroup(m_testCtx, "partial_specify", "Partial buffer data specification with glBufferSubData()");
    708 		addChild(partialSpecifyGroup);
    709 
    710 #define PARTIAL_SPECIFY_CASE(NAME, DESC, TARGET, USAGE, SIZE, RANGELIST)																									\
    711 		do {																																								\
    712 			std::vector<tcu::IVec2> ranges;																																	\
    713 			RangeVecBuilder builder(ranges);																																\
    714 			builder RANGELIST;																																				\
    715 			partialSpecifyGroup->addChild(new SubDataToUndefinedCase(m_context, #NAME, DESC, TARGET, USAGE, SIZE, &ranges[0], (int)ranges.size(), VERIFY_AS_VERTEX_ARRAY));	\
    716 		} while (deGetFalse())
    717 
    718 		PARTIAL_SPECIFY_CASE(whole_1, "Whole buffer specification with single glBufferSubData()", GL_ARRAY_BUFFER, GL_STATIC_DRAW, 996,
    719 			<< IVec2(0, 996));
    720 		PARTIAL_SPECIFY_CASE(whole_2, "Whole buffer specification with two calls", GL_ELEMENT_ARRAY_BUFFER, GL_DYNAMIC_DRAW, 1728,
    721 			<< IVec2(729, 999)
    722 			<< IVec2(0, 729));
    723 		PARTIAL_SPECIFY_CASE(whole_3, "Whole buffer specification with three calls", GL_ARRAY_BUFFER, GL_STREAM_DRAW, 1944,
    724 			<< IVec2(0, 421)
    725 			<< IVec2(1421, 523)
    726 			<< IVec2(421, 1000));
    727 		PARTIAL_SPECIFY_CASE(whole_4, "Whole buffer specification with three calls", GL_ELEMENT_ARRAY_BUFFER, GL_STREAM_DRAW, 1200,
    728 			<< IVec2(0, 500)
    729 			<< IVec2(429, 200)
    730 			<< IVec2(513, 687));
    731 
    732 		PARTIAL_SPECIFY_CASE(low_1, "Low part of buffer specified with single call", GL_ELEMENT_ARRAY_BUFFER, GL_STATIC_DRAW, 1000,
    733 			<< IVec2(0, 513));
    734 		PARTIAL_SPECIFY_CASE(low_2, "Low part of buffer specified with two calls", GL_ARRAY_BUFFER, GL_STATIC_DRAW, 996,
    735 			<< IVec2(0, 98)
    736 			<< IVec2(98, 511));
    737 		PARTIAL_SPECIFY_CASE(low_3, "Low part of buffer specified with two calls", GL_ARRAY_BUFFER, GL_DYNAMIC_DRAW, 1200,
    738 			<< IVec2(0, 591)
    739 			<< IVec2(371, 400));
    740 
    741 		PARTIAL_SPECIFY_CASE(high_1, "High part of buffer specified with single call", GL_ELEMENT_ARRAY_BUFFER, GL_STATIC_DRAW, 1000,
    742 			<< IVec2(500, 500));
    743 		PARTIAL_SPECIFY_CASE(high_2, "High part of buffer specified with two calls", GL_ARRAY_BUFFER, GL_STREAM_DRAW, 1200,
    744 			<< IVec2(600, 123)
    745 			<< IVec2(723, 477));
    746 		PARTIAL_SPECIFY_CASE(high_3, "High part of buffer specified with two calls", GL_ARRAY_BUFFER, GL_STREAM_DRAW, 1200,
    747 			<< IVec2(600, 200)
    748 			<< IVec2(601, 599));
    749 
    750 		PARTIAL_SPECIFY_CASE(middle_1, "Middle part of buffer specified with single call", GL_ELEMENT_ARRAY_BUFFER, GL_STREAM_DRAW, 2500,
    751 			<< IVec2(1000, 799));
    752 		PARTIAL_SPECIFY_CASE(middle_2, "Middle part of buffer specified with two calls", GL_ELEMENT_ARRAY_BUFFER, GL_STATIC_DRAW, 2500,
    753 			<< IVec2(780, 220)
    754 			<< IVec2(1000, 500));
    755 		PARTIAL_SPECIFY_CASE(middle_3, "Middle part of buffer specified with two calls", GL_ARRAY_BUFFER, GL_DYNAMIC_DRAW, 2500,
    756 			<< IVec2(780, 321)
    757 			<< IVec2(1000, 501));
    758 
    759 #undef PARTIAL_SPECIFY_CASE
    760 	}
    761 
    762 	// .random
    763 	{
    764 		tcu::TestCaseGroup* const randomGroup = new tcu::TestCaseGroup(m_testCtx, "random", "Randomized buffer data cases");
    765 		addChild(randomGroup);
    766 
    767 		for (int i = 0; i < 10; i++)
    768 			randomGroup->addChild(new RandomBufferWriteCase(m_context, de::toString(i).c_str(), "", deInt32Hash(i)));
    769 	}
    770 }
    771 
    772 } // Functional
    773 } // gles2
    774 } // deqp
    775