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