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