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 Draw stress tests
22 *//*--------------------------------------------------------------------*/
23
24#include "es3sDrawTests.hpp"
25#include "tcuVector.hpp"
26#include "tcuTestLog.hpp"
27#include "tcuRenderTarget.hpp"
28#include "tcuSurface.hpp"
29#include "gluCallLogWrapper.hpp"
30#include "gluObjectWrapper.hpp"
31#include "gluPixelTransfer.hpp"
32#include "gluRenderContext.hpp"
33#include "gluShaderProgram.hpp"
34#include "gluStrUtil.hpp"
35#include "glsDrawTest.hpp"
36#include "glwFunctions.hpp"
37#include "glwEnums.hpp"
38#include "deRandom.hpp"
39#include "deStringUtil.hpp"
40#include "deUniquePtr.hpp"
41
42#include <set>
43
44namespace deqp
45{
46namespace gles3
47{
48namespace Stress
49{
50namespace
51{
52
53static const char* const s_vertexSource =		"#version 300 es\n"
54												"in highp vec4 a_position;\n"
55												"void main (void)\n"
56												"{\n"
57												"	gl_Position = a_position;\n"
58												"}\n";
59static const char* const s_fragmentSource =		"#version 300 es\n"
60												"layout(location = 0) out mediump vec4 fragColor;\n"
61												"void main (void)\n"
62												"{\n"
63												"	fragColor = vec4(1.0, 1.0, 1.0, 1.0);\n"
64												"}\n";
65
66class DrawInvalidRangeCase : public TestCase
67{
68public:
69						DrawInvalidRangeCase	(Context& ctx, const char* name, const char* desc, deUint32 min, deUint32 max, bool useLimitMin = false, bool useLimitMax = false);
70						~DrawInvalidRangeCase	(void);
71
72	void				init					(void);
73	void				deinit					(void);
74	IterateResult		iterate					(void);
75
76private:
77	const int			m_min;
78	const int			m_max;
79	const int			m_bufferedElements;
80	const int			m_numIndices;
81	const bool			m_useLimitMin;
82	const bool			m_useLimitMax;
83
84	deUint32			m_buffer;
85	deUint32			m_indexBuffer;
86	glu::ShaderProgram*	m_program;
87};
88
89DrawInvalidRangeCase::DrawInvalidRangeCase (Context& ctx, const char* name, const char* desc, deUint32 min, deUint32 max, bool useLimitMin, bool useLimitMax)
90	: TestCase				(ctx, name, desc)
91	, m_min					(min)
92	, m_max					(max)
93	, m_bufferedElements	(128)
94	, m_numIndices			(64)
95	, m_useLimitMin			(useLimitMin)
96	, m_useLimitMax			(useLimitMax)
97	, m_buffer				(0)
98	, m_indexBuffer			(0)
99	, m_program				(DE_NULL)
100{
101}
102
103DrawInvalidRangeCase::~DrawInvalidRangeCase (void)
104{
105	deinit();
106}
107
108void DrawInvalidRangeCase::init (void)
109{
110	const glw::Functions&	gl		= m_context.getRenderContext().getFunctions();
111	std::vector<tcu::Vec4>	data	(m_bufferedElements); // !< some junk data to make sure buffer is really allocated
112	std::vector<deUint32>	indices	(m_numIndices);
113
114	for (int ndx = 0; ndx < m_numIndices; ++ndx)
115		indices[ndx] = ndx;
116
117	gl.genBuffers(1, &m_buffer);
118	gl.bindBuffer(GL_ARRAY_BUFFER, m_buffer);
119	gl.bufferData(GL_ARRAY_BUFFER, int(m_bufferedElements * sizeof(tcu::Vec4)), &data[0], GL_STATIC_DRAW);
120	GLU_EXPECT_NO_ERROR(gl.getError(), "buffer gen");
121
122	gl.genBuffers(1, &m_indexBuffer);
123	gl.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_indexBuffer);
124	gl.bufferData(GL_ELEMENT_ARRAY_BUFFER, int(m_numIndices * sizeof(deUint32)), &indices[0], GL_STATIC_DRAW);
125	GLU_EXPECT_NO_ERROR(gl.getError(), "buffer gen");
126
127	m_program = new glu::ShaderProgram(m_context.getRenderContext(), glu::ProgramSources() << glu::VertexSource(s_vertexSource) << glu::FragmentSource(s_fragmentSource));
128	if (!m_program->isOk())
129	{
130		m_testCtx.getLog() << *m_program;
131		throw tcu::TestError("could not build program");
132	}
133}
134
135void DrawInvalidRangeCase::deinit (void)
136{
137	if (m_buffer)
138	{
139		m_context.getRenderContext().getFunctions().deleteBuffers(1, &m_buffer);
140		m_buffer = 0;
141	}
142
143	if (m_indexBuffer)
144	{
145		m_context.getRenderContext().getFunctions().deleteBuffers(1, &m_indexBuffer);
146		m_indexBuffer = 0;
147	}
148
149	delete m_program;
150	m_program = DE_NULL;
151}
152
153DrawInvalidRangeCase::IterateResult DrawInvalidRangeCase::iterate (void)
154{
155	glu::CallLogWrapper		gl			(m_context.getRenderContext().getFunctions(), m_testCtx.getLog());
156	const deInt32			positionLoc = gl.glGetAttribLocation(m_program->getProgram(), "a_position");
157	tcu::Surface			dst			(m_context.getRenderTarget().getWidth(), m_context.getRenderTarget().getHeight());
158	glu::VertexArray		vao			(m_context.getRenderContext());
159
160	deInt64					indexLimit	= 0;
161	deUint32				min			= m_min;
162	deUint32				max			= m_max;
163
164	gl.enableLogging(true);
165
166	if (m_useLimitMin || m_useLimitMax)
167	{
168		gl.glGetInteger64v(GL_MAX_ELEMENT_INDEX, &indexLimit);
169		GLU_EXPECT_NO_ERROR(gl.glGetError(), "query limit");
170	}
171
172	if (m_useLimitMin)
173	{
174		if ((deUint64)indexLimit > 0xFFFFFFFFULL)
175			min = 0xFFFFFFF0;
176		else
177			min = (deUint32)(indexLimit - 16);
178	}
179
180	if (m_useLimitMax)
181	{
182		if ((deUint64)indexLimit > 0xFFFFFFFFULL)
183			max = 0xFFFFFFFF;
184		else
185			max = (deUint32)indexLimit;
186	}
187
188	gl.glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
189	gl.glClear(GL_COLOR_BUFFER_BIT);
190	GLU_EXPECT_NO_ERROR(gl.glGetError(), "setup");
191
192	gl.glUseProgram(m_program->getProgram());
193	GLU_EXPECT_NO_ERROR(gl.glGetError(), "use program");
194
195	gl.glBindVertexArray(*vao);
196	gl.glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_indexBuffer);
197
198	gl.glBindBuffer(GL_ARRAY_BUFFER, m_buffer);
199	gl.glEnableVertexAttribArray(positionLoc);
200	gl.glVertexAttribPointer(positionLoc, 4, GL_FLOAT, GL_FALSE, 0, DE_NULL);
201	GLU_EXPECT_NO_ERROR(gl.glGetError(), "set buffer");
202
203	gl.glDrawRangeElements(GL_POINTS, min, max, m_numIndices, GL_UNSIGNED_INT, DE_NULL);
204
205	// Indexing outside range is an error, but it doesnt need to be checked. Causes implementation-dependent behavior.
206	// Even if the indices are in range (m_min = 0), the specification allows partial processing of vertices in the range,
207	// which might cause access over buffer bounds. Causes implementation-dependent behavior.
208
209	// allow errors
210	{
211		const deUint32 error = gl.glGetError();
212
213		if (error != GL_NO_ERROR)
214			m_testCtx.getLog() << tcu::TestLog::Message << "Got error: " << glu::getErrorStr(error) << ", ignoring..." << tcu::TestLog::EndMessage;
215	}
216
217	// read pixels to wait for rendering
218	gl.glFinish();
219	glu::readPixels(m_context.getRenderContext(), 0, 0, dst.getAccess());
220
221	m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
222	return STOP;
223}
224
225static void genBasicSpec (gls::DrawTestSpec& spec, gls::DrawTestSpec::DrawMethod method)
226{
227	spec.apiType				= glu::ApiType::es(3,0);
228	spec.primitive				= gls::DrawTestSpec::PRIMITIVE_TRIANGLES;
229	spec.primitiveCount			= 5;
230	spec.drawMethod				= method;
231	spec.indexType				= gls::DrawTestSpec::INDEXTYPE_LAST;
232	spec.indexPointerOffset		= 0;
233	spec.indexStorage			= gls::DrawTestSpec::STORAGE_LAST;
234	spec.first					= 0;
235	spec.indexMin				= 0;
236	spec.indexMax				= 0;
237	spec.instanceCount			= 1;
238
239	spec.attribs.resize(2);
240
241	spec.attribs[0].inputType				= gls::DrawTestSpec::INPUTTYPE_FLOAT;
242	spec.attribs[0].outputType				= gls::DrawTestSpec::OUTPUTTYPE_VEC2;
243	spec.attribs[0].storage					= gls::DrawTestSpec::STORAGE_BUFFER;
244	spec.attribs[0].usage					= gls::DrawTestSpec::USAGE_STATIC_DRAW;
245	spec.attribs[0].componentCount			= 4;
246	spec.attribs[0].offset					= 0;
247	spec.attribs[0].stride					= 0;
248	spec.attribs[0].normalize				= false;
249	spec.attribs[0].instanceDivisor			= 0;
250	spec.attribs[0].useDefaultAttribute		= false;
251
252	spec.attribs[1].inputType				= gls::DrawTestSpec::INPUTTYPE_FLOAT;
253	spec.attribs[1].outputType				= gls::DrawTestSpec::OUTPUTTYPE_VEC2;
254	spec.attribs[1].storage					= gls::DrawTestSpec::STORAGE_BUFFER;
255	spec.attribs[1].usage					= gls::DrawTestSpec::USAGE_STATIC_DRAW;
256	spec.attribs[1].componentCount			= 2;
257	spec.attribs[1].offset					= 0;
258	spec.attribs[1].stride					= 0;
259	spec.attribs[1].normalize				= false;
260	spec.attribs[1].instanceDivisor			= 0;
261	spec.attribs[1].useDefaultAttribute		= false;
262}
263
264class IndexGroup : public TestCaseGroup
265{
266public:
267									IndexGroup		(Context& context, const char* name, const char* descr, gls::DrawTestSpec::DrawMethod drawMethod);
268									~IndexGroup		(void);
269
270	void							init			(void);
271
272private:
273	gls::DrawTestSpec::DrawMethod	m_method;
274};
275
276IndexGroup::IndexGroup (Context& context, const char* name, const char* descr, gls::DrawTestSpec::DrawMethod drawMethod)
277	: TestCaseGroup		(context, name, descr)
278	, m_method			(drawMethod)
279{
280}
281
282IndexGroup::~IndexGroup (void)
283{
284}
285
286void IndexGroup::init (void)
287{
288	struct IndexTest
289	{
290		gls::DrawTestSpec::Storage		storage;
291		gls::DrawTestSpec::IndexType	type;
292		bool							aligned;
293		int								offsets[3];
294	};
295
296	const IndexTest tests[] =
297	{
298		{ gls::DrawTestSpec::STORAGE_USER,		gls::DrawTestSpec::INDEXTYPE_BYTE,	true,	{ 0, 1, -1 } },
299		{ gls::DrawTestSpec::STORAGE_USER,		gls::DrawTestSpec::INDEXTYPE_SHORT,	true,	{ 0, 2, -1 } },
300		{ gls::DrawTestSpec::STORAGE_USER,		gls::DrawTestSpec::INDEXTYPE_INT,	true,	{ 0, 4, -1 } },
301
302		{ gls::DrawTestSpec::STORAGE_USER,		gls::DrawTestSpec::INDEXTYPE_SHORT,	false,	{ 1, 3, -1 } },
303		{ gls::DrawTestSpec::STORAGE_USER,		gls::DrawTestSpec::INDEXTYPE_INT,	false,	{ 2, 3, -1 } },
304
305		{ gls::DrawTestSpec::STORAGE_BUFFER,	gls::DrawTestSpec::INDEXTYPE_BYTE,	true,	{ 0, 1, -1 } },
306		{ gls::DrawTestSpec::STORAGE_BUFFER,	gls::DrawTestSpec::INDEXTYPE_SHORT,	true,	{ 0, 2, -1 } },
307		{ gls::DrawTestSpec::STORAGE_BUFFER,	gls::DrawTestSpec::INDEXTYPE_INT,	true,	{ 0, 4, -1 } },
308
309		{ gls::DrawTestSpec::STORAGE_BUFFER,	gls::DrawTestSpec::INDEXTYPE_SHORT,	false,	{ 1, 3, -1 } },
310		{ gls::DrawTestSpec::STORAGE_BUFFER,	gls::DrawTestSpec::INDEXTYPE_INT,	false,	{ 2, 3, -1 } },
311	};
312
313	gls::DrawTestSpec spec;
314
315	tcu::TestCaseGroup* const	userPtrGroup			= new tcu::TestCaseGroup(m_testCtx, "user_ptr", "user pointer");
316	tcu::TestCaseGroup* const	unalignedUserPtrGroup	= new tcu::TestCaseGroup(m_testCtx, "unaligned_user_ptr", "unaligned user pointer");
317	tcu::TestCaseGroup* const	bufferGroup				= new tcu::TestCaseGroup(m_testCtx, "buffer", "buffer");
318	tcu::TestCaseGroup* const	unalignedBufferGroup	= new tcu::TestCaseGroup(m_testCtx, "unaligned_buffer", "unaligned buffer");
319	const bool					isRangedMethod			= (m_method == gls::DrawTestSpec::DRAWMETHOD_DRAWELEMENTS_RANGED || m_method == gls::DrawTestSpec::DRAWMETHOD_DRAWELEMENTS_RANGED_BASEVERTEX);
320
321	genBasicSpec(spec, m_method);
322
323	this->addChild(userPtrGroup);
324	this->addChild(unalignedUserPtrGroup);
325	this->addChild(bufferGroup);
326	this->addChild(unalignedBufferGroup);
327
328	for (int testNdx = 0; testNdx < DE_LENGTH_OF_ARRAY(tests); ++testNdx)
329	{
330		const IndexTest&				indexTest	= tests[testNdx];
331		tcu::TestCaseGroup*				group		= (indexTest.storage == gls::DrawTestSpec::STORAGE_USER) ? ((indexTest.aligned) ? (userPtrGroup) : (unalignedUserPtrGroup)) : ((indexTest.aligned) ? (bufferGroup) : (unalignedBufferGroup));
332
333		const std::string				name		= std::string("index_") + gls::DrawTestSpec::indexTypeToString(indexTest.type);
334		const std::string				desc		= std::string("index ") + gls::DrawTestSpec::indexTypeToString(indexTest.type) + " in " + gls::DrawTestSpec::storageToString(indexTest.storage);
335		de::MovePtr<gls::DrawTest>		test		(new gls::DrawTest(m_testCtx, m_context.getRenderContext(), name.c_str(), desc.c_str()));
336
337		spec.indexType			= indexTest.type;
338		spec.indexStorage		= indexTest.storage;
339
340		if (isRangedMethod)
341		{
342			spec.indexMin = 0;
343			spec.indexMax = 55;
344		}
345
346		for (int iterationNdx = 0; iterationNdx < DE_LENGTH_OF_ARRAY(indexTest.offsets) && indexTest.offsets[iterationNdx] != -1; ++iterationNdx)
347		{
348			const std::string iterationDesc = std::string("offset ") + de::toString(indexTest.offsets[iterationNdx]);
349			spec.indexPointerOffset	= indexTest.offsets[iterationNdx];
350			test->addIteration(spec, iterationDesc.c_str());
351		}
352
353		if (spec.isCompatibilityTest() == gls::DrawTestSpec::COMPATIBILITY_UNALIGNED_OFFSET ||
354			spec.isCompatibilityTest() == gls::DrawTestSpec::COMPATIBILITY_UNALIGNED_STRIDE)
355			group->addChild(test.release());
356	}
357}
358
359class MethodGroup : public TestCaseGroup
360{
361public:
362									MethodGroup			(Context& context, const char* name, const char* descr, gls::DrawTestSpec::DrawMethod drawMethod);
363									~MethodGroup		(void);
364
365	void							init				(void);
366
367private:
368	gls::DrawTestSpec::DrawMethod	m_method;
369};
370
371MethodGroup::MethodGroup (Context& context, const char* name, const char* descr, gls::DrawTestSpec::DrawMethod drawMethod)
372	: TestCaseGroup		(context, name, descr)
373	, m_method			(drawMethod)
374{
375}
376
377MethodGroup::~MethodGroup (void)
378{
379}
380
381void MethodGroup::init (void)
382{
383	const bool indexed		= (m_method == gls::DrawTestSpec::DRAWMETHOD_DRAWELEMENTS) || (m_method == gls::DrawTestSpec::DRAWMETHOD_DRAWELEMENTS_INSTANCED) || (m_method == gls::DrawTestSpec::DRAWMETHOD_DRAWELEMENTS_RANGED);
384
385	DE_ASSERT(indexed);
386	DE_UNREF(indexed);
387
388	this->addChild(new IndexGroup(m_context, "indices", "Index tests", m_method));
389}
390
391class RandomGroup : public TestCaseGroup
392{
393public:
394									RandomGroup		(Context& context, const char* name, const char* descr);
395									~RandomGroup	(void);
396
397	void							init			(void);
398};
399
400template <int SIZE>
401struct UniformWeightArray
402{
403	float weights[SIZE];
404
405	UniformWeightArray (void)
406	{
407		for (int i=0; i<SIZE; ++i)
408			weights[i] = 1.0f;
409	}
410};
411
412RandomGroup::RandomGroup (Context& context, const char* name, const char* descr)
413	: TestCaseGroup	(context, name, descr)
414{
415}
416
417RandomGroup::~RandomGroup (void)
418{
419}
420
421void RandomGroup::init (void)
422{
423	const int	numAttempts				= 300;
424
425	const int	attribCounts[]			= { 1, 2, 5 };
426	const float	attribWeights[]			= { 30, 10, 1 };
427	const int	primitiveCounts[]		= { 1, 5, 64 };
428	const float	primitiveCountWeights[]	= { 20, 10, 1 };
429	const int	indexOffsets[]			= { 0, 7, 13 };
430	const float	indexOffsetWeights[]	= { 20, 20, 1 };
431	const int	firsts[]				= { 0, 7, 13 };
432	const float	firstWeights[]			= { 20, 20, 1 };
433	const int	instanceCounts[]		= { 1, 2, 16, 17 };
434	const float	instanceWeights[]		= { 20, 10, 5, 1 };
435	const int	indexMins[]				= { 0, 1, 3, 8 };
436	const int	indexMaxs[]				= { 4, 8, 128, 257 };
437	const float	indexWeights[]			= { 50, 50, 50, 50 };
438	const int	offsets[]				= { 0, 1, 5, 12 };
439	const float	offsetWeights[]			= { 50, 10, 10, 10 };
440	const int	strides[]				= { 0, 7, 16, 17 };
441	const float	strideWeights[]			= { 50, 10, 10, 10 };
442	const int	instanceDivisors[]		= { 0, 1, 3, 129 };
443	const float	instanceDivisorWeights[]= { 70, 30, 10, 10 };
444
445	gls::DrawTestSpec::Primitive primitives[] =
446	{
447		gls::DrawTestSpec::PRIMITIVE_POINTS,
448		gls::DrawTestSpec::PRIMITIVE_TRIANGLES,
449		gls::DrawTestSpec::PRIMITIVE_TRIANGLE_FAN,
450		gls::DrawTestSpec::PRIMITIVE_TRIANGLE_STRIP,
451		gls::DrawTestSpec::PRIMITIVE_LINES,
452		gls::DrawTestSpec::PRIMITIVE_LINE_STRIP,
453		gls::DrawTestSpec::PRIMITIVE_LINE_LOOP
454	};
455	const UniformWeightArray<DE_LENGTH_OF_ARRAY(primitives)> primitiveWeights;
456
457	gls::DrawTestSpec::DrawMethod drawMethods[] =
458	{
459		gls::DrawTestSpec::DRAWMETHOD_DRAWARRAYS,
460		gls::DrawTestSpec::DRAWMETHOD_DRAWARRAYS_INSTANCED,
461		gls::DrawTestSpec::DRAWMETHOD_DRAWELEMENTS,
462		gls::DrawTestSpec::DRAWMETHOD_DRAWELEMENTS_RANGED,
463		gls::DrawTestSpec::DRAWMETHOD_DRAWELEMENTS_INSTANCED
464	};
465	const UniformWeightArray<DE_LENGTH_OF_ARRAY(drawMethods)> drawMethodWeights;
466
467	gls::DrawTestSpec::IndexType indexTypes[] =
468	{
469		gls::DrawTestSpec::INDEXTYPE_BYTE,
470		gls::DrawTestSpec::INDEXTYPE_SHORT,
471		gls::DrawTestSpec::INDEXTYPE_INT,
472	};
473	const UniformWeightArray<DE_LENGTH_OF_ARRAY(indexTypes)> indexTypeWeights;
474
475	gls::DrawTestSpec::Storage storages[] =
476	{
477		gls::DrawTestSpec::STORAGE_USER,
478		gls::DrawTestSpec::STORAGE_BUFFER,
479	};
480	const UniformWeightArray<DE_LENGTH_OF_ARRAY(storages)> storageWeights;
481
482	gls::DrawTestSpec::InputType inputTypes[] =
483	{
484		gls::DrawTestSpec::INPUTTYPE_FLOAT,
485		gls::DrawTestSpec::INPUTTYPE_FIXED,
486		gls::DrawTestSpec::INPUTTYPE_BYTE,
487		gls::DrawTestSpec::INPUTTYPE_SHORT,
488		gls::DrawTestSpec::INPUTTYPE_UNSIGNED_BYTE,
489		gls::DrawTestSpec::INPUTTYPE_UNSIGNED_SHORT,
490		gls::DrawTestSpec::INPUTTYPE_INT,
491		gls::DrawTestSpec::INPUTTYPE_UNSIGNED_INT,
492		gls::DrawTestSpec::INPUTTYPE_HALF,
493		gls::DrawTestSpec::INPUTTYPE_UNSIGNED_INT_2_10_10_10,
494		gls::DrawTestSpec::INPUTTYPE_INT_2_10_10_10,
495	};
496	const UniformWeightArray<DE_LENGTH_OF_ARRAY(inputTypes)> inputTypeWeights;
497
498	gls::DrawTestSpec::OutputType outputTypes[] =
499	{
500		gls::DrawTestSpec::OUTPUTTYPE_FLOAT,
501		gls::DrawTestSpec::OUTPUTTYPE_VEC2,
502		gls::DrawTestSpec::OUTPUTTYPE_VEC3,
503		gls::DrawTestSpec::OUTPUTTYPE_VEC4,
504		gls::DrawTestSpec::OUTPUTTYPE_INT,
505		gls::DrawTestSpec::OUTPUTTYPE_UINT,
506		gls::DrawTestSpec::OUTPUTTYPE_IVEC2,
507		gls::DrawTestSpec::OUTPUTTYPE_IVEC3,
508		gls::DrawTestSpec::OUTPUTTYPE_IVEC4,
509		gls::DrawTestSpec::OUTPUTTYPE_UVEC2,
510		gls::DrawTestSpec::OUTPUTTYPE_UVEC3,
511		gls::DrawTestSpec::OUTPUTTYPE_UVEC4,
512	};
513	const UniformWeightArray<DE_LENGTH_OF_ARRAY(outputTypes)> outputTypeWeights;
514
515	gls::DrawTestSpec::Usage usages[] =
516	{
517		gls::DrawTestSpec::USAGE_DYNAMIC_DRAW,
518		gls::DrawTestSpec::USAGE_STATIC_DRAW,
519		gls::DrawTestSpec::USAGE_STREAM_DRAW,
520		gls::DrawTestSpec::USAGE_STREAM_READ,
521		gls::DrawTestSpec::USAGE_STREAM_COPY,
522		gls::DrawTestSpec::USAGE_STATIC_READ,
523		gls::DrawTestSpec::USAGE_STATIC_COPY,
524		gls::DrawTestSpec::USAGE_DYNAMIC_READ,
525		gls::DrawTestSpec::USAGE_DYNAMIC_COPY,
526	};
527	const UniformWeightArray<DE_LENGTH_OF_ARRAY(usages)> usageWeights;
528
529	std::set<deUint32>	insertedHashes;
530	size_t				insertedCount = 0;
531
532	for (int ndx = 0; ndx < numAttempts; ++ndx)
533	{
534		de::Random random(0xc551393 + ndx); // random does not depend on previous cases
535
536		int					attributeCount = random.chooseWeighted<int, const int*, const float*>(DE_ARRAY_BEGIN(attribCounts), DE_ARRAY_END(attribCounts), attribWeights);
537		gls::DrawTestSpec	spec;
538
539		spec.apiType				= glu::ApiType::es(3,0);
540		spec.primitive				= random.chooseWeighted<gls::DrawTestSpec::Primitive>	(DE_ARRAY_BEGIN(primitives),		DE_ARRAY_END(primitives),		primitiveWeights.weights);
541		spec.primitiveCount			= random.chooseWeighted<int, const int*, const float*>	(DE_ARRAY_BEGIN(primitiveCounts),	DE_ARRAY_END(primitiveCounts),	primitiveCountWeights);
542		spec.drawMethod				= random.chooseWeighted<gls::DrawTestSpec::DrawMethod>	(DE_ARRAY_BEGIN(drawMethods),		DE_ARRAY_END(drawMethods),		drawMethodWeights.weights);
543		spec.indexType				= random.chooseWeighted<gls::DrawTestSpec::IndexType>	(DE_ARRAY_BEGIN(indexTypes),		DE_ARRAY_END(indexTypes),		indexTypeWeights.weights);
544		spec.indexPointerOffset		= random.chooseWeighted<int, const int*, const float*>	(DE_ARRAY_BEGIN(indexOffsets),		DE_ARRAY_END(indexOffsets),		indexOffsetWeights);
545		spec.indexStorage			= random.chooseWeighted<gls::DrawTestSpec::Storage>		(DE_ARRAY_BEGIN(storages),			DE_ARRAY_END(storages),			storageWeights.weights);
546		spec.first					= random.chooseWeighted<int, const int*, const float*>	(DE_ARRAY_BEGIN(firsts),			DE_ARRAY_END(firsts),			firstWeights);
547		spec.indexMin				= random.chooseWeighted<int, const int*, const float*>	(DE_ARRAY_BEGIN(indexMins),			DE_ARRAY_END(indexMins),		indexWeights);
548		spec.indexMax				= random.chooseWeighted<int, const int*, const float*>	(DE_ARRAY_BEGIN(indexMaxs),			DE_ARRAY_END(indexMaxs),		indexWeights);
549		spec.instanceCount			= random.chooseWeighted<int, const int*, const float*>	(DE_ARRAY_BEGIN(instanceCounts),	DE_ARRAY_END(instanceCounts),	instanceWeights);
550
551		// check spec is legal
552		if (!spec.valid())
553			continue;
554
555		for (int attrNdx = 0; attrNdx < attributeCount;)
556		{
557			bool valid;
558			gls::DrawTestSpec::AttributeSpec attribSpec;
559
560			attribSpec.inputType			= random.chooseWeighted<gls::DrawTestSpec::InputType>	(DE_ARRAY_BEGIN(inputTypes),		DE_ARRAY_END(inputTypes),		inputTypeWeights.weights);
561			attribSpec.outputType			= random.chooseWeighted<gls::DrawTestSpec::OutputType>	(DE_ARRAY_BEGIN(outputTypes),		DE_ARRAY_END(outputTypes),		outputTypeWeights.weights);
562			attribSpec.storage				= random.chooseWeighted<gls::DrawTestSpec::Storage>		(DE_ARRAY_BEGIN(storages),			DE_ARRAY_END(storages),			storageWeights.weights);
563			attribSpec.usage				= random.chooseWeighted<gls::DrawTestSpec::Usage>		(DE_ARRAY_BEGIN(usages),			DE_ARRAY_END(usages),			usageWeights.weights);
564			attribSpec.componentCount		= random.getInt(1, 4);
565			attribSpec.offset				= random.chooseWeighted<int, const int*, const float*>(DE_ARRAY_BEGIN(offsets), DE_ARRAY_END(offsets), offsetWeights);
566			attribSpec.stride				= random.chooseWeighted<int, const int*, const float*>(DE_ARRAY_BEGIN(strides), DE_ARRAY_END(strides), strideWeights);
567			attribSpec.normalize			= random.getBool();
568			attribSpec.instanceDivisor		= random.chooseWeighted<int, const int*, const float*>(DE_ARRAY_BEGIN(instanceDivisors), DE_ARRAY_END(instanceDivisors), instanceDivisorWeights);
569			attribSpec.useDefaultAttribute	= random.getBool();
570
571			// check spec is legal
572			valid = attribSpec.valid(spec.apiType);
573
574			// we do not want interleaved elements. (Might result in some weird floating point values)
575			if (attribSpec.stride && attribSpec.componentCount * gls::DrawTestSpec::inputTypeSize(attribSpec.inputType) > attribSpec.stride)
576				valid = false;
577
578			// try again if not valid
579			if (valid)
580			{
581				spec.attribs.push_back(attribSpec);
582				++attrNdx;
583			}
584		}
585
586		// Do not collapse all vertex positions to a single positions
587		if (spec.primitive != gls::DrawTestSpec::PRIMITIVE_POINTS)
588			spec.attribs[0].instanceDivisor = 0;
589
590		// Is render result meaningful?
591		{
592			// Only one vertex
593			if (spec.drawMethod == gls::DrawTestSpec::DRAWMETHOD_DRAWELEMENTS_RANGED && spec.indexMin == spec.indexMax && spec.primitive != gls::DrawTestSpec::PRIMITIVE_POINTS)
594				continue;
595			if (spec.attribs[0].useDefaultAttribute && spec.primitive != gls::DrawTestSpec::PRIMITIVE_POINTS)
596				continue;
597
598			// Triangle only on one axis
599			if (spec.primitive == gls::DrawTestSpec::PRIMITIVE_TRIANGLES || spec.primitive == gls::DrawTestSpec::PRIMITIVE_TRIANGLE_FAN || spec.primitive == gls::DrawTestSpec::PRIMITIVE_TRIANGLE_STRIP)
600			{
601				if (spec.attribs[0].componentCount == 1)
602					continue;
603				if (spec.attribs[0].outputType == gls::DrawTestSpec::OUTPUTTYPE_FLOAT || spec.attribs[0].outputType == gls::DrawTestSpec::OUTPUTTYPE_INT || spec.attribs[0].outputType == gls::DrawTestSpec::OUTPUTTYPE_UINT)
604					continue;
605				if (spec.drawMethod == gls::DrawTestSpec::DRAWMETHOD_DRAWELEMENTS_RANGED && (spec.indexMax - spec.indexMin) < 2)
606					continue;
607			}
608		}
609
610		// Add case
611		{
612			deUint32 hash = spec.hash();
613			for (int attrNdx = 0; attrNdx < attributeCount; ++attrNdx)
614				hash = (hash << 2) ^ (deUint32)spec.attribs[attrNdx].hash();
615
616			if (insertedHashes.find(hash) == insertedHashes.end())
617			{
618				// Only unaligned cases
619				if (spec.isCompatibilityTest() == gls::DrawTestSpec::COMPATIBILITY_UNALIGNED_OFFSET ||
620					spec.isCompatibilityTest() == gls::DrawTestSpec::COMPATIBILITY_UNALIGNED_STRIDE)
621					this->addChild(new gls::DrawTest(m_testCtx, m_context.getRenderContext(), spec, de::toString(insertedCount).c_str(), spec.getDesc().c_str()));
622				insertedHashes.insert(hash);
623
624				++insertedCount;
625			}
626		}
627	}
628}
629
630} // anonymous
631
632DrawTests::DrawTests (Context& context)
633	: TestCaseGroup(context, "draw", "Draw stress tests")
634{
635}
636
637DrawTests::~DrawTests (void)
638{
639}
640
641void DrawTests::init (void)
642{
643	tcu::TestCaseGroup* const unalignedGroup	= new tcu::TestCaseGroup(m_testCtx, "unaligned_data", "Test with unaligned data");
644	tcu::TestCaseGroup* const drawRangeGroup	= new tcu::TestCaseGroup(m_testCtx, "draw_range_elements", "Test drawRangeElements");
645
646	addChild(unalignedGroup);
647	addChild(drawRangeGroup);
648
649	// .unaligned_data
650	{
651		const gls::DrawTestSpec::DrawMethod basicMethods[] =
652		{
653			// gls::DrawTestSpec::DRAWMETHOD_DRAWARRAYS,
654			gls::DrawTestSpec::DRAWMETHOD_DRAWELEMENTS,
655			// gls::DrawTestSpec::DRAWMETHOD_DRAWARRAYS_INSTANCED,
656			gls::DrawTestSpec::DRAWMETHOD_DRAWELEMENTS_INSTANCED,
657			gls::DrawTestSpec::DRAWMETHOD_DRAWELEMENTS_RANGED,
658		};
659
660		for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(basicMethods); ++ndx)
661		{
662			const std::string name = gls::DrawTestSpec::drawMethodToString(basicMethods[ndx]);
663			const std::string desc = gls::DrawTestSpec::drawMethodToString(basicMethods[ndx]);
664
665			unalignedGroup->addChild(new MethodGroup(m_context, name.c_str(), desc.c_str(), basicMethods[ndx]));
666		}
667
668		// Random
669
670		unalignedGroup->addChild(new RandomGroup(m_context, "random", "random draw commands."));
671	}
672
673	// .draw_range_elements
674	{
675		// use a larger range than the buffer size is
676		drawRangeGroup->addChild(new DrawInvalidRangeCase(m_context, "range_max_over_bounds",							"Range over buffer bounds",	0x00000000,	0x00210000));
677		drawRangeGroup->addChild(new DrawInvalidRangeCase(m_context, "range_max_over_bounds_near_signed_wrap",			"Range over buffer bounds",	0x00000000,	0x7FFFFFFF));
678		drawRangeGroup->addChild(new DrawInvalidRangeCase(m_context, "range_max_over_bounds_near_unsigned_wrap",		"Range over buffer bounds",	0x00000000,	0xFFFFFFFF));
679		drawRangeGroup->addChild(new DrawInvalidRangeCase(m_context, "range_max_over_bounds_near_max",					"Range over buffer bounds",	0x00000000, 0x00000000, false, true));
680
681		drawRangeGroup->addChild(new DrawInvalidRangeCase(m_context, "range_min_max_over_bounds",						"Range over buffer bounds",	0x00200000,	0x00210000));
682		drawRangeGroup->addChild(new DrawInvalidRangeCase(m_context, "range_min_max_over_bounds_near_signed_wrap",		"Range over buffer bounds",	0x7FFFFFF0,	0x7FFFFFFF));
683		drawRangeGroup->addChild(new DrawInvalidRangeCase(m_context, "range_min_max_over_bounds_near_unsigned_wrap",	"Range over buffer bounds",	0xFFFFFFF0,	0xFFFFFFFF));
684		drawRangeGroup->addChild(new DrawInvalidRangeCase(m_context, "range_min_max_over_bounds_near_max",				"Range over buffer bounds",	0x00000000, 0x00000000, true, true));
685	}
686}
687
688} // Stress
689} // gles3
690} // deqp
691