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
39using std::set;
40using std::vector;
41using std::string;
42using tcu::TestLog;
43using tcu::IVec2;
44
45namespace deqp
46{
47namespace gles3
48{
49namespace Functional
50{
51
52using namespace gls::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.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
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.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
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.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
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.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
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.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
537private:
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
548BufferWriteTests::BufferWriteTests (Context& context)
549	: TestCaseGroup(context, "write", "Buffer data upload tests")
550{
551}
552
553BufferWriteTests::~BufferWriteTests (void)
554{
555}
556
557void 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