es2sDrawTests.cpp revision 3c827367444ee418f129b2c238299f49d3264554
1/*-------------------------------------------------------------------------
2 * drawElements Quality Program OpenGL ES 2.0 Module
3 * -------------------------------------------------
4 *
5 * Copyright 2014 The Android Open Source Project
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 *      http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 *
19 *//*!
20 * \file
21 * \brief Drawing tests.
22 *//*--------------------------------------------------------------------*/
23
24#include "es2sDrawTests.hpp"
25#include "glsDrawTest.hpp"
26#include "tcuRenderTarget.hpp"
27#include "deRandom.hpp"
28#include "deStringUtil.hpp"
29#include "deUniquePtr.hpp"
30
31#include "glwEnums.hpp"
32
33#include <set>
34
35namespace deqp
36{
37namespace gles2
38{
39namespace Stress
40{
41namespace
42{
43
44static void genBasicSpec (gls::DrawTestSpec& spec, gls::DrawTestSpec::DrawMethod method)
45{
46	spec.apiType							= glu::ApiType::es(2,0);
47	spec.primitive							= gls::DrawTestSpec::PRIMITIVE_TRIANGLES;
48	spec.primitiveCount						= 5;
49	spec.drawMethod							= method;
50	spec.indexType							= gls::DrawTestSpec::INDEXTYPE_LAST;
51	spec.indexPointerOffset					= 0;
52	spec.indexStorage						= gls::DrawTestSpec::STORAGE_LAST;
53	spec.first								= 0;
54	spec.indexMin							= 0;
55	spec.indexMax							= 0;
56	spec.instanceCount						= 1;
57
58	spec.attribs.resize(2);
59
60	spec.attribs[0].inputType				= gls::DrawTestSpec::INPUTTYPE_FLOAT;
61	spec.attribs[0].outputType				= gls::DrawTestSpec::OUTPUTTYPE_VEC2;
62	spec.attribs[0].storage					= gls::DrawTestSpec::STORAGE_BUFFER;
63	spec.attribs[0].usage					= gls::DrawTestSpec::USAGE_STATIC_DRAW;
64	spec.attribs[0].componentCount			= 4;
65	spec.attribs[0].offset					= 0;
66	spec.attribs[0].stride					= 0;
67	spec.attribs[0].normalize				= false;
68	spec.attribs[0].instanceDivisor			= 0;
69	spec.attribs[0].useDefaultAttribute		= false;
70
71	spec.attribs[1].inputType				= gls::DrawTestSpec::INPUTTYPE_FLOAT;
72	spec.attribs[1].outputType				= gls::DrawTestSpec::OUTPUTTYPE_VEC2;
73	spec.attribs[1].storage					= gls::DrawTestSpec::STORAGE_BUFFER;
74	spec.attribs[1].usage					= gls::DrawTestSpec::USAGE_STATIC_DRAW;
75	spec.attribs[1].componentCount			= 2;
76	spec.attribs[1].offset					= 0;
77	spec.attribs[1].stride					= 0;
78	spec.attribs[1].normalize				= false;
79	spec.attribs[1].instanceDivisor			= 0;
80	spec.attribs[1].useDefaultAttribute		= false;
81}
82
83class IndexGroup : public TestCaseGroup
84{
85public:
86									IndexGroup		(Context& context, const char* name, const char* descr, gls::DrawTestSpec::DrawMethod drawMethod);
87									~IndexGroup		(void);
88
89	void							init			(void);
90
91private:
92	gls::DrawTestSpec::DrawMethod	m_method;
93};
94
95IndexGroup::IndexGroup (Context& context, const char* name, const char* descr, gls::DrawTestSpec::DrawMethod drawMethod)
96	: TestCaseGroup		(context, name, descr)
97	, m_method			(drawMethod)
98{
99}
100
101IndexGroup::~IndexGroup (void)
102{
103}
104
105void IndexGroup::init (void)
106{
107	struct IndexTest
108	{
109		gls::DrawTestSpec::Storage		storage;
110		gls::DrawTestSpec::IndexType	type;
111		bool							aligned;
112		int								offsets[3];
113	};
114
115	const IndexTest tests[] =
116	{
117		{ gls::DrawTestSpec::STORAGE_USER,		gls::DrawTestSpec::INDEXTYPE_BYTE,	true,	{ 0, 1, -1 } },
118		{ gls::DrawTestSpec::STORAGE_USER,		gls::DrawTestSpec::INDEXTYPE_SHORT,	true,	{ 0, 2, -1 } },
119
120		{ gls::DrawTestSpec::STORAGE_USER,		gls::DrawTestSpec::INDEXTYPE_SHORT,	false,	{ 1, 3, -1 } },
121
122		{ gls::DrawTestSpec::STORAGE_BUFFER,	gls::DrawTestSpec::INDEXTYPE_BYTE,	true,	{ 0, 1, -1 } },
123		{ gls::DrawTestSpec::STORAGE_BUFFER,	gls::DrawTestSpec::INDEXTYPE_SHORT,	true,	{ 0, 2, -1 } },
124
125		{ gls::DrawTestSpec::STORAGE_BUFFER,	gls::DrawTestSpec::INDEXTYPE_SHORT,	false,	{ 1, 3, -1 } },
126	};
127
128	gls::DrawTestSpec spec;
129
130	tcu::TestCaseGroup* userPtrGroup			= new tcu::TestCaseGroup(m_testCtx, "user_ptr", "user pointer");
131	tcu::TestCaseGroup* unalignedUserPtrGroup	= new tcu::TestCaseGroup(m_testCtx, "unaligned_user_ptr", "unaligned user pointer");
132	tcu::TestCaseGroup* bufferGroup				= new tcu::TestCaseGroup(m_testCtx, "buffer", "buffer");
133	tcu::TestCaseGroup* unalignedBufferGroup	= new tcu::TestCaseGroup(m_testCtx, "unaligned_buffer", "unaligned buffer");
134
135	genBasicSpec(spec, m_method);
136
137	this->addChild(userPtrGroup);
138	this->addChild(unalignedUserPtrGroup);
139	this->addChild(bufferGroup);
140	this->addChild(unalignedBufferGroup);
141
142	for (int testNdx = 0; testNdx < DE_LENGTH_OF_ARRAY(tests); ++testNdx)
143	{
144		const IndexTest&				indexTest	= tests[testNdx];
145		tcu::TestCaseGroup*				group		= (indexTest.storage == gls::DrawTestSpec::STORAGE_USER) ? ((indexTest.aligned) ? (userPtrGroup) : (unalignedUserPtrGroup)) : ((indexTest.aligned) ? (bufferGroup) : (unalignedBufferGroup));
146
147		const std::string				name		= std::string("index_") + gls::DrawTestSpec::indexTypeToString(indexTest.type);
148		const std::string				desc		= std::string("index ") + gls::DrawTestSpec::indexTypeToString(indexTest.type) + " in " + gls::DrawTestSpec::storageToString(indexTest.storage);
149		de::MovePtr<gls::DrawTest>		test		(new gls::DrawTest(m_testCtx, m_context.getRenderContext(), name.c_str(), desc.c_str()));
150
151		spec.indexType			= indexTest.type;
152		spec.indexStorage		= indexTest.storage;
153
154		for (int iterationNdx = 0; iterationNdx < DE_LENGTH_OF_ARRAY(indexTest.offsets) && indexTest.offsets[iterationNdx] != -1; ++iterationNdx)
155		{
156			const std::string iterationDesc = std::string("offset ") + de::toString(indexTest.offsets[iterationNdx]);
157			spec.indexPointerOffset	= indexTest.offsets[iterationNdx];
158			test->addIteration(spec, iterationDesc.c_str());
159		}
160
161		if (spec.isCompatibilityTest() == gls::DrawTestSpec::COMPATIBILITY_UNALIGNED_OFFSET ||
162			spec.isCompatibilityTest() == gls::DrawTestSpec::COMPATIBILITY_UNALIGNED_STRIDE)
163			group->addChild(test.release());
164	}
165}
166
167class MethodGroup : public TestCaseGroup
168{
169public:
170									MethodGroup			(Context& context, const char* name, const char* descr, gls::DrawTestSpec::DrawMethod drawMethod);
171									~MethodGroup		(void);
172
173	void							init				(void);
174
175private:
176	gls::DrawTestSpec::DrawMethod	m_method;
177};
178
179MethodGroup::MethodGroup (Context& context, const char* name, const char* descr, gls::DrawTestSpec::DrawMethod drawMethod)
180	: TestCaseGroup		(context, name, descr)
181	, m_method			(drawMethod)
182{
183}
184
185MethodGroup::~MethodGroup (void)
186{
187}
188
189void MethodGroup::init (void)
190{
191	const bool indexed = (m_method == gls::DrawTestSpec::DRAWMETHOD_DRAWELEMENTS) || (m_method == gls::DrawTestSpec::DRAWMETHOD_DRAWELEMENTS_INSTANCED) || (m_method == gls::DrawTestSpec::DRAWMETHOD_DRAWELEMENTS_RANGED);
192
193	DE_ASSERT(indexed);
194	DE_UNREF(indexed);
195
196	this->addChild(new IndexGroup(m_context, "indices", "Index tests", m_method));
197}
198
199class RandomGroup : public TestCaseGroup
200{
201public:
202									RandomGroup		(Context& context, const char* name, const char* descr);
203									~RandomGroup	(void);
204
205	void							init			(void);
206};
207
208template <int SIZE>
209struct UniformWeightArray
210{
211	float weights[SIZE];
212
213	UniformWeightArray (void)
214	{
215		for (int i=0; i<SIZE; ++i)
216			weights[i] = 1.0f;
217	}
218};
219
220RandomGroup::RandomGroup (Context& context, const char* name, const char* descr)
221	: TestCaseGroup	(context, name, descr)
222{
223}
224
225RandomGroup::~RandomGroup (void)
226{
227}
228
229void RandomGroup::init (void)
230{
231	const int	numAttempts				= 100;
232
233	const int	attribCounts[]			= { 1, 2, 5 };
234	const float	attribWeights[]			= { 30, 10, 1 };
235	const int	primitiveCounts[]		= { 1, 5, 64 };
236	const float	primitiveCountWeights[]	= { 20, 10, 1 };
237	const int	indexOffsets[]			= { 0, 7, 13 };
238	const float	indexOffsetWeights[]	= { 20, 20, 1 };
239	const int	firsts[]				= { 0, 7, 13 };
240	const float	firstWeights[]			= { 20, 20, 1 };
241	const int	offsets[]				= { 0, 1, 5, 12 };
242	const float	offsetWeights[]			= { 50, 10, 10, 10 };
243	const int	strides[]				= { 0, 7, 16, 17 };
244	const float	strideWeights[]			= { 50, 10, 10, 10 };
245
246	gls::DrawTestSpec::Primitive primitives[] =
247	{
248		gls::DrawTestSpec::PRIMITIVE_POINTS,
249		gls::DrawTestSpec::PRIMITIVE_TRIANGLES,
250		gls::DrawTestSpec::PRIMITIVE_TRIANGLE_FAN,
251		gls::DrawTestSpec::PRIMITIVE_TRIANGLE_STRIP,
252		gls::DrawTestSpec::PRIMITIVE_LINES,
253		gls::DrawTestSpec::PRIMITIVE_LINE_STRIP,
254		gls::DrawTestSpec::PRIMITIVE_LINE_LOOP
255	};
256	const UniformWeightArray<DE_LENGTH_OF_ARRAY(primitives)> primitiveWeights;
257
258	gls::DrawTestSpec::DrawMethod drawMethods[] =
259	{
260		gls::DrawTestSpec::DRAWMETHOD_DRAWARRAYS,
261		gls::DrawTestSpec::DRAWMETHOD_DRAWELEMENTS,
262	};
263	const UniformWeightArray<DE_LENGTH_OF_ARRAY(drawMethods)> drawMethodWeights;
264
265	gls::DrawTestSpec::IndexType indexTypes[] =
266	{
267		gls::DrawTestSpec::INDEXTYPE_BYTE,
268		gls::DrawTestSpec::INDEXTYPE_SHORT,
269	};
270	const UniformWeightArray<DE_LENGTH_OF_ARRAY(indexTypes)> indexTypeWeights;
271
272	gls::DrawTestSpec::Storage storages[] =
273	{
274		gls::DrawTestSpec::STORAGE_USER,
275		gls::DrawTestSpec::STORAGE_BUFFER,
276	};
277	const UniformWeightArray<DE_LENGTH_OF_ARRAY(storages)> storageWeights;
278
279	gls::DrawTestSpec::InputType inputTypes[] =
280	{
281		gls::DrawTestSpec::INPUTTYPE_FLOAT,
282		gls::DrawTestSpec::INPUTTYPE_FIXED,
283		gls::DrawTestSpec::INPUTTYPE_BYTE,
284		gls::DrawTestSpec::INPUTTYPE_SHORT,
285		gls::DrawTestSpec::INPUTTYPE_UNSIGNED_BYTE,
286		gls::DrawTestSpec::INPUTTYPE_UNSIGNED_SHORT
287	};
288	const UniformWeightArray<DE_LENGTH_OF_ARRAY(inputTypes)> inputTypeWeights;
289
290	gls::DrawTestSpec::OutputType outputTypes[] =
291	{
292		gls::DrawTestSpec::OUTPUTTYPE_FLOAT,
293		gls::DrawTestSpec::OUTPUTTYPE_VEC2,
294		gls::DrawTestSpec::OUTPUTTYPE_VEC3,
295		gls::DrawTestSpec::OUTPUTTYPE_VEC4,
296	};
297	const UniformWeightArray<DE_LENGTH_OF_ARRAY(outputTypes)> outputTypeWeights;
298
299	gls::DrawTestSpec::Usage usages[] =
300	{
301		gls::DrawTestSpec::USAGE_STATIC_DRAW,
302		gls::DrawTestSpec::USAGE_DYNAMIC_DRAW,
303		gls::DrawTestSpec::USAGE_STREAM_DRAW,
304	};
305	const UniformWeightArray<DE_LENGTH_OF_ARRAY(usages)> usageWeights;
306
307	const deUint32 blacklistedCases[]=
308	{
309		3153,	//!< extremely narrow triangle, results depend on sample positions
310	};
311
312	std::set<deUint32>	insertedHashes;
313	size_t				insertedCount = 0;
314
315	for (int ndx = 0; ndx < numAttempts; ++ndx)
316	{
317		de::Random random(0xc551393 + ndx); // random does not depend on previous cases
318
319		int					attributeCount = random.chooseWeighted<int, const int*, const float*>(DE_ARRAY_BEGIN(attribCounts), DE_ARRAY_END(attribCounts), attribWeights);
320		gls::DrawTestSpec	spec;
321
322		spec.apiType				= glu::ApiType::es(2,0);
323		spec.primitive				= random.chooseWeighted<gls::DrawTestSpec::Primitive>	(DE_ARRAY_BEGIN(primitives),		DE_ARRAY_END(primitives),		primitiveWeights.weights);
324		spec.primitiveCount			= random.chooseWeighted<int, const int*, const float*>	(DE_ARRAY_BEGIN(primitiveCounts),	DE_ARRAY_END(primitiveCounts),	primitiveCountWeights);
325		spec.drawMethod				= random.chooseWeighted<gls::DrawTestSpec::DrawMethod>	(DE_ARRAY_BEGIN(drawMethods),		DE_ARRAY_END(drawMethods),		drawMethodWeights.weights);
326		spec.indexType				= random.chooseWeighted<gls::DrawTestSpec::IndexType>	(DE_ARRAY_BEGIN(indexTypes),		DE_ARRAY_END(indexTypes),		indexTypeWeights.weights);
327		spec.indexPointerOffset		= random.chooseWeighted<int, const int*, const float*>	(DE_ARRAY_BEGIN(indexOffsets),		DE_ARRAY_END(indexOffsets),		indexOffsetWeights);
328		spec.indexStorage			= random.chooseWeighted<gls::DrawTestSpec::Storage>		(DE_ARRAY_BEGIN(storages),			DE_ARRAY_END(storages),			storageWeights.weights);
329		spec.first					= random.chooseWeighted<int, const int*, const float*>	(DE_ARRAY_BEGIN(firsts),			DE_ARRAY_END(firsts),			firstWeights);
330		spec.indexMin				= 0;
331		spec.indexMax				= 0;
332		spec.instanceCount			= 0;
333
334		// check spec is legal
335		if (!spec.valid())
336			continue;
337
338		for (int attrNdx = 0; attrNdx < attributeCount;)
339		{
340			bool valid;
341			gls::DrawTestSpec::AttributeSpec attribSpec;
342
343			attribSpec.inputType			= random.chooseWeighted<gls::DrawTestSpec::InputType>	(DE_ARRAY_BEGIN(inputTypes),		DE_ARRAY_END(inputTypes),		inputTypeWeights.weights);
344			attribSpec.outputType			= random.chooseWeighted<gls::DrawTestSpec::OutputType>	(DE_ARRAY_BEGIN(outputTypes),		DE_ARRAY_END(outputTypes),		outputTypeWeights.weights);
345			attribSpec.storage				= random.chooseWeighted<gls::DrawTestSpec::Storage>		(DE_ARRAY_BEGIN(storages),			DE_ARRAY_END(storages),			storageWeights.weights);
346			attribSpec.usage				= random.chooseWeighted<gls::DrawTestSpec::Usage>		(DE_ARRAY_BEGIN(usages),			DE_ARRAY_END(usages),			usageWeights.weights);
347			attribSpec.componentCount		= random.getInt(1, 4);
348			attribSpec.offset				= random.chooseWeighted<int, const int*, const float*>(DE_ARRAY_BEGIN(offsets), DE_ARRAY_END(offsets), offsetWeights);
349			attribSpec.stride				= random.chooseWeighted<int, const int*, const float*>(DE_ARRAY_BEGIN(strides), DE_ARRAY_END(strides), strideWeights);
350			attribSpec.normalize			= random.getBool();
351			attribSpec.instanceDivisor		= 0;
352			attribSpec.useDefaultAttribute	= random.getBool();
353
354			// check spec is legal
355			valid = attribSpec.valid(spec.apiType);
356
357			// we do not want interleaved elements. (Might result in some weird floating point values)
358			if (attribSpec.stride && attribSpec.componentCount * gls::DrawTestSpec::inputTypeSize(attribSpec.inputType) > attribSpec.stride)
359				valid = false;
360
361			// try again if not valid
362			if (valid)
363			{
364				spec.attribs.push_back(attribSpec);
365				++attrNdx;
366			}
367		}
368
369		// Do not collapse all vertex positions to a single positions
370		if (spec.primitive != gls::DrawTestSpec::PRIMITIVE_POINTS)
371			spec.attribs[0].instanceDivisor = 0;
372
373		// Is render result meaningful?
374		{
375			// Only one vertex
376			if (spec.drawMethod == gls::DrawTestSpec::DRAWMETHOD_DRAWELEMENTS_RANGED && spec.indexMin == spec.indexMax && spec.primitive != gls::DrawTestSpec::PRIMITIVE_POINTS)
377				continue;
378			if (spec.attribs[0].useDefaultAttribute && spec.primitive != gls::DrawTestSpec::PRIMITIVE_POINTS)
379				continue;
380
381			// Triangle only on one axis
382			if (spec.primitive == gls::DrawTestSpec::PRIMITIVE_TRIANGLES || spec.primitive == gls::DrawTestSpec::PRIMITIVE_TRIANGLE_FAN || spec.primitive == gls::DrawTestSpec::PRIMITIVE_TRIANGLE_STRIP)
383			{
384				if (spec.attribs[0].componentCount == 1)
385					continue;
386				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)
387					continue;
388				if (spec.drawMethod == gls::DrawTestSpec::DRAWMETHOD_DRAWELEMENTS_RANGED && (spec.indexMax - spec.indexMin) < 2)
389					continue;
390			}
391		}
392
393		// Add case
394		{
395			deUint32 hash = spec.hash();
396			for (int attrNdx = 0; attrNdx < attributeCount; ++attrNdx)
397				hash = (hash << 2) ^ (deUint32)spec.attribs[attrNdx].hash();
398
399			if (insertedHashes.find(hash) == insertedHashes.end() &&
400				std::find(DE_ARRAY_BEGIN(blacklistedCases), DE_ARRAY_END(blacklistedCases), hash) == DE_ARRAY_END(blacklistedCases))
401			{
402				// Only unaligned cases
403				if (spec.isCompatibilityTest() == gls::DrawTestSpec::COMPATIBILITY_UNALIGNED_OFFSET ||
404					spec.isCompatibilityTest() == gls::DrawTestSpec::COMPATIBILITY_UNALIGNED_STRIDE)
405					this->addChild(new gls::DrawTest(m_testCtx, m_context.getRenderContext(), spec, de::toString(insertedCount).c_str(), spec.getDesc().c_str()));
406				insertedHashes.insert(hash);
407
408				++insertedCount;
409			}
410		}
411	}
412}
413
414} // anonymous
415
416DrawTests::DrawTests (Context& context)
417	: TestCaseGroup(context, "draw", "Drawing tests")
418{
419}
420
421DrawTests::~DrawTests (void)
422{
423}
424
425void DrawTests::init (void)
426{
427	tcu::TestCaseGroup* const unalignedGroup	= new tcu::TestCaseGroup(m_testCtx, "unaligned_data", "Test with unaligned data");
428
429	addChild(unalignedGroup);
430
431	// .unaligned_data
432	{
433		const gls::DrawTestSpec::DrawMethod basicMethods[] =
434		{
435			// gls::DrawTestSpec::DRAWMETHOD_DRAWARRAYS,
436			gls::DrawTestSpec::DRAWMETHOD_DRAWELEMENTS,
437		};
438
439		for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(basicMethods); ++ndx)
440		{
441			std::string name = gls::DrawTestSpec::drawMethodToString(basicMethods[ndx]);
442			std::string desc = gls::DrawTestSpec::drawMethodToString(basicMethods[ndx]);
443
444			unalignedGroup->addChild(new MethodGroup(m_context, name.c_str(), desc.c_str(), basicMethods[ndx]));
445		}
446
447		// Random
448
449		unalignedGroup->addChild(new RandomGroup(m_context, "random", "random draw commands."));
450	}
451
452}
453
454} // Stress
455} // gles2
456} // deqp
457