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 
35 namespace deqp
36 {
37 namespace gles2
38 {
39 namespace Stress
40 {
41 namespace
42 {
43 
genBasicSpec(gls::DrawTestSpec & spec,gls::DrawTestSpec::DrawMethod method)44 static 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 
83 class IndexGroup : public TestCaseGroup
84 {
85 public:
86 									IndexGroup		(Context& context, const char* name, const char* descr, gls::DrawTestSpec::DrawMethod drawMethod);
87 									~IndexGroup		(void);
88 
89 	void							init			(void);
90 
91 private:
92 	gls::DrawTestSpec::DrawMethod	m_method;
93 };
94 
IndexGroup(Context & context,const char * name,const char * descr,gls::DrawTestSpec::DrawMethod drawMethod)95 IndexGroup::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 
~IndexGroup(void)101 IndexGroup::~IndexGroup (void)
102 {
103 }
104 
init(void)105 void 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_BUFFER,	gls::DrawTestSpec::INDEXTYPE_SHORT,	false,	{ 1, 3, -1 } },
118 	};
119 
120 	gls::DrawTestSpec spec;
121 
122 	tcu::TestCaseGroup* unalignedBufferGroup	= new tcu::TestCaseGroup(m_testCtx, "unaligned_buffer", "unaligned buffer");
123 
124 	genBasicSpec(spec, m_method);
125 
126 	this->addChild(unalignedBufferGroup);
127 
128 	for (int testNdx = 0; testNdx < DE_LENGTH_OF_ARRAY(tests); ++testNdx)
129 	{
130 		const IndexTest&				indexTest	= tests[testNdx];
131 
132 		DE_ASSERT(indexTest.storage != gls::DrawTestSpec::STORAGE_USER);
133 		DE_ASSERT(!indexTest.aligned);
134 		tcu::TestCaseGroup*				group		= unalignedBufferGroup;
135 
136 		const std::string				name		= std::string("index_") + gls::DrawTestSpec::indexTypeToString(indexTest.type);
137 		const std::string				desc		= std::string("index ") + gls::DrawTestSpec::indexTypeToString(indexTest.type) + " in " + gls::DrawTestSpec::storageToString(indexTest.storage);
138 		de::MovePtr<gls::DrawTest>		test		(new gls::DrawTest(m_testCtx, m_context.getRenderContext(), name.c_str(), desc.c_str()));
139 
140 		spec.indexType			= indexTest.type;
141 		spec.indexStorage		= indexTest.storage;
142 
143 		for (int iterationNdx = 0; iterationNdx < DE_LENGTH_OF_ARRAY(indexTest.offsets) && indexTest.offsets[iterationNdx] != -1; ++iterationNdx)
144 		{
145 			const std::string iterationDesc = std::string("offset ") + de::toString(indexTest.offsets[iterationNdx]);
146 			spec.indexPointerOffset	= indexTest.offsets[iterationNdx];
147 			test->addIteration(spec, iterationDesc.c_str());
148 		}
149 
150 		DE_ASSERT(spec.isCompatibilityTest() == gls::DrawTestSpec::COMPATIBILITY_UNALIGNED_OFFSET ||
151 				  spec.isCompatibilityTest() == gls::DrawTestSpec::COMPATIBILITY_UNALIGNED_STRIDE);
152 		group->addChild(test.release());
153 	}
154 }
155 
156 class MethodGroup : public TestCaseGroup
157 {
158 public:
159 									MethodGroup			(Context& context, const char* name, const char* descr, gls::DrawTestSpec::DrawMethod drawMethod);
160 									~MethodGroup		(void);
161 
162 	void							init				(void);
163 
164 private:
165 	gls::DrawTestSpec::DrawMethod	m_method;
166 };
167 
MethodGroup(Context & context,const char * name,const char * descr,gls::DrawTestSpec::DrawMethod drawMethod)168 MethodGroup::MethodGroup (Context& context, const char* name, const char* descr, gls::DrawTestSpec::DrawMethod drawMethod)
169 	: TestCaseGroup		(context, name, descr)
170 	, m_method			(drawMethod)
171 {
172 }
173 
~MethodGroup(void)174 MethodGroup::~MethodGroup (void)
175 {
176 }
177 
init(void)178 void MethodGroup::init (void)
179 {
180 	const bool indexed = (m_method == gls::DrawTestSpec::DRAWMETHOD_DRAWELEMENTS) || (m_method == gls::DrawTestSpec::DRAWMETHOD_DRAWELEMENTS_INSTANCED) || (m_method == gls::DrawTestSpec::DRAWMETHOD_DRAWELEMENTS_RANGED);
181 
182 	DE_ASSERT(indexed);
183 	DE_UNREF(indexed);
184 
185 	this->addChild(new IndexGroup(m_context, "indices", "Index tests", m_method));
186 }
187 
188 class RandomGroup : public TestCaseGroup
189 {
190 public:
191 									RandomGroup		(Context& context, const char* name, const char* descr);
192 									~RandomGroup	(void);
193 
194 	void							init			(void);
195 };
196 
197 template <int SIZE>
198 struct UniformWeightArray
199 {
200 	float weights[SIZE];
201 
UniformWeightArraydeqp::gles2::Stress::__anon39e5ba200111::UniformWeightArray202 	UniformWeightArray (void)
203 	{
204 		for (int i=0; i<SIZE; ++i)
205 			weights[i] = 1.0f;
206 	}
207 };
208 
RandomGroup(Context & context,const char * name,const char * descr)209 RandomGroup::RandomGroup (Context& context, const char* name, const char* descr)
210 	: TestCaseGroup	(context, name, descr)
211 {
212 }
213 
~RandomGroup(void)214 RandomGroup::~RandomGroup (void)
215 {
216 }
217 
init(void)218 void RandomGroup::init (void)
219 {
220 	const int	numAttempts				= 100;
221 
222 	const int	attribCounts[]			= { 1, 2, 5 };
223 	const float	attribWeights[]			= { 30, 10, 1 };
224 	const int	primitiveCounts[]		= { 1, 5, 64 };
225 	const float	primitiveCountWeights[]	= { 20, 10, 1 };
226 	const int	indexOffsets[]			= { 0, 7, 13 };
227 	const float	indexOffsetWeights[]	= { 20, 20, 1 };
228 	const int	firsts[]				= { 0, 7, 13 };
229 	const float	firstWeights[]			= { 20, 20, 1 };
230 	const int	offsets[]				= { 0, 1, 5, 12 };
231 	const float	offsetWeights[]			= { 50, 10, 10, 10 };
232 	const int	strides[]				= { 0, 7, 16, 17 };
233 	const float	strideWeights[]			= { 50, 10, 10, 10 };
234 
235 	gls::DrawTestSpec::Primitive primitives[] =
236 	{
237 		gls::DrawTestSpec::PRIMITIVE_POINTS,
238 		gls::DrawTestSpec::PRIMITIVE_TRIANGLES,
239 		gls::DrawTestSpec::PRIMITIVE_TRIANGLE_FAN,
240 		gls::DrawTestSpec::PRIMITIVE_TRIANGLE_STRIP,
241 		gls::DrawTestSpec::PRIMITIVE_LINES,
242 		gls::DrawTestSpec::PRIMITIVE_LINE_STRIP,
243 		gls::DrawTestSpec::PRIMITIVE_LINE_LOOP
244 	};
245 	const UniformWeightArray<DE_LENGTH_OF_ARRAY(primitives)> primitiveWeights;
246 
247 	gls::DrawTestSpec::DrawMethod drawMethods[] =
248 	{
249 		gls::DrawTestSpec::DRAWMETHOD_DRAWARRAYS,
250 		gls::DrawTestSpec::DRAWMETHOD_DRAWELEMENTS,
251 	};
252 	const UniformWeightArray<DE_LENGTH_OF_ARRAY(drawMethods)> drawMethodWeights;
253 
254 	gls::DrawTestSpec::IndexType indexTypes[] =
255 	{
256 		gls::DrawTestSpec::INDEXTYPE_BYTE,
257 		gls::DrawTestSpec::INDEXTYPE_SHORT,
258 	};
259 	const UniformWeightArray<DE_LENGTH_OF_ARRAY(indexTypes)> indexTypeWeights;
260 
261 	gls::DrawTestSpec::Storage storages[] =
262 	{
263 		gls::DrawTestSpec::STORAGE_USER,
264 		gls::DrawTestSpec::STORAGE_BUFFER,
265 	};
266 	const UniformWeightArray<DE_LENGTH_OF_ARRAY(storages)> storageWeights;
267 
268 	gls::DrawTestSpec::InputType inputTypes[] =
269 	{
270 		gls::DrawTestSpec::INPUTTYPE_FLOAT,
271 		gls::DrawTestSpec::INPUTTYPE_FIXED,
272 		gls::DrawTestSpec::INPUTTYPE_BYTE,
273 		gls::DrawTestSpec::INPUTTYPE_SHORT,
274 		gls::DrawTestSpec::INPUTTYPE_UNSIGNED_BYTE,
275 		gls::DrawTestSpec::INPUTTYPE_UNSIGNED_SHORT
276 	};
277 	const UniformWeightArray<DE_LENGTH_OF_ARRAY(inputTypes)> inputTypeWeights;
278 
279 	gls::DrawTestSpec::OutputType outputTypes[] =
280 	{
281 		gls::DrawTestSpec::OUTPUTTYPE_FLOAT,
282 		gls::DrawTestSpec::OUTPUTTYPE_VEC2,
283 		gls::DrawTestSpec::OUTPUTTYPE_VEC3,
284 		gls::DrawTestSpec::OUTPUTTYPE_VEC4,
285 	};
286 	const UniformWeightArray<DE_LENGTH_OF_ARRAY(outputTypes)> outputTypeWeights;
287 
288 	gls::DrawTestSpec::Usage usages[] =
289 	{
290 		gls::DrawTestSpec::USAGE_STATIC_DRAW,
291 		gls::DrawTestSpec::USAGE_DYNAMIC_DRAW,
292 		gls::DrawTestSpec::USAGE_STREAM_DRAW,
293 	};
294 	const UniformWeightArray<DE_LENGTH_OF_ARRAY(usages)> usageWeights;
295 
296 	const deUint32 blacklistedCases[]=
297 	{
298 		3153,	//!< extremely narrow triangle, results depend on sample positions
299 	};
300 
301 	std::set<deUint32>	insertedHashes;
302 	size_t				insertedCount = 0;
303 
304 	for (int ndx = 0; ndx < numAttempts; ++ndx)
305 	{
306 		de::Random random(0xc551393 + ndx); // random does not depend on previous cases
307 
308 		int					attributeCount = random.chooseWeighted<int, const int*, const float*>(DE_ARRAY_BEGIN(attribCounts), DE_ARRAY_END(attribCounts), attribWeights);
309 		gls::DrawTestSpec	spec;
310 
311 		spec.apiType				= glu::ApiType::es(2,0);
312 		spec.primitive				= random.chooseWeighted<gls::DrawTestSpec::Primitive>	(DE_ARRAY_BEGIN(primitives),		DE_ARRAY_END(primitives),		primitiveWeights.weights);
313 		spec.primitiveCount			= random.chooseWeighted<int, const int*, const float*>	(DE_ARRAY_BEGIN(primitiveCounts),	DE_ARRAY_END(primitiveCounts),	primitiveCountWeights);
314 		spec.drawMethod				= random.chooseWeighted<gls::DrawTestSpec::DrawMethod>	(DE_ARRAY_BEGIN(drawMethods),		DE_ARRAY_END(drawMethods),		drawMethodWeights.weights);
315 		spec.indexType				= random.chooseWeighted<gls::DrawTestSpec::IndexType>	(DE_ARRAY_BEGIN(indexTypes),		DE_ARRAY_END(indexTypes),		indexTypeWeights.weights);
316 		spec.indexPointerOffset		= random.chooseWeighted<int, const int*, const float*>	(DE_ARRAY_BEGIN(indexOffsets),		DE_ARRAY_END(indexOffsets),		indexOffsetWeights);
317 		spec.indexStorage			= random.chooseWeighted<gls::DrawTestSpec::Storage>		(DE_ARRAY_BEGIN(storages),			DE_ARRAY_END(storages),			storageWeights.weights);
318 		spec.first					= random.chooseWeighted<int, const int*, const float*>	(DE_ARRAY_BEGIN(firsts),			DE_ARRAY_END(firsts),			firstWeights);
319 		spec.indexMin				= 0;
320 		spec.indexMax				= 0;
321 		spec.instanceCount			= 0;
322 
323 		// check spec is legal
324 		if (!spec.valid())
325 			continue;
326 
327 		for (int attrNdx = 0; attrNdx < attributeCount;)
328 		{
329 			bool valid;
330 			gls::DrawTestSpec::AttributeSpec attribSpec;
331 
332 			attribSpec.inputType			= random.chooseWeighted<gls::DrawTestSpec::InputType>	(DE_ARRAY_BEGIN(inputTypes),		DE_ARRAY_END(inputTypes),		inputTypeWeights.weights);
333 			attribSpec.outputType			= random.chooseWeighted<gls::DrawTestSpec::OutputType>	(DE_ARRAY_BEGIN(outputTypes),		DE_ARRAY_END(outputTypes),		outputTypeWeights.weights);
334 			attribSpec.storage				= random.chooseWeighted<gls::DrawTestSpec::Storage>		(DE_ARRAY_BEGIN(storages),			DE_ARRAY_END(storages),			storageWeights.weights);
335 			attribSpec.usage				= random.chooseWeighted<gls::DrawTestSpec::Usage>		(DE_ARRAY_BEGIN(usages),			DE_ARRAY_END(usages),			usageWeights.weights);
336 			attribSpec.componentCount		= random.getInt(1, 4);
337 			attribSpec.offset				= random.chooseWeighted<int, const int*, const float*>(DE_ARRAY_BEGIN(offsets), DE_ARRAY_END(offsets), offsetWeights);
338 			attribSpec.stride				= random.chooseWeighted<int, const int*, const float*>(DE_ARRAY_BEGIN(strides), DE_ARRAY_END(strides), strideWeights);
339 			attribSpec.normalize			= random.getBool();
340 			attribSpec.instanceDivisor		= 0;
341 			attribSpec.useDefaultAttribute	= random.getBool();
342 
343 			// check spec is legal
344 			valid = attribSpec.valid(spec.apiType);
345 
346 			// we do not want interleaved elements. (Might result in some weird floating point values)
347 			if (attribSpec.stride && attribSpec.componentCount * gls::DrawTestSpec::inputTypeSize(attribSpec.inputType) > attribSpec.stride)
348 				valid = false;
349 
350 			// try again if not valid
351 			if (valid)
352 			{
353 				spec.attribs.push_back(attribSpec);
354 				++attrNdx;
355 			}
356 		}
357 
358 		// Do not collapse all vertex positions to a single positions
359 		if (spec.primitive != gls::DrawTestSpec::PRIMITIVE_POINTS)
360 			spec.attribs[0].instanceDivisor = 0;
361 
362 		// Is render result meaningful?
363 		{
364 			// Only one vertex
365 			if (spec.drawMethod == gls::DrawTestSpec::DRAWMETHOD_DRAWELEMENTS_RANGED && spec.indexMin == spec.indexMax && spec.primitive != gls::DrawTestSpec::PRIMITIVE_POINTS)
366 				continue;
367 			if (spec.attribs[0].useDefaultAttribute && spec.primitive != gls::DrawTestSpec::PRIMITIVE_POINTS)
368 				continue;
369 
370 			// Triangle only on one axis
371 			if (spec.primitive == gls::DrawTestSpec::PRIMITIVE_TRIANGLES || spec.primitive == gls::DrawTestSpec::PRIMITIVE_TRIANGLE_FAN || spec.primitive == gls::DrawTestSpec::PRIMITIVE_TRIANGLE_STRIP)
372 			{
373 				if (spec.attribs[0].componentCount == 1)
374 					continue;
375 				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)
376 					continue;
377 				if (spec.drawMethod == gls::DrawTestSpec::DRAWMETHOD_DRAWELEMENTS_RANGED && (spec.indexMax - spec.indexMin) < 2)
378 					continue;
379 			}
380 		}
381 
382 		// Add case
383 		{
384 			deUint32 hash = spec.hash();
385 			for (int attrNdx = 0; attrNdx < attributeCount; ++attrNdx)
386 				hash = (hash << 2) ^ (deUint32)spec.attribs[attrNdx].hash();
387 
388 			if (insertedHashes.find(hash) == insertedHashes.end() &&
389 				std::find(DE_ARRAY_BEGIN(blacklistedCases), DE_ARRAY_END(blacklistedCases), hash) == DE_ARRAY_END(blacklistedCases))
390 			{
391 				// Only unaligned cases
392 				if (spec.isCompatibilityTest() == gls::DrawTestSpec::COMPATIBILITY_UNALIGNED_OFFSET ||
393 					spec.isCompatibilityTest() == gls::DrawTestSpec::COMPATIBILITY_UNALIGNED_STRIDE)
394 					this->addChild(new gls::DrawTest(m_testCtx, m_context.getRenderContext(), spec, de::toString(insertedCount).c_str(), spec.getDesc().c_str()));
395 				insertedHashes.insert(hash);
396 
397 				++insertedCount;
398 			}
399 		}
400 	}
401 }
402 
403 } // anonymous
404 
DrawTests(Context & context)405 DrawTests::DrawTests (Context& context)
406 	: TestCaseGroup(context, "draw", "Drawing tests")
407 {
408 }
409 
~DrawTests(void)410 DrawTests::~DrawTests (void)
411 {
412 }
413 
init(void)414 void DrawTests::init (void)
415 {
416 	tcu::TestCaseGroup* const unalignedGroup	= new tcu::TestCaseGroup(m_testCtx, "unaligned_data", "Test with unaligned data");
417 
418 	addChild(unalignedGroup);
419 
420 	// .unaligned_data
421 	{
422 		const gls::DrawTestSpec::DrawMethod basicMethods[] =
423 		{
424 			// gls::DrawTestSpec::DRAWMETHOD_DRAWARRAYS,
425 			gls::DrawTestSpec::DRAWMETHOD_DRAWELEMENTS,
426 		};
427 
428 		for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(basicMethods); ++ndx)
429 		{
430 			std::string name = gls::DrawTestSpec::drawMethodToString(basicMethods[ndx]);
431 			std::string desc = gls::DrawTestSpec::drawMethodToString(basicMethods[ndx]);
432 
433 			unalignedGroup->addChild(new MethodGroup(m_context, name.c_str(), desc.c_str(), basicMethods[ndx]));
434 		}
435 
436 		// Random
437 
438 		unalignedGroup->addChild(new RandomGroup(m_context, "random", "random draw commands."));
439 	}
440 
441 }
442 
443 } // Stress
444 } // gles2
445 } // deqp
446