es3fDrawTests.cpp revision c8ed84ccebfb0a36fb9f128dee67ee903bb3a5ab
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 Drawing tests.
22 *//*--------------------------------------------------------------------*/
23
24#include "es3fDrawTests.hpp"
25#include "glsDrawTest.hpp"
26#include "tcuRenderTarget.hpp"
27#include "sglrGLContext.hpp"
28#include "glwEnums.hpp"
29#include "deRandom.hpp"
30#include "deStringUtil.hpp"
31#include "deUniquePtr.hpp"
32#include "deSTLUtil.hpp"
33
34#include <set>
35
36namespace deqp
37{
38namespace gles3
39{
40namespace Functional
41{
42namespace
43{
44
45enum TestIterationType
46{
47	TYPE_DRAW_COUNT,		// !< test with 1, 5, and 25 primitives
48	TYPE_INSTANCE_COUNT,	// !< test with 1, 4, and 11 instances
49	TYPE_INDEX_RANGE,		// !< test with index range of [0, 23], [23, 40], and [5, 5]
50
51	TYPE_LAST
52};
53
54static void addTestIterations (gls::DrawTest* test, const gls::DrawTestSpec& baseSpec, TestIterationType type)
55{
56	gls::DrawTestSpec spec(baseSpec);
57
58	if (type == TYPE_DRAW_COUNT)
59	{
60		spec.primitiveCount = 1;
61		test->addIteration(spec, "draw count = 1");
62
63		spec.primitiveCount = 5;
64		test->addIteration(spec, "draw count = 5");
65
66		spec.primitiveCount = 25;
67		test->addIteration(spec, "draw count = 25");
68	}
69	else if (type == TYPE_INSTANCE_COUNT)
70	{
71		spec.instanceCount = 1;
72		test->addIteration(spec, "instance count = 1");
73
74		spec.instanceCount = 4;
75		test->addIteration(spec, "instance count = 4");
76
77		spec.instanceCount = 11;
78		test->addIteration(spec, "instance count = 11");
79	}
80	else if (type == TYPE_INDEX_RANGE)
81	{
82		spec.indexMin = 0;
83		spec.indexMax = 23;
84		test->addIteration(spec, "index range = [0, 23]");
85
86		spec.indexMin = 23;
87		spec.indexMax = 40;
88		test->addIteration(spec, "index range = [23, 40]");
89
90		// Only makes sense with points
91		if (spec.primitive == gls::DrawTestSpec::PRIMITIVE_POINTS)
92		{
93			spec.indexMin = 5;
94			spec.indexMax = 5;
95			test->addIteration(spec, "index range = [5, 5]");
96		}
97	}
98	else
99		DE_ASSERT(false);
100}
101
102static void genBasicSpec (gls::DrawTestSpec& spec, gls::DrawTestSpec::DrawMethod method)
103{
104	spec.apiType				= glu::ApiType::es(3,0);
105	spec.primitive				= gls::DrawTestSpec::PRIMITIVE_TRIANGLES;
106	spec.primitiveCount			= 5;
107	spec.drawMethod				= method;
108	spec.indexType				= gls::DrawTestSpec::INDEXTYPE_LAST;
109	spec.indexPointerOffset		= 0;
110	spec.indexStorage			= gls::DrawTestSpec::STORAGE_LAST;
111	spec.first					= 0;
112	spec.indexMin				= 0;
113	spec.indexMax				= 0;
114	spec.instanceCount			= 1;
115
116	spec.attribs.resize(2);
117
118	spec.attribs[0].inputType				= gls::DrawTestSpec::INPUTTYPE_FLOAT;
119	spec.attribs[0].outputType				= gls::DrawTestSpec::OUTPUTTYPE_VEC2;
120	spec.attribs[0].storage					= gls::DrawTestSpec::STORAGE_BUFFER;
121	spec.attribs[0].usage					= gls::DrawTestSpec::USAGE_STATIC_DRAW;
122	spec.attribs[0].componentCount			= 4;
123	spec.attribs[0].offset					= 0;
124	spec.attribs[0].stride					= 0;
125	spec.attribs[0].normalize				= false;
126	spec.attribs[0].instanceDivisor			= 0;
127	spec.attribs[0].useDefaultAttribute		= false;
128
129	spec.attribs[1].inputType				= gls::DrawTestSpec::INPUTTYPE_FLOAT;
130	spec.attribs[1].outputType				= gls::DrawTestSpec::OUTPUTTYPE_VEC2;
131	spec.attribs[1].storage					= gls::DrawTestSpec::STORAGE_BUFFER;
132	spec.attribs[1].usage					= gls::DrawTestSpec::USAGE_STATIC_DRAW;
133	spec.attribs[1].componentCount			= 2;
134	spec.attribs[1].offset					= 0;
135	spec.attribs[1].stride					= 0;
136	spec.attribs[1].normalize				= false;
137	spec.attribs[1].instanceDivisor			= 0;
138	spec.attribs[1].useDefaultAttribute		= false;
139}
140
141class AttributeGroup : public TestCaseGroup
142{
143public:
144									AttributeGroup	(Context& context, const char* name, const char* descr, gls::DrawTestSpec::DrawMethod drawMethod, gls::DrawTestSpec::Primitive primitive, gls::DrawTestSpec::IndexType indexType, gls::DrawTestSpec::Storage indexStorage);
145									~AttributeGroup	(void);
146
147	void							init			(void);
148
149private:
150	gls::DrawTestSpec::DrawMethod	m_method;
151	gls::DrawTestSpec::Primitive	m_primitive;
152	gls::DrawTestSpec::IndexType	m_indexType;
153	gls::DrawTestSpec::Storage		m_indexStorage;
154};
155
156AttributeGroup::AttributeGroup (Context& context, const char* name, const char* descr, gls::DrawTestSpec::DrawMethod drawMethod, gls::DrawTestSpec::Primitive primitive, gls::DrawTestSpec::IndexType indexType, gls::DrawTestSpec::Storage indexStorage)
157	: TestCaseGroup		(context, name, descr)
158	, m_method			(drawMethod)
159	, m_primitive		(primitive)
160	, m_indexType		(indexType)
161	, m_indexStorage	(indexStorage)
162{
163}
164
165AttributeGroup::~AttributeGroup (void)
166{
167}
168
169void AttributeGroup::init (void)
170{
171	// select test type
172	const bool				instanced			= (m_method == gls::DrawTestSpec::DRAWMETHOD_DRAWARRAYS_INSTANCED) ||
173												  (m_method == gls::DrawTestSpec::DRAWMETHOD_DRAWELEMENTS_INSTANCED);
174	const bool				ranged				= (m_method == gls::DrawTestSpec::DRAWMETHOD_DRAWELEMENTS_RANGED);
175	const TestIterationType	testType			= (instanced) ? (TYPE_INSTANCE_COUNT) : ((ranged) ? (TYPE_INDEX_RANGE) : (TYPE_DRAW_COUNT));
176
177	// Single attribute
178	{
179		gls::DrawTest*		test				= new gls::DrawTest(m_testCtx, m_context.getRenderContext(), "single_attribute", "Single attribute array.");
180		gls::DrawTestSpec	spec;
181
182		spec.apiType							= glu::ApiType::es(3,0);
183		spec.primitive							= m_primitive;
184		spec.primitiveCount						= 5;
185		spec.drawMethod							= m_method;
186		spec.indexType							= m_indexType;
187		spec.indexPointerOffset					= 0;
188		spec.indexStorage						= m_indexStorage;
189		spec.first								= 0;
190		spec.indexMin							= 0;
191		spec.indexMax							= 0;
192		spec.instanceCount						= 1;
193
194		spec.attribs.resize(1);
195
196		spec.attribs[0].inputType				= gls::DrawTestSpec::INPUTTYPE_FLOAT;
197		spec.attribs[0].outputType				= gls::DrawTestSpec::OUTPUTTYPE_VEC2;
198		spec.attribs[0].storage					= gls::DrawTestSpec::STORAGE_BUFFER;
199		spec.attribs[0].usage					= gls::DrawTestSpec::USAGE_STATIC_DRAW;
200		spec.attribs[0].componentCount			= 2;
201		spec.attribs[0].offset					= 0;
202		spec.attribs[0].stride					= 0;
203		spec.attribs[0].normalize				= false;
204		spec.attribs[0].instanceDivisor			= 0;
205		spec.attribs[0].useDefaultAttribute		= false;
206
207		addTestIterations(test, spec, testType);
208
209		this->addChild(test);
210	}
211
212	// Multiple attribute
213	{
214		gls::DrawTest*		test				= new gls::DrawTest(m_testCtx, m_context.getRenderContext(), "multiple_attributes", "Multiple attribute arrays.");
215		gls::DrawTestSpec	spec;
216
217		spec.apiType							= glu::ApiType::es(3,0);
218		spec.primitive							= m_primitive;
219		spec.primitiveCount						= 5;
220		spec.drawMethod							= m_method;
221		spec.indexType							= m_indexType;
222		spec.indexPointerOffset					= 0;
223		spec.indexStorage						= m_indexStorage;
224		spec.first								= 0;
225		spec.indexMin							= 0;
226		spec.indexMax							= 0;
227		spec.instanceCount						= 1;
228
229		spec.attribs.resize(2);
230
231		spec.attribs[0].inputType				= gls::DrawTestSpec::INPUTTYPE_FLOAT;
232		spec.attribs[0].outputType				= gls::DrawTestSpec::OUTPUTTYPE_VEC2;
233		spec.attribs[0].storage					= gls::DrawTestSpec::STORAGE_BUFFER;
234		spec.attribs[0].usage					= gls::DrawTestSpec::USAGE_STATIC_DRAW;
235		spec.attribs[0].componentCount			= 4;
236		spec.attribs[0].offset					= 0;
237		spec.attribs[0].stride					= 0;
238		spec.attribs[0].normalize				= false;
239		spec.attribs[0].instanceDivisor			= 0;
240		spec.attribs[0].useDefaultAttribute		= false;
241
242		spec.attribs[1].inputType				= gls::DrawTestSpec::INPUTTYPE_FLOAT;
243		spec.attribs[1].outputType				= gls::DrawTestSpec::OUTPUTTYPE_VEC2;
244		spec.attribs[1].storage					= gls::DrawTestSpec::STORAGE_BUFFER;
245		spec.attribs[1].usage					= gls::DrawTestSpec::USAGE_STATIC_DRAW;
246		spec.attribs[1].componentCount			= 2;
247		spec.attribs[1].offset					= 0;
248		spec.attribs[1].stride					= 0;
249		spec.attribs[1].normalize				= false;
250		spec.attribs[1].instanceDivisor			= 0;
251		spec.attribs[1].useDefaultAttribute		= false;
252
253		addTestIterations(test, spec, testType);
254
255		this->addChild(test);
256	}
257
258	// Multiple attribute, second one divided
259	{
260		gls::DrawTest*		test					= new gls::DrawTest(m_testCtx, m_context.getRenderContext(), "instanced_attributes", "Instanced attribute array.");
261		gls::DrawTestSpec	spec;
262
263		spec.apiType								= glu::ApiType::es(3,0);
264		spec.primitive								= m_primitive;
265		spec.primitiveCount							= 5;
266		spec.drawMethod								= m_method;
267		spec.indexType								= m_indexType;
268		spec.indexPointerOffset						= 0;
269		spec.indexStorage							= m_indexStorage;
270		spec.first									= 0;
271		spec.indexMin								= 0;
272		spec.indexMax								= 0;
273		spec.instanceCount							= 1;
274
275		spec.attribs.resize(3);
276
277		spec.attribs[0].inputType					= gls::DrawTestSpec::INPUTTYPE_FLOAT;
278		spec.attribs[0].outputType					= gls::DrawTestSpec::OUTPUTTYPE_VEC2;
279		spec.attribs[0].storage						= gls::DrawTestSpec::STORAGE_BUFFER;
280		spec.attribs[0].usage						= gls::DrawTestSpec::USAGE_STATIC_DRAW;
281		spec.attribs[0].componentCount				= 4;
282		spec.attribs[0].offset						= 0;
283		spec.attribs[0].stride						= 0;
284		spec.attribs[0].normalize					= false;
285		spec.attribs[0].instanceDivisor				= 0;
286		spec.attribs[0].useDefaultAttribute			= false;
287
288		// Add another position component so the instances wont be drawn on each other
289		spec.attribs[1].inputType					= gls::DrawTestSpec::INPUTTYPE_FLOAT;
290		spec.attribs[1].outputType					= gls::DrawTestSpec::OUTPUTTYPE_VEC2;
291		spec.attribs[1].storage						= gls::DrawTestSpec::STORAGE_BUFFER;
292		spec.attribs[1].usage						= gls::DrawTestSpec::USAGE_STATIC_DRAW;
293		spec.attribs[1].componentCount				= 2;
294		spec.attribs[1].offset						= 0;
295		spec.attribs[1].stride						= 0;
296		spec.attribs[1].normalize					= false;
297		spec.attribs[1].instanceDivisor				= 1;
298		spec.attribs[1].useDefaultAttribute			= false;
299		spec.attribs[1].additionalPositionAttribute	= true;
300
301		// Instanced color
302		spec.attribs[2].inputType					= gls::DrawTestSpec::INPUTTYPE_FLOAT;
303		spec.attribs[2].outputType					= gls::DrawTestSpec::OUTPUTTYPE_VEC2;
304		spec.attribs[2].storage						= gls::DrawTestSpec::STORAGE_BUFFER;
305		spec.attribs[2].usage						= gls::DrawTestSpec::USAGE_STATIC_DRAW;
306		spec.attribs[2].componentCount				= 3;
307		spec.attribs[2].offset						= 0;
308		spec.attribs[2].stride						= 0;
309		spec.attribs[2].normalize					= false;
310		spec.attribs[2].instanceDivisor				= 1;
311		spec.attribs[2].useDefaultAttribute			= false;
312
313		addTestIterations(test, spec, testType);
314
315		this->addChild(test);
316	}
317
318	// Multiple attribute, second one default
319	{
320		gls::DrawTest*		test				= new gls::DrawTest(m_testCtx, m_context.getRenderContext(), "default_attribute", "Attribute specified with glVertexAttrib*.");
321		gls::DrawTestSpec	spec;
322
323		spec.apiType							= glu::ApiType::es(3,0);
324		spec.primitive							= m_primitive;
325		spec.primitiveCount						= 5;
326		spec.drawMethod							= m_method;
327		spec.indexType							= m_indexType;
328		spec.indexPointerOffset					= 0;
329		spec.indexStorage						= m_indexStorage;
330		spec.first								= 0;
331		spec.indexMin							= 0;
332		spec.indexMax							= 20; // \note addTestIterations is not called for the spec, so we must ensure [indexMin, indexMax] is a good range
333		spec.instanceCount						= 1;
334
335		spec.attribs.resize(2);
336
337		spec.attribs[0].inputType				= gls::DrawTestSpec::INPUTTYPE_FLOAT;
338		spec.attribs[0].outputType				= gls::DrawTestSpec::OUTPUTTYPE_VEC2;
339		spec.attribs[0].storage					= gls::DrawTestSpec::STORAGE_BUFFER;
340		spec.attribs[0].usage					= gls::DrawTestSpec::USAGE_STATIC_DRAW;
341		spec.attribs[0].componentCount			= 2;
342		spec.attribs[0].offset					= 0;
343		spec.attribs[0].stride					= 0;
344		spec.attribs[0].normalize				= false;
345		spec.attribs[0].instanceDivisor			= 0;
346		spec.attribs[0].useDefaultAttribute		= false;
347
348		struct IOPair
349		{
350			gls::DrawTestSpec::InputType  input;
351			gls::DrawTestSpec::OutputType output;
352			int							  componentCount;
353		} iopairs[] =
354		{
355			{ gls::DrawTestSpec::INPUTTYPE_FLOAT,        gls::DrawTestSpec::OUTPUTTYPE_VEC2,  4 },
356			{ gls::DrawTestSpec::INPUTTYPE_FLOAT,        gls::DrawTestSpec::OUTPUTTYPE_VEC4,  2 },
357			{ gls::DrawTestSpec::INPUTTYPE_INT,          gls::DrawTestSpec::OUTPUTTYPE_IVEC3, 4 },
358			{ gls::DrawTestSpec::INPUTTYPE_UNSIGNED_INT, gls::DrawTestSpec::OUTPUTTYPE_UVEC2, 4 },
359		};
360
361		for (int ioNdx = 0; ioNdx < DE_LENGTH_OF_ARRAY(iopairs); ++ioNdx)
362		{
363			const std::string desc = gls::DrawTestSpec::inputTypeToString(iopairs[ioNdx].input) + de::toString(iopairs[ioNdx].componentCount) + " to " + gls::DrawTestSpec::outputTypeToString(iopairs[ioNdx].output);
364
365			spec.attribs[1].inputType			= iopairs[ioNdx].input;
366			spec.attribs[1].outputType			= iopairs[ioNdx].output;
367			spec.attribs[1].storage				= gls::DrawTestSpec::STORAGE_BUFFER;
368			spec.attribs[1].usage				= gls::DrawTestSpec::USAGE_STATIC_DRAW;
369			spec.attribs[1].componentCount		= iopairs[ioNdx].componentCount;
370			spec.attribs[1].offset				= 0;
371			spec.attribs[1].stride				= 0;
372			spec.attribs[1].normalize			= false;
373			spec.attribs[1].instanceDivisor		= 0;
374			spec.attribs[1].useDefaultAttribute	= true;
375
376			test->addIteration(spec, desc.c_str());
377		}
378
379		this->addChild(test);
380	}
381}
382
383class IndexGroup : public TestCaseGroup
384{
385public:
386									IndexGroup		(Context& context, const char* name, const char* descr, gls::DrawTestSpec::DrawMethod drawMethod);
387									~IndexGroup		(void);
388
389	void							init			(void);
390
391private:
392	gls::DrawTestSpec::DrawMethod	m_method;
393};
394
395IndexGroup::IndexGroup (Context& context, const char* name, const char* descr, gls::DrawTestSpec::DrawMethod drawMethod)
396	: TestCaseGroup		(context, name, descr)
397	, m_method			(drawMethod)
398{
399}
400
401IndexGroup::~IndexGroup (void)
402{
403}
404
405void IndexGroup::init (void)
406{
407	struct IndexTest
408	{
409		gls::DrawTestSpec::Storage		storage;
410		gls::DrawTestSpec::IndexType	type;
411		bool							aligned;
412		int								offsets[3];
413	};
414
415	const IndexTest tests[] =
416	{
417		{ gls::DrawTestSpec::STORAGE_USER,		gls::DrawTestSpec::INDEXTYPE_BYTE,	true,	{ 0, 1, -1 } },
418		{ gls::DrawTestSpec::STORAGE_USER,		gls::DrawTestSpec::INDEXTYPE_SHORT,	true,	{ 0, 2, -1 } },
419		{ gls::DrawTestSpec::STORAGE_USER,		gls::DrawTestSpec::INDEXTYPE_INT,	true,	{ 0, 4, -1 } },
420
421		{ gls::DrawTestSpec::STORAGE_USER,		gls::DrawTestSpec::INDEXTYPE_SHORT,	false,	{ 1, 3, -1 } },
422		{ gls::DrawTestSpec::STORAGE_USER,		gls::DrawTestSpec::INDEXTYPE_INT,	false,	{ 2, 3, -1 } },
423
424		{ gls::DrawTestSpec::STORAGE_BUFFER,	gls::DrawTestSpec::INDEXTYPE_BYTE,	true,	{ 0, 1, -1 } },
425		{ gls::DrawTestSpec::STORAGE_BUFFER,	gls::DrawTestSpec::INDEXTYPE_SHORT,	true,	{ 0, 2, -1 } },
426		{ gls::DrawTestSpec::STORAGE_BUFFER,	gls::DrawTestSpec::INDEXTYPE_INT,	true,	{ 0, 4, -1 } },
427	};
428
429	gls::DrawTestSpec spec;
430
431	tcu::TestCaseGroup* userPtrGroup			= new tcu::TestCaseGroup(m_testCtx, "user_ptr", "user pointer");
432	tcu::TestCaseGroup* unalignedUserPtrGroup	= new tcu::TestCaseGroup(m_testCtx, "unaligned_user_ptr", "unaligned user pointer");
433	tcu::TestCaseGroup* bufferGroup				= new tcu::TestCaseGroup(m_testCtx, "buffer", "buffer");
434
435	genBasicSpec(spec, m_method);
436
437	this->addChild(userPtrGroup);
438	this->addChild(unalignedUserPtrGroup);
439	this->addChild(bufferGroup);
440
441	for (int testNdx = 0; testNdx < DE_LENGTH_OF_ARRAY(tests); ++testNdx)
442	{
443		const IndexTest&				indexTest	= tests[testNdx];
444		tcu::TestCaseGroup*				group		= (indexTest.storage == gls::DrawTestSpec::STORAGE_USER)
445													? ((indexTest.aligned) ? (userPtrGroup) : (unalignedUserPtrGroup))
446													: ((indexTest.aligned) ? (bufferGroup) : (DE_NULL));
447
448		const std::string				name		= std::string("index_") + gls::DrawTestSpec::indexTypeToString(indexTest.type);
449		const std::string				desc		= std::string("index ") + gls::DrawTestSpec::indexTypeToString(indexTest.type) + " in " + gls::DrawTestSpec::storageToString(indexTest.storage);
450		de::MovePtr<gls::DrawTest>		test		(new gls::DrawTest(m_testCtx, m_context.getRenderContext(), name.c_str(), desc.c_str()));
451
452		spec.indexType			= indexTest.type;
453		spec.indexStorage		= indexTest.storage;
454
455		for (int iterationNdx = 0; iterationNdx < DE_LENGTH_OF_ARRAY(indexTest.offsets) && indexTest.offsets[iterationNdx] != -1; ++iterationNdx)
456		{
457			const std::string iterationDesc = std::string("offset ") + de::toString(indexTest.offsets[iterationNdx]);
458			spec.indexPointerOffset	= indexTest.offsets[iterationNdx];
459			test->addIteration(spec, iterationDesc.c_str());
460		}
461
462		DE_ASSERT(spec.isCompatibilityTest() != gls::DrawTestSpec::COMPATIBILITY_UNALIGNED_OFFSET);
463		DE_ASSERT(spec.isCompatibilityTest() != gls::DrawTestSpec::COMPATIBILITY_UNALIGNED_STRIDE);
464		group->addChild(test.release());
465	}
466}
467
468
469class FirstGroup : public TestCaseGroup
470{
471public:
472									FirstGroup		(Context& context, const char* name, const char* descr, gls::DrawTestSpec::DrawMethod drawMethod);
473									~FirstGroup		(void);
474
475	void							init			(void);
476
477private:
478	gls::DrawTestSpec::DrawMethod	m_method;
479};
480
481FirstGroup::FirstGroup (Context& context, const char* name, const char* descr, gls::DrawTestSpec::DrawMethod drawMethod)
482	: TestCaseGroup		(context, name, descr)
483	, m_method			(drawMethod)
484{
485}
486
487FirstGroup::~FirstGroup (void)
488{
489}
490
491void FirstGroup::init (void)
492{
493	const int firsts[] =
494	{
495		1, 3, 17
496	};
497
498	gls::DrawTestSpec spec;
499	genBasicSpec(spec, m_method);
500
501	for (int firstNdx = 0; firstNdx < DE_LENGTH_OF_ARRAY(firsts); ++firstNdx)
502	{
503		const std::string	name = std::string("first_") + de::toString(firsts[firstNdx]);
504		const std::string	desc = std::string("first ") + de::toString(firsts[firstNdx]);
505		gls::DrawTest*		test = new gls::DrawTest(m_testCtx, m_context.getRenderContext(), name.c_str(), desc.c_str());
506
507		spec.first = firsts[firstNdx];
508
509		addTestIterations(test, spec, TYPE_DRAW_COUNT);
510
511		this->addChild(test);
512	}
513}
514
515class MethodGroup : public TestCaseGroup
516{
517public:
518									MethodGroup			(Context& context, const char* name, const char* descr, gls::DrawTestSpec::DrawMethod drawMethod);
519									~MethodGroup		(void);
520
521	void							init				(void);
522
523private:
524	gls::DrawTestSpec::DrawMethod	m_method;
525};
526
527MethodGroup::MethodGroup (Context& context, const char* name, const char* descr, gls::DrawTestSpec::DrawMethod drawMethod)
528	: TestCaseGroup		(context, name, descr)
529	, m_method			(drawMethod)
530{
531}
532
533MethodGroup::~MethodGroup (void)
534{
535}
536
537void MethodGroup::init (void)
538{
539	const bool indexed		= (m_method == gls::DrawTestSpec::DRAWMETHOD_DRAWELEMENTS) || (m_method == gls::DrawTestSpec::DRAWMETHOD_DRAWELEMENTS_INSTANCED) || (m_method == gls::DrawTestSpec::DRAWMETHOD_DRAWELEMENTS_RANGED);
540	const bool hasFirst		= (m_method == gls::DrawTestSpec::DRAWMETHOD_DRAWARRAYS) || (m_method == gls::DrawTestSpec::DRAWMETHOD_DRAWARRAYS_INSTANCED);
541
542	const gls::DrawTestSpec::Primitive primitive[] =
543	{
544		gls::DrawTestSpec::PRIMITIVE_POINTS,
545		gls::DrawTestSpec::PRIMITIVE_TRIANGLES,
546		gls::DrawTestSpec::PRIMITIVE_TRIANGLE_FAN,
547		gls::DrawTestSpec::PRIMITIVE_TRIANGLE_STRIP,
548		gls::DrawTestSpec::PRIMITIVE_LINES,
549		gls::DrawTestSpec::PRIMITIVE_LINE_STRIP,
550		gls::DrawTestSpec::PRIMITIVE_LINE_LOOP
551	};
552
553	if (hasFirst)
554	{
555		// First-tests
556		this->addChild(new FirstGroup(m_context, "first", "First tests", m_method));
557	}
558
559	if (indexed)
560	{
561		// Index-tests
562		if (m_method != gls::DrawTestSpec::DRAWMETHOD_DRAWELEMENTS_RANGED)
563			this->addChild(new IndexGroup(m_context, "indices", "Index tests", m_method));
564	}
565
566	for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(primitive); ++ndx)
567	{
568		const std::string name = gls::DrawTestSpec::primitiveToString(primitive[ndx]);
569		const std::string desc = gls::DrawTestSpec::primitiveToString(primitive[ndx]);
570
571		this->addChild(new AttributeGroup(m_context, name.c_str(), desc.c_str(), m_method, primitive[ndx], gls::DrawTestSpec::INDEXTYPE_SHORT, gls::DrawTestSpec::STORAGE_BUFFER));
572	}
573}
574
575class GridProgram : public sglr::ShaderProgram
576{
577public:
578			GridProgram		(void);
579
580	void	shadeVertices	(const rr::VertexAttrib* inputs, rr::VertexPacket* const* packets, const int numPackets) const;
581	void	shadeFragments	(rr::FragmentPacket* packets, const int numPackets, const rr::FragmentShadingContext& context) const;
582};
583
584GridProgram::GridProgram (void)
585	: sglr::ShaderProgram(sglr::pdec::ShaderProgramDeclaration()
586							<< sglr::pdec::VertexAttribute("a_position", rr::GENERICVECTYPE_FLOAT)
587							<< sglr::pdec::VertexAttribute("a_offset", rr::GENERICVECTYPE_FLOAT)
588							<< sglr::pdec::VertexAttribute("a_color", rr::GENERICVECTYPE_FLOAT)
589							<< sglr::pdec::VertexToFragmentVarying(rr::GENERICVECTYPE_FLOAT)
590							<< sglr::pdec::FragmentOutput(rr::GENERICVECTYPE_FLOAT)
591							<< sglr::pdec::VertexSource("#version 300 es\n"
592														"in highp vec4 a_position;\n"
593														"in highp vec4 a_offset;\n"
594														"in highp vec4 a_color;\n"
595														"out mediump vec4 v_color;\n"
596														"void main(void)\n"
597														"{\n"
598														"	gl_Position = a_position + a_offset;\n"
599														"	v_color = a_color;\n"
600														"}\n")
601							<< sglr::pdec::FragmentSource(
602														"#version 300 es\n"
603														"layout(location = 0) out mediump vec4 dEQP_FragColor;\n"
604														"in mediump vec4 v_color;\n"
605														"void main(void)\n"
606														"{\n"
607														"	dEQP_FragColor = v_color;\n"
608														"}\n"))
609{
610}
611
612void GridProgram::shadeVertices (const rr::VertexAttrib* inputs, rr::VertexPacket* const* packets, const int numPackets) const
613{
614	for (int ndx = 0; ndx < numPackets; ++ndx)
615	{
616		packets[ndx]->position = rr::readVertexAttribFloat(inputs[0], packets[ndx]->instanceNdx, packets[ndx]->vertexNdx) + rr::readVertexAttribFloat(inputs[1], packets[ndx]->instanceNdx, packets[ndx]->vertexNdx);
617		packets[ndx]->outputs[0] = rr::readVertexAttribFloat(inputs[2], packets[ndx]->instanceNdx, packets[ndx]->vertexNdx);
618	}
619}
620
621void GridProgram::shadeFragments (rr::FragmentPacket* packets, const int numPackets, const rr::FragmentShadingContext& context) const
622{
623	for (int packetNdx = 0; packetNdx < numPackets; ++packetNdx)
624	for (int fragNdx = 0; fragNdx < 4; ++fragNdx)
625		rr::writeFragmentOutput(context, packetNdx, fragNdx, 0, rr::readTriangleVarying<float>(packets[packetNdx], context, 0, fragNdx));
626}
627
628class InstancedGridRenderTest : public TestCase
629{
630public:
631					InstancedGridRenderTest		(Context& context, const char* name, const char* desc, int gridSide, bool useIndices);
632					~InstancedGridRenderTest	(void);
633
634	IterateResult	iterate						(void);
635
636private:
637	void			renderTo					(sglr::Context& ctx, sglr::ShaderProgram& program, tcu::Surface& dst);
638	bool			verifyImage					(const tcu::Surface& image);
639
640	const int		m_gridSide;
641	const bool		m_useIndices;
642};
643
644InstancedGridRenderTest::InstancedGridRenderTest (Context& context, const char* name, const char* desc, int gridSide, bool useIndices)
645	: TestCase		(context, name, desc)
646	, m_gridSide	(gridSide)
647	, m_useIndices	(useIndices)
648{
649}
650
651InstancedGridRenderTest::~InstancedGridRenderTest (void)
652{
653}
654
655InstancedGridRenderTest::IterateResult InstancedGridRenderTest::iterate (void)
656{
657	const int renderTargetWidth  = de::min(1024, m_context.getRenderTarget().getWidth());
658	const int renderTargetHeight = de::min(1024, m_context.getRenderTarget().getHeight());
659
660	sglr::GLContext ctx		(m_context.getRenderContext(), m_testCtx.getLog(), sglr::GLCONTEXT_LOG_CALLS | sglr::GLCONTEXT_LOG_PROGRAMS, tcu::IVec4(0, 0, renderTargetWidth, renderTargetHeight));
661	tcu::Surface	surface	(renderTargetWidth, renderTargetHeight);
662	GridProgram		program;
663
664	// render
665
666	renderTo(ctx, program, surface);
667
668	// verify image
669
670	if (verifyImage(surface))
671		m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
672	else
673		m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Incorrect rendering result");
674	return STOP;
675}
676
677void InstancedGridRenderTest::renderTo (sglr::Context& ctx, sglr::ShaderProgram& program, tcu::Surface& dst)
678{
679	const tcu::Vec4 green	(0, 1, 0, 1);
680	const tcu::Vec4 yellow	(1, 1, 0, 1);
681
682	deUint32 positionBuf	= 0;
683	deUint32 offsetBuf		= 0;
684	deUint32 colorBuf		= 0;
685	deUint32 indexBuf		= 0;
686	deUint32 programID		= ctx.createProgram(&program);
687	deInt32 posLocation		= ctx.getAttribLocation(programID, "a_position");
688	deInt32 offsetLocation	= ctx.getAttribLocation(programID, "a_offset");
689	deInt32 colorLocation	= ctx.getAttribLocation(programID, "a_color");
690
691	float cellW	= 2.0f / (float)m_gridSide;
692	float cellH	= 2.0f / (float)m_gridSide;
693	const tcu::Vec4 vertexPositions[] =
694	{
695		tcu::Vec4(0,		0,		0, 1),
696		tcu::Vec4(cellW,	0,		0, 1),
697		tcu::Vec4(0,		cellH,	0, 1),
698
699		tcu::Vec4(0,		cellH,	0, 1),
700		tcu::Vec4(cellW,	0,		0, 1),
701		tcu::Vec4(cellW,	cellH,	0, 1),
702	};
703
704	const deUint16 indices[] =
705	{
706		0, 4, 3,
707		2, 1, 5
708	};
709
710	std::vector<tcu::Vec4> offsets;
711	for (int x = 0; x < m_gridSide; ++x)
712	for (int y = 0; y < m_gridSide; ++y)
713		offsets.push_back(tcu::Vec4((float)x * cellW - 1.0f, (float)y * cellW - 1.0f, 0, 0));
714
715	std::vector<tcu::Vec4> colors;
716	for (int x = 0; x < m_gridSide; ++x)
717	for (int y = 0; y < m_gridSide; ++y)
718		colors.push_back(((x + y) % 2 == 0) ? (green) : (yellow));
719
720	ctx.genBuffers(1, &positionBuf);
721	ctx.bindBuffer(GL_ARRAY_BUFFER, positionBuf);
722	ctx.bufferData(GL_ARRAY_BUFFER, sizeof(vertexPositions), vertexPositions, GL_STATIC_DRAW);
723	ctx.vertexAttribPointer(posLocation, 4, GL_FLOAT, GL_FALSE, 0, DE_NULL);
724	ctx.vertexAttribDivisor(posLocation, 0);
725	ctx.enableVertexAttribArray(posLocation);
726
727	ctx.genBuffers(1, &offsetBuf);
728	ctx.bindBuffer(GL_ARRAY_BUFFER, offsetBuf);
729	ctx.bufferData(GL_ARRAY_BUFFER, offsets.size() * sizeof(tcu::Vec4), &offsets[0], GL_STATIC_DRAW);
730	ctx.vertexAttribPointer(offsetLocation, 4, GL_FLOAT, GL_FALSE, 0, DE_NULL);
731	ctx.vertexAttribDivisor(offsetLocation, 1);
732	ctx.enableVertexAttribArray(offsetLocation);
733
734	ctx.genBuffers(1, &colorBuf);
735	ctx.bindBuffer(GL_ARRAY_BUFFER, colorBuf);
736	ctx.bufferData(GL_ARRAY_BUFFER, colors.size() * sizeof(tcu::Vec4), &colors[0], GL_STATIC_DRAW);
737	ctx.vertexAttribPointer(colorLocation, 4, GL_FLOAT, GL_FALSE, 0, DE_NULL);
738	ctx.vertexAttribDivisor(colorLocation, 1);
739	ctx.enableVertexAttribArray(colorLocation);
740
741	if (m_useIndices)
742	{
743		ctx.genBuffers(1, &indexBuf);
744		ctx.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuf);
745		ctx.bufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
746	}
747
748	ctx.clearColor(0, 0, 0, 1);
749	ctx.clear(GL_COLOR_BUFFER_BIT);
750
751	ctx.viewport(0, 0, dst.getWidth(), dst.getHeight());
752
753	ctx.useProgram(programID);
754	if (m_useIndices)
755		ctx.drawElementsInstanced(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, DE_NULL, m_gridSide * m_gridSide);
756	else
757		ctx.drawArraysInstanced(GL_TRIANGLES, 0, 6, m_gridSide * m_gridSide);
758	ctx.useProgram(0);
759
760	if (m_useIndices)
761		ctx.deleteBuffers(1, &indexBuf);
762	ctx.deleteBuffers(1, &colorBuf);
763	ctx.deleteBuffers(1, &offsetBuf);
764	ctx.deleteBuffers(1, &positionBuf);
765	ctx.deleteProgram(programID);
766
767	ctx.finish();
768	ctx.readPixels(dst, 0, 0, dst.getWidth(), dst.getHeight());
769
770	glu::checkError(ctx.getError(), "", __FILE__, __LINE__);
771}
772
773bool InstancedGridRenderTest::verifyImage (const tcu::Surface& image)
774{
775	// \note the green/yellow pattern is only for clarity. The test will only verify that all instances were drawn by looking for anything non-green/yellow.
776	using tcu::TestLog;
777
778	const int colorThreshold	= 20;
779
780	tcu::Surface error			(image.getWidth(), image.getHeight());
781	bool isOk					= true;
782
783	for (int y = 0; y < image.getHeight(); y++)
784	for (int x = 0; x < image.getWidth(); x++)
785	{
786		if (x == 0 || y == 0 || y + 1 == image.getHeight() || x + 1 == image.getWidth())
787		{
788			// Background color might bleed in at the borders with msaa
789			error.setPixel(x, y, tcu::RGBA(0, 255, 0, 255));
790		}
791		else
792		{
793			const tcu::RGBA pixel = image.getPixel(x, y);
794			bool pixelOk = true;
795
796			// Any pixel with !(G ~= 255) is faulty (not a linear combinations of green and yellow)
797			if (de::abs(pixel.getGreen() - 255) > colorThreshold)
798				pixelOk = false;
799
800			// Any pixel with !(B ~= 0) is faulty (not a linear combinations of green and yellow)
801			if (de::abs(pixel.getBlue() - 0) > colorThreshold)
802				pixelOk = false;
803
804			error.setPixel(x, y, (pixelOk) ? (tcu::RGBA(0, 255, 0, 255)) : (tcu::RGBA(255, 0, 0, 255)));
805			isOk = isOk && pixelOk;
806		}
807	}
808
809	if (!isOk)
810	{
811		tcu::TestLog& log = m_testCtx.getLog();
812
813		log << TestLog::Message << "Image verification failed." << TestLog::EndMessage;
814		log << TestLog::ImageSet("Verfication result", "Result of rendering")
815			<< TestLog::Image("Result",		"Result",		image)
816			<< TestLog::Image("ErrorMask",	"Error mask",	error)
817			<< TestLog::EndImageSet;
818	}
819	else
820	{
821		tcu::TestLog& log = m_testCtx.getLog();
822
823		log << TestLog::ImageSet("Verfication result", "Result of rendering")
824			<< TestLog::Image("Result", "Result", image)
825			<< TestLog::EndImageSet;
826	}
827
828	return isOk;
829}
830
831class InstancingGroup : public TestCaseGroup
832{
833public:
834									InstancingGroup		(Context& context, const char* name, const char* descr);
835									~InstancingGroup	(void);
836
837	void							init				(void);
838};
839
840InstancingGroup::InstancingGroup (Context& context, const char* name, const char* descr)
841	: TestCaseGroup	(context, name, descr)
842{
843}
844
845InstancingGroup::~InstancingGroup (void)
846{
847}
848
849void InstancingGroup::init (void)
850{
851	const int gridWidths[] =
852	{
853		2,
854		5,
855		10,
856		32,
857		100,
858	};
859
860	// drawArrays
861	for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(gridWidths); ++ndx)
862	{
863		const std::string name = std::string("draw_arrays_instanced_grid_") + de::toString(gridWidths[ndx]) + "x" + de::toString(gridWidths[ndx]);
864		const std::string desc = std::string("DrawArraysInstanced, Grid size ") + de::toString(gridWidths[ndx]) + "x" + de::toString(gridWidths[ndx]);
865
866		this->addChild(new InstancedGridRenderTest(m_context, name.c_str(), desc.c_str(), gridWidths[ndx], false));
867	}
868
869	// drawElements
870	for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(gridWidths); ++ndx)
871	{
872		const std::string name = std::string("draw_elements_instanced_grid_") + de::toString(gridWidths[ndx]) + "x" + de::toString(gridWidths[ndx]);
873		const std::string desc = std::string("DrawElementsInstanced, Grid size ") + de::toString(gridWidths[ndx]) + "x" + de::toString(gridWidths[ndx]);
874
875		this->addChild(new InstancedGridRenderTest(m_context, name.c_str(), desc.c_str(), gridWidths[ndx], true));
876	}
877}
878
879class RandomGroup : public TestCaseGroup
880{
881public:
882									RandomGroup		(Context& context, const char* name, const char* descr);
883									~RandomGroup	(void);
884
885	void							init			(void);
886};
887
888template <int SIZE>
889struct UniformWeightArray
890{
891	float weights[SIZE];
892
893	UniformWeightArray (void)
894	{
895		for (int i=0; i<SIZE; ++i)
896			weights[i] = 1.0f;
897	}
898};
899
900RandomGroup::RandomGroup (Context& context, const char* name, const char* descr)
901	: TestCaseGroup	(context, name, descr)
902{
903}
904
905RandomGroup::~RandomGroup (void)
906{
907}
908
909void RandomGroup::init (void)
910{
911	const int			numAttempts				= 300;
912
913	static const int	attribCounts[]			= { 1, 2, 5 };
914	static const float	attribWeights[]			= { 30, 10, 1 };
915	static const int	primitiveCounts[]		= { 1, 5, 64 };
916	static const float	primitiveCountWeights[]	= { 20, 10, 1 };
917	static const int	indexOffsets[]			= { 0, 7, 13 };
918	static const float	indexOffsetWeights[]	= { 20, 20, 1 };
919	static const int	firsts[]				= { 0, 7, 13 };
920	static const float	firstWeights[]			= { 20, 20, 1 };
921	static const int	instanceCounts[]		= { 1, 2, 16, 17 };
922	static const float	instanceWeights[]		= { 20, 10, 5, 1 };
923	static const int	indexMins[]				= { 0, 1, 3, 8 };
924	static const int	indexMaxs[]				= { 4, 8, 128, 257 };
925	static const float	indexWeights[]			= { 50, 50, 50, 50 };
926	static const int	offsets[]				= { 0, 1, 5, 12 };
927	static const float	offsetWeights[]			= { 50, 10, 10, 10 };
928	static const int	strides[]				= { 0, 7, 16, 17 };
929	static const float	strideWeights[]			= { 50, 10, 10, 10 };
930	static const int	instanceDivisors[]		= { 0, 1, 3, 129 };
931	static const float	instanceDivisorWeights[]= { 70, 30, 10, 10 };
932
933	static const gls::DrawTestSpec::Primitive primitives[] =
934	{
935		gls::DrawTestSpec::PRIMITIVE_POINTS,
936		gls::DrawTestSpec::PRIMITIVE_TRIANGLES,
937		gls::DrawTestSpec::PRIMITIVE_TRIANGLE_FAN,
938		gls::DrawTestSpec::PRIMITIVE_TRIANGLE_STRIP,
939		gls::DrawTestSpec::PRIMITIVE_LINES,
940		gls::DrawTestSpec::PRIMITIVE_LINE_STRIP,
941		gls::DrawTestSpec::PRIMITIVE_LINE_LOOP
942	};
943	const UniformWeightArray<DE_LENGTH_OF_ARRAY(primitives)> primitiveWeights;
944
945	static const gls::DrawTestSpec::DrawMethod drawMethods[] =
946	{
947		gls::DrawTestSpec::DRAWMETHOD_DRAWARRAYS,
948		gls::DrawTestSpec::DRAWMETHOD_DRAWARRAYS_INSTANCED,
949		gls::DrawTestSpec::DRAWMETHOD_DRAWELEMENTS,
950		gls::DrawTestSpec::DRAWMETHOD_DRAWELEMENTS_RANGED,
951		gls::DrawTestSpec::DRAWMETHOD_DRAWELEMENTS_INSTANCED
952	};
953	const UniformWeightArray<DE_LENGTH_OF_ARRAY(drawMethods)> drawMethodWeights;
954
955	static const gls::DrawTestSpec::IndexType indexTypes[] =
956	{
957		gls::DrawTestSpec::INDEXTYPE_BYTE,
958		gls::DrawTestSpec::INDEXTYPE_SHORT,
959		gls::DrawTestSpec::INDEXTYPE_INT,
960	};
961	const UniformWeightArray<DE_LENGTH_OF_ARRAY(indexTypes)> indexTypeWeights;
962
963	static const gls::DrawTestSpec::Storage storages[] =
964	{
965		gls::DrawTestSpec::STORAGE_USER,
966		gls::DrawTestSpec::STORAGE_BUFFER,
967	};
968	const UniformWeightArray<DE_LENGTH_OF_ARRAY(storages)> storageWeights;
969
970	static const gls::DrawTestSpec::InputType inputTypes[] =
971	{
972		gls::DrawTestSpec::INPUTTYPE_FLOAT,
973		gls::DrawTestSpec::INPUTTYPE_FIXED,
974		gls::DrawTestSpec::INPUTTYPE_BYTE,
975		gls::DrawTestSpec::INPUTTYPE_SHORT,
976		gls::DrawTestSpec::INPUTTYPE_UNSIGNED_BYTE,
977		gls::DrawTestSpec::INPUTTYPE_UNSIGNED_SHORT,
978		gls::DrawTestSpec::INPUTTYPE_INT,
979		gls::DrawTestSpec::INPUTTYPE_UNSIGNED_INT,
980		gls::DrawTestSpec::INPUTTYPE_HALF,
981		gls::DrawTestSpec::INPUTTYPE_UNSIGNED_INT_2_10_10_10,
982		gls::DrawTestSpec::INPUTTYPE_INT_2_10_10_10,
983	};
984	const UniformWeightArray<DE_LENGTH_OF_ARRAY(inputTypes)> inputTypeWeights;
985
986	static const gls::DrawTestSpec::OutputType outputTypes[] =
987	{
988		gls::DrawTestSpec::OUTPUTTYPE_FLOAT,
989		gls::DrawTestSpec::OUTPUTTYPE_VEC2,
990		gls::DrawTestSpec::OUTPUTTYPE_VEC3,
991		gls::DrawTestSpec::OUTPUTTYPE_VEC4,
992		gls::DrawTestSpec::OUTPUTTYPE_INT,
993		gls::DrawTestSpec::OUTPUTTYPE_UINT,
994		gls::DrawTestSpec::OUTPUTTYPE_IVEC2,
995		gls::DrawTestSpec::OUTPUTTYPE_IVEC3,
996		gls::DrawTestSpec::OUTPUTTYPE_IVEC4,
997		gls::DrawTestSpec::OUTPUTTYPE_UVEC2,
998		gls::DrawTestSpec::OUTPUTTYPE_UVEC3,
999		gls::DrawTestSpec::OUTPUTTYPE_UVEC4,
1000	};
1001	const UniformWeightArray<DE_LENGTH_OF_ARRAY(outputTypes)> outputTypeWeights;
1002
1003	static const gls::DrawTestSpec::Usage usages[] =
1004	{
1005		gls::DrawTestSpec::USAGE_DYNAMIC_DRAW,
1006		gls::DrawTestSpec::USAGE_STATIC_DRAW,
1007		gls::DrawTestSpec::USAGE_STREAM_DRAW,
1008		gls::DrawTestSpec::USAGE_STREAM_READ,
1009		gls::DrawTestSpec::USAGE_STREAM_COPY,
1010		gls::DrawTestSpec::USAGE_STATIC_READ,
1011		gls::DrawTestSpec::USAGE_STATIC_COPY,
1012		gls::DrawTestSpec::USAGE_DYNAMIC_READ,
1013		gls::DrawTestSpec::USAGE_DYNAMIC_COPY,
1014	};
1015	const UniformWeightArray<DE_LENGTH_OF_ARRAY(usages)> usageWeights;
1016
1017	static const deUint32 blacklistedCases[]=
1018	{
1019		544,	//!< extremely narrow triangle
1020	};
1021
1022	std::set<deUint32>	insertedHashes;
1023	size_t				insertedCount = 0;
1024
1025	for (int ndx = 0; ndx < numAttempts; ++ndx)
1026	{
1027		de::Random random(0xc551393 + ndx); // random does not depend on previous cases
1028
1029		int					attributeCount = random.chooseWeighted<int, const int*, const float*>(DE_ARRAY_BEGIN(attribCounts), DE_ARRAY_END(attribCounts), attribWeights);
1030		gls::DrawTestSpec	spec;
1031
1032		spec.apiType				= glu::ApiType::es(3,0);
1033		spec.primitive				= random.chooseWeighted<gls::DrawTestSpec::Primitive>	(DE_ARRAY_BEGIN(primitives),		DE_ARRAY_END(primitives),		primitiveWeights.weights);
1034		spec.primitiveCount			= random.chooseWeighted<int, const int*, const float*>	(DE_ARRAY_BEGIN(primitiveCounts),	DE_ARRAY_END(primitiveCounts),	primitiveCountWeights);
1035		spec.drawMethod				= random.chooseWeighted<gls::DrawTestSpec::DrawMethod>	(DE_ARRAY_BEGIN(drawMethods),		DE_ARRAY_END(drawMethods),		drawMethodWeights.weights);
1036		spec.indexType				= random.chooseWeighted<gls::DrawTestSpec::IndexType>	(DE_ARRAY_BEGIN(indexTypes),		DE_ARRAY_END(indexTypes),		indexTypeWeights.weights);
1037		spec.indexPointerOffset		= random.chooseWeighted<int, const int*, const float*>	(DE_ARRAY_BEGIN(indexOffsets),		DE_ARRAY_END(indexOffsets),		indexOffsetWeights);
1038		spec.indexStorage			= random.chooseWeighted<gls::DrawTestSpec::Storage>		(DE_ARRAY_BEGIN(storages),			DE_ARRAY_END(storages),			storageWeights.weights);
1039		spec.first					= random.chooseWeighted<int, const int*, const float*>	(DE_ARRAY_BEGIN(firsts),			DE_ARRAY_END(firsts),			firstWeights);
1040		spec.indexMin				= random.chooseWeighted<int, const int*, const float*>	(DE_ARRAY_BEGIN(indexMins),			DE_ARRAY_END(indexMins),		indexWeights);
1041		spec.indexMax				= random.chooseWeighted<int, const int*, const float*>	(DE_ARRAY_BEGIN(indexMaxs),			DE_ARRAY_END(indexMaxs),		indexWeights);
1042		spec.instanceCount			= random.chooseWeighted<int, const int*, const float*>	(DE_ARRAY_BEGIN(instanceCounts),	DE_ARRAY_END(instanceCounts),	instanceWeights);
1043
1044		// check spec is legal
1045		if (!spec.valid())
1046			continue;
1047
1048		for (int attrNdx = 0; attrNdx < attributeCount;)
1049		{
1050			bool valid;
1051			gls::DrawTestSpec::AttributeSpec attribSpec;
1052
1053			attribSpec.inputType			= random.chooseWeighted<gls::DrawTestSpec::InputType>	(DE_ARRAY_BEGIN(inputTypes),		DE_ARRAY_END(inputTypes),		inputTypeWeights.weights);
1054			attribSpec.outputType			= random.chooseWeighted<gls::DrawTestSpec::OutputType>	(DE_ARRAY_BEGIN(outputTypes),		DE_ARRAY_END(outputTypes),		outputTypeWeights.weights);
1055			attribSpec.storage				= random.chooseWeighted<gls::DrawTestSpec::Storage>		(DE_ARRAY_BEGIN(storages),			DE_ARRAY_END(storages),			storageWeights.weights);
1056			attribSpec.usage				= random.chooseWeighted<gls::DrawTestSpec::Usage>		(DE_ARRAY_BEGIN(usages),			DE_ARRAY_END(usages),			usageWeights.weights);
1057			attribSpec.componentCount		= random.getInt(1, 4);
1058			attribSpec.offset				= random.chooseWeighted<int, const int*, const float*>(DE_ARRAY_BEGIN(offsets), DE_ARRAY_END(offsets), offsetWeights);
1059			attribSpec.stride				= random.chooseWeighted<int, const int*, const float*>(DE_ARRAY_BEGIN(strides), DE_ARRAY_END(strides), strideWeights);
1060			attribSpec.normalize			= random.getBool();
1061			attribSpec.instanceDivisor		= random.chooseWeighted<int, const int*, const float*>(DE_ARRAY_BEGIN(instanceDivisors), DE_ARRAY_END(instanceDivisors), instanceDivisorWeights);
1062			attribSpec.useDefaultAttribute	= random.getBool();
1063
1064			// check spec is legal
1065			valid = attribSpec.valid(spec.apiType);
1066
1067			// we do not want interleaved elements. (Might result in some weird floating point values)
1068			if (attribSpec.stride && attribSpec.componentCount * gls::DrawTestSpec::inputTypeSize(attribSpec.inputType) > attribSpec.stride)
1069				valid = false;
1070
1071			// try again if not valid
1072			if (valid)
1073			{
1074				spec.attribs.push_back(attribSpec);
1075				++attrNdx;
1076			}
1077		}
1078
1079		// Do not collapse all vertex positions to a single positions
1080		if (spec.primitive != gls::DrawTestSpec::PRIMITIVE_POINTS)
1081			spec.attribs[0].instanceDivisor = 0;
1082
1083		// Is render result meaningful?
1084		{
1085			// Only one vertex
1086			if (spec.drawMethod == gls::DrawTestSpec::DRAWMETHOD_DRAWELEMENTS_RANGED && spec.indexMin == spec.indexMax && spec.primitive != gls::DrawTestSpec::PRIMITIVE_POINTS)
1087				continue;
1088			if (spec.attribs[0].useDefaultAttribute && spec.primitive != gls::DrawTestSpec::PRIMITIVE_POINTS)
1089				continue;
1090
1091			// Triangle only on one axis
1092			if (spec.primitive == gls::DrawTestSpec::PRIMITIVE_TRIANGLES || spec.primitive == gls::DrawTestSpec::PRIMITIVE_TRIANGLE_FAN || spec.primitive == gls::DrawTestSpec::PRIMITIVE_TRIANGLE_STRIP)
1093			{
1094				if (spec.attribs[0].componentCount == 1)
1095					continue;
1096				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)
1097					continue;
1098				if (spec.drawMethod == gls::DrawTestSpec::DRAWMETHOD_DRAWELEMENTS_RANGED && (spec.indexMax - spec.indexMin) < 2)
1099					continue;
1100			}
1101		}
1102
1103		// Add case
1104		{
1105			deUint32 hash = spec.hash();
1106			for (int attrNdx = 0; attrNdx < attributeCount; ++attrNdx)
1107				hash = (hash << 2) ^ (deUint32)spec.attribs[attrNdx].hash();
1108
1109			if (insertedHashes.find(hash) == insertedHashes.end())
1110			{
1111				// Only properly aligned and not blacklisted cases
1112				if (spec.isCompatibilityTest() != gls::DrawTestSpec::COMPATIBILITY_UNALIGNED_OFFSET			&&
1113					spec.isCompatibilityTest() != gls::DrawTestSpec::COMPATIBILITY_UNALIGNED_STRIDE			&&
1114					!de::contains(DE_ARRAY_BEGIN(blacklistedCases), DE_ARRAY_END(blacklistedCases), hash))
1115				{
1116					this->addChild(new gls::DrawTest(m_testCtx, m_context.getRenderContext(), spec, de::toString(insertedCount).c_str(), spec.getDesc().c_str()));
1117				}
1118				insertedHashes.insert(hash);
1119
1120				++insertedCount;
1121			}
1122		}
1123	}
1124}
1125
1126} // anonymous
1127
1128DrawTests::DrawTests (Context& context)
1129	: TestCaseGroup(context, "draw", "Drawing tests")
1130{
1131}
1132
1133DrawTests::~DrawTests (void)
1134{
1135}
1136
1137void DrawTests::init (void)
1138{
1139	// Basic
1140	{
1141		const gls::DrawTestSpec::DrawMethod basicMethods[] =
1142		{
1143			gls::DrawTestSpec::DRAWMETHOD_DRAWARRAYS,
1144			gls::DrawTestSpec::DRAWMETHOD_DRAWELEMENTS,
1145			gls::DrawTestSpec::DRAWMETHOD_DRAWARRAYS_INSTANCED,
1146			gls::DrawTestSpec::DRAWMETHOD_DRAWELEMENTS_INSTANCED,
1147			gls::DrawTestSpec::DRAWMETHOD_DRAWELEMENTS_RANGED,
1148		};
1149
1150		for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(basicMethods); ++ndx)
1151		{
1152			const std::string name = gls::DrawTestSpec::drawMethodToString(basicMethods[ndx]);
1153			const std::string desc = gls::DrawTestSpec::drawMethodToString(basicMethods[ndx]);
1154
1155			this->addChild(new MethodGroup(m_context, name.c_str(), desc.c_str(), basicMethods[ndx]));
1156		}
1157	}
1158
1159	// extreme instancing
1160
1161	this->addChild(new InstancingGroup(m_context, "instancing", "draw tests with a large instance count."));
1162
1163	// Random
1164
1165	this->addChild(new RandomGroup(m_context, "random", "random draw commands."));
1166}
1167
1168} // Functional
1169} // gles3
1170} // deqp
1171