• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 {
DataStoreSpecdeqp::gles2::Functional::DataStoreSpec56 	DataStoreSpec (void)
57 		: target	(0)
58 		, usage		(0)
59 		, size		(0)
60 	{
61 	}
62 
DataStoreSpecdeqp::gles2::Functional::DataStoreSpec63 	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 
DataStoreSpecVecBuilderdeqp::gles2::Functional::DataStoreSpecVecBuilder79 	DataStoreSpecVecBuilder (std::vector<DataStoreSpec>& list_)
80 		: list(list_)
81 	{
82 	}
83 
operator <<deqp::gles2::Functional::DataStoreSpecVecBuilder84 	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 
RangeVecBuilderdeqp::gles2::Functional::RangeVecBuilder95 	RangeVecBuilder (std::vector<tcu::IVec2>& list_)
96 		: list(list_)
97 	{
98 	}
99 
operator <<deqp::gles2::Functional::RangeVecBuilder100 	RangeVecBuilder& operator<< (const tcu::IVec2& vec)
101 	{
102 		list.push_back(vec);
103 		return *this;
104 	}
105 };
106 
107 template<typename Iterator>
isRangeListValid(Iterator begin,Iterator end)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 
rangesIntersect(const tcu::IVec2 & a,const tcu::IVec2 & b)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 
unionRanges(const tcu::IVec2 & a,const tcu::IVec2 & b)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.
addRangeToList(const std::vector<tcu::IVec2> & oldList,const tcu::IVec2 & newRange)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:
BasicBufferDataCase(Context & context,const char * name,const char * desc,deUint32 target,deUint32 usage,int size,VerifyType verify)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 
iterate(void)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:
RecreateBufferDataStoreCase(Context & context,const char * name,const char * desc,const DataStoreSpec * specs,int numSpecs,VerifyType verify)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 
iterate(void)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:
BasicBufferSubDataCase(Context & context,const char * name,const char * desc,deUint32 target,deUint32 usage,int size,int subDataOffs,int subDataSize,VerifyType verify)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 
iterate(void)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:
SubDataToUndefinedCase(Context & context,const char * name,const char * desc,deUint32 target,deUint32 usage,int size,const tcu::IVec2 * ranges,int numRanges,VerifyType verify)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 
iterate(void)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:
RandomBufferWriteCase(Context & context,const char * name,const char * desc,deUint32 seed)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 
~RandomBufferWriteCase(void)399 	~RandomBufferWriteCase (void)
400 	{
401 		delete m_verifier;
402 	}
403 
init(void)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 
deinit(void)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 
iterate(void)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 
BufferWriteTests(Context & context)535 BufferWriteTests::BufferWriteTests (Context& context)
536 	: TestCaseGroup(context, "write", "Buffer data upload tests")
537 {
538 }
539 
~BufferWriteTests(void)540 BufferWriteTests::~BufferWriteTests (void)
541 {
542 }
543 
init(void)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