• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 Vertex array object tests
22  *//*--------------------------------------------------------------------*/
23 #include "es3fVertexArrayObjectTests.hpp"
24 
25 #include "gluShaderProgram.hpp"
26 #include "gluPixelTransfer.hpp"
27 #include "gluRenderContext.hpp"
28 
29 #include "tcuTestLog.hpp"
30 #include "tcuImageCompare.hpp"
31 #include "tcuSurface.hpp"
32 #include "tcuRenderTarget.hpp"
33 
34 #include "deRandom.hpp"
35 #include "deString.h"
36 #include "deMemory.h"
37 
38 #include <vector>
39 #include <string>
40 #include <memory>
41 
42 #include "glw.h"
43 
44 using std::vector;
45 using std::string;
46 
47 namespace deqp
48 {
49 namespace gles3
50 {
51 namespace Functional
52 {
53 
54 namespace
55 {
56 struct Attribute
57 {
58 				Attribute (void);
59 	GLboolean	enabled;
60 	GLint		size;
61 	GLint		stride;
62 	GLenum		type;
63 	GLboolean	integer;
64 	GLint		divisor;
65 	GLint		offset;
66 	GLboolean	normalized;
67 
68 	int			bufferNdx;
69 };
70 
71 struct VertexArrayState
72 {
73 						VertexArrayState	(void);
74 
75 	vector<Attribute>	attributes;
76 	int					elementArrayBuffer;
77 };
78 
VertexArrayState(void)79 VertexArrayState::VertexArrayState (void)
80 	: elementArrayBuffer(-1)
81 {
82 }
83 
Attribute(void)84 Attribute::Attribute (void)
85 	: enabled		(GL_FALSE)
86 	, size			(1)
87 	, stride		(0)
88 	, type			(GL_FLOAT)
89 	, integer		(GL_FALSE)
90 	, divisor		(0)
91 	, offset		(0)
92 	, normalized	(GL_FALSE)
93 	, bufferNdx		(0)
94 {
95 }
96 
97 struct BufferSpec
98 {
99 	int		count;
100 	int		size;
101 	int		componentCount;
102 	int		stride;
103 	int		offset;
104 
105 	GLenum	type;
106 
107 	int		intRangeMin;
108 	int		intRangeMax;
109 
110 	float	floatRangeMin;
111 	float	floatRangeMax;
112 };
113 
114 struct Spec
115 {
116 						Spec	(void);
117 
118 	int					count;
119 	int					instances;
120 	bool				useDrawElements;
121 	GLenum				indexType;
122 	int					indexOffset;
123 	int					indexRangeMin;
124 	int					indexRangeMax;
125 	int					indexCount;
126 	VertexArrayState	state;
127 	VertexArrayState	vao;
128 	vector<BufferSpec>	buffers;
129 };
130 
Spec(void)131 Spec::Spec (void)
132 	: count				(-1)
133 	, instances			(-1)
134 	, useDrawElements	(false)
135 	, indexType			(GL_NONE)
136 	, indexOffset		(-1)
137 	, indexRangeMin		(-1)
138 	, indexRangeMax		(-1)
139 	, indexCount		(-1)
140 {
141 }
142 
143 } // anonymous
144 
145 class VertexArrayObjectTest : public TestCase
146 {
147 public:
148 
149 							VertexArrayObjectTest	(Context& context, const Spec& spec, const char* name, const char* description);
150 							~VertexArrayObjectTest	(void);
151 	virtual void			init					(void);
152 	virtual void			deinit					(void);
153 	virtual IterateResult	iterate					(void);
154 
155 private:
156 	Spec					m_spec;
157 	tcu::TestLog&			m_log;
158 	vector<GLuint>			m_buffers;
159 	glu::ShaderProgram*		m_vaoProgram;
160 	glu::ShaderProgram*		m_stateProgram;
161 	de::Random				m_random;
162 	deUint8*				m_indices;
163 
164 	void					logVertexArrayState (tcu::TestLog& log, const VertexArrayState& state, const std::string& msg);
165 	deUint8*				createRandomBufferData	(const BufferSpec& buffer);
166 	deUint8*				generateIndices			(void);
167 	glu::ShaderProgram*		createProgram			(const VertexArrayState& state);
168 	void					setState				(const VertexArrayState& state);
169 	void					render					(tcu::Surface& vaoResult, tcu::Surface& defaultResult);
170 	void					makeDrawCall			(const VertexArrayState& state);
171 	void					genReferences			(tcu::Surface& vaoRef, tcu::Surface& defaultRef);
172 
173 							VertexArrayObjectTest	(const VertexArrayObjectTest&);
174 	VertexArrayObjectTest&	operator=				(const VertexArrayObjectTest&);
175 };
176 
VertexArrayObjectTest(Context & context,const Spec & spec,const char * name,const char * description)177 VertexArrayObjectTest::VertexArrayObjectTest (Context& context, const Spec& spec, const char* name, const char* description)
178 	: TestCase			(context, name, description)
179 	, m_spec			(spec)
180 	, m_log				(context.getTestContext().getLog())
181 	, m_vaoProgram		(NULL)
182 	, m_stateProgram	(NULL)
183 	, m_random			(deStringHash(name))
184 	, m_indices			(NULL)
185 {
186 	// Makes zero to zero mapping for buffers
187 	m_buffers.push_back(0);
188 }
189 
~VertexArrayObjectTest(void)190 VertexArrayObjectTest::~VertexArrayObjectTest (void)
191 {
192 }
193 
logVertexArrayState(tcu::TestLog & log,const VertexArrayState & state,const std::string & msg)194 void VertexArrayObjectTest::logVertexArrayState (tcu::TestLog& log, const VertexArrayState& state, const std::string& msg)
195 {
196 	std::stringstream message;
197 
198 	message << msg << "\n";
199 	message << "GL_ELEMENT_ARRAY_BUFFER : " << state.elementArrayBuffer << "\n";
200 
201 	for (int attribNdx = 0; attribNdx < (int)state.attributes.size(); attribNdx++)
202 	{
203 		message
204 		<< "attribute : " << attribNdx << "\n"
205 		<< "\tGL_VERTEX_ATTRIB_ARRAY_ENABLED : " << (state.attributes[attribNdx].enabled ? "GL_TRUE" : "GL_FALSE") <<  "\n"
206 		<< "\tGL_VERTEX_ATTRIB_ARRAY_SIZE : " << state.attributes[attribNdx].size <<  "\n"
207 		<< "\tGL_VERTEX_ATTRIB_ARRAY_STRIDE : " << state.attributes[attribNdx].stride <<  "\n"
208 		<< "\tGL_VERTEX_ATTRIB_ARRAY_TYPE : " << state.attributes[attribNdx].type <<  "\n"
209 		<< "\tGL_VERTEX_ATTRIB_ARRAY_NORMALIZED : " << (state.attributes[attribNdx].normalized ? "GL_TRUE" : "GL_FALSE") <<  "\n"
210 		<< "\tGL_VERTEX_ATTRIB_ARRAY_INTEGER : " << (state.attributes[attribNdx].integer ? "GL_TRUE" : "GL_FALSE") <<  "\n"
211 		<< "\tGL_VERTEX_ATTRIB_ARRAY_DIVISOR : " << state.attributes[attribNdx].divisor <<  "\n"
212 		<< "\tGL_VERTEX_ATTRIB_ARRAY_POINTER : " << state.attributes[attribNdx].offset <<  "\n"
213 		<< "\tGL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING : " << m_buffers[state.attributes[attribNdx].bufferNdx] <<  "\n";
214 	}
215 	log << tcu::TestLog::Message << message.str() << tcu::TestLog::EndMessage;
216 }
217 
218 
init(void)219 void VertexArrayObjectTest::init (void)
220 {
221 	// \note [mika] Index 0 is reserved for 0 buffer
222 	for (int bufferNdx = 0; bufferNdx < (int)m_spec.buffers.size(); bufferNdx++)
223 	{
224 		deUint8* data = createRandomBufferData(m_spec.buffers[bufferNdx]);
225 
226 		try
227 		{
228 			GLuint buffer;
229 			GLU_CHECK_CALL(glGenBuffers(1, &buffer));
230 			m_buffers.push_back(buffer);
231 
232 			GLU_CHECK_CALL(glBindBuffer(GL_ARRAY_BUFFER, buffer));
233 			GLU_CHECK_CALL(glBufferData(GL_ARRAY_BUFFER, m_spec.buffers[bufferNdx].size, data, GL_DYNAMIC_DRAW));
234 			GLU_CHECK_CALL(glBindBuffer(GL_ARRAY_BUFFER, 0));
235 
236 		} catch (...) {
237 			delete[] data;
238 			throw;
239 		}
240 
241 		delete[] data;
242 	}
243 
244 	m_vaoProgram	= createProgram(m_spec.vao);
245 	m_log << tcu::TestLog::Message << "Program used with Vertex Array Object" << tcu::TestLog::EndMessage;
246 	m_log << *m_vaoProgram;
247 	m_stateProgram	= createProgram(m_spec.state);
248 	m_log << tcu::TestLog::Message << "Program used with Vertex Array State" << tcu::TestLog::EndMessage;
249 	m_log << *m_stateProgram;
250 
251 	if (!m_vaoProgram->isOk() || !m_stateProgram->isOk())
252 		TCU_FAIL("Failed to compile shaders");
253 
254 	if (m_spec.useDrawElements && (m_spec.vao.elementArrayBuffer == 0 || m_spec.state.elementArrayBuffer == 0))
255 		m_indices = generateIndices();
256 }
257 
deinit(void)258 void VertexArrayObjectTest::deinit (void)
259 {
260 	GLU_CHECK_CALL(glDeleteBuffers((GLsizei)m_buffers.size(), &(m_buffers[0])));
261 	m_buffers.clear();
262 	delete m_vaoProgram;
263 	delete m_stateProgram;
264 	delete[] m_indices;
265 }
266 
generateIndices(void)267 deUint8* VertexArrayObjectTest::generateIndices (void)
268 {
269 	int typeSize = 0;
270 	switch (m_spec.indexType)
271 	{
272 		case GL_UNSIGNED_INT:	typeSize = sizeof(GLuint);		break;
273 		case GL_UNSIGNED_SHORT:	typeSize = sizeof(GLushort);	break;
274 		case GL_UNSIGNED_BYTE:	typeSize = sizeof(GLubyte);		break;
275 		default:
276 			DE_ASSERT(false);
277 	}
278 
279 	deUint8* indices = new deUint8[m_spec.indexCount * typeSize];
280 
281 	for (int i = 0; i < m_spec.indexCount; i++)
282 	{
283 		deUint8* pos = indices + typeSize * i;
284 
285 		switch (m_spec.indexType)
286 		{
287 			case GL_UNSIGNED_INT:
288 			{
289 				GLuint v = (GLuint)m_random.getInt(m_spec.indexRangeMin, m_spec.indexRangeMax);
290 				deMemcpy(pos, &v, sizeof(v));
291 				break;
292 			}
293 
294 			case GL_UNSIGNED_SHORT:
295 			{
296 				GLushort v = (GLushort)m_random.getInt(m_spec.indexRangeMin, m_spec.indexRangeMax);
297 				deMemcpy(pos, &v, sizeof(v));
298 				break;
299 			}
300 
301 			case GL_UNSIGNED_BYTE:
302 			{
303 				GLubyte v = (GLubyte)m_random.getInt(m_spec.indexRangeMin, m_spec.indexRangeMax);
304 				deMemcpy(pos, &v, sizeof(v));
305 				break;
306 			}
307 
308 			default:
309 				DE_ASSERT(false);
310 		}
311 	}
312 
313 	return indices;
314 }
315 
createRandomBufferData(const BufferSpec & buffer)316 deUint8* VertexArrayObjectTest::createRandomBufferData (const BufferSpec& buffer)
317 {
318 	deUint8* data = new deUint8[buffer.size];
319 
320 	int stride;
321 
322 	if (buffer.stride != 0)
323 	{
324 		stride = buffer.stride;
325 	}
326 	else
327 	{
328 		switch (buffer.type)
329 		{
330 			case GL_FLOAT:			stride = buffer.componentCount * (int)sizeof(GLfloat);	break;
331 			case GL_INT:			stride = buffer.componentCount * (int)sizeof(GLint);	break;
332 			case GL_UNSIGNED_INT:	stride = buffer.componentCount * (int)sizeof(GLuint);	break;
333 			case GL_SHORT:			stride = buffer.componentCount * (int)sizeof(GLshort);	break;
334 			case GL_UNSIGNED_SHORT:	stride = buffer.componentCount * (int)sizeof(GLushort);	break;
335 			case GL_BYTE:			stride = buffer.componentCount * (int)sizeof(GLbyte);	break;
336 			case GL_UNSIGNED_BYTE:	stride = buffer.componentCount * (int)sizeof(GLubyte);	break;
337 
338 			default:
339 				stride = 0;
340 				DE_ASSERT(DE_FALSE);
341 		}
342 	}
343 
344 	deUint8* itr = data;
345 
346 	for (int pos = 0; pos < buffer.count; pos++)
347 	{
348 		deUint8* componentItr = itr;
349 		for (int componentNdx = 0; componentNdx < buffer.componentCount; componentNdx++)
350 		{
351 			switch (buffer.type)
352 			{
353 				case GL_FLOAT:
354 				{
355 					float v = buffer.floatRangeMin + (buffer.floatRangeMax - buffer.floatRangeMin) * m_random.getFloat();
356 					deMemcpy(componentItr, &v, sizeof(v));
357 					componentItr += sizeof(v);
358 					break;
359 				}
360 
361 				case GL_INT:
362 				{
363 					GLint v = m_random.getInt(buffer.intRangeMin, buffer.intRangeMax);
364 					deMemcpy(componentItr, &v, sizeof(v));
365 					componentItr += sizeof(v);
366 					break;
367 				}
368 
369 				case GL_UNSIGNED_INT:
370 				{
371 					GLuint v = m_random.getInt(buffer.intRangeMin, buffer.intRangeMax);
372 					deMemcpy(componentItr, &v, sizeof(v));
373 					componentItr += sizeof(v);
374 					break;
375 				}
376 
377 				case GL_SHORT:
378 				{
379 					GLshort v = (GLshort)m_random.getInt(buffer.intRangeMin, buffer.intRangeMax);
380 					deMemcpy(componentItr, &v, sizeof(v));
381 					componentItr += sizeof(v);
382 					break;
383 				}
384 
385 				case GL_UNSIGNED_SHORT:
386 				{
387 					GLushort v = (GLushort)m_random.getInt(buffer.intRangeMin, buffer.intRangeMax);
388 					deMemcpy(componentItr, &v, sizeof(v));
389 					componentItr += sizeof(v);
390 					break;
391 				}
392 
393 				case GL_BYTE:
394 				{
395 					GLbyte v = (GLbyte)m_random.getInt(buffer.intRangeMin, buffer.intRangeMax);
396 					deMemcpy(componentItr, &v, sizeof(v));
397 					componentItr += sizeof(v);
398 					break;
399 				}
400 
401 				case GL_UNSIGNED_BYTE:
402 				{
403 					GLubyte v = (GLubyte)m_random.getInt(buffer.intRangeMin, buffer.intRangeMax);
404 					deMemcpy(componentItr, &v, sizeof(v));
405 					componentItr += sizeof(v);
406 					break;
407 				}
408 
409 				default:
410 					DE_ASSERT(false);
411 			};
412 		}
413 
414 		itr += stride;
415 	}
416 
417 	return data;
418 }
419 
createProgram(const VertexArrayState & state)420 glu::ShaderProgram* VertexArrayObjectTest::createProgram (const VertexArrayState& state)
421 {
422 	std::stringstream vertexShaderStream;
423 	std::stringstream value;
424 
425 	vertexShaderStream << "#version 300 es\n";
426 
427 	for (int attribNdx = 0; attribNdx < (int)state.attributes.size(); attribNdx++)
428 	{
429 		if (state.attributes[attribNdx].integer)
430 			vertexShaderStream << "layout(location = " << attribNdx << ") in mediump ivec4 a_attrib" << attribNdx << ";\n";
431 		else
432 			vertexShaderStream << "layout(location = " << attribNdx << ") in mediump vec4 a_attrib" << attribNdx << ";\n";
433 
434 		if (state.attributes[attribNdx].integer)
435 		{
436 			float scale = 0.0f;
437 
438 			switch (state.attributes[0].type)
439 			{
440 				case GL_SHORT:			scale  = (1.0f/float((1u<<14)-1u));	break;
441 				case GL_UNSIGNED_SHORT:	scale  = (1.0f/float((1u<<15)-1u));	break;
442 				case GL_INT:			scale  = (1.0f/float((1u<<30)-1u));	break;
443 				case GL_UNSIGNED_INT:	scale  = (1.0f/float((1u<<31)-1u));	break;
444 				case GL_BYTE:			scale  = (1.0f/float((1u<<6)-1u));	break;
445 				case GL_UNSIGNED_BYTE:	scale  = (1.0f/float((1u<<7)-1u));	break;
446 
447 				default:
448 					DE_ASSERT(DE_FALSE);
449 			}
450 			value << (attribNdx != 0 ? " + " : "" ) << scale << " * vec4(a_attrib" << attribNdx << ")";
451 		}
452 		else if (state.attributes[attribNdx].type != GL_FLOAT && !state.attributes[attribNdx].normalized)
453 		{
454 			float scale = 0.0f;
455 
456 			switch (state.attributes[0].type)
457 			{
458 				case GL_SHORT:			scale  = (0.5f/float((1u<<14)-1u));	break;
459 				case GL_UNSIGNED_SHORT:	scale  = (0.5f/float((1u<<15)-1u));	break;
460 				case GL_INT:			scale  = (0.5f/float((1u<<30)-1u));	break;
461 				case GL_UNSIGNED_INT:	scale  = (0.5f/float((1u<<31)-1u));	break;
462 				case GL_BYTE:			scale  = (0.5f/float((1u<<6)-1u));	break;
463 				case GL_UNSIGNED_BYTE:	scale  = (0.5f/float((1u<<7)-1u));	break;
464 
465 				default:
466 					DE_ASSERT(DE_FALSE);
467 			}
468 			value << (attribNdx != 0 ? " + " : "" ) << scale << " * a_attrib" << attribNdx;
469 		}
470 		else
471 			value << (attribNdx != 0 ? " + " : "" ) << "a_attrib" << attribNdx;
472 	}
473 
474 	vertexShaderStream
475 		<< "out mediump vec4 v_value;\n"
476 		<< "void main (void)\n"
477 		<< "{\n"
478 		<< "\tv_value = " << value.str() << ";\n";
479 
480 	if (state.attributes[0].integer)
481 	{
482 		float scale = 0.0f;
483 
484 		switch (state.attributes[0].type)
485 		{
486 			case GL_SHORT:			scale  = (1.0f/float((1u<<14)-1u));	break;
487 			case GL_UNSIGNED_SHORT:	scale  = (1.0f/float((1u<<15)-1u));	break;
488 			case GL_INT:			scale  = (1.0f/float((1u<<30)-1u));	break;
489 			case GL_UNSIGNED_INT:	scale  = (1.0f/float((1u<<31)-1u));	break;
490 			case GL_BYTE:			scale  = (1.0f/float((1u<<6)-1u));	break;
491 			case GL_UNSIGNED_BYTE:	scale  = (1.0f/float((1u<<7)-1u));	break;
492 
493 			default:
494 				DE_ASSERT(DE_FALSE);
495 		}
496 
497 		vertexShaderStream
498 			<< "\tgl_Position = vec4(" << scale << " * " <<  "vec3(a_attrib0.xyz), 1.0);\n"
499 			<< "}";
500 	}
501 	else
502 	{
503 		if (state.attributes[0].normalized || state.attributes[0].type == GL_FLOAT)
504 		{
505 			vertexShaderStream
506 				<< "\tgl_Position = vec4(a_attrib0.xyz, 1.0);\n"
507 				<< "}";
508 		}
509 		else
510 		{
511 			float scale = 0.0f;
512 
513 			switch (state.attributes[0].type)
514 			{
515 				case GL_SHORT:			scale  = (1.0f/float((1u<<14)-1u));	break;
516 				case GL_UNSIGNED_SHORT:	scale  = (1.0f/float((1u<<15)-1u));	break;
517 				case GL_INT:			scale  = (1.0f/float((1u<<30)-1u));	break;
518 				case GL_UNSIGNED_INT:	scale  = (1.0f/float((1u<<31)-1u));	break;
519 				case GL_BYTE:			scale  = (1.0f/float((1u<<6)-1u));	break;
520 				case GL_UNSIGNED_BYTE:	scale  = (1.0f/float((1u<<7)-1u));	break;
521 
522 				default:
523 					DE_ASSERT(DE_FALSE);
524 			}
525 
526 			scale *= 0.5f;
527 
528 			vertexShaderStream
529 				<< "\tgl_Position = vec4(" << scale << " * " <<  "a_attrib0.xyz, 1.0);\n"
530 				<< "}";
531 		}
532 	}
533 
534 	const char* fragmentShader =
535 	"#version 300 es\n"
536 	"in mediump vec4 v_value;\n"
537 	"layout(location = 0) out mediump vec4 fragColor;\n"
538 	"void main (void)\n"
539 	"{\n"
540 	"\tfragColor = vec4(v_value.xyz, 1.0);\n"
541 	"}";
542 
543 	return new glu::ShaderProgram(m_context.getRenderContext(), glu::makeVtxFragSources(vertexShaderStream.str(), fragmentShader));
544 }
545 
setState(const VertexArrayState & state)546 void VertexArrayObjectTest::setState (const VertexArrayState& state)
547 {
548 	GLU_CHECK_CALL(glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_buffers[state.elementArrayBuffer]));
549 
550 	for (int attribNdx = 0; attribNdx < (int)state.attributes.size(); attribNdx++)
551 	{
552 		GLU_CHECK_CALL(glBindBuffer(GL_ARRAY_BUFFER, m_buffers[state.attributes[attribNdx].bufferNdx]));
553 		if (state.attributes[attribNdx].enabled)
554 			GLU_CHECK_CALL(glEnableVertexAttribArray(attribNdx));
555 		else
556 			GLU_CHECK_CALL(glDisableVertexAttribArray(attribNdx));
557 
558 		if (state.attributes[attribNdx].integer)
559 			GLU_CHECK_CALL(glVertexAttribIPointer(attribNdx, state.attributes[attribNdx].size, state.attributes[attribNdx].type, state.attributes[attribNdx].stride, (const GLvoid*)((GLintptr)state.attributes[attribNdx].offset)));
560 		else
561 			GLU_CHECK_CALL(glVertexAttribPointer(attribNdx, state.attributes[attribNdx].size, state.attributes[attribNdx].type, state.attributes[attribNdx].normalized, state.attributes[attribNdx].stride, (const GLvoid*)((GLintptr)state.attributes[attribNdx].offset)));
562 
563 		GLU_CHECK_CALL(glVertexAttribDivisor(attribNdx, state.attributes[attribNdx].divisor));
564 	}
565 }
566 
makeDrawCall(const VertexArrayState & state)567 void VertexArrayObjectTest::makeDrawCall (const VertexArrayState& state)
568 {
569 	GLU_CHECK_CALL(glClearColor(0.7f, 0.7f, 0.7f, 1.0f));
570 	GLU_CHECK_CALL(glClear(GL_COLOR_BUFFER_BIT));
571 
572 	if (m_spec.useDrawElements)
573 	{
574 		if (state.elementArrayBuffer == 0)
575 		{
576 			if (m_spec.instances == 0)
577 				GLU_CHECK_CALL(glDrawElements(GL_TRIANGLES, m_spec.count, m_spec.indexType, m_indices));
578 			else
579 				GLU_CHECK_CALL(glDrawElementsInstanced(GL_TRIANGLES, m_spec.count, m_spec.indexType, m_indices, m_spec.instances));
580 		}
581 		else
582 		{
583 			if (m_spec.instances == 0)
584 				GLU_CHECK_CALL(glDrawElements(GL_TRIANGLES, m_spec.count, m_spec.indexType, (GLvoid*)((GLintptr)m_spec.indexOffset)));
585 			else
586 				GLU_CHECK_CALL(glDrawElementsInstanced(GL_TRIANGLES, m_spec.count, m_spec.indexType, (GLvoid*)((GLintptr)m_spec.indexOffset), m_spec.instances));
587 		}
588 	}
589 	else
590 	{
591 		if (m_spec.instances == 0)
592 			GLU_CHECK_CALL(glDrawArrays(GL_TRIANGLES, 0, m_spec.count));
593 		else
594 			GLU_CHECK_CALL(glDrawArraysInstanced(GL_TRIANGLES, 0, m_spec.count, m_spec.instances));
595 	}
596 }
597 
render(tcu::Surface & vaoResult,tcu::Surface & defaultResult)598 void VertexArrayObjectTest::render (tcu::Surface& vaoResult, tcu::Surface& defaultResult)
599 {
600 	GLuint vao = 0;
601 
602 	GLU_CHECK_CALL(glGenVertexArrays(1, &vao));
603 	GLU_CHECK_CALL(glBindVertexArray(vao));
604 	setState(m_spec.vao);
605 	GLU_CHECK_CALL(glBindVertexArray(0));
606 
607 	setState(m_spec.state);
608 
609 	GLU_CHECK_CALL(glBindVertexArray(vao));
610 	GLU_CHECK_CALL(glUseProgram(m_vaoProgram->getProgram()));
611 	makeDrawCall(m_spec.vao);
612 	glu::readPixels(m_context.getRenderContext(), 0, 0, vaoResult.getAccess());
613 	setState(m_spec.vao);
614 	GLU_CHECK_CALL(glBindVertexArray(0));
615 
616 	GLU_CHECK_CALL(glUseProgram(m_stateProgram->getProgram()));
617 	makeDrawCall(m_spec.state);
618 	glu::readPixels(m_context.getRenderContext(), 0, 0, defaultResult.getAccess());
619 }
620 
genReferences(tcu::Surface & vaoRef,tcu::Surface & defaultRef)621 void VertexArrayObjectTest::genReferences (tcu::Surface& vaoRef, tcu::Surface& defaultRef)
622 {
623 	setState(m_spec.vao);
624 	GLU_CHECK_CALL(glUseProgram(m_vaoProgram->getProgram()));
625 	makeDrawCall(m_spec.vao);
626 	glu::readPixels(m_context.getRenderContext(), 0, 0, vaoRef.getAccess());
627 
628 	setState(m_spec.state);
629 	GLU_CHECK_CALL(glUseProgram(m_stateProgram->getProgram()));
630 	makeDrawCall(m_spec.state);
631 	glu::readPixels(m_context.getRenderContext(), 0, 0, defaultRef.getAccess());
632 }
633 
iterate(void)634 TestCase::IterateResult VertexArrayObjectTest::iterate (void)
635 {
636 	tcu::Surface	vaoReference	(m_context.getRenderContext().getRenderTarget().getWidth(), m_context.getRenderContext().getRenderTarget().getHeight());
637 	tcu::Surface	stateReference	(m_context.getRenderContext().getRenderTarget().getWidth(), m_context.getRenderContext().getRenderTarget().getHeight());
638 
639 	tcu::Surface	vaoResult		(m_context.getRenderContext().getRenderTarget().getWidth(), m_context.getRenderContext().getRenderTarget().getHeight());
640 	tcu::Surface	stateResult		(m_context.getRenderContext().getRenderTarget().getWidth(), m_context.getRenderContext().getRenderTarget().getHeight());
641 
642 	bool			isOk;
643 
644 	logVertexArrayState(m_log, m_spec.vao, "Vertex Array Object State");
645 	logVertexArrayState(m_log, m_spec.state, "OpenGL Vertex Array State");
646 	genReferences(stateReference, vaoReference);
647 	render(stateResult, vaoResult);
648 
649 	isOk = tcu::pixelThresholdCompare (m_log, "Results", "Comparison result from rendering with Vertex Array State", stateReference, stateResult, tcu::RGBA(0,0,0,0), tcu::COMPARE_LOG_RESULT);
650 	isOk = isOk && tcu::pixelThresholdCompare (m_log, "Results", "Comparison result from rendering with Vertex Array Object", vaoReference, vaoResult, tcu::RGBA(0,0,0,0), tcu::COMPARE_LOG_RESULT);
651 
652 	if (isOk)
653 	{
654 		m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
655 		return STOP;
656 	}
657 	else
658 	{
659 		m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
660 		return STOP;
661 	}
662 }
663 
664 class MultiVertexArrayObjectTest : public TestCase
665 {
666 public:
667 
668 							MultiVertexArrayObjectTest	(Context& context, const char* name, const char* description);
669 							~MultiVertexArrayObjectTest	(void);
670 	virtual void			init						(void);
671 	virtual void			deinit						(void);
672 	virtual IterateResult	iterate						(void);
673 
674 private:
675 	Spec					m_spec;
676 	tcu::TestLog&			m_log;
677 	vector<GLuint>			m_buffers;
678 	glu::ShaderProgram*		m_vaoProgram;
679 	glu::ShaderProgram*		m_stateProgram;
680 	de::Random				m_random;
681 	deUint8*				m_indices;
682 
683 	void					logVertexArrayState			(tcu::TestLog& log, const VertexArrayState& state, const std::string& msg);
684 	deUint8*				createRandomBufferData		(const BufferSpec& buffer);
685 	deUint8*				generateIndices				(void);
686 	glu::ShaderProgram*		createProgram				(const VertexArrayState& state);
687 	void					setState					(const VertexArrayState& state);
688 	void					render						(tcu::Surface& vaoResult, tcu::Surface& defaultResult);
689 	void					makeDrawCall				(const VertexArrayState& state);
690 	void					genReferences				(tcu::Surface& vaoRef, tcu::Surface& defaultRef);
691 
692 							MultiVertexArrayObjectTest	(const MultiVertexArrayObjectTest&);
693 	MultiVertexArrayObjectTest&	operator=				(const MultiVertexArrayObjectTest&);
694 };
695 
MultiVertexArrayObjectTest(Context & context,const char * name,const char * description)696 MultiVertexArrayObjectTest::MultiVertexArrayObjectTest (Context& context, const char* name, const char* description)
697 	: TestCase			(context, name, description)
698 	, m_log				(context.getTestContext().getLog())
699 	, m_vaoProgram		(NULL)
700 	, m_stateProgram	(NULL)
701 	, m_random			(deStringHash(name))
702 	, m_indices			(NULL)
703 {
704 	// Makes zero to zero mapping for buffers
705 	m_buffers.push_back(0);
706 }
707 
~MultiVertexArrayObjectTest(void)708 MultiVertexArrayObjectTest::~MultiVertexArrayObjectTest (void)
709 {
710 }
711 
logVertexArrayState(tcu::TestLog & log,const VertexArrayState & state,const std::string & msg)712 void MultiVertexArrayObjectTest::logVertexArrayState (tcu::TestLog& log, const VertexArrayState& state, const std::string& msg)
713 {
714 	std::stringstream message;
715 
716 	message << msg << "\n";
717 	message << "GL_ELEMENT_ARRAY_BUFFER : " << state.elementArrayBuffer << "\n";
718 
719 	for (int attribNdx = 0; attribNdx < (int)state.attributes.size(); attribNdx++)
720 	{
721 		message
722 		<< "attribute : " << attribNdx << "\n"
723 		<< "\tGL_VERTEX_ATTRIB_ARRAY_ENABLED : " << (state.attributes[attribNdx].enabled ? "GL_TRUE" : "GL_FALSE") <<  "\n"
724 		<< "\tGL_VERTEX_ATTRIB_ARRAY_SIZE : " << state.attributes[attribNdx].size <<  "\n"
725 		<< "\tGL_VERTEX_ATTRIB_ARRAY_STRIDE : " << state.attributes[attribNdx].stride <<  "\n"
726 		<< "\tGL_VERTEX_ATTRIB_ARRAY_TYPE : " << state.attributes[attribNdx].type <<  "\n"
727 		<< "\tGL_VERTEX_ATTRIB_ARRAY_NORMALIZED : " << (state.attributes[attribNdx].normalized ? "GL_TRUE" : "GL_FALSE") <<  "\n"
728 		<< "\tGL_VERTEX_ATTRIB_ARRAY_INTEGER : " << (state.attributes[attribNdx].integer ? "GL_TRUE" : "GL_FALSE") <<  "\n"
729 		<< "\tGL_VERTEX_ATTRIB_ARRAY_DIVISOR : " << state.attributes[attribNdx].divisor <<  "\n"
730 		<< "\tGL_VERTEX_ATTRIB_ARRAY_POINTER : " << state.attributes[attribNdx].offset <<  "\n"
731 		<< "\t GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING : " << m_buffers[state.attributes[attribNdx].bufferNdx] <<  "\n";
732 	}
733 	log << tcu::TestLog::Message << message.str() << tcu::TestLog::EndMessage;
734 }
735 
736 
init(void)737 void MultiVertexArrayObjectTest::init (void)
738 {
739 	GLint attribCount;
740 
741 	GLU_CHECK_CALL(glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &attribCount));
742 
743 	m_spec.useDrawElements			= false;
744 	m_spec.instances				= 0;
745 	m_spec.count					= 24;
746 	m_spec.indexOffset				= 0;
747 	m_spec.indexRangeMin			= 0;
748 	m_spec.indexRangeMax			= 0;
749 	m_spec.indexType				= GL_NONE;
750 	m_spec.indexCount				= 0;
751 	m_spec.vao.elementArrayBuffer	= 0;
752 	m_spec.state.elementArrayBuffer	= 0;
753 
754 	for (int attribNdx = 0; attribNdx < attribCount; attribNdx++)
755 	{
756 		BufferSpec shortCoordBuffer48 = { 48, 2*384, 4, 0, 0, GL_SHORT, -32768, 32768, 0.0f, 0.0f };
757 		m_spec.buffers.push_back(shortCoordBuffer48);
758 
759 		m_spec.state.attributes.push_back(Attribute());
760 		m_spec.state.attributes[attribNdx].enabled		= (m_random.getInt(0, 4) == 0) ? GL_FALSE : GL_TRUE;
761 		m_spec.state.attributes[attribNdx].size			= m_random.getInt(2,4);
762 		m_spec.state.attributes[attribNdx].stride		= 2*m_random.getInt(1, 3);
763 		m_spec.state.attributes[attribNdx].type			= GL_SHORT;
764 		m_spec.state.attributes[attribNdx].integer		= m_random.getBool();
765 		m_spec.state.attributes[attribNdx].divisor		= m_random.getInt(0, 1);
766 		m_spec.state.attributes[attribNdx].offset		= 2*m_random.getInt(0, 2);
767 		m_spec.state.attributes[attribNdx].normalized	= m_random.getBool();
768 		m_spec.state.attributes[attribNdx].bufferNdx	= attribNdx+1;
769 
770 		if (attribNdx == 0)
771 		{
772 			m_spec.state.attributes[attribNdx].divisor	= 0;
773 			m_spec.state.attributes[attribNdx].enabled	= GL_TRUE;
774 			m_spec.state.attributes[attribNdx].size		= 2;
775 		}
776 
777 		m_spec.vao.attributes.push_back(Attribute());
778 		m_spec.vao.attributes[attribNdx].enabled		= (m_random.getInt(0, 4) == 0) ? GL_FALSE : GL_TRUE;
779 		m_spec.vao.attributes[attribNdx].size			= m_random.getInt(2,4);
780 		m_spec.vao.attributes[attribNdx].stride			= 2*m_random.getInt(1, 3);
781 		m_spec.vao.attributes[attribNdx].type			= GL_SHORT;
782 		m_spec.vao.attributes[attribNdx].integer		= m_random.getBool();
783 		m_spec.vao.attributes[attribNdx].divisor		= m_random.getInt(0, 1);
784 		m_spec.vao.attributes[attribNdx].offset			= 2*m_random.getInt(0, 2);
785 		m_spec.vao.attributes[attribNdx].normalized		= m_random.getBool();
786 		m_spec.vao.attributes[attribNdx].bufferNdx		= attribCount - attribNdx;
787 
788 		if (attribNdx == 0)
789 		{
790 			m_spec.vao.attributes[attribNdx].divisor	= 0;
791 			m_spec.vao.attributes[attribNdx].enabled	= GL_TRUE;
792 			m_spec.vao.attributes[attribNdx].size		= 2;
793 		}
794 
795 	}
796 
797 	// \note [mika] Index 0 is reserved for 0 buffer
798 	for (int bufferNdx = 0; bufferNdx < (int)m_spec.buffers.size(); bufferNdx++)
799 	{
800 		deUint8* data = createRandomBufferData(m_spec.buffers[bufferNdx]);
801 
802 		try
803 		{
804 			GLuint buffer;
805 			GLU_CHECK_CALL(glGenBuffers(1, &buffer));
806 			m_buffers.push_back(buffer);
807 
808 			GLU_CHECK_CALL(glBindBuffer(GL_ARRAY_BUFFER, buffer));
809 			GLU_CHECK_CALL(glBufferData(GL_ARRAY_BUFFER, m_spec.buffers[bufferNdx].size, data, GL_DYNAMIC_DRAW));
810 			GLU_CHECK_CALL(glBindBuffer(GL_ARRAY_BUFFER, 0));
811 
812 		} catch (...) {
813 			delete[] data;
814 			throw;
815 		}
816 
817 		delete[] data;
818 	}
819 
820 	m_vaoProgram	= createProgram(m_spec.vao);
821 	m_log << tcu::TestLog::Message << "Program used with Vertex Array Object" << tcu::TestLog::EndMessage;
822 	m_log << *m_vaoProgram;
823 	m_stateProgram	= createProgram(m_spec.state);
824 	m_log << tcu::TestLog::Message << "Program used with Vertex Array State" << tcu::TestLog::EndMessage;
825 	m_log << *m_stateProgram;
826 
827 	if (!m_vaoProgram->isOk() || !m_stateProgram->isOk())
828 		TCU_FAIL("Failed to compile shaders");
829 
830 	if (m_spec.useDrawElements && (m_spec.vao.elementArrayBuffer == 0 || m_spec.state.elementArrayBuffer == 0))
831 		m_indices = generateIndices();
832 }
833 
deinit(void)834 void MultiVertexArrayObjectTest::deinit (void)
835 {
836 	GLU_CHECK_CALL(glDeleteBuffers((GLsizei)m_buffers.size(), &(m_buffers[0])));
837 	m_buffers.clear();
838 	delete m_vaoProgram;
839 	delete m_stateProgram;
840 	delete[] m_indices;
841 }
842 
generateIndices(void)843 deUint8* MultiVertexArrayObjectTest::generateIndices (void)
844 {
845 	int typeSize = 0;
846 	switch (m_spec.indexType)
847 	{
848 		case GL_UNSIGNED_INT:	typeSize = sizeof(GLuint);		break;
849 		case GL_UNSIGNED_SHORT:	typeSize = sizeof(GLushort);	break;
850 		case GL_UNSIGNED_BYTE:	typeSize = sizeof(GLubyte);		break;
851 		default:
852 			DE_ASSERT(false);
853 	}
854 
855 	deUint8* indices = new deUint8[m_spec.indexCount * typeSize];
856 
857 	for (int i = 0; i < m_spec.indexCount; i++)
858 	{
859 		deUint8* pos = indices + typeSize * i;
860 
861 		switch (m_spec.indexType)
862 		{
863 			case GL_UNSIGNED_INT:
864 			{
865 				GLuint v = (GLuint)m_random.getInt(m_spec.indexRangeMin, m_spec.indexRangeMax);
866 				deMemcpy(pos, &v, sizeof(v));
867 				break;
868 			}
869 
870 			case GL_UNSIGNED_SHORT:
871 			{
872 				GLushort v = (GLushort)m_random.getInt(m_spec.indexRangeMin, m_spec.indexRangeMax);
873 				deMemcpy(pos, &v, sizeof(v));
874 				break;
875 			}
876 
877 			case GL_UNSIGNED_BYTE:
878 			{
879 				GLubyte v = (GLubyte)m_random.getInt(m_spec.indexRangeMin, m_spec.indexRangeMax);
880 				deMemcpy(pos, &v, sizeof(v));
881 				break;
882 			}
883 
884 			default:
885 				DE_ASSERT(false);
886 		}
887 	}
888 
889 	return indices;
890 }
891 
createRandomBufferData(const BufferSpec & buffer)892 deUint8* MultiVertexArrayObjectTest::createRandomBufferData (const BufferSpec& buffer)
893 {
894 	deUint8* data = new deUint8[buffer.size];
895 
896 	int stride;
897 
898 	if (buffer.stride != 0)
899 	{
900 		stride = buffer.stride;
901 	}
902 	else
903 	{
904 		switch (buffer.type)
905 		{
906 			case GL_FLOAT:			stride = buffer.componentCount * (int)sizeof(GLfloat);	break;
907 			case GL_INT:			stride = buffer.componentCount * (int)sizeof(GLint);	break;
908 			case GL_UNSIGNED_INT:	stride = buffer.componentCount * (int)sizeof(GLuint);	break;
909 			case GL_SHORT:			stride = buffer.componentCount * (int)sizeof(GLshort);	break;
910 			case GL_UNSIGNED_SHORT:	stride = buffer.componentCount * (int)sizeof(GLushort);	break;
911 			case GL_BYTE:			stride = buffer.componentCount * (int)sizeof(GLbyte);	break;
912 			case GL_UNSIGNED_BYTE:	stride = buffer.componentCount * (int)sizeof(GLubyte);	break;
913 
914 			default:
915 				stride = 0;
916 				DE_ASSERT(DE_FALSE);
917 		}
918 	}
919 
920 	deUint8* itr = data;
921 
922 	for (int pos = 0; pos < buffer.count; pos++)
923 	{
924 		deUint8* componentItr = itr;
925 		for (int componentNdx = 0; componentNdx < buffer.componentCount; componentNdx++)
926 		{
927 			switch (buffer.type)
928 			{
929 				case GL_FLOAT:
930 				{
931 					float v = buffer.floatRangeMin + (buffer.floatRangeMax - buffer.floatRangeMin) * m_random.getFloat();
932 					deMemcpy(componentItr, &v, sizeof(v));
933 					componentItr += sizeof(v);
934 					break;
935 				}
936 
937 				case GL_INT:
938 				{
939 					GLint v = m_random.getInt(buffer.intRangeMin, buffer.intRangeMax);
940 					deMemcpy(componentItr, &v, sizeof(v));
941 					componentItr += sizeof(v);
942 					break;
943 				}
944 
945 				case GL_UNSIGNED_INT:
946 				{
947 					GLuint v = (GLuint)m_random.getInt(buffer.intRangeMin, buffer.intRangeMax);
948 					deMemcpy(componentItr, &v, sizeof(v));
949 					componentItr += sizeof(v);
950 					break;
951 				}
952 
953 				case GL_SHORT:
954 				{
955 					GLshort v = (GLshort)m_random.getInt(buffer.intRangeMin, buffer.intRangeMax);
956 					deMemcpy(componentItr, &v, sizeof(v));
957 					componentItr += sizeof(v);
958 					break;
959 				}
960 
961 				case GL_UNSIGNED_SHORT:
962 				{
963 					GLushort v = (GLushort)m_random.getInt(buffer.intRangeMin, buffer.intRangeMax);
964 					deMemcpy(componentItr, &v, sizeof(v));
965 					componentItr += sizeof(v);
966 					break;
967 				}
968 
969 				case GL_BYTE:
970 				{
971 					GLbyte v = (GLbyte)m_random.getInt(buffer.intRangeMin, buffer.intRangeMax);
972 					deMemcpy(componentItr, &v, sizeof(v));
973 					componentItr += sizeof(v);
974 					break;
975 				}
976 
977 				case GL_UNSIGNED_BYTE:
978 				{
979 					GLubyte v = (GLubyte)m_random.getInt(buffer.intRangeMin, buffer.intRangeMax);
980 					deMemcpy(componentItr, &v, sizeof(v));
981 					componentItr += sizeof(v);
982 					break;
983 				}
984 
985 				default:
986 					DE_ASSERT(false);
987 			};
988 		}
989 
990 		itr += stride;
991 	}
992 
993 	return data;
994 }
995 
createProgram(const VertexArrayState & state)996 glu::ShaderProgram* MultiVertexArrayObjectTest::createProgram (const VertexArrayState& state)
997 {
998 	std::stringstream vertexShaderStream;
999 	std::stringstream value;
1000 
1001 	vertexShaderStream << "#version 300 es\n";
1002 
1003 	for (int attribNdx = 0; attribNdx < (int)state.attributes.size(); attribNdx++)
1004 	{
1005 		if (state.attributes[attribNdx].integer)
1006 			vertexShaderStream << "layout(location = " << attribNdx << ") in mediump ivec4 a_attrib" << attribNdx << ";\n";
1007 		else
1008 			vertexShaderStream << "layout(location = " << attribNdx << ") in mediump vec4 a_attrib" << attribNdx << ";\n";
1009 
1010 		if (state.attributes[attribNdx].integer)
1011 		{
1012 			float scale = 0.0f;
1013 
1014 			switch (state.attributes[0].type)
1015 			{
1016 				case GL_SHORT:			scale  = (1.0f/float((1u<<14)-1u));	break;
1017 				case GL_UNSIGNED_SHORT:	scale  = (1.0f/float((1u<<15)-1u));	break;
1018 				case GL_INT:			scale  = (1.0f/float((1u<<30)-1u));	break;
1019 				case GL_UNSIGNED_INT:	scale  = (1.0f/float((1u<<31)-1u));	break;
1020 				case GL_BYTE:			scale  = (1.0f/float((1u<<6)-1u));	break;
1021 				case GL_UNSIGNED_BYTE:	scale  = (1.0f/float((1u<<7)-1u));	break;
1022 
1023 				default:
1024 					DE_ASSERT(DE_FALSE);
1025 			}
1026 			value << (attribNdx != 0 ? " + " : "" ) << scale << " * vec4(a_attrib" << attribNdx << ")";
1027 		}
1028 		else if (state.attributes[attribNdx].type != GL_FLOAT && !state.attributes[attribNdx].normalized)
1029 		{
1030 			float scale = 0.0f;
1031 
1032 			switch (state.attributes[0].type)
1033 			{
1034 				case GL_SHORT:			scale  = (0.5f/float((1u<<14)-1u));	break;
1035 				case GL_UNSIGNED_SHORT:	scale  = (0.5f/float((1u<<15)-1u));	break;
1036 				case GL_INT:			scale  = (0.5f/float((1u<<30)-1u));	break;
1037 				case GL_UNSIGNED_INT:	scale  = (0.5f/float((1u<<31)-1u));	break;
1038 				case GL_BYTE:			scale  = (0.5f/float((1u<<6)-1u));	break;
1039 				case GL_UNSIGNED_BYTE:	scale  = (0.5f/float((1u<<7)-1u));	break;
1040 
1041 				default:
1042 					DE_ASSERT(DE_FALSE);
1043 			}
1044 			value << (attribNdx != 0 ? " + " : "" ) << scale << " * a_attrib" << attribNdx;
1045 		}
1046 		else
1047 			value << (attribNdx != 0 ? " + " : "" ) << "a_attrib" << attribNdx;
1048 	}
1049 
1050 	vertexShaderStream
1051 		<< "out mediump vec4 v_value;\n"
1052 		<< "void main (void)\n"
1053 		<< "{\n"
1054 		<< "\tv_value = " << value.str() << ";\n";
1055 
1056 	if (state.attributes[0].integer)
1057 	{
1058 		float scale = 0.0f;
1059 
1060 		switch (state.attributes[0].type)
1061 		{
1062 			case GL_SHORT:			scale  = (1.0f/float((1u<<14)-1u));	break;
1063 			case GL_UNSIGNED_SHORT:	scale  = (1.0f/float((1u<<15)-1u));	break;
1064 			case GL_INT:			scale  = (1.0f/float((1u<<30)-1u));	break;
1065 			case GL_UNSIGNED_INT:	scale  = (1.0f/float((1u<<31)-1u));	break;
1066 			case GL_BYTE:			scale  = (1.0f/float((1u<<6)-1u));	break;
1067 			case GL_UNSIGNED_BYTE:	scale  = (1.0f/float((1u<<7)-1u));	break;
1068 
1069 
1070 			default:
1071 				DE_ASSERT(DE_FALSE);
1072 		}
1073 
1074 		vertexShaderStream
1075 			<< "\tgl_Position = vec4(" << scale << " * " <<  "a_attrib0.xyz, 1.0);\n"
1076 			<< "}";
1077 	}
1078 	else
1079 	{
1080 		if (state.attributes[0].normalized || state.attributes[0].type == GL_FLOAT)
1081 		{
1082 			vertexShaderStream
1083 				<< "\tgl_Position = vec4(a_attrib0.xyz, 1.0);\n"
1084 				<< "}";
1085 		}
1086 		else
1087 		{
1088 			float scale = 0.0f;
1089 
1090 			switch (state.attributes[0].type)
1091 			{
1092 				case GL_SHORT:			scale  = (1.0f/float((1u<<14)-1u));	break;
1093 				case GL_UNSIGNED_SHORT:	scale  = (1.0f/float((1u<<15)-1u));	break;
1094 				case GL_INT:			scale  = (1.0f/float((1u<<30)-1u));	break;
1095 				case GL_UNSIGNED_INT:	scale  = (1.0f/float((1u<<31)-1u));	break;
1096 				case GL_BYTE:			scale  = (1.0f/float((1u<<6)-1u));	break;
1097 				case GL_UNSIGNED_BYTE:	scale  = (1.0f/float((1u<<7)-1u));	break;
1098 
1099 				default:
1100 					DE_ASSERT(DE_FALSE);
1101 			}
1102 
1103 			scale *= 0.5f;
1104 
1105 			vertexShaderStream
1106 				<< "\tgl_Position = vec4(" << scale << " * " <<  "vec3(a_attrib0.xyz), 1.0);\n"
1107 				<< "}";
1108 		}
1109 	}
1110 
1111 	const char* fragmentShader =
1112 	"#version 300 es\n"
1113 	"in mediump vec4 v_value;\n"
1114 	"layout(location = 0) out mediump vec4 fragColor;\n"
1115 	"void main (void)\n"
1116 	"{\n"
1117 	"\tfragColor = vec4(v_value.xyz, 1.0);\n"
1118 	"}";
1119 
1120 	return new glu::ShaderProgram(m_context.getRenderContext(), glu::makeVtxFragSources(vertexShaderStream.str(), fragmentShader));
1121 }
1122 
setState(const VertexArrayState & state)1123 void MultiVertexArrayObjectTest::setState (const VertexArrayState& state)
1124 {
1125 	GLU_CHECK_CALL(glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_buffers[state.elementArrayBuffer]));
1126 
1127 	for (int attribNdx = 0; attribNdx < (int)state.attributes.size(); attribNdx++)
1128 	{
1129 		GLU_CHECK_CALL(glBindBuffer(GL_ARRAY_BUFFER, m_buffers[state.attributes[attribNdx].bufferNdx]));
1130 		if (state.attributes[attribNdx].enabled)
1131 			GLU_CHECK_CALL(glEnableVertexAttribArray(attribNdx));
1132 		else
1133 			GLU_CHECK_CALL(glDisableVertexAttribArray(attribNdx));
1134 
1135 		if (state.attributes[attribNdx].integer)
1136 			GLU_CHECK_CALL(glVertexAttribIPointer(attribNdx, state.attributes[attribNdx].size, state.attributes[attribNdx].type, state.attributes[attribNdx].stride, (const GLvoid*)((GLintptr)state.attributes[attribNdx].offset)));
1137 		else
1138 			GLU_CHECK_CALL(glVertexAttribPointer(attribNdx, state.attributes[attribNdx].size, state.attributes[attribNdx].type, state.attributes[attribNdx].normalized, state.attributes[attribNdx].stride, (const GLvoid*)((GLintptr)state.attributes[attribNdx].offset)));
1139 
1140 		GLU_CHECK_CALL(glVertexAttribDivisor(attribNdx, state.attributes[attribNdx].divisor));
1141 	}
1142 }
1143 
makeDrawCall(const VertexArrayState & state)1144 void MultiVertexArrayObjectTest::makeDrawCall (const VertexArrayState& state)
1145 {
1146 	GLU_CHECK_CALL(glClearColor(0.7f, 0.7f, 0.7f, 1.0f));
1147 	GLU_CHECK_CALL(glClear(GL_COLOR_BUFFER_BIT));
1148 
1149 	if (m_spec.useDrawElements)
1150 	{
1151 		if (state.elementArrayBuffer == 0)
1152 		{
1153 			if (m_spec.instances == 0)
1154 				GLU_CHECK_CALL(glDrawElements(GL_TRIANGLES, m_spec.count, m_spec.indexType, m_indices));
1155 			else
1156 				GLU_CHECK_CALL(glDrawElementsInstanced(GL_TRIANGLES, m_spec.count, m_spec.indexType, m_indices, m_spec.instances));
1157 		}
1158 		else
1159 		{
1160 			if (m_spec.instances == 0)
1161 				GLU_CHECK_CALL(glDrawElements(GL_TRIANGLES, m_spec.count, m_spec.indexType, (GLvoid*)((GLintptr)m_spec.indexOffset)));
1162 			else
1163 				GLU_CHECK_CALL(glDrawElementsInstanced(GL_TRIANGLES, m_spec.count, m_spec.indexType, (GLvoid*)((GLintptr)m_spec.indexOffset), m_spec.instances));
1164 		}
1165 	}
1166 	else
1167 	{
1168 		if (m_spec.instances == 0)
1169 			GLU_CHECK_CALL(glDrawArrays(GL_TRIANGLES, 0, m_spec.count));
1170 		else
1171 			GLU_CHECK_CALL(glDrawArraysInstanced(GL_TRIANGLES, 0, m_spec.count, m_spec.instances));
1172 	}
1173 }
1174 
render(tcu::Surface & vaoResult,tcu::Surface & defaultResult)1175 void MultiVertexArrayObjectTest::render (tcu::Surface& vaoResult, tcu::Surface& defaultResult)
1176 {
1177 	GLuint vao = 0;
1178 
1179 	GLU_CHECK_CALL(glGenVertexArrays(1, &vao));
1180 	GLU_CHECK_CALL(glBindVertexArray(vao));
1181 	setState(m_spec.vao);
1182 	GLU_CHECK_CALL(glBindVertexArray(0));
1183 
1184 	setState(m_spec.state);
1185 
1186 	GLU_CHECK_CALL(glBindVertexArray(vao));
1187 	GLU_CHECK_CALL(glUseProgram(m_vaoProgram->getProgram()));
1188 	makeDrawCall(m_spec.vao);
1189 	glu::readPixels(m_context.getRenderContext(), 0, 0, vaoResult.getAccess());
1190 	setState(m_spec.vao);
1191 	GLU_CHECK_CALL(glBindVertexArray(0));
1192 
1193 	GLU_CHECK_CALL(glUseProgram(m_stateProgram->getProgram()));
1194 	makeDrawCall(m_spec.state);
1195 	glu::readPixels(m_context.getRenderContext(), 0, 0, defaultResult.getAccess());
1196 }
1197 
genReferences(tcu::Surface & vaoRef,tcu::Surface & defaultRef)1198 void MultiVertexArrayObjectTest::genReferences (tcu::Surface& vaoRef, tcu::Surface& defaultRef)
1199 {
1200 	setState(m_spec.vao);
1201 	GLU_CHECK_CALL(glUseProgram(m_vaoProgram->getProgram()));
1202 	makeDrawCall(m_spec.vao);
1203 	glu::readPixels(m_context.getRenderContext(), 0, 0, vaoRef.getAccess());
1204 
1205 	setState(m_spec.state);
1206 	GLU_CHECK_CALL(glUseProgram(m_stateProgram->getProgram()));
1207 	makeDrawCall(m_spec.state);
1208 	glu::readPixels(m_context.getRenderContext(), 0, 0, defaultRef.getAccess());
1209 }
1210 
iterate(void)1211 TestCase::IterateResult MultiVertexArrayObjectTest::iterate (void)
1212 {
1213 	tcu::Surface	vaoReference	(m_context.getRenderContext().getRenderTarget().getWidth(), m_context.getRenderContext().getRenderTarget().getHeight());
1214 	tcu::Surface	stateReference	(m_context.getRenderContext().getRenderTarget().getWidth(), m_context.getRenderContext().getRenderTarget().getHeight());
1215 
1216 	tcu::Surface	vaoResult		(m_context.getRenderContext().getRenderTarget().getWidth(), m_context.getRenderContext().getRenderTarget().getHeight());
1217 	tcu::Surface	stateResult		(m_context.getRenderContext().getRenderTarget().getWidth(), m_context.getRenderContext().getRenderTarget().getHeight());
1218 
1219 	bool			isOk;
1220 
1221 	logVertexArrayState(m_log, m_spec.vao, "Vertex Array Object State");
1222 	logVertexArrayState(m_log, m_spec.state, "OpenGL Vertex Array State");
1223 	genReferences(stateReference, vaoReference);
1224 	render(stateResult, vaoResult);
1225 
1226 	isOk = tcu::pixelThresholdCompare (m_log, "Results", "Comparison result from rendering with Vertex Array State", stateReference, stateResult, tcu::RGBA(0,0,0,0), tcu::COMPARE_LOG_RESULT);
1227 	isOk = isOk && tcu::pixelThresholdCompare (m_log, "Results", "Comparison result from rendering with Vertex Array Object", vaoReference, vaoResult, tcu::RGBA(0,0,0,0), tcu::COMPARE_LOG_RESULT);
1228 
1229 	if (isOk)
1230 	{
1231 		m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
1232 		return STOP;
1233 	}
1234 	else
1235 	{
1236 		m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
1237 		return STOP;
1238 	}
1239 }
1240 
VertexArrayObjectTestGroup(Context & context)1241 VertexArrayObjectTestGroup::VertexArrayObjectTestGroup (Context& context)
1242 	: TestCaseGroup(context, "vertex_array_objects", "Vertex array object test cases")
1243 {
1244 }
1245 
~VertexArrayObjectTestGroup(void)1246 VertexArrayObjectTestGroup::~VertexArrayObjectTestGroup (void)
1247 {
1248 }
1249 
init(void)1250 void VertexArrayObjectTestGroup::init (void)
1251 {
1252 	BufferSpec floatCoordBuffer48_1 = { 48, 384, 2, 0, 0, GL_FLOAT, 0, 0, -1.0f, 1.0f };
1253 	BufferSpec floatCoordBuffer48_2 = { 48, 384, 2, 0, 0, GL_FLOAT, 0, 0, -1.0f, 1.0f };
1254 
1255 	BufferSpec shortCoordBuffer48 = { 48, 192, 2, 0, 0, GL_SHORT, -32768, 32768, 0.0f, 0.0f };
1256 
1257 	// Different buffer
1258 	{
1259 		Spec spec;
1260 
1261 		VertexArrayState state;
1262 
1263 		state.attributes.push_back(Attribute());
1264 
1265 		state.attributes[0].enabled		= true;
1266 		state.attributes[0].size		= 2;
1267 		state.attributes[0].stride		= 0;
1268 		state.attributes[0].type		= GL_FLOAT;
1269 		state.attributes[0].integer		= GL_FALSE;
1270 		state.attributes[0].divisor		= 0;
1271 		state.attributes[0].offset		= 0;
1272 		state.attributes[0].normalized	= GL_FALSE;
1273 
1274 		state.elementArrayBuffer = 0;
1275 
1276 		spec.buffers.push_back(floatCoordBuffer48_1);
1277 		spec.buffers.push_back(floatCoordBuffer48_2);
1278 
1279 		spec.useDrawElements	= false;
1280 		spec.instances			= 0;
1281 		spec.count				= 48;
1282 		spec.vao				= state;
1283 		spec.state				= state;
1284 		spec.indexOffset		= 0;
1285 		spec.indexRangeMin		= 0;
1286 		spec.indexRangeMax		= 0;
1287 		spec.indexType			= GL_NONE;
1288 		spec.indexCount			= 0;
1289 
1290 		spec.state.attributes[0].bufferNdx	= 1;
1291 		spec.vao.attributes[0].bufferNdx	= 2;
1292 		addChild(new VertexArrayObjectTest(m_context, spec, "diff_buffer", "diff_buffer"));
1293 	}
1294 	// Different size
1295 	{
1296 		Spec spec;
1297 
1298 		VertexArrayState state;
1299 
1300 		state.attributes.push_back(Attribute());
1301 
1302 		state.attributes[0].enabled		= true;
1303 		state.attributes[0].size		= 2;
1304 		state.attributes[0].stride		= 0;
1305 		state.attributes[0].type		= GL_FLOAT;
1306 		state.attributes[0].integer		= GL_FALSE;
1307 		state.attributes[0].divisor		= 0;
1308 		state.attributes[0].offset		= 0;
1309 		state.attributes[0].normalized	= GL_FALSE;
1310 		state.attributes[0].bufferNdx	= 1;
1311 
1312 		state.elementArrayBuffer = 0;
1313 
1314 		spec.buffers.push_back(floatCoordBuffer48_1);
1315 
1316 		spec.useDrawElements	= false;
1317 		spec.instances			= 0;
1318 		spec.count				= 24;
1319 		spec.vao				= state;
1320 		spec.state				= state;
1321 		spec.indexOffset		= 0;
1322 		spec.indexRangeMin		= 0;
1323 		spec.indexRangeMax		= 0;
1324 		spec.indexType			= GL_NONE;
1325 		spec.indexCount			= 0;
1326 
1327 		spec.state.attributes[0].size		= 2;
1328 		spec.vao.attributes[0].size			= 3;
1329 		addChild(new VertexArrayObjectTest(m_context, spec, "diff_size", "diff_size"));
1330 	}
1331 
1332 	// Different stride
1333 	{
1334 		Spec spec;
1335 
1336 		VertexArrayState state;
1337 
1338 		state.attributes.push_back(Attribute());
1339 
1340 		state.attributes[0].enabled		= true;
1341 		state.attributes[0].size		= 2;
1342 		state.attributes[0].stride		= 0;
1343 		state.attributes[0].type		= GL_SHORT;
1344 		state.attributes[0].integer		= GL_FALSE;
1345 		state.attributes[0].divisor		= 0;
1346 		state.attributes[0].offset		= 0;
1347 		state.attributes[0].normalized	= GL_TRUE;
1348 		state.attributes[0].bufferNdx	= 1;
1349 
1350 		state.elementArrayBuffer = 0;
1351 
1352 		spec.buffers.push_back(shortCoordBuffer48);
1353 
1354 		spec.useDrawElements	= false;
1355 		spec.instances			= 0;
1356 		spec.count				= 24;
1357 		spec.vao				= state;
1358 		spec.state				= state;
1359 		spec.indexOffset		= 0;
1360 		spec.indexRangeMin		= 0;
1361 		spec.indexRangeMax		= 0;
1362 		spec.indexType			= GL_NONE;
1363 		spec.indexCount			= 0;
1364 
1365 		spec.vao.attributes[0].stride	= 2;
1366 		spec.state.attributes[0].stride	= 4;
1367 		addChild(new VertexArrayObjectTest(m_context, spec, "diff_stride", "diff_stride"));
1368 	}
1369 
1370 	// Different types
1371 	{
1372 		Spec spec;
1373 
1374 		VertexArrayState state;
1375 
1376 		state.attributes.push_back(Attribute());
1377 
1378 		state.attributes[0].enabled		= true;
1379 		state.attributes[0].size		= 2;
1380 		state.attributes[0].stride		= 0;
1381 		state.attributes[0].type		= GL_SHORT;
1382 		state.attributes[0].integer		= GL_FALSE;
1383 		state.attributes[0].divisor		= 0;
1384 		state.attributes[0].offset		= 0;
1385 		state.attributes[0].normalized	= GL_TRUE;
1386 		state.attributes[0].bufferNdx	= 1;
1387 
1388 		state.elementArrayBuffer = 0;
1389 
1390 		spec.buffers.push_back(shortCoordBuffer48);
1391 
1392 		spec.useDrawElements	= false;
1393 		spec.instances			= 0;
1394 		spec.count				= 24;
1395 		spec.vao				= state;
1396 		spec.state				= state;
1397 		spec.indexOffset		= 0;
1398 		spec.indexRangeMin		= 0;
1399 		spec.indexRangeMax		= 0;
1400 		spec.indexType			= GL_NONE;
1401 		spec.indexCount			= 0;
1402 
1403 		spec.vao.attributes[0].type		= GL_SHORT;
1404 		spec.state.attributes[0].type	= GL_BYTE;
1405 		addChild(new VertexArrayObjectTest(m_context, spec, "diff_type", "diff_type"));
1406 	}
1407 	// Different "integer"
1408 	{
1409 		Spec spec;
1410 
1411 		VertexArrayState state;
1412 
1413 		state.attributes.push_back(Attribute());
1414 
1415 		state.attributes[0].enabled		= true;
1416 		state.attributes[0].size		= 2;
1417 		state.attributes[0].stride		= 0;
1418 		state.attributes[0].type		= GL_BYTE;
1419 		state.attributes[0].integer		= GL_TRUE;
1420 		state.attributes[0].divisor		= 0;
1421 		state.attributes[0].offset		= 0;
1422 		state.attributes[0].normalized	= GL_FALSE;
1423 		state.attributes[0].bufferNdx	= 1;
1424 
1425 		state.elementArrayBuffer = 0;
1426 
1427 		spec.buffers.push_back(shortCoordBuffer48);
1428 
1429 		spec.useDrawElements	= false;
1430 		spec.count				= 24;
1431 		spec.vao				= state;
1432 		spec.state				= state;
1433 		spec.instances			= 0;
1434 		spec.indexOffset		= 0;
1435 		spec.indexRangeMin		= 0;
1436 		spec.indexRangeMax		= 0;
1437 		spec.indexType			= GL_NONE;
1438 		spec.indexCount			= 0;
1439 
1440 		spec.state.attributes[0].integer	= GL_FALSE;
1441 		spec.vao.attributes[0].integer		= GL_TRUE;
1442 		addChild(new VertexArrayObjectTest(m_context, spec, "diff_integer", "diff_integer"));
1443 	}
1444 	// Different divisor
1445 	{
1446 		Spec spec;
1447 
1448 		VertexArrayState state;
1449 
1450 		state.attributes.push_back(Attribute());
1451 		state.attributes.push_back(Attribute());
1452 
1453 		state.attributes[0].enabled		= true;
1454 		state.attributes[0].size		= 2;
1455 		state.attributes[0].stride		= 0;
1456 		state.attributes[0].type		= GL_SHORT;
1457 		state.attributes[0].integer		= GL_FALSE;
1458 		state.attributes[0].divisor		= 0;
1459 		state.attributes[0].offset		= 0;
1460 		state.attributes[0].normalized	= GL_TRUE;
1461 		state.attributes[0].bufferNdx	= 1;
1462 
1463 		state.attributes[1].enabled		= true;
1464 		state.attributes[1].size		= 4;
1465 		state.attributes[1].stride		= 0;
1466 		state.attributes[1].type		= GL_FLOAT;
1467 		state.attributes[1].integer		= GL_FALSE;
1468 		state.attributes[1].divisor		= 0;
1469 		state.attributes[1].offset		= 0;
1470 		state.attributes[1].normalized	= GL_FALSE;
1471 		state.attributes[1].bufferNdx	= 2;
1472 
1473 		state.elementArrayBuffer = 0;
1474 
1475 		spec.buffers.push_back(shortCoordBuffer48);
1476 		spec.buffers.push_back(floatCoordBuffer48_1);
1477 
1478 		spec.useDrawElements	= false;
1479 		spec.instances			= 10;
1480 		spec.count				= 12;
1481 		spec.vao				= state;
1482 		spec.state				= state;
1483 		spec.indexOffset		= 0;
1484 		spec.indexRangeMin		= 0;
1485 		spec.indexRangeMax		= 0;
1486 		spec.indexType			= GL_NONE;
1487 		spec.indexCount			= 0;
1488 
1489 		spec.vao.attributes[1].divisor		= 3;
1490 		spec.state.attributes[1].divisor	= 2;
1491 
1492 		addChild(new VertexArrayObjectTest(m_context, spec, "diff_divisor", "diff_divisor"));
1493 	}
1494 	// Different offset
1495 	{
1496 		Spec spec;
1497 
1498 		VertexArrayState state;
1499 
1500 		state.attributes.push_back(Attribute());
1501 
1502 		state.attributes[0].enabled		= true;
1503 		state.attributes[0].size		= 2;
1504 		state.attributes[0].stride		= 0;
1505 		state.attributes[0].type		= GL_SHORT;
1506 		state.attributes[0].integer		= GL_FALSE;
1507 		state.attributes[0].divisor		= 0;
1508 		state.attributes[0].offset		= 0;
1509 		state.attributes[0].normalized	= GL_TRUE;
1510 		state.attributes[0].bufferNdx	= 1;
1511 
1512 		state.elementArrayBuffer = 0;
1513 
1514 		spec.buffers.push_back(shortCoordBuffer48);
1515 
1516 		spec.useDrawElements	= false;
1517 		spec.instances			= 0;
1518 		spec.count				= 24;
1519 		spec.vao				= state;
1520 		spec.state				= state;
1521 		spec.indexOffset		= 0;
1522 		spec.indexRangeMin		= 0;
1523 		spec.indexRangeMax		= 0;
1524 		spec.indexType			= GL_NONE;
1525 		spec.indexCount			= 0;
1526 
1527 		spec.vao.attributes[0].offset	= 2;
1528 		spec.state.attributes[0].offset	= 4;
1529 		addChild(new VertexArrayObjectTest(m_context, spec, "diff_offset", "diff_offset"));
1530 	}
1531 	// Different normalize
1532 	{
1533 		Spec spec;
1534 
1535 		VertexArrayState state;
1536 
1537 		state.attributes.push_back(Attribute());
1538 
1539 		state.attributes[0].enabled		= true;
1540 		state.attributes[0].size		= 2;
1541 		state.attributes[0].stride		= 0;
1542 		state.attributes[0].type		= GL_SHORT;
1543 		state.attributes[0].integer		= GL_FALSE;
1544 		state.attributes[0].divisor		= 0;
1545 		state.attributes[0].offset		= 0;
1546 		state.attributes[0].normalized	= GL_TRUE;
1547 		state.attributes[0].bufferNdx	= 1;
1548 
1549 		state.elementArrayBuffer = 0;
1550 
1551 		spec.buffers.push_back(shortCoordBuffer48);
1552 
1553 		spec.useDrawElements	= false;
1554 		spec.instances			= 0;
1555 		spec.count				= 48;
1556 		spec.vao				= state;
1557 		spec.state				= state;
1558 		spec.indexOffset		= 0;
1559 		spec.indexRangeMin		= 0;
1560 		spec.indexRangeMax		= 0;
1561 		spec.indexType			= GL_NONE;
1562 		spec.indexCount			= 0;
1563 
1564 		spec.vao.attributes[0].normalized	= GL_TRUE;
1565 		spec.state.attributes[0].normalized	= GL_FALSE;;
1566 		addChild(new VertexArrayObjectTest(m_context, spec, "diff_normalize", "diff_normalize"));
1567 	}
1568 	// DrawElements with buffer / Pointer
1569 	{
1570 		Spec spec;
1571 
1572 		VertexArrayState state;
1573 
1574 		state.attributes.push_back(Attribute());
1575 
1576 		state.attributes[0].enabled		= true;
1577 		state.attributes[0].size		= 2;
1578 		state.attributes[0].stride		= 0;
1579 		state.attributes[0].type		= GL_FLOAT;
1580 		state.attributes[0].integer		= GL_FALSE;
1581 		state.attributes[0].divisor		= 0;
1582 		state.attributes[0].offset		= 0;
1583 		state.attributes[0].normalized	= GL_TRUE;
1584 		state.attributes[0].bufferNdx	= 1;
1585 
1586 		state.elementArrayBuffer = 0;
1587 
1588 		spec.buffers.push_back(floatCoordBuffer48_1);
1589 
1590 		BufferSpec indexBuffer = { 24, 192, 1, 0, 0, GL_UNSIGNED_SHORT, 0, 48, 0.0f, 0.0f };
1591 		spec.buffers.push_back(indexBuffer);
1592 
1593 		spec.useDrawElements	= true;
1594 		spec.count				= 24;
1595 		spec.vao				= state;
1596 		spec.state				= state;
1597 		spec.instances			= 0;
1598 		spec.indexOffset		= 0;
1599 		spec.indexRangeMin		= 0;
1600 		spec.indexRangeMax		= 48;
1601 		spec.indexType			= GL_UNSIGNED_SHORT;
1602 		spec.indexCount			= 24;
1603 
1604 		spec.state.elementArrayBuffer	= 0;
1605 		spec.vao.elementArrayBuffer		= 2;
1606 		addChild(new VertexArrayObjectTest(m_context, spec, "diff_indices", "diff_indices"));
1607 	}
1608 	// Use all attributes
1609 
1610 	addChild(new MultiVertexArrayObjectTest(m_context, "all_attributes", "all_attributes"));
1611 }
1612 
1613 } // Functional
1614 } // gles3
1615 } // deqp
1616