1
2/*-------------------------------------------------------------------------
3 * drawElements Quality Program OpenGL ES 3.1 Module
4 * -------------------------------------------------
5 *
6 * Copyright 2014 The Android Open Source Project
7 *
8 * Licensed under the Apache License, Version 2.0 (the "License");
9 * you may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
11 *
12 *      http://www.apache.org/licenses/LICENSE-2.0
13 *
14 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS,
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
19 *
20 *//*!
21 * \file
22 * \brief Drawing stress tests.
23 *//*--------------------------------------------------------------------*/
24
25#include "es31sDrawTests.hpp"
26#include "glsDrawTest.hpp"
27#include "gluRenderContext.hpp"
28#include "gluCallLogWrapper.hpp"
29#include "gluShaderProgram.hpp"
30#include "glwEnums.hpp"
31#include "glwFunctions.hpp"
32#include "deRandom.hpp"
33#include "deStringUtil.hpp"
34#include "deUniquePtr.hpp"
35
36#include <set>
37
38namespace deqp
39{
40namespace gles31
41{
42namespace Stress
43{
44namespace
45{
46
47static const char* s_colorVertexShaderSource =		"#version 310 es\n"
48													"in highp vec4 a_position;\n"
49													"in highp vec4 a_color;\n"
50													"out highp vec4 v_color;\n"
51													"void main (void)\n"
52													"{\n"
53													"	gl_Position = a_position;\n"
54													"	v_color = a_color;\n"
55													"}\n";
56static const char* s_colorFragmentShaderSource	=	"#version 310 es\n"
57													"layout(location = 0) out highp vec4 fragColor;\n"
58													"in highp vec4 v_color;\n"
59													"void main (void)\n"
60													"{\n"
61													"	fragColor = v_color;\n"
62													"}\n";
63struct DrawElementsCommand
64{
65	deUint32 count;
66	deUint32 primCount;
67	deUint32 firstIndex;
68	deInt32  baseVertex;
69	deUint32 reservedMustBeZero;
70};
71DE_STATIC_ASSERT(5 * sizeof(deUint32) == sizeof(DrawElementsCommand)); // tight packing
72
73struct DrawArraysCommand
74{
75	deUint32 count;
76	deUint32 primCount;
77	deUint32 first;
78	deUint32 reservedMustBeZero;
79};
80DE_STATIC_ASSERT(4 * sizeof(deUint32) == sizeof(DrawArraysCommand)); // tight packing
81
82class InvalidDrawCase : public TestCase
83{
84public:
85	enum DrawType
86	{
87		DRAW_ARRAYS,
88		DRAW_ELEMENTS,
89
90		DRAW_LAST
91	};
92	enum InvalidOperation
93	{
94		INVALID_DATA_COUNT = 0,
95		INVALID_DATA_FIRST,
96		INVALID_DATA_INSTANCED,
97		INVALID_INDEX_COUNT,
98		INVALID_INDEX_FIRST,
99		INVALID_RESERVED,
100		INVALID_INDEX,
101
102		INVALID_LAST
103	};
104
105							InvalidDrawCase		(Context& context, const char* name, const char* desc, DrawType type, InvalidOperation op);
106							~InvalidDrawCase	(void);
107
108	void					init				(void);
109	void					deinit				(void);
110	IterateResult			iterate				(void);
111
112private:
113	const DrawType			m_drawType;
114	const InvalidOperation	m_op;
115	glw::GLuint				m_dataBufferID;
116	glw::GLuint				m_indexBufferID;
117	glw::GLuint				m_cmdBufferID;
118	glw::GLuint				m_colorBufferID;
119	glw::GLuint				m_vao;
120};
121
122InvalidDrawCase::InvalidDrawCase (Context& context, const char* name, const char* desc, DrawType type, InvalidOperation op)
123	: TestCase			(context, name, desc)
124	, m_drawType		(type)
125	, m_op				(op)
126	, m_dataBufferID	(0)
127	, m_indexBufferID	(0)
128	, m_cmdBufferID		(0)
129	, m_colorBufferID	(0)
130	, m_vao				(0)
131{
132	DE_ASSERT(type < DRAW_LAST);
133	DE_ASSERT(op < INVALID_LAST);
134}
135
136InvalidDrawCase::~InvalidDrawCase (void)
137{
138	deinit();
139}
140
141void InvalidDrawCase::init (void)
142{
143}
144
145void InvalidDrawCase::deinit (void)
146{
147	if (m_dataBufferID)
148	{
149		m_context.getRenderContext().getFunctions().deleteBuffers(1, &m_dataBufferID);
150		m_dataBufferID = 0;
151	}
152	if (m_indexBufferID)
153	{
154		m_context.getRenderContext().getFunctions().deleteBuffers(1, &m_indexBufferID);
155		m_indexBufferID = 0;
156	}
157	if (m_cmdBufferID)
158	{
159		m_context.getRenderContext().getFunctions().deleteBuffers(1, &m_cmdBufferID);
160		m_cmdBufferID = 0;
161	}
162	if (m_colorBufferID)
163	{
164		m_context.getRenderContext().getFunctions().deleteBuffers(1, &m_colorBufferID);
165		m_colorBufferID = 0;
166	}
167	if (m_vao)
168	{
169		m_context.getRenderContext().getFunctions().deleteVertexArrays(1, &m_vao);
170		m_vao = 0;
171	}
172}
173
174InvalidDrawCase::IterateResult InvalidDrawCase::iterate (void)
175{
176	const int drawCount				= 10;		//!< number of elements safe to draw (all buffers have this)
177	const int overBoundDrawCount	= 10000;	//!< number of elements in all other buffers than our target buffer
178	const int drawInstances			= 1;
179	const int overBoundInstances	= 1000;
180
181	glu::CallLogWrapper gl				(m_context.getRenderContext().getFunctions(), m_testCtx.getLog());
182	glu::ShaderProgram	program			(m_context.getRenderContext(), glu::ProgramSources() << glu::VertexSource(s_colorVertexShaderSource) << glu::FragmentSource(s_colorFragmentShaderSource));
183	const deUint32		programID		= program.getProgram();
184	const deInt32		posLocation		= gl.glGetAttribLocation(programID, "a_position");
185	const deInt32		colorLocation	= gl.glGetAttribLocation(programID, "a_color");
186
187	gl.enableLogging(true);
188
189	gl.glGenVertexArrays(1, &m_vao);
190	gl.glBindVertexArray(m_vao);
191	glu::checkError(gl.glGetError(), "gen vao", __FILE__, __LINE__);
192
193	// indices
194	if (m_drawType == DRAW_ELEMENTS)
195	{
196		const int				indexBufferSize = (m_op == INVALID_INDEX_COUNT) ? (drawCount) : (overBoundDrawCount);
197		std::vector<deUint16>	indices			(indexBufferSize);
198
199		for (int ndx = 0; ndx < (int)indices.size(); ++ndx)
200			indices[ndx] = (m_op == INVALID_INDEX) ? (overBoundDrawCount + ndx) : (ndx);
201
202		gl.glGenBuffers(1, &m_indexBufferID);
203		gl.glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_indexBufferID);
204		gl.glBufferData(GL_ELEMENT_ARRAY_BUFFER, (int)(indices.size() * sizeof(deUint16)), &indices[0], GL_STATIC_DRAW);
205		glu::checkError(gl.glGetError(), "", __FILE__, __LINE__);
206	}
207
208	// data
209	{
210		const int dataSize = (m_op == INVALID_DATA_COUNT) ? (drawCount) : (overBoundDrawCount);
211
212		// any data is ok
213		gl.glGenBuffers(1, &m_dataBufferID);
214		gl.glBindBuffer(GL_ARRAY_BUFFER, m_dataBufferID);
215		gl.glBufferData(GL_ARRAY_BUFFER, dataSize * sizeof(float[4]), DE_NULL, GL_STATIC_DRAW);
216		gl.glVertexAttribPointer(posLocation, 4, GL_FLOAT, GL_FALSE, 0, DE_NULL);
217		gl.glEnableVertexAttribArray(posLocation);
218		glu::checkError(gl.glGetError(), "", __FILE__, __LINE__);
219	}
220
221	// potentially instanced data
222	{
223		const int dataSize = drawInstances;
224
225		gl.glGenBuffers(1, &m_colorBufferID);
226		gl.glBindBuffer(GL_ARRAY_BUFFER, m_colorBufferID);
227		gl.glBufferData(GL_ARRAY_BUFFER, dataSize * sizeof(float[4]), DE_NULL, GL_STATIC_DRAW);
228		gl.glVertexAttribPointer(colorLocation, 4, GL_FLOAT, GL_FALSE, 0, DE_NULL);
229		gl.glEnableVertexAttribArray(colorLocation);
230		gl.glVertexAttribDivisor(colorLocation, 1);
231		glu::checkError(gl.glGetError(), "", __FILE__, __LINE__);
232	}
233
234	// command
235	if (m_drawType == DRAW_ARRAYS)
236	{
237		DrawArraysCommand drawCommand;
238		drawCommand.count				= overBoundDrawCount;
239		drawCommand.primCount			= (m_op == INVALID_DATA_INSTANCED)	? (overBoundInstances)	: (drawInstances);
240		drawCommand.first				= (m_op == INVALID_DATA_FIRST)		? (overBoundDrawCount)	: (0);
241		drawCommand.reservedMustBeZero	= (m_op == INVALID_RESERVED)		? (5)					: (0);
242
243		m_testCtx.getLog()
244			<< tcu::TestLog::Message
245			<< "drawCommand:"
246			<< "\n\tcount:\t" << drawCommand.count
247			<< "\n\tprimCount\t" << drawCommand.primCount
248			<< "\n\tfirst\t" << drawCommand.first
249			<< "\n\treservedMustBeZero\t" << drawCommand.reservedMustBeZero
250			<< tcu::TestLog::EndMessage;
251
252		gl.glGenBuffers(1, &m_cmdBufferID);
253		gl.glBindBuffer(GL_DRAW_INDIRECT_BUFFER, m_cmdBufferID);
254		gl.glBufferData(GL_DRAW_INDIRECT_BUFFER, sizeof(drawCommand), &drawCommand, GL_STATIC_DRAW);
255		glu::checkError(gl.glGetError(), "", __FILE__, __LINE__);
256	}
257	else if (m_drawType == DRAW_ELEMENTS)
258	{
259		DrawElementsCommand drawCommand;
260		drawCommand.count				= overBoundDrawCount;
261		drawCommand.primCount			= (m_op == INVALID_DATA_INSTANCED)	? (overBoundInstances)	: (drawInstances);
262		drawCommand.firstIndex			= (m_op == INVALID_INDEX_FIRST)		? (overBoundDrawCount)	: (0);
263		drawCommand.baseVertex			= (m_op == INVALID_DATA_FIRST)		? (overBoundDrawCount)	: (0);
264		drawCommand.reservedMustBeZero	= (m_op == INVALID_RESERVED)		? (5)					: (0);
265
266		m_testCtx.getLog()
267			<< tcu::TestLog::Message
268			<< "drawCommand:"
269			<< "\n\tcount:\t" << drawCommand.count
270			<< "\n\tprimCount\t" << drawCommand.primCount
271			<< "\n\tfirstIndex\t" << drawCommand.firstIndex
272			<< "\n\tbaseVertex\t" << drawCommand.baseVertex
273			<< "\n\treservedMustBeZero\t" << drawCommand.reservedMustBeZero
274			<< tcu::TestLog::EndMessage;
275
276		gl.glGenBuffers(1, &m_cmdBufferID);
277		gl.glBindBuffer(GL_DRAW_INDIRECT_BUFFER, m_cmdBufferID);
278		gl.glBufferData(GL_DRAW_INDIRECT_BUFFER, sizeof(drawCommand), &drawCommand, GL_STATIC_DRAW);
279		glu::checkError(gl.glGetError(), "", __FILE__, __LINE__);
280	}
281	else
282		DE_ASSERT(DE_FALSE);
283
284	gl.glViewport(0, 0, 1, 1);
285	gl.glUseProgram(programID);
286
287	if (m_drawType == DRAW_ELEMENTS)
288		gl.glDrawElementsIndirect(GL_TRIANGLES, GL_UNSIGNED_SHORT, DE_NULL);
289	else if (m_drawType == DRAW_ARRAYS)
290		gl.glDrawArraysIndirect(GL_TRIANGLES, DE_NULL);
291	else
292		DE_ASSERT(DE_FALSE);
293
294	gl.glUseProgram(0);
295	gl.glFinish();
296
297	m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
298	return STOP;
299}
300
301class RandomGroup : public TestCaseGroup
302{
303public:
304			RandomGroup		(Context& context, const char* name, const char* descr);
305			~RandomGroup	(void);
306
307	void	init			(void);
308};
309
310template <int SIZE>
311struct UniformWeightArray
312{
313	float weights[SIZE];
314
315	UniformWeightArray (void)
316	{
317		for (int i=0; i<SIZE; ++i)
318			weights[i] = 1.0f;
319	}
320};
321
322RandomGroup::RandomGroup (Context& context, const char* name, const char* descr)
323	: TestCaseGroup	(context, name, descr)
324{
325}
326
327RandomGroup::~RandomGroup (void)
328{
329}
330
331void RandomGroup::init (void)
332{
333	const int	numAttempts				= 100;
334
335	const int	attribCounts[]			= { 1,   2,   5 };
336	const float	attribWeights[]			= { 30, 10,   1 };
337	const int	primitiveCounts[]		= { 1,   5,  64 };
338	const float	primitiveCountWeights[]	= { 20, 10,   1 };
339	const int	indexOffsets[]			= { 0,   7,  13 };
340	const float	indexOffsetWeights[]	= { 20, 20,   1 };
341	const int	firsts[]				= { 0,   7,  13 };
342	const float	firstWeights[]			= { 20, 20,   1 };
343
344	const int	instanceCounts[]		= { 1,   2,  16,  17 };
345	const float	instanceWeights[]		= { 20, 10,   5,   1 };
346	const int	indexMins[]				= { 0,   1,   3,   8 };
347	const int	indexMaxs[]				= { 4,   8, 128, 257 };
348	const float	indexWeights[]			= { 50, 50,  50,  50 };
349	const int	offsets[]				= { 0,   1,   5,  12 };
350	const float	offsetWeights[]			= { 50, 10,  10,  10 };
351	const int	strides[]				= { 0,   7,  16,  17 };
352	const float	strideWeights[]			= { 50, 10,  10,  10 };
353	const int	instanceDivisors[]		= { 0,   1,   3, 129 };
354	const float	instanceDivisorWeights[]= { 70, 30,  10,  10 };
355
356	const int	indirectOffsets[]		= { 0,   1,   2 };
357	const float indirectOffsetWeigths[]	= { 2,   1,   1 };
358	const int	baseVertices[]			= { 0,   1,  -2,   4,  3 };
359	const float baseVertexWeigths[]		= { 4,   1,   1,   1,  1 };
360
361	gls::DrawTestSpec::Primitive primitives[] =
362	{
363		gls::DrawTestSpec::PRIMITIVE_POINTS,
364		gls::DrawTestSpec::PRIMITIVE_TRIANGLES,
365		gls::DrawTestSpec::PRIMITIVE_TRIANGLE_FAN,
366		gls::DrawTestSpec::PRIMITIVE_TRIANGLE_STRIP,
367		gls::DrawTestSpec::PRIMITIVE_LINES,
368		gls::DrawTestSpec::PRIMITIVE_LINE_STRIP,
369		gls::DrawTestSpec::PRIMITIVE_LINE_LOOP
370	};
371	const UniformWeightArray<DE_LENGTH_OF_ARRAY(primitives)> primitiveWeights;
372
373	gls::DrawTestSpec::DrawMethod drawMethods[] =
374	{
375		gls::DrawTestSpec::DRAWMETHOD_DRAWARRAYS_INDIRECT,
376		gls::DrawTestSpec::DRAWMETHOD_DRAWELEMENTS_INDIRECT,
377	};
378	const UniformWeightArray<DE_LENGTH_OF_ARRAY(drawMethods)> drawMethodWeights;
379
380	gls::DrawTestSpec::IndexType indexTypes[] =
381	{
382		gls::DrawTestSpec::INDEXTYPE_BYTE,
383		gls::DrawTestSpec::INDEXTYPE_SHORT,
384		gls::DrawTestSpec::INDEXTYPE_INT,
385	};
386	const UniformWeightArray<DE_LENGTH_OF_ARRAY(indexTypes)> indexTypeWeights;
387
388	gls::DrawTestSpec::InputType inputTypes[] =
389	{
390		gls::DrawTestSpec::INPUTTYPE_FLOAT,
391		gls::DrawTestSpec::INPUTTYPE_FIXED,
392		gls::DrawTestSpec::INPUTTYPE_BYTE,
393		gls::DrawTestSpec::INPUTTYPE_SHORT,
394		gls::DrawTestSpec::INPUTTYPE_UNSIGNED_BYTE,
395		gls::DrawTestSpec::INPUTTYPE_UNSIGNED_SHORT,
396		gls::DrawTestSpec::INPUTTYPE_INT,
397		gls::DrawTestSpec::INPUTTYPE_UNSIGNED_INT,
398		gls::DrawTestSpec::INPUTTYPE_HALF,
399		gls::DrawTestSpec::INPUTTYPE_UNSIGNED_INT_2_10_10_10,
400		gls::DrawTestSpec::INPUTTYPE_INT_2_10_10_10,
401	};
402	const UniformWeightArray<DE_LENGTH_OF_ARRAY(inputTypes)> inputTypeWeights;
403
404	gls::DrawTestSpec::OutputType outputTypes[] =
405	{
406		gls::DrawTestSpec::OUTPUTTYPE_FLOAT,
407		gls::DrawTestSpec::OUTPUTTYPE_VEC2,
408		gls::DrawTestSpec::OUTPUTTYPE_VEC3,
409		gls::DrawTestSpec::OUTPUTTYPE_VEC4,
410		gls::DrawTestSpec::OUTPUTTYPE_INT,
411		gls::DrawTestSpec::OUTPUTTYPE_UINT,
412		gls::DrawTestSpec::OUTPUTTYPE_IVEC2,
413		gls::DrawTestSpec::OUTPUTTYPE_IVEC3,
414		gls::DrawTestSpec::OUTPUTTYPE_IVEC4,
415		gls::DrawTestSpec::OUTPUTTYPE_UVEC2,
416		gls::DrawTestSpec::OUTPUTTYPE_UVEC3,
417		gls::DrawTestSpec::OUTPUTTYPE_UVEC4,
418	};
419	const UniformWeightArray<DE_LENGTH_OF_ARRAY(outputTypes)> outputTypeWeights;
420
421	gls::DrawTestSpec::Usage usages[] =
422	{
423		gls::DrawTestSpec::USAGE_DYNAMIC_DRAW,
424		gls::DrawTestSpec::USAGE_STATIC_DRAW,
425		gls::DrawTestSpec::USAGE_STREAM_DRAW,
426		gls::DrawTestSpec::USAGE_STREAM_READ,
427		gls::DrawTestSpec::USAGE_STREAM_COPY,
428		gls::DrawTestSpec::USAGE_STATIC_READ,
429		gls::DrawTestSpec::USAGE_STATIC_COPY,
430		gls::DrawTestSpec::USAGE_DYNAMIC_READ,
431		gls::DrawTestSpec::USAGE_DYNAMIC_COPY,
432	};
433	const UniformWeightArray<DE_LENGTH_OF_ARRAY(usages)> usageWeights;
434
435	std::set<deUint32>	insertedHashes;
436	size_t				insertedCount = 0;
437
438	for (int ndx = 0; ndx < numAttempts; ++ndx)
439	{
440		de::Random random(0xc551393 + ndx); // random does not depend on previous cases
441
442		int					attributeCount = random.chooseWeighted<int, const int*, const float*>(DE_ARRAY_BEGIN(attribCounts), DE_ARRAY_END(attribCounts), attribWeights);
443		int					drawCommandSize;
444		gls::DrawTestSpec	spec;
445
446		spec.apiType				= glu::ApiType::es(3,1);
447		spec.primitive				= random.chooseWeighted<gls::DrawTestSpec::Primitive>	(DE_ARRAY_BEGIN(primitives),		DE_ARRAY_END(primitives),		primitiveWeights.weights);
448		spec.primitiveCount			= random.chooseWeighted<int, const int*, const float*>	(DE_ARRAY_BEGIN(primitiveCounts),	DE_ARRAY_END(primitiveCounts),	primitiveCountWeights);
449		spec.drawMethod				= random.chooseWeighted<gls::DrawTestSpec::DrawMethod>	(DE_ARRAY_BEGIN(drawMethods),		DE_ARRAY_END(drawMethods),		drawMethodWeights.weights);
450
451		if (spec.drawMethod == gls::DrawTestSpec::DRAWMETHOD_DRAWARRAYS_INDIRECT)
452			drawCommandSize = sizeof(deUint32[4]);
453		else if (spec.drawMethod == gls::DrawTestSpec::DRAWMETHOD_DRAWELEMENTS_INDIRECT)
454			drawCommandSize = sizeof(deUint32[5]);
455		else
456		{
457			DE_ASSERT(DE_FALSE);
458			return;
459		}
460
461		spec.indexType				= random.chooseWeighted<gls::DrawTestSpec::IndexType>	(DE_ARRAY_BEGIN(indexTypes),		DE_ARRAY_END(indexTypes),		indexTypeWeights.weights);
462		spec.indexPointerOffset		= random.chooseWeighted<int, const int*, const float*>	(DE_ARRAY_BEGIN(indexOffsets),		DE_ARRAY_END(indexOffsets),		indexOffsetWeights);
463		spec.indexStorage			= gls::DrawTestSpec::STORAGE_BUFFER;
464		spec.first					= random.chooseWeighted<int, const int*, const float*>	(DE_ARRAY_BEGIN(firsts),			DE_ARRAY_END(firsts),			firstWeights);
465		spec.indexMin				= random.chooseWeighted<int, const int*, const float*>	(DE_ARRAY_BEGIN(indexMins),			DE_ARRAY_END(indexMins),		indexWeights);
466		spec.indexMax				= random.chooseWeighted<int, const int*, const float*>	(DE_ARRAY_BEGIN(indexMaxs),			DE_ARRAY_END(indexMaxs),		indexWeights);
467		spec.instanceCount			= random.chooseWeighted<int, const int*, const float*>	(DE_ARRAY_BEGIN(instanceCounts),	DE_ARRAY_END(instanceCounts),	instanceWeights);
468		spec.indirectOffset			= random.chooseWeighted<int, const int*, const float*>	(DE_ARRAY_BEGIN(indirectOffsets),	DE_ARRAY_END(indirectOffsets),	indirectOffsetWeigths) * drawCommandSize;
469		spec.baseVertex				= random.chooseWeighted<int, const int*, const float*>	(DE_ARRAY_BEGIN(baseVertices),		DE_ARRAY_END(baseVertices),		baseVertexWeigths);
470
471		// check spec is legal
472		if (!spec.valid())
473			continue;
474
475		for (int attrNdx = 0; attrNdx < attributeCount;)
476		{
477			bool valid;
478			gls::DrawTestSpec::AttributeSpec attribSpec;
479
480			attribSpec.inputType			= random.chooseWeighted<gls::DrawTestSpec::InputType>	(DE_ARRAY_BEGIN(inputTypes),		DE_ARRAY_END(inputTypes),		inputTypeWeights.weights);
481			attribSpec.outputType			= random.chooseWeighted<gls::DrawTestSpec::OutputType>	(DE_ARRAY_BEGIN(outputTypes),		DE_ARRAY_END(outputTypes),		outputTypeWeights.weights);
482			attribSpec.storage				= gls::DrawTestSpec::STORAGE_BUFFER;
483			attribSpec.usage				= random.chooseWeighted<gls::DrawTestSpec::Usage>		(DE_ARRAY_BEGIN(usages),			DE_ARRAY_END(usages),			usageWeights.weights);
484			attribSpec.componentCount		= random.getInt(1, 4);
485			attribSpec.offset				= random.chooseWeighted<int, const int*, const float*>(DE_ARRAY_BEGIN(offsets), DE_ARRAY_END(offsets), offsetWeights);
486			attribSpec.stride				= random.chooseWeighted<int, const int*, const float*>(DE_ARRAY_BEGIN(strides), DE_ARRAY_END(strides), strideWeights);
487			attribSpec.normalize			= random.getBool();
488			attribSpec.instanceDivisor		= random.chooseWeighted<int, const int*, const float*>(DE_ARRAY_BEGIN(instanceDivisors), DE_ARRAY_END(instanceDivisors), instanceDivisorWeights);
489			attribSpec.useDefaultAttribute	= random.getBool();
490
491			// check spec is legal
492			valid = attribSpec.valid(spec.apiType);
493
494			// we do not want interleaved elements. (Might result in some weird floating point values)
495			if (attribSpec.stride && attribSpec.componentCount * gls::DrawTestSpec::inputTypeSize(attribSpec.inputType) > attribSpec.stride)
496				valid = false;
497
498			// try again if not valid
499			if (valid)
500			{
501				spec.attribs.push_back(attribSpec);
502				++attrNdx;
503			}
504		}
505
506		// Do not collapse all vertex positions to a single positions
507		if (spec.primitive != gls::DrawTestSpec::PRIMITIVE_POINTS)
508			spec.attribs[0].instanceDivisor = 0;
509
510		// Is render result meaningful?
511		{
512			// Only one vertex
513			if (spec.drawMethod == gls::DrawTestSpec::DRAWMETHOD_DRAWELEMENTS_RANGED && spec.indexMin == spec.indexMax && spec.primitive != gls::DrawTestSpec::PRIMITIVE_POINTS)
514				continue;
515			if (spec.attribs[0].useDefaultAttribute && spec.primitive != gls::DrawTestSpec::PRIMITIVE_POINTS)
516				continue;
517
518			// Triangle only on one axis
519			if (spec.primitive == gls::DrawTestSpec::PRIMITIVE_TRIANGLES || spec.primitive == gls::DrawTestSpec::PRIMITIVE_TRIANGLE_FAN || spec.primitive == gls::DrawTestSpec::PRIMITIVE_TRIANGLE_STRIP)
520			{
521				if (spec.attribs[0].componentCount == 1)
522					continue;
523				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)
524					continue;
525				if (spec.drawMethod == gls::DrawTestSpec::DRAWMETHOD_DRAWELEMENTS_RANGED && (spec.indexMax - spec.indexMin) < 2)
526					continue;
527			}
528		}
529
530		// Add case
531		{
532			deUint32 hash = spec.hash();
533			for (int attrNdx = 0; attrNdx < attributeCount; ++attrNdx)
534				hash = (hash << 2) ^ (deUint32)spec.attribs[attrNdx].hash();
535
536			if (insertedHashes.find(hash) == insertedHashes.end())
537			{
538				// Only unaligned cases
539				if (spec.isCompatibilityTest() == gls::DrawTestSpec::COMPATIBILITY_UNALIGNED_OFFSET ||
540					spec.isCompatibilityTest() == gls::DrawTestSpec::COMPATIBILITY_UNALIGNED_STRIDE)
541					this->addChild(new gls::DrawTest(m_testCtx, m_context.getRenderContext(), spec, de::toString(insertedCount).c_str(), spec.getDesc().c_str()));
542				insertedHashes.insert(hash);
543
544				++insertedCount;
545			}
546		}
547	}
548}
549
550} // anonymous
551
552DrawTests::DrawTests (Context& context)
553	: TestCaseGroup(context, "draw_indirect", "Indirect drawing tests")
554{
555}
556
557DrawTests::~DrawTests (void)
558{
559}
560
561void DrawTests::init (void)
562{
563	tcu::TestCaseGroup* const unalignedGroup	= new tcu::TestCaseGroup(m_testCtx, "unaligned_data", "Test with unaligned data");
564	tcu::TestCaseGroup* const drawArraysGroup	= new tcu::TestCaseGroup(m_testCtx, "drawarrays", "draw arrays");
565	tcu::TestCaseGroup* const drawElementsGroup	= new tcu::TestCaseGroup(m_testCtx, "drawelements", "draw elements");
566
567	addChild(unalignedGroup);
568	addChild(drawArraysGroup);
569	addChild(drawElementsGroup);
570
571	// .unaligned_data
572	{
573		unalignedGroup->addChild(new RandomGroup(m_context, "random", "random draw commands."));
574	}
575
576	// .drawarrays
577	{
578		drawArraysGroup->addChild(new InvalidDrawCase(m_context, "data_over_bounds_with_count",			"Draw arrays vertex elements beyond the array end are accessed",	InvalidDrawCase::DRAW_ARRAYS,	InvalidDrawCase::INVALID_DATA_COUNT));
579		drawArraysGroup->addChild(new InvalidDrawCase(m_context, "data_over_bounds_with_first",			"Draw arrays vertex elements beyond the array end are accessed",	InvalidDrawCase::DRAW_ARRAYS,	InvalidDrawCase::INVALID_DATA_FIRST));
580		drawArraysGroup->addChild(new InvalidDrawCase(m_context, "data_over_bounds_with_primcount",		"Draw arrays vertex elements beyond the array end are accessed",	InvalidDrawCase::DRAW_ARRAYS,	InvalidDrawCase::INVALID_DATA_INSTANCED));
581		drawArraysGroup->addChild(new InvalidDrawCase(m_context, "reserved_non_zero",					"reservedMustBeZero is set to non-zero value",						InvalidDrawCase::DRAW_ARRAYS,	InvalidDrawCase::INVALID_RESERVED));
582	}
583
584	// .drawelements
585	{
586		drawElementsGroup->addChild(new InvalidDrawCase(m_context, "data_over_bounds_with_count",		"Draw elements vertex elements beyond the array end are accessed",	InvalidDrawCase::DRAW_ELEMENTS, InvalidDrawCase::INVALID_DATA_COUNT));
587		drawElementsGroup->addChild(new InvalidDrawCase(m_context, "data_over_bounds_with_basevertex",	"Draw elements vertex elements beyond the array end are accessed",	InvalidDrawCase::DRAW_ELEMENTS,	InvalidDrawCase::INVALID_DATA_FIRST));
588		drawElementsGroup->addChild(new InvalidDrawCase(m_context, "data_over_bounds_with_indices",		"Draw elements vertex elements beyond the array end are accessed",	InvalidDrawCase::DRAW_ELEMENTS,	InvalidDrawCase::INVALID_INDEX));
589		drawElementsGroup->addChild(new InvalidDrawCase(m_context, "data_over_bounds_with_primcount",	"Draw elements vertex elements beyond the array end are accessed",	InvalidDrawCase::DRAW_ELEMENTS,	InvalidDrawCase::INVALID_DATA_INSTANCED));
590		drawElementsGroup->addChild(new InvalidDrawCase(m_context, "index_over_bounds_with_count",		"Draw elements index elements beyond the array end are accessed",	InvalidDrawCase::DRAW_ELEMENTS,	InvalidDrawCase::INVALID_INDEX_COUNT));
591		drawElementsGroup->addChild(new InvalidDrawCase(m_context, "index_over_bounds_with_firstindex",	"Draw elements index elements beyond the array end are accessed",	InvalidDrawCase::DRAW_ELEMENTS,	InvalidDrawCase::INVALID_INDEX_FIRST));
592		drawElementsGroup->addChild(new InvalidDrawCase(m_context, "reserved_non_zero",					"reservedMustBeZero is set to non-zero value",						InvalidDrawCase::DRAW_ELEMENTS,	InvalidDrawCase::INVALID_RESERVED));
593	}
594}
595
596} // Stress
597} // gles31
598} // deqp