Home | History | Annotate | Download | only in functional
      1 /*-------------------------------------------------------------------------
      2  * drawElements Quality Program OpenGL ES 3.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 "es3fBufferWriteTests.hpp"
     25 #include "glsBufferTestUtil.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 gles3
     48 {
     49 namespace Functional
     50 {
     51 
     52 using namespace gls::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.getTestContext(), context.getRenderContext(), 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_renderCtx, m_testCtx.getLog(), 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, m_target);
    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.getTestContext(), context.getRenderContext(), 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_renderCtx, m_testCtx.getLog(), 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, spec->target);
    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.getTestContext(), context.getRenderContext(), 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_renderCtx, m_testCtx.getLog(), 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, m_target);
    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.getTestContext(), context.getRenderContext(), 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_renderCtx, m_testCtx.getLog(), 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(), m_target))
    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.getTestContext(), context.getRenderContext(), 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_renderCtx, m_testCtx.getLog(), 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_COPY_READ_BUFFER,
    441 			GL_COPY_WRITE_BUFFER,
    442 			GL_ELEMENT_ARRAY_BUFFER,
    443 			GL_PIXEL_PACK_BUFFER,
    444 			GL_PIXEL_UNPACK_BUFFER,
    445 			GL_TRANSFORM_FEEDBACK_BUFFER,
    446 			GL_UNIFORM_BUFFER
    447 		};
    448 
    449 		static const deUint32 usageHints[] =
    450 		{
    451 			GL_STREAM_DRAW,
    452 			GL_STREAM_READ,
    453 			GL_STREAM_COPY,
    454 			GL_STATIC_DRAW,
    455 			GL_STATIC_READ,
    456 			GL_STATIC_COPY,
    457 			GL_DYNAMIC_DRAW,
    458 			GL_DYNAMIC_READ,
    459 			GL_DYNAMIC_COPY
    460 		};
    461 
    462 		bool		iterOk					= true;
    463 		deUint32	curBoundTarget			= GL_NONE;
    464 		de::Random	rnd						(m_seed ^ deInt32Hash(m_iterNdx) ^ 0xacf92e);
    465 
    466 		m_testCtx.getLog() << TestLog::Section(string("Iteration") + de::toString(m_iterNdx+1), string("Iteration ") + de::toString(m_iterNdx+1) + " / " + de::toString(numIterations));
    467 
    468 		for (int uploadNdx = 0; uploadNdx < uploadsPerIteration; uploadNdx++)
    469 		{
    470 			const deUint32	target		= bufferTargets[rnd.getInt(0, DE_LENGTH_OF_ARRAY(bufferTargets)-1)];
    471 			const bool		respecify	= m_curSize == 0 || rnd.getFloat() < respecifyProbability;
    472 
    473 			if (target != curBoundTarget)
    474 			{
    475 				glBindBuffer(target, m_buffer);
    476 				curBoundTarget = target;
    477 			}
    478 
    479 			if (respecify)
    480 			{
    481 				const int		size			= rnd.getInt(minSize, maxSize);
    482 				const deUint32	hint			= usageHints[rnd.getInt(0, DE_LENGTH_OF_ARRAY(usageHints)-1)];
    483 				const bool		fillWithData	= rnd.getFloat() < respecifyDataProbability;
    484 
    485 				m_refBuffer.setSize(size);
    486 				if (fillWithData)
    487 					fillWithRandomBytes(m_refBuffer.getPtr(), size, rnd.getUint32());
    488 
    489 				glBufferData(target, size, fillWithData ? m_refBuffer.getPtr() : DE_NULL, hint);
    490 
    491 				m_validRanges.clear();
    492 				if (fillWithData)
    493 					m_validRanges.push_back(tcu::IVec2(0, size));
    494 
    495 				m_curSize = size;
    496 			}
    497 			else
    498 			{
    499 				// \note Non-uniform size distribution.
    500 				const int	size	= de::clamp(deRoundFloatToInt32((float)m_curSize * deFloatPow(rnd.getFloat(0.0f, 0.7f), 3.0f)), minSize, m_curSize);
    501 				const int	offset	= rnd.getInt(0, m_curSize-size);
    502 
    503 				fillWithRandomBytes(m_refBuffer.getPtr()+offset, size, rnd.getUint32());
    504 				glBufferSubData(target, offset, size, m_refBuffer.getPtr()+offset);
    505 
    506 				m_validRanges = addRangeToList(m_validRanges, tcu::IVec2(offset, size));
    507 			}
    508 		}
    509 
    510 		// Check error.
    511 		{
    512 			deUint32 err = glGetError();
    513 			if (err != GL_NO_ERROR)
    514 				throw tcu::TestError(string("Got ") + glu::getErrorStr(err).toString());
    515 		}
    516 
    517 		// Verify valid ranges.
    518 		for (vector<IVec2>::const_iterator range = m_validRanges.begin(); range != m_validRanges.end(); range++)
    519 		{
    520 			const deUint32 targetHint = GL_ARRAY_BUFFER;
    521 			if (!m_verifier->verify(m_buffer, m_refBuffer.getPtr(), range->x(), range->y(), targetHint))
    522 			{
    523 				m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Buffer verification failed");
    524 				iterOk = false;
    525 				break;
    526 			}
    527 		}
    528 
    529 		m_testCtx.getLog() << TestLog::EndSection;
    530 
    531 		DE_ASSERT(iterOk || m_testCtx.getTestResult() != QP_TEST_RESULT_PASS);
    532 
    533 		m_iterNdx += 1;
    534 		return (iterOk && m_iterNdx < numIterations) ? CONTINUE : STOP;
    535 	}
    536 
    537 private:
    538 	deUint32				m_seed;
    539 
    540 	BufferVerifier*			m_verifier;
    541 	deUint32				m_buffer;
    542 	ReferenceBuffer			m_refBuffer;
    543 	std::vector<tcu::IVec2>	m_validRanges;
    544 	int						m_curSize;
    545 	int						m_iterNdx;
    546 };
    547 
    548 BufferWriteTests::BufferWriteTests (Context& context)
    549 	: TestCaseGroup(context, "write", "Buffer data upload tests")
    550 {
    551 }
    552 
    553 BufferWriteTests::~BufferWriteTests (void)
    554 {
    555 }
    556 
    557 void BufferWriteTests::init (void)
    558 {
    559 	static const deUint32 bufferTargets[] =
    560 	{
    561 		GL_ARRAY_BUFFER,
    562 		GL_COPY_READ_BUFFER,
    563 		GL_COPY_WRITE_BUFFER,
    564 		GL_ELEMENT_ARRAY_BUFFER,
    565 		GL_PIXEL_PACK_BUFFER,
    566 		GL_PIXEL_UNPACK_BUFFER,
    567 		GL_TRANSFORM_FEEDBACK_BUFFER,
    568 		GL_UNIFORM_BUFFER
    569 	};
    570 
    571 	static const deUint32 usageHints[] =
    572 	{
    573 		GL_STREAM_DRAW,
    574 		GL_STREAM_READ,
    575 		GL_STREAM_COPY,
    576 		GL_STATIC_DRAW,
    577 		GL_STATIC_READ,
    578 		GL_STATIC_COPY,
    579 		GL_DYNAMIC_DRAW,
    580 		GL_DYNAMIC_READ,
    581 		GL_DYNAMIC_COPY
    582 	};
    583 
    584 	// .basic
    585 	{
    586 		tcu::TestCaseGroup* const basicGroup = new tcu::TestCaseGroup(m_testCtx, "basic", "Basic upload with glBufferData()");
    587 		addChild(basicGroup);
    588 
    589 		for (int targetNdx = 0; targetNdx < DE_LENGTH_OF_ARRAY(bufferTargets); targetNdx++)
    590 		{
    591 			for (int usageNdx = 0; usageNdx < DE_LENGTH_OF_ARRAY(usageHints); usageNdx++)
    592 			{
    593 				const deUint32		target	= bufferTargets[targetNdx];
    594 				const deUint32		usage	= usageHints[usageNdx];
    595 				const int			size	= 1020;
    596 				const VerifyType	verify	= VERIFY_AS_VERTEX_ARRAY;
    597 				const string		name	= string(getBufferTargetName(target)) + "_" + getUsageHintName(usage);
    598 
    599 				basicGroup->addChild(new BasicBufferDataCase(m_context, name.c_str(), "", target, usage, size, verify));
    600 			}
    601 		}
    602 	}
    603 
    604 	// .recreate_store
    605 	{
    606 		tcu::TestCaseGroup* const recreateStoreGroup = new tcu::TestCaseGroup(m_testCtx, "recreate_store", "Data store recreate using glBufferData()");
    607 		addChild(recreateStoreGroup);
    608 
    609 #define RECREATE_STORE_CASE(NAME, DESC, SPECLIST)																												\
    610 		do {																																				\
    611 			std::vector<DataStoreSpec> specs;																												\
    612 			DataStoreSpecVecBuilder builder(specs);																											\
    613 			builder SPECLIST;																																\
    614 			recreateStoreGroup->addChild(new RecreateBufferDataStoreCase(m_context, #NAME, DESC, &specs[0], (int)specs.size(), VERIFY_AS_VERTEX_ARRAY));	\
    615 		} while (deGetFalse())
    616 
    617 		RECREATE_STORE_CASE(identical_1, "Recreate with identical parameters",
    618 			<< DataStoreSpec(GL_ARRAY_BUFFER, GL_STATIC_DRAW, 996)
    619 			<< DataStoreSpec(GL_ARRAY_BUFFER, GL_STATIC_DRAW, 996)
    620 			<< DataStoreSpec(GL_ARRAY_BUFFER, GL_STATIC_DRAW, 996));
    621 
    622 		RECREATE_STORE_CASE(identical_2, "Recreate with identical parameters",
    623 			<< DataStoreSpec(GL_COPY_WRITE_BUFFER, GL_STATIC_DRAW, 72)
    624 			<< DataStoreSpec(GL_COPY_WRITE_BUFFER, GL_STATIC_DRAW, 72)
    625 			<< DataStoreSpec(GL_COPY_WRITE_BUFFER, GL_STATIC_DRAW, 72));
    626 
    627 		RECREATE_STORE_CASE(different_target, "Recreate with different target",
    628 			<< DataStoreSpec(GL_ARRAY_BUFFER,				GL_STATIC_DRAW, 504)
    629 			<< DataStoreSpec(GL_COPY_READ_BUFFER,			GL_STATIC_DRAW, 504)
    630 			<< DataStoreSpec(GL_COPY_WRITE_BUFFER,			GL_STATIC_DRAW, 504)
    631 			<< DataStoreSpec(GL_ELEMENT_ARRAY_BUFFER,		GL_STATIC_DRAW, 504)
    632 			<< DataStoreSpec(GL_PIXEL_PACK_BUFFER,			GL_STATIC_DRAW, 504)
    633 			<< DataStoreSpec(GL_PIXEL_UNPACK_BUFFER,		GL_STATIC_DRAW, 504)
    634 			<< DataStoreSpec(GL_TRANSFORM_FEEDBACK_BUFFER,	GL_STATIC_DRAW, 504)
    635 			<< DataStoreSpec(GL_UNIFORM_BUFFER,				GL_STATIC_DRAW, 504)
    636 			<< DataStoreSpec(GL_ARRAY_BUFFER,				GL_STATIC_DRAW, 504));
    637 
    638 		RECREATE_STORE_CASE(different_usage, "Recreate with different usage",
    639 			<< DataStoreSpec(GL_ARRAY_BUFFER,				GL_STREAM_DRAW,		1644)
    640 			<< DataStoreSpec(GL_ARRAY_BUFFER,				GL_STREAM_COPY,		1644)
    641 			<< DataStoreSpec(GL_ARRAY_BUFFER,				GL_STATIC_READ,		1644)
    642 			<< DataStoreSpec(GL_ARRAY_BUFFER,				GL_STREAM_READ,		1644)
    643 			<< DataStoreSpec(GL_ARRAY_BUFFER,				GL_DYNAMIC_COPY,	1644)
    644 			<< DataStoreSpec(GL_ARRAY_BUFFER,				GL_STATIC_COPY,		1644)
    645 			<< DataStoreSpec(GL_ARRAY_BUFFER,				GL_DYNAMIC_READ,	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,		123795)
    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_UNIFORM_BUFFER, GL_DYNAMIC_READ, 1728,
    721 			<< IVec2(729, 999)
    722 			<< IVec2(0, 729));
    723 		PARTIAL_SPECIFY_CASE(whole_3, "Whole buffer specification with three calls", GL_TRANSFORM_FEEDBACK_BUFFER, GL_STREAM_COPY, 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_TRANSFORM_FEEDBACK_BUFFER, GL_STREAM_COPY, 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_DYNAMIC_DRAW, 1000,
    733 			<< IVec2(0, 513));
    734 		PARTIAL_SPECIFY_CASE(low_2, "Low part of buffer specified with two calls", GL_COPY_READ_BUFFER, GL_DYNAMIC_COPY, 996,
    735 			<< IVec2(0, 98)
    736 			<< IVec2(98, 511));
    737 		PARTIAL_SPECIFY_CASE(low_3, "Low part of buffer specified with two calls", GL_COPY_READ_BUFFER, GL_DYNAMIC_COPY, 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_COPY_WRITE_BUFFER, GL_STATIC_COPY, 1000,
    742 			<< IVec2(500, 500));
    743 		PARTIAL_SPECIFY_CASE(high_2, "High part of buffer specified with two calls", GL_TRANSFORM_FEEDBACK_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_PIXEL_PACK_BUFFER, GL_STREAM_READ, 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_PIXEL_UNPACK_BUFFER, GL_STREAM_READ, 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_STREAM_READ, 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 } // gles3
    774 } // deqp
    775