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
39using std::set;
40using std::vector;
41using std::string;
42using tcu::TestLog;
43using tcu::IVec2;
44
45namespace deqp
46{
47namespace gles2
48{
49namespace Functional
50{
51
52using namespace BufferTestUtil;
53
54struct 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
75struct 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
91struct 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
107template<typename Iterator>
108static 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
128inline 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
134inline 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.
145std::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
177class BasicBufferDataCase : public BufferCase
178{
179public:
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
214private:
215	deUint32		m_target;
216	deUint32		m_usage;
217	int				m_size;
218	VerifyType		m_verify;
219};
220
221class RecreateBufferDataStoreCase : public BufferCase
222{
223public:
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
265private:
266	std::vector<DataStoreSpec>	m_specs;
267	VerifyType					m_verify;
268};
269
270class BasicBufferSubDataCase : public BufferCase
271{
272public:
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
315private:
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
324class SubDataToUndefinedCase : public BufferCase
325{
326public:
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
378private:
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
386class RandomBufferWriteCase : public BufferCase
387{
388public:
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
524private:
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
535BufferWriteTests::BufferWriteTests (Context& context)
536	: TestCaseGroup(context, "write", "Buffer data upload tests")
537{
538}
539
540BufferWriteTests::~BufferWriteTests (void)
541{
542}
543
544void 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