1 /*-------------------------------------------------------------------------
2  * drawElements Quality Program OpenGL ES 3.1 Module
3  * -------------------------------------------------
4  *
5  * Copyright 2017 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 GL_EXT_draw_elements_base_vertex tests.
22  *//*--------------------------------------------------------------------*/
23 
24 #include "es31fDrawElementsBaseVertexTests.hpp"
25 #include "deRandom.hpp"
26 #include "deStringUtil.hpp"
27 #include "tcuRenderTarget.hpp"
28 #include "tcuVectorUtil.hpp"
29 #include "sglrGLContext.hpp"
30 #include "glsDrawTest.hpp"
31 #include "gluStrUtil.hpp"
32 #include "gluPixelTransfer.hpp"
33 #include "gluContextInfo.hpp"
34 
35 #include "glwEnums.hpp"
36 #include "glwFunctions.hpp"
37 
38 #include <string>
39 #include <set>
40 
41 using std::vector;
42 using std::string;
43 using tcu::TestLog;
44 
45 using namespace glw;
46 
47 namespace deqp
48 {
49 namespace gles31
50 {
51 namespace Functional
52 {
53 namespace
54 {
55 
56 enum TestIterationType
57 {
58 	TYPE_DRAW_COUNT,		// !< test with 1, 5, and 25 primitives
59 	TYPE_INSTANCE_COUNT,	// !< test with 1, 4, and 11 instances
60 
61 	TYPE_LAST
62 };
63 
getElementCount(gls::DrawTestSpec::Primitive primitive,size_t primitiveCount)64 static size_t getElementCount (gls::DrawTestSpec::Primitive primitive, size_t primitiveCount)
65 {
66 	switch (primitive)
67 	{
68 		case gls::DrawTestSpec::PRIMITIVE_POINTS:						return primitiveCount;
69 		case gls::DrawTestSpec::PRIMITIVE_TRIANGLES:					return primitiveCount * 3;
70 		case gls::DrawTestSpec::PRIMITIVE_TRIANGLE_FAN:					return primitiveCount + 2;
71 		case gls::DrawTestSpec::PRIMITIVE_TRIANGLE_STRIP:				return primitiveCount + 2;
72 		case gls::DrawTestSpec::PRIMITIVE_LINES:						return primitiveCount * 2;
73 		case gls::DrawTestSpec::PRIMITIVE_LINE_STRIP:					return primitiveCount + 1;
74 		case gls::DrawTestSpec::PRIMITIVE_LINE_LOOP:					return (primitiveCount==1) ? (2) : (primitiveCount);
75 		case gls::DrawTestSpec::PRIMITIVE_LINES_ADJACENCY:				return primitiveCount * 4;
76 		case gls::DrawTestSpec::PRIMITIVE_LINE_STRIP_ADJACENCY:			return primitiveCount + 3;
77 		case gls::DrawTestSpec::PRIMITIVE_TRIANGLES_ADJACENCY:			return primitiveCount * 6;
78 		case gls::DrawTestSpec::PRIMITIVE_TRIANGLE_STRIP_ADJACENCY:		return primitiveCount * 2 + 4;
79 		default:
80 			DE_ASSERT(false);
81 			return 0;
82 	}
83 }
84 
addRangeElementsToSpec(gls::DrawTestSpec & spec)85 static void addRangeElementsToSpec (gls::DrawTestSpec& spec)
86 {
87 	if (spec.drawMethod == gls::DrawTestSpec::DRAWMETHOD_DRAWELEMENTS_RANGED_BASEVERTEX)
88 	{
89 		spec.indexMin = 0;
90 		spec.indexMax = (int)getElementCount(spec.primitive, spec.primitiveCount);
91 	}
92 }
93 
addTestIterations(gls::DrawTest * test,gls::DrawTestSpec & spec,TestIterationType type)94 static void addTestIterations (gls::DrawTest* test, gls::DrawTestSpec& spec, TestIterationType type)
95 {
96 	if (type == TYPE_DRAW_COUNT)
97 	{
98 		spec.primitiveCount = 1;
99 		addRangeElementsToSpec(spec);
100 		test->addIteration(spec, "draw count = 1");
101 
102 		spec.primitiveCount = 5;
103 		addRangeElementsToSpec(spec);
104 		test->addIteration(spec, "draw count = 5");
105 
106 		spec.primitiveCount = 25;
107 		addRangeElementsToSpec(spec);
108 		test->addIteration(spec, "draw count = 25");
109 	}
110 	else if (type == TYPE_INSTANCE_COUNT)
111 	{
112 		spec.instanceCount = 1;
113 		addRangeElementsToSpec(spec);
114 		test->addIteration(spec, "instance count = 1");
115 
116 		spec.instanceCount = 4;
117 		addRangeElementsToSpec(spec);
118 		test->addIteration(spec, "instance count = 4");
119 
120 		spec.instanceCount = 11;
121 		addRangeElementsToSpec(spec);
122 		test->addIteration(spec, "instance count = 11");
123 	}
124 	else
125 		DE_ASSERT(false);
126 }
127 
genBasicSpec(gls::DrawTestSpec & spec,gls::DrawTestSpec::DrawMethod method)128 static void genBasicSpec (gls::DrawTestSpec& spec, gls::DrawTestSpec::DrawMethod method)
129 {
130 	spec.apiType							= glu::ApiType::es(3,1);
131 	spec.primitive							= gls::DrawTestSpec::PRIMITIVE_TRIANGLES;
132 	spec.primitiveCount						= 5;
133 	spec.drawMethod							= method;
134 	spec.indexType							= gls::DrawTestSpec::INDEXTYPE_LAST;
135 	spec.indexPointerOffset					= 0;
136 	spec.indexStorage						= gls::DrawTestSpec::STORAGE_LAST;
137 	spec.first								= 0;
138 	spec.indexMin							= 0;
139 	spec.indexMax							= 0;
140 	spec.instanceCount						= 1;
141 	spec.indirectOffset						= 0;
142 
143 	spec.attribs.resize(2);
144 
145 	spec.attribs[0].inputType				= gls::DrawTestSpec::INPUTTYPE_FLOAT;
146 	spec.attribs[0].outputType				= gls::DrawTestSpec::OUTPUTTYPE_VEC2;
147 	spec.attribs[0].storage					= gls::DrawTestSpec::STORAGE_BUFFER;
148 	spec.attribs[0].usage					= gls::DrawTestSpec::USAGE_STATIC_DRAW;
149 	spec.attribs[0].componentCount			= 4;
150 	spec.attribs[0].offset					= 0;
151 	spec.attribs[0].stride					= 0;
152 	spec.attribs[0].normalize				= false;
153 	spec.attribs[0].instanceDivisor			= 0;
154 	spec.attribs[0].useDefaultAttribute		= false;
155 
156 	spec.attribs[1].inputType				= gls::DrawTestSpec::INPUTTYPE_FLOAT;
157 	spec.attribs[1].outputType				= gls::DrawTestSpec::OUTPUTTYPE_VEC2;
158 	spec.attribs[1].storage					= gls::DrawTestSpec::STORAGE_BUFFER;
159 	spec.attribs[1].usage					= gls::DrawTestSpec::USAGE_STATIC_DRAW;
160 	spec.attribs[1].componentCount			= 2;
161 	spec.attribs[1].offset					= 0;
162 	spec.attribs[1].stride					= 0;
163 	spec.attribs[1].normalize				= false;
164 	spec.attribs[1].instanceDivisor			= 0;
165 	spec.attribs[1].useDefaultAttribute		= false;
166 
167 	addRangeElementsToSpec(spec);
168 }
169 
170 class VertexIDCase : public TestCase
171 {
172 public:
173 									VertexIDCase			(Context& context, gls::DrawTestSpec::DrawMethod drawMethod);
174 									~VertexIDCase			(void);
175 
176 	void							init					(void);
177 	void							deinit					(void);
178 	IterateResult					iterate					(void);
179 
180 	void							draw					(GLenum mode, GLsizei count, GLenum type, GLvoid* indices, GLint baseVertex);
181 	void							verifyImage				(const tcu::Surface& image);
182 
183 private:
184 	const glw::Functions&			m_gl;
185 	glu::ShaderProgram*				m_program;
186 	GLuint							m_coordinatesBuffer;
187 	GLuint							m_elementsBuffer;
188 	int								m_iterNdx;
189 	gls::DrawTestSpec::DrawMethod	m_method;
190 
191 	enum
192 	{
193 		VIEWPORT_WIDTH = 64,
194 		VIEWPORT_HEIGHT = 64
195 	};
196 
197 	enum
198 	{
199 		MAX_VERTICES = 2*3	//!< 2 triangles, totals 6 vertices
200 	};
201 };
202 
VertexIDCase(Context & context,gls::DrawTestSpec::DrawMethod drawMethod)203 VertexIDCase::VertexIDCase (Context& context,  gls::DrawTestSpec::DrawMethod drawMethod)
204 	: TestCase				(context, "vertex_id", "gl_VertexID Test")
205 	, m_gl					(m_context.getRenderContext().getFunctions())
206 	, m_program				(DE_NULL)
207 	, m_coordinatesBuffer	(0)
208 	, m_elementsBuffer		(0)
209 	, m_iterNdx				(0)
210 	, m_method				(drawMethod)
211 {
212 }
213 
~VertexIDCase(void)214 VertexIDCase::~VertexIDCase (void)
215 {
216 	VertexIDCase::deinit();
217 }
218 
init(void)219 void VertexIDCase::init (void)
220 {
221 	if (m_method == deqp::gls::DrawTestSpec::DRAWMETHOD_DRAWELEMENTS_BASEVERTEX ||
222 		m_method == gls::DrawTestSpec::DRAWMETHOD_DRAWELEMENTS_RANGED_BASEVERTEX ||
223 		m_method == gls::DrawTestSpec::DRAWMETHOD_DRAWELEMENTS_INSTANCED_BASEVERTEX)
224 	{
225 		const bool supportsES32 = contextSupports(m_context.getRenderContext().getType(), glu::ApiType::es(3, 2));
226 		TCU_CHECK_AND_THROW(NotSupportedError, supportsES32 || m_context.getContextInfo().isExtensionSupported("GL_EXT_draw_elements_base_vertex"), "GL_EXT_draw_elements_base_vertex is not supported.");
227 	}
228 
229 	m_testCtx.getLog()	<< TestLog::Message
230 						<< "gl_VertexID should be the index of the vertex that is being passed to the shader. i.e. indices[i] + basevertex"
231 						<< TestLog::EndMessage;
232 
233 	DE_ASSERT(!m_program);
234 	m_program = new glu::ShaderProgram(m_context.getRenderContext(), glu::makeVtxFragSources(
235 		"#version 310 es\n"
236 		"in highp vec4 a_position;\n"
237 		"out mediump vec4 v_color;\n"
238 		"uniform highp vec4 u_colors[8];\n"
239 		"void main (void)\n"
240 		"{\n"
241 		"	gl_Position = a_position;\n"
242 		"	v_color = u_colors[gl_VertexID];\n"
243 		"}\n",
244 
245 		"#version 310 es\n"
246 		"in mediump vec4 v_color;\n"
247 		"layout(location = 0) out mediump vec4 o_color;\n"
248 		"void main (void)\n"
249 		"{\n"
250 		"	o_color = v_color;\n"
251 		"}\n"));
252 
253 	m_testCtx.getLog() << *m_program;
254 
255 	if (!m_program->isOk())
256 	{
257 		delete m_program;
258 		m_program = DE_NULL;
259 		TCU_FAIL("Failed to compile shader program");
260 	}
261 
262 	GLU_CHECK_GLW_CALL(m_gl, useProgram(m_program->getProgram()));
263 
264 	GLU_CHECK_GLW_CALL(m_gl, genBuffers(1, &m_coordinatesBuffer));
265 	GLU_CHECK_GLW_CALL(m_gl, genBuffers(1, &m_elementsBuffer));
266 }
267 
deinit(void)268 void VertexIDCase::deinit (void)
269 {
270 	delete m_program;
271 	m_program = DE_NULL;
272 
273 	if (m_elementsBuffer)
274 	{
275 		GLU_CHECK_GLW_CALL(m_gl, deleteBuffers(1, &m_elementsBuffer));
276 		m_elementsBuffer = 0;
277 	}
278 
279 	if (m_coordinatesBuffer)
280 	{
281 		GLU_CHECK_GLW_CALL(m_gl, deleteBuffers(1, &m_coordinatesBuffer));
282 		m_coordinatesBuffer = 0;
283 	}
284 }
285 
draw(GLenum mode,GLsizei count,GLenum type,GLvoid * indices,GLint baseVertex)286 void VertexIDCase::draw (GLenum mode, GLsizei count, GLenum type, GLvoid* indices, GLint baseVertex)
287 {
288 	switch (m_method)
289 	{
290 		case gls::DrawTestSpec::DRAWMETHOD_DRAWELEMENTS_BASEVERTEX:
291 			GLU_CHECK_GLW_CALL(m_gl, drawElementsBaseVertex(mode, count, type, indices, baseVertex));
292 			break;
293 
294 		case gls::DrawTestSpec::DRAWMETHOD_DRAWELEMENTS_RANGED_BASEVERTEX:
295 		{
296 			GLint maxElementsVertices = 0;
297 			GLU_CHECK_GLW_CALL(m_gl, getIntegerv(GL_MAX_ELEMENTS_VERTICES, &maxElementsVertices));
298 			GLU_CHECK_GLW_CALL(m_gl, drawRangeElementsBaseVertex(mode, 0, maxElementsVertices, count, type, indices, baseVertex));
299 			break;
300 		}
301 
302 		case gls::DrawTestSpec::DRAWMETHOD_DRAWELEMENTS_INSTANCED_BASEVERTEX:
303 				GLU_CHECK_GLW_CALL(m_gl, drawElementsInstancedBaseVertex(mode, count, type, indices, 1, baseVertex));
304 				break;
305 
306 		default:
307 			DE_FATAL("Draw method not supported");
308 	}
309 }
310 
verifyImage(const tcu::Surface & image)311 void VertexIDCase::verifyImage (const tcu::Surface& image)
312 {
313 	tcu::TestLog&	log				= m_testCtx.getLog();
314 	bool			isOk			= true;
315 
316 	const int		colorThreshold	= 0; // expect perfect match
317 	tcu::Surface	error			(image.getWidth(), image.getHeight());
318 
319 	for (int y = 0; y < image.getHeight(); y++)
320 	for (int x = 0; x < image.getWidth(); x++)
321 	{
322 		const tcu::RGBA pixel = image.getPixel(x, y);
323 		bool pixelOk = true;
324 
325 		// Ignore pixels not drawn with basevertex
326 		if ((x < image.getWidth()* 1/4) || (x > image.getWidth()  * 3/4)
327 			|| (y < image.getHeight() * 1/4) || (y > image.getHeight() * 3/4))
328 			continue;
329 
330 		// Any pixel with !(B ~= 255) is faulty
331 		if (de::abs(pixel.getBlue() - 255) > colorThreshold)
332 			pixelOk = false;
333 
334 		error.setPixel(x, y, (pixelOk) ? (tcu::RGBA(0, 255, 0, 255)) : (tcu::RGBA(255, 0, 0, 255)));
335 		isOk = isOk && pixelOk;
336 	}
337 
338 	if (!isOk)
339 	{
340 		log << TestLog::Message << "Image verification failed." << TestLog::EndMessage;
341 		log << TestLog::ImageSet("Verification result", "Result of rendering")
342 			<< TestLog::Image("Result",		"Result",		image)
343 			<< TestLog::Image("Error Mask",	"Error mask",	error)
344 			<< TestLog::EndImageSet;
345 	}
346 	else
347 	{
348 		log << TestLog::ImageSet("Verification result", "Result of rendering")
349 			<< TestLog::Image("Result", "Result", image)
350 			<< TestLog::EndImageSet;
351 	}
352 
353 	if (isOk)
354 		m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
355 	else
356 		m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Result image invalid");
357 }
358 
iterate(void)359 VertexIDCase::IterateResult VertexIDCase::iterate (void)
360 {
361 	const GLuint			drawCount			= 6;
362 	const GLuint			baseVertex			= 4;
363 	const GLuint			coordLocation		= m_gl.getAttribLocation(m_program->getProgram(), "a_position");
364 	const GLuint			colorLocation		= m_gl.getUniformLocation(m_program->getProgram(), "u_colors[0]");
365 
366 	tcu::Surface			surface(VIEWPORT_WIDTH, VIEWPORT_HEIGHT);
367 
368 	const GLfloat coords[] =
369 	{
370 		// full viewport quad
371 		-1.0f, -1.0f,
372 		+1.0f, -1.0f,
373 		+1.0f, +1.0f,
374 		-1.0f, +1.0f,
375 
376 		// half viewport quad centred
377 		-0.5f, -0.5f,
378 		+0.5f, -0.5f,
379 		+0.5f, +0.5f,
380 		-0.5f, +0.5f,
381 	};
382 
383 	const GLushort indices[] =
384 	{
385 		0, 1, 2, 2, 3, 0,
386 	};
387 
388 	const GLfloat colors[] =
389 	{
390 		0.0f, 0.0f, 0.0f, 1.0f,
391 		0.5f, 1.0f, 0.5f, 1.0f,
392 		0.0f, 0.5f, 1.0f, 1.0f,
393 		0.0f, 1.0f, 0.0f, 1.0f,
394 
395 		0.0f, 0.0f, 1.0f, 1.0f, // blue
396 		0.0f, 0.0f, 1.0f, 1.0f, // blue
397 		0.0f, 0.0f, 1.0f, 1.0f, // blue
398 		0.0f, 0.0f, 1.0f, 1.0f, // blue
399 	};
400 
401 	GLU_CHECK_GLW_CALL(m_gl, viewport(0, 0, VIEWPORT_WIDTH, VIEWPORT_HEIGHT));
402 	GLU_CHECK_GLW_CALL(m_gl, clearColor(1.0f, 1.0f, 1.0f, 1.0f)); // white
403 	GLU_CHECK_GLW_CALL(m_gl, clear(GL_COLOR_BUFFER_BIT));
404 
405 	GLU_CHECK_GLW_CALL(m_gl, uniform4fv(colorLocation, DE_LENGTH_OF_ARRAY(colors), &colors[0]));
406 
407 	GLU_CHECK_GLW_CALL(m_gl, bindBuffer(GL_ARRAY_BUFFER, m_coordinatesBuffer));
408 	GLU_CHECK_GLW_CALL(m_gl, bufferData(GL_ARRAY_BUFFER, (GLsizeiptr)sizeof(coords), coords, GL_STATIC_DRAW));
409 	GLU_CHECK_GLW_CALL(m_gl, enableVertexAttribArray(coordLocation));
410 	GLU_CHECK_GLW_CALL(m_gl, vertexAttribPointer(coordLocation, 2, GL_FLOAT, GL_FALSE, 0, DE_NULL));
411 
412 	if (m_iterNdx == 0)
413 	{
414 		tcu::ScopedLogSection	logSection	(m_testCtx.getLog(), "Iter0", "Indices in client-side array");
415 		draw(GL_TRIANGLES, drawCount, GL_UNSIGNED_SHORT, (GLvoid*)indices, baseVertex);
416 	}
417 
418 	if (m_iterNdx == 1)
419 	{
420 		tcu::ScopedLogSection	logSection	(m_testCtx.getLog(), "Iter1", "Indices in element array buffer");
421 		GLU_CHECK_GLW_CALL(m_gl, bindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_elementsBuffer));
422 		GLU_CHECK_GLW_CALL(m_gl, bufferData(GL_ELEMENT_ARRAY_BUFFER, (GLsizeiptr)sizeof(indices), &indices[0], GL_STATIC_DRAW));
423 		draw(GL_TRIANGLES, drawCount, GL_UNSIGNED_SHORT, DE_NULL, baseVertex);
424 	}
425 
426 	glu::readPixels(m_context.getRenderContext(), 0, 0, surface.getAccess());
427 	verifyImage(surface);
428 
429 	m_iterNdx += 1;
430 
431 	return (m_iterNdx < 2) ? CONTINUE : STOP;
432 }
433 
434 class BuiltInVariableGroup : public TestCaseGroup
435 {
436 public:
437 									BuiltInVariableGroup		(Context& context, const char* name, const char* descr, gls::DrawTestSpec::DrawMethod drawMethod);
438 									~BuiltInVariableGroup		(void);
439 
440 	void							init						(void);
441 
442 private:
443 	gls::DrawTestSpec::DrawMethod	m_method;
444 };
445 
BuiltInVariableGroup(Context & context,const char * name,const char * descr,gls::DrawTestSpec::DrawMethod drawMethod)446 BuiltInVariableGroup::BuiltInVariableGroup (Context& context, const char* name, const char* descr, gls::DrawTestSpec::DrawMethod drawMethod)
447 	: TestCaseGroup		(context, name, descr)
448 	, m_method			(drawMethod)
449 {
450 }
451 
~BuiltInVariableGroup(void)452 BuiltInVariableGroup::~BuiltInVariableGroup (void)
453 {
454 }
455 
init(void)456 void BuiltInVariableGroup::init (void)
457 {
458 	addChild(new VertexIDCase(m_context, m_method));
459 }
460 
461 class IndexGroup : public TestCaseGroup
462 {
463 public:
464 									IndexGroup		(Context& context, const char* name, const char* descr, gls::DrawTestSpec::DrawMethod drawMethod);
465 									~IndexGroup		(void);
466 
467 	void							init			(void);
468 
469 private:
470 	gls::DrawTestSpec::DrawMethod	m_method;
471 };
472 
IndexGroup(Context & context,const char * name,const char * descr,gls::DrawTestSpec::DrawMethod drawMethod)473 IndexGroup::IndexGroup (Context& context, const char* name, const char* descr, gls::DrawTestSpec::DrawMethod drawMethod)
474 	: TestCaseGroup		(context, name, descr)
475 	, m_method			(drawMethod)
476 {
477 }
478 
~IndexGroup(void)479 IndexGroup::~IndexGroup (void)
480 {
481 }
482 
init(void)483 void IndexGroup::init (void)
484 {
485 	struct IndexTest
486 	{
487 		gls::DrawTestSpec::IndexType	type;
488 		int								offsets[3];
489 	};
490 
491 	const IndexTest tests[] =
492 	{
493 		{ gls::DrawTestSpec::INDEXTYPE_BYTE,	{ 0, 1, -1 } },
494 		{ gls::DrawTestSpec::INDEXTYPE_SHORT,	{ 0, 2, -1 } },
495 		{ gls::DrawTestSpec::INDEXTYPE_INT,		{ 0, 4, -1 } },
496 	};
497 
498 	gls::DrawTestSpec spec;
499 	genBasicSpec(spec, m_method);
500 
501 	spec.indexStorage = gls::DrawTestSpec::STORAGE_BUFFER;
502 
503 	for (int testNdx = 0; testNdx < DE_LENGTH_OF_ARRAY(tests); ++testNdx)
504 	{
505 		const IndexTest&	indexTest	= tests[testNdx];
506 
507 		const std::string	name		= std::string("index_") + gls::DrawTestSpec::indexTypeToString(indexTest.type);
508 		const std::string	desc		= std::string("index ") + gls::DrawTestSpec::indexTypeToString(indexTest.type);
509 		gls::DrawTest*		test		= new gls::DrawTest(m_testCtx, m_context.getRenderContext(), name.c_str(), desc.c_str());
510 
511 		spec.indexType			= indexTest.type;
512 
513 		for (int iterationNdx = 0; iterationNdx < DE_LENGTH_OF_ARRAY(indexTest.offsets) && indexTest.offsets[iterationNdx] != -1; ++iterationNdx)
514 		{
515 			const std::string iterationDesc = std::string("first vertex ") + de::toString(indexTest.offsets[iterationNdx] / gls::DrawTestSpec::indexTypeSize(indexTest.type));
516 			spec.indexPointerOffset	= indexTest.offsets[iterationNdx];
517 			test->addIteration(spec, iterationDesc.c_str());
518 		}
519 
520 		addChild(test);
521 	}
522 }
523 
524 class BaseVertexGroup : public TestCaseGroup
525 {
526 public:
527 									BaseVertexGroup		(Context& context, const char* name, const char* descr, gls::DrawTestSpec::DrawMethod drawMethod);
528 									~BaseVertexGroup	(void);
529 
530 	void							init				(void);
531 
532 private:
533 	gls::DrawTestSpec::DrawMethod	m_method;
534 };
535 
BaseVertexGroup(Context & context,const char * name,const char * descr,gls::DrawTestSpec::DrawMethod drawMethod)536 BaseVertexGroup::BaseVertexGroup (Context& context, const char* name, const char* descr, gls::DrawTestSpec::DrawMethod drawMethod)
537 	: TestCaseGroup		(context, name, descr)
538 	, m_method			(drawMethod)
539 {
540 }
541 
~BaseVertexGroup(void)542 BaseVertexGroup::~BaseVertexGroup (void)
543 {
544 }
545 
init(void)546 void BaseVertexGroup::init (void)
547 {
548 	struct IndexTest
549 	{
550 		bool							positiveBase;
551 		gls::DrawTestSpec::IndexType	type;
552 		int								baseVertex[2];
553 	};
554 
555 	const IndexTest tests[] =
556 	{
557 		{ true,  gls::DrawTestSpec::INDEXTYPE_BYTE,		{  1,  2 } },
558 		{ true,  gls::DrawTestSpec::INDEXTYPE_SHORT,	{  1,  2 } },
559 		{ true,  gls::DrawTestSpec::INDEXTYPE_INT,		{  1,  2 } },
560 		{ false, gls::DrawTestSpec::INDEXTYPE_BYTE,		{ -1, -2 } },
561 		{ false, gls::DrawTestSpec::INDEXTYPE_SHORT,	{ -1, -2 } },
562 		{ false, gls::DrawTestSpec::INDEXTYPE_INT,		{ -1, -2 } },
563 	};
564 
565 	gls::DrawTestSpec spec;
566 	genBasicSpec(spec, m_method);
567 
568 	spec.indexStorage = gls::DrawTestSpec::STORAGE_BUFFER;
569 
570 	for (int testNdx = 0; testNdx < DE_LENGTH_OF_ARRAY(tests); ++testNdx)
571 	{
572 		const IndexTest&	indexTest	= tests[testNdx];
573 
574 		const std::string	name		= std::string("index_") + (indexTest.positiveBase ? "" : "neg_") + gls::DrawTestSpec::indexTypeToString(indexTest.type);
575 		const std::string	desc		= std::string("index ") + gls::DrawTestSpec::indexTypeToString(indexTest.type);
576 		gls::DrawTest*		test		= new gls::DrawTest(m_testCtx, m_context.getRenderContext(), name.c_str(), desc.c_str());
577 
578 		spec.indexType			= indexTest.type;
579 
580 		for (int iterationNdx = 0; iterationNdx < DE_LENGTH_OF_ARRAY(indexTest.baseVertex); ++iterationNdx)
581 		{
582 			const std::string iterationDesc = std::string("base vertex ") + de::toString(indexTest.baseVertex[iterationNdx]);
583 			spec.baseVertex	= indexTest.baseVertex[iterationNdx];
584 			// spec.indexMin + spec.baseVertex can not be a negative value
585 			if (spec.indexMin + spec.baseVertex < 0)
586 			{
587 				spec.indexMax -= (spec.indexMin + spec.baseVertex);
588 				spec.indexMin -= (spec.indexMin + spec.baseVertex);
589 			}
590 			test->addIteration(spec, iterationDesc.c_str());
591 		}
592 
593 		addChild(test);
594 	}
595 }
596 
597 class AttributeGroup : public TestCaseGroup
598 {
599 public:
600 									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);
601 									~AttributeGroup	(void);
602 
603 	void							init			(void);
604 
605 private:
606 	gls::DrawTestSpec::DrawMethod	m_method;
607 	gls::DrawTestSpec::Primitive	m_primitive;
608 	gls::DrawTestSpec::IndexType	m_indexType;
609 	gls::DrawTestSpec::Storage		m_indexStorage;
610 };
611 
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)612 AttributeGroup::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)
613 	: TestCaseGroup		(context, name, descr)
614 	, m_method			(drawMethod)
615 	, m_primitive		(primitive)
616 	, m_indexType		(indexType)
617 	, m_indexStorage	(indexStorage)
618 {
619 }
620 
~AttributeGroup(void)621 AttributeGroup::~AttributeGroup (void)
622 {
623 }
624 
init(void)625 void AttributeGroup::init (void)
626 {
627 	// Single attribute
628 	{
629 		gls::DrawTest*		test				= new gls::DrawTest(m_testCtx, m_context.getRenderContext(), "single_attribute", "Single attribute array.");
630 		gls::DrawTestSpec	spec;
631 
632 		spec.apiType							= glu::ApiType::es(3,1);
633 		spec.primitive							= m_primitive;
634 		spec.primitiveCount						= 5;
635 		spec.drawMethod							= m_method;
636 		spec.indexType							= m_indexType;
637 		spec.indexPointerOffset					= 0;
638 		spec.indexStorage						= m_indexStorage;
639 		spec.first								= 0;
640 		spec.indexMin							= 0;
641 		spec.indexMax							= 0;
642 		spec.instanceCount						= 1;
643 		spec.indirectOffset						= 0;
644 
645 		spec.attribs.resize(1);
646 
647 		spec.attribs[0].inputType				= gls::DrawTestSpec::INPUTTYPE_FLOAT;
648 		spec.attribs[0].outputType				= gls::DrawTestSpec::OUTPUTTYPE_VEC2;
649 		spec.attribs[0].storage					= gls::DrawTestSpec::STORAGE_BUFFER;
650 		spec.attribs[0].usage					= gls::DrawTestSpec::USAGE_STATIC_DRAW;
651 		spec.attribs[0].componentCount			= 2;
652 		spec.attribs[0].offset					= 0;
653 		spec.attribs[0].stride					= 0;
654 		spec.attribs[0].normalize				= false;
655 		spec.attribs[0].instanceDivisor			= 0;
656 		spec.attribs[0].useDefaultAttribute		= false;
657 
658 		addTestIterations(test, spec, TYPE_DRAW_COUNT);
659 
660 		this->addChild(test);
661 	}
662 
663 	// Multiple attribute
664 	{
665 		gls::DrawTest*		test				= new gls::DrawTest(m_testCtx, m_context.getRenderContext(), "multiple_attributes", "Multiple attribute arrays.");
666 		gls::DrawTestSpec	spec;
667 
668 		spec.apiType							= glu::ApiType::es(3,1);
669 		spec.primitive							= m_primitive;
670 		spec.primitiveCount						= 5;
671 		spec.drawMethod							= m_method;
672 		spec.indexType							= m_indexType;
673 		spec.indexPointerOffset					= 0;
674 		spec.indexStorage						= m_indexStorage;
675 		spec.first								= 0;
676 		spec.indexMin							= 0;
677 		spec.indexMax							= 0;
678 		spec.instanceCount						= 1;
679 		spec.indirectOffset						= 0;
680 
681 		spec.attribs.resize(2);
682 
683 		spec.attribs[0].inputType				= gls::DrawTestSpec::INPUTTYPE_FLOAT;
684 		spec.attribs[0].outputType				= gls::DrawTestSpec::OUTPUTTYPE_VEC2;
685 		spec.attribs[0].storage					= gls::DrawTestSpec::STORAGE_BUFFER;
686 		spec.attribs[0].usage					= gls::DrawTestSpec::USAGE_STATIC_DRAW;
687 		spec.attribs[0].componentCount			= 4;
688 		spec.attribs[0].offset					= 0;
689 		spec.attribs[0].stride					= 0;
690 		spec.attribs[0].normalize				= false;
691 		spec.attribs[0].instanceDivisor			= 0;
692 		spec.attribs[0].useDefaultAttribute		= false;
693 
694 		spec.attribs[1].inputType				= gls::DrawTestSpec::INPUTTYPE_FLOAT;
695 		spec.attribs[1].outputType				= gls::DrawTestSpec::OUTPUTTYPE_VEC2;
696 		spec.attribs[1].storage					= gls::DrawTestSpec::STORAGE_BUFFER;
697 		spec.attribs[1].usage					= gls::DrawTestSpec::USAGE_STATIC_DRAW;
698 		spec.attribs[1].componentCount			= 2;
699 		spec.attribs[1].offset					= 0;
700 		spec.attribs[1].stride					= 0;
701 		spec.attribs[1].normalize				= false;
702 		spec.attribs[1].instanceDivisor			= 0;
703 		spec.attribs[1].useDefaultAttribute		= false;
704 
705 		addTestIterations(test, spec, TYPE_DRAW_COUNT);
706 
707 		this->addChild(test);
708 	}
709 
710 	// Multiple attribute, second one divided
711 	{
712 		gls::DrawTest*		test					= new gls::DrawTest(m_testCtx, m_context.getRenderContext(), "instanced_attributes", "Instanced attribute array.");
713 		gls::DrawTestSpec	spec;
714 
715 		spec.apiType								= glu::ApiType::es(3,1);
716 		spec.primitive								= m_primitive;
717 		spec.primitiveCount							= 5;
718 		spec.drawMethod								= m_method;
719 		spec.indexType								= m_indexType;
720 		spec.indexPointerOffset						= 0;
721 		spec.indexStorage							= m_indexStorage;
722 		spec.first									= 0;
723 		spec.indexMin								= 0;
724 		spec.indexMax								= 0;
725 		spec.instanceCount							= 1;
726 		spec.indirectOffset							= 0;
727 
728 		spec.attribs.resize(3);
729 
730 		spec.attribs[0].inputType					= gls::DrawTestSpec::INPUTTYPE_FLOAT;
731 		spec.attribs[0].outputType					= gls::DrawTestSpec::OUTPUTTYPE_VEC2;
732 		spec.attribs[0].storage						= gls::DrawTestSpec::STORAGE_BUFFER;
733 		spec.attribs[0].usage						= gls::DrawTestSpec::USAGE_STATIC_DRAW;
734 		spec.attribs[0].componentCount				= 4;
735 		spec.attribs[0].offset						= 0;
736 		spec.attribs[0].stride						= 0;
737 		spec.attribs[0].normalize					= false;
738 		spec.attribs[0].instanceDivisor				= 0;
739 		spec.attribs[0].useDefaultAttribute			= false;
740 
741 		// Add another position component so the instances wont be drawn on each other
742 		spec.attribs[1].inputType					= gls::DrawTestSpec::INPUTTYPE_FLOAT;
743 		spec.attribs[1].outputType					= gls::DrawTestSpec::OUTPUTTYPE_VEC2;
744 		spec.attribs[1].storage						= gls::DrawTestSpec::STORAGE_BUFFER;
745 		spec.attribs[1].usage						= gls::DrawTestSpec::USAGE_STATIC_DRAW;
746 		spec.attribs[1].componentCount				= 2;
747 		spec.attribs[1].offset						= 0;
748 		spec.attribs[1].stride						= 0;
749 		spec.attribs[1].normalize					= false;
750 		spec.attribs[1].instanceDivisor				= 1;
751 		spec.attribs[1].useDefaultAttribute			= false;
752 		spec.attribs[1].additionalPositionAttribute	= true;
753 
754 		// Instanced color
755 		spec.attribs[2].inputType					= gls::DrawTestSpec::INPUTTYPE_FLOAT;
756 		spec.attribs[2].outputType					= gls::DrawTestSpec::OUTPUTTYPE_VEC2;
757 		spec.attribs[2].storage						= gls::DrawTestSpec::STORAGE_BUFFER;
758 		spec.attribs[2].usage						= gls::DrawTestSpec::USAGE_STATIC_DRAW;
759 		spec.attribs[2].componentCount				= 3;
760 		spec.attribs[2].offset						= 0;
761 		spec.attribs[2].stride						= 0;
762 		spec.attribs[2].normalize					= false;
763 		spec.attribs[2].instanceDivisor				= 1;
764 		spec.attribs[2].useDefaultAttribute			= false;
765 
766 		addTestIterations(test, spec, TYPE_INSTANCE_COUNT);
767 
768 		this->addChild(test);
769 	}
770 
771 	// Multiple attribute, second one default
772 	{
773 		gls::DrawTest*		test				= new gls::DrawTest(m_testCtx, m_context.getRenderContext(), "default_attribute", "Attribute specified with glVertexAttrib*.");
774 		gls::DrawTestSpec	spec;
775 
776 		spec.apiType							= glu::ApiType::es(3,1);
777 		spec.primitive							= m_primitive;
778 		spec.primitiveCount						= 5;
779 		spec.drawMethod							= m_method;
780 		spec.indexType							= m_indexType;
781 		spec.indexPointerOffset					= 0;
782 		spec.indexStorage						= m_indexStorage;
783 		spec.first								= 0;
784 		spec.indexMin							= 0;
785 		spec.indexMax							= 0;
786 		spec.instanceCount						= 1;
787 		spec.indirectOffset						= 0;
788 
789 		spec.attribs.resize(2);
790 
791 		spec.attribs[0].inputType				= gls::DrawTestSpec::INPUTTYPE_FLOAT;
792 		spec.attribs[0].outputType				= gls::DrawTestSpec::OUTPUTTYPE_VEC2;
793 		spec.attribs[0].storage					= gls::DrawTestSpec::STORAGE_BUFFER;
794 		spec.attribs[0].usage					= gls::DrawTestSpec::USAGE_STATIC_DRAW;
795 		spec.attribs[0].componentCount			= 2;
796 		spec.attribs[0].offset					= 0;
797 		spec.attribs[0].stride					= 0;
798 		spec.attribs[0].normalize				= false;
799 		spec.attribs[0].instanceDivisor			= 0;
800 		spec.attribs[0].useDefaultAttribute		= false;
801 
802 		struct IOPair
803 		{
804 			gls::DrawTestSpec::InputType  input;
805 			gls::DrawTestSpec::OutputType output;
806 			int							  componentCount;
807 		} iopairs[] =
808 		{
809 			{ gls::DrawTestSpec::INPUTTYPE_FLOAT,		 gls::DrawTestSpec::OUTPUTTYPE_VEC2,  4 },
810 			{ gls::DrawTestSpec::INPUTTYPE_FLOAT,		 gls::DrawTestSpec::OUTPUTTYPE_VEC4,  2 },
811 			{ gls::DrawTestSpec::INPUTTYPE_INT,			 gls::DrawTestSpec::OUTPUTTYPE_IVEC3, 4 },
812 			{ gls::DrawTestSpec::INPUTTYPE_UNSIGNED_INT, gls::DrawTestSpec::OUTPUTTYPE_UVEC2, 4 },
813 		};
814 
815 		for (int ioNdx = 0; ioNdx < DE_LENGTH_OF_ARRAY(iopairs); ++ioNdx)
816 		{
817 			const std::string desc = gls::DrawTestSpec::inputTypeToString(iopairs[ioNdx].input) + de::toString(iopairs[ioNdx].componentCount) + " to " + gls::DrawTestSpec::outputTypeToString(iopairs[ioNdx].output);
818 
819 			spec.attribs[1].inputType			= iopairs[ioNdx].input;
820 			spec.attribs[1].outputType			= iopairs[ioNdx].output;
821 			spec.attribs[1].storage				= gls::DrawTestSpec::STORAGE_BUFFER;
822 			spec.attribs[1].usage				= gls::DrawTestSpec::USAGE_STATIC_DRAW;
823 			spec.attribs[1].componentCount		= iopairs[ioNdx].componentCount;
824 			spec.attribs[1].offset				= 0;
825 			spec.attribs[1].stride				= 0;
826 			spec.attribs[1].normalize			= false;
827 			spec.attribs[1].instanceDivisor		= 0;
828 			spec.attribs[1].useDefaultAttribute	= true;
829 
830 			test->addIteration(spec, desc.c_str());
831 		}
832 
833 		this->addChild(test);
834 	}
835 }
836 
837 class MethodGroup : public TestCaseGroup
838 {
839 public:
840 									MethodGroup			(Context& context, const char* name, const char* descr, gls::DrawTestSpec::DrawMethod drawMethod);
841 									~MethodGroup		(void);
842 
843 	void							init				(void);
844 
845 private:
846 	gls::DrawTestSpec::DrawMethod	m_method;
847 };
848 
MethodGroup(Context & context,const char * name,const char * descr,gls::DrawTestSpec::DrawMethod drawMethod)849 MethodGroup::MethodGroup (Context& context, const char* name, const char* descr, gls::DrawTestSpec::DrawMethod drawMethod)
850 	: TestCaseGroup		(context, name, descr)
851 	, m_method			(drawMethod)
852 {
853 }
854 
~MethodGroup(void)855 MethodGroup::~MethodGroup (void)
856 {
857 }
858 
init(void)859 void MethodGroup::init (void)
860 {
861 	const bool indexed		=	(m_method == gls::DrawTestSpec::DRAWMETHOD_DRAWELEMENTS_BASEVERTEX)
862 							||	(m_method == gls::DrawTestSpec::DRAWMETHOD_DRAWELEMENTS_RANGED_BASEVERTEX)
863 							||	(m_method == gls::DrawTestSpec::DRAWMETHOD_DRAWELEMENTS_INSTANCED_BASEVERTEX);
864 
865 	const gls::DrawTestSpec::Primitive primitive[] =
866 	{
867 		gls::DrawTestSpec::PRIMITIVE_POINTS,
868 		gls::DrawTestSpec::PRIMITIVE_TRIANGLES,
869 		gls::DrawTestSpec::PRIMITIVE_TRIANGLE_FAN,
870 		gls::DrawTestSpec::PRIMITIVE_TRIANGLE_STRIP,
871 		gls::DrawTestSpec::PRIMITIVE_LINES,
872 		gls::DrawTestSpec::PRIMITIVE_LINE_STRIP,
873 		gls::DrawTestSpec::PRIMITIVE_LINE_LOOP
874 	};
875 
876 	if (indexed)
877 	{
878 		// Index-tests
879 		this->addChild(new IndexGroup(m_context, "indices", "Index tests", m_method));
880 		this->addChild(new BaseVertexGroup(m_context, "base_vertex", "Base vertex tests", m_method));
881 		this->addChild(new BuiltInVariableGroup(m_context, "builtin_variable", "Built in shader variable tests", m_method));
882 	}
883 
884 	for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(primitive); ++ndx)
885 	{
886 		const std::string name = gls::DrawTestSpec::primitiveToString(primitive[ndx]);
887 		const std::string desc = gls::DrawTestSpec::primitiveToString(primitive[ndx]);
888 
889 		this->addChild(new AttributeGroup(m_context, name.c_str(), desc.c_str(), m_method, primitive[ndx], gls::DrawTestSpec::INDEXTYPE_SHORT, gls::DrawTestSpec::STORAGE_BUFFER));
890 	}
891 }
892 
893 } // anonymous
894 
DrawElementsBaseVertexTests(Context & context)895 DrawElementsBaseVertexTests::DrawElementsBaseVertexTests (Context& context)
896 	: TestCaseGroup(context, "draw_base_vertex", "Base vertex extension drawing tests")
897 {
898 }
899 
~DrawElementsBaseVertexTests(void)900 DrawElementsBaseVertexTests::~DrawElementsBaseVertexTests (void)
901 {
902 }
903 
init(void)904 void DrawElementsBaseVertexTests::init (void)
905 {
906 	const gls::DrawTestSpec::DrawMethod basicMethods[] =
907 	{
908 		gls::DrawTestSpec::DRAWMETHOD_DRAWELEMENTS_BASEVERTEX,
909 		gls::DrawTestSpec::DRAWMETHOD_DRAWELEMENTS_RANGED_BASEVERTEX,
910 		gls::DrawTestSpec::DRAWMETHOD_DRAWELEMENTS_INSTANCED_BASEVERTEX,
911 	};
912 
913 	for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(basicMethods); ++ndx)
914 	{
915 		const std::string name = gls::DrawTestSpec::drawMethodToString(basicMethods[ndx]);
916 		const std::string desc = gls::DrawTestSpec::drawMethodToString(basicMethods[ndx]);
917 
918 		this->addChild(new MethodGroup(m_context, name.c_str(), desc.c_str(), basicMethods[ndx]));
919 	}
920 }
921 
922 } // Functional
923 } // gles31
924 } // deqp
925