1 /*-------------------------------------------------------------------------
2  * drawElements Quality Program OpenGL (ES) 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 Attribute location tests
22  *//*--------------------------------------------------------------------*/
23 
24 #include "glsAttributeLocationTests.hpp"
25 
26 #include "tcuStringTemplate.hpp"
27 #include "tcuTestLog.hpp"
28 
29 #include "gluDefs.hpp"
30 #include "gluRenderContext.hpp"
31 #include "gluShaderProgram.hpp"
32 #include "gluShaderUtil.hpp"
33 #include "gluStrUtil.hpp"
34 
35 #include "glwFunctions.hpp"
36 
37 #include "deStringUtil.hpp"
38 
39 #include <map>
40 #include <set>
41 #include <sstream>
42 #include <string>
43 #include <vector>
44 
45 #include <cstring>
46 
47 #include "glw.h"
48 
49 using tcu::TestLog;
50 
51 using std::string;
52 using std::vector;
53 using std::set;
54 using std::map;
55 using std::pair;
56 
57 using namespace deqp::gls::AttributeLocationTestUtil;
58 
59 namespace deqp
60 {
61 namespace gls
62 {
63 namespace
64 {
65 
getBoundLocation(const map<string,deUint32> & bindings,const string & attrib)66 deInt32 getBoundLocation (const map<string, deUint32>& bindings, const string& attrib)
67 {
68 	std::map<string, deUint32>::const_iterator iter = bindings.find(attrib);
69 
70 	return (iter == bindings.end() ? (deInt32)Attribute::LOC_UNDEF : iter->second);
71 }
72 
hasAttributeAliasing(const vector<Attribute> & attributes,const map<string,deUint32> & bindings)73 bool hasAttributeAliasing (const vector<Attribute>& attributes, const map<string, deUint32>& bindings)
74 {
75 	vector<bool> reservedSpaces;
76 
77 	for (int attribNdx = 0; attribNdx < (int)attributes.size(); attribNdx++)
78 	{
79 		const deInt32	location	= getBoundLocation(bindings, attributes[attribNdx].getName());
80 		const deUint32	size		= attributes[attribNdx].getType().getLocationSize();
81 
82 		if (location != Attribute::LOC_UNDEF)
83 		{
84 			if (reservedSpaces.size() < location + size)
85 				reservedSpaces.resize(location + size, false);
86 
87 			for (int i = 0; i < (int)size; i++)
88 			{
89 				if (reservedSpaces[location + i])
90 					return true;
91 
92 				reservedSpaces[location + i] = true;
93 			}
94 		}
95 	}
96 
97 	return false;
98 }
99 
getMaxAttributeLocations(glu::RenderContext & renderCtx)100 deInt32 getMaxAttributeLocations (glu::RenderContext& renderCtx)
101 {
102 	const glw::Functions& gl = renderCtx.getFunctions();
103 	deInt32 maxAttribs;
104 
105 	gl.getIntegerv(GL_MAX_VERTEX_ATTRIBS, &maxAttribs);
106 	GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv()");
107 
108 	return maxAttribs;
109 }
110 
generateAttributeDefinitions(const vector<Attribute> & attributes)111 string generateAttributeDefinitions (const vector<Attribute>& attributes)
112 {
113 	std::ostringstream src;
114 
115 	for (vector<Attribute>::const_iterator iter = attributes.begin(); iter != attributes.end(); ++iter)
116 	{
117 		if (iter->getLayoutLocation() != Attribute::LOC_UNDEF)
118 			src << "layout(location = " << iter->getLayoutLocation() << ") ";
119 
120 		src << "${VTX_INPUT} mediump "
121 			<< iter->getType().getName() << " "
122 			<< iter->getName()
123 			<<  (iter->getArraySize() != Attribute::NOT_ARRAY ? "[" + de::toString(iter->getArraySize()) + "]" : "") << ";\n";
124 	}
125 
126 	return src.str();
127 }
128 
generateConditionUniformDefinitions(const vector<Attribute> & attributes)129 string generateConditionUniformDefinitions (const vector<Attribute>& attributes)
130 {
131 	std::ostringstream src;
132 	set<string> conditions;
133 
134 	for (vector<Attribute>::const_iterator iter = attributes.begin(); iter != attributes.end(); ++iter)
135 	{
136 		if (iter->getCondition() != Cond::COND_NEVER && iter->getCondition() != Cond::COND_ALWAYS)
137 			conditions.insert(iter->getCondition().getName());
138 	}
139 
140 	for (set<string>::const_iterator iter = conditions.begin(); iter != conditions.end(); ++iter)
141 			src << "uniform mediump float u_" << (*iter) << ";\n";
142 
143 	return src.str();
144 }
145 
generateToVec4Expression(const Attribute & attrib,int id=-1)146 string generateToVec4Expression (const Attribute& attrib, int id=-1)
147 {
148 	const string		variableName(attrib.getName() + (attrib.getArraySize() != Attribute::NOT_ARRAY ? "[" + de::toString(id) + "]" : ""));
149 	std::ostringstream	src;
150 
151 	switch (attrib.getType().getGLTypeEnum())
152 	{
153 		case GL_INT_VEC2:
154 		case GL_UNSIGNED_INT_VEC2:
155 		case GL_FLOAT_VEC2:
156 			src << "vec4(" << variableName << ".xy, " << variableName << ".yx)";
157 			break;
158 
159 		case GL_INT_VEC3:
160 		case GL_UNSIGNED_INT_VEC3:
161 		case GL_FLOAT_VEC3:
162 			src << "vec4(" << variableName << ".xyz, " << variableName << ".x)";
163 			break;
164 
165 		default:
166 			src << "vec4(" << variableName << ")";
167 			break;
168 	}
169 
170 	return src.str();
171 }
172 
generateOutputCode(const vector<Attribute> & attributes)173 string generateOutputCode (const vector<Attribute>& attributes)
174 {
175 	std::ostringstream src;
176 
177 	for (vector<Attribute>::const_iterator iter = attributes.begin(); iter != attributes.end(); ++iter)
178 	{
179 		if (iter->getCondition() == Cond::COND_NEVER)
180 		{
181 			src <<
182 			"\tif (0 != 0)\n"
183 			"\t{\n";
184 
185 			if (iter->getArraySize() == Attribute::NOT_ARRAY)
186 				src << "\t\tcolor += " << generateToVec4Expression(*iter) << ";\n";
187 			else
188 			{
189 				for (int i = 0; i < iter->getArraySize(); i++)
190 					src << "\t\tcolor += " << generateToVec4Expression(*iter, i) << ";\n";
191 			}
192 
193 			src << "\t}\n";
194 		}
195 		else if (iter->getCondition() == Cond::COND_ALWAYS)
196 		{
197 			if (iter->getArraySize() == Attribute::NOT_ARRAY)
198 				src << "\tcolor += " << generateToVec4Expression(*iter) << ";\n";
199 			else
200 			{
201 				for (int i = 0; i < iter->getArraySize(); i++)
202 					src << "\tcolor += " << generateToVec4Expression(*iter, i) << ";\n";
203 			}
204 		}
205 		else
206 		{
207 			src <<
208 			"\tif (u_" << iter->getCondition().getName() << (iter->getCondition().getNegate() ? " != " : " == ") << "0.0)\n"
209 			"\t{\n";
210 
211 			if (iter->getArraySize() == Attribute::NOT_ARRAY)
212 				src << "\t\tcolor += " << generateToVec4Expression(*iter) << ";\n";
213 			else
214 			{
215 				for (int i = 0; i < iter->getArraySize(); i++)
216 					src << "\t\tcolor += " << generateToVec4Expression(*iter, i) << ";\n";
217 			}
218 
219 			src <<
220 			"\t}\n";
221 		}
222 	}
223 
224 	return src.str();
225 }
226 
generateVertexShaderTemplate(const vector<Attribute> & attributes)227 string generateVertexShaderTemplate (const vector<Attribute>& attributes)
228 {
229 	std::ostringstream src;
230 
231 	src <<	"${VERSION}\n"
232 			"${VTX_OUTPUT} mediump vec4 v_color;\n";
233 
234 	src << generateAttributeDefinitions(attributes)
235 		<< "\n"
236 		<< generateConditionUniformDefinitions(attributes)
237 		<< "\n";
238 
239 	src <<	"void main (void)\n"
240 			"{\n"
241 			"\tmediump vec4 color = vec4(0.0);\n"
242 			"\n";
243 
244 	src << generateOutputCode(attributes);
245 
246 	src <<	"\n"
247 			"\tv_color = color;\n"
248 			"\tgl_Position = color;\n"
249 			"}\n";
250 
251 	return src.str();
252 }
253 
createVertexShaderSource(glu::RenderContext & renderCtx,const vector<Attribute> & attributes,bool attributeAliasing)254 string createVertexShaderSource (glu::RenderContext& renderCtx, const vector<Attribute>& attributes, bool attributeAliasing)
255 {
256 	// \note On GLES only GLSL #version 100 supports aliasing
257 	const glu::GLSLVersion		contextGLSLVersion		= glu::getContextTypeGLSLVersion(renderCtx.getType());
258 	const glu::GLSLVersion		glslVersion				= (attributeAliasing && glu::glslVersionIsES(contextGLSLVersion) ? glu::GLSL_VERSION_100_ES : contextGLSLVersion);
259 	const bool					usesInOutQualifiers		= glu::glslVersionUsesInOutQualifiers(glslVersion);
260 	const tcu::StringTemplate	vertexShaderTemplate(generateVertexShaderTemplate(attributes));
261 
262 	map<string, string> parameters;
263 
264 	parameters["VERSION"]					= glu::getGLSLVersionDeclaration(glslVersion);
265 	parameters["VTX_OUTPUT"]				= (usesInOutQualifiers ? "out"				: "varying");
266 	parameters["VTX_INPUT"]					= (usesInOutQualifiers ? "in"				: "attribute");
267 	parameters["FRAG_INPUT"]				= (usesInOutQualifiers ? "in"				: "varying");
268 	parameters["FRAG_OUTPUT_VAR"]			= (usesInOutQualifiers ? "dEQP_FragColor"	: "gl_FragColor");
269 	parameters["FRAG_OUTPUT_DECLARATION"]	= (usesInOutQualifiers
270 													? "layout(location=0) out mediump vec4 dEQP_FragColor;"
271 													: "");
272 
273 	return vertexShaderTemplate.specialize(parameters);
274 }
275 
createFragmentShaderSource(glu::RenderContext & renderCtx,bool attributeAliasing)276 string createFragmentShaderSource (glu::RenderContext& renderCtx, bool attributeAliasing)
277 {
278 	const char* const fragmentShaderSource =
279 		"${VERSION}\n"
280 		"${FRAG_OUTPUT_DECLARATION}\n"
281 		"${FRAG_INPUT} mediump vec4 v_color;\n"
282 		"void main (void)\n"
283 		"{\n"
284 		"\t${FRAG_OUTPUT_VAR} = v_color;\n"
285 		"}\n";
286 
287 	// \note On GLES only GLSL #version 100 supports aliasing
288 	const glu::GLSLVersion		contextGLSLVersion		= glu::getContextTypeGLSLVersion(renderCtx.getType());
289 	const glu::GLSLVersion		glslVersion				= (attributeAliasing && glu::glslVersionIsES(contextGLSLVersion) ? glu::GLSL_VERSION_100_ES : contextGLSLVersion);
290 	const tcu::StringTemplate	fragmentShaderTemplate(fragmentShaderSource);
291 	const bool					usesInOutQualifiers		= glu::glslVersionUsesInOutQualifiers(glslVersion);
292 
293 	map<string, string> parameters;
294 
295 	parameters["VERSION"]					= glu::getGLSLVersionDeclaration(glslVersion);
296 	parameters["VTX_OUTPUT"]				= (usesInOutQualifiers ? "out"				: "varying");
297 	parameters["VTX_INPUT"]					= (usesInOutQualifiers ? "in"				: "attribute");
298 	parameters["FRAG_INPUT"]				= (usesInOutQualifiers ? "in"				: "varying");
299 	parameters["FRAG_OUTPUT_VAR"]			= (usesInOutQualifiers ? "dEQP_FragColor"	: "gl_FragColor");
300 	parameters["FRAG_OUTPUT_DECLARATION"]	= (usesInOutQualifiers
301 													? "layout(location=0) out mediump vec4 dEQP_FragColor;"
302 													: "");
303 
304 	return fragmentShaderTemplate.specialize(parameters);
305 }
306 
getShaderInfoLog(const glw::Functions & gl,deUint32 shader)307 string getShaderInfoLog (const glw::Functions& gl, deUint32 shader)
308 {
309 	deInt32	length = 0;
310 	string	infoLog;
311 
312 	gl.getShaderiv(shader, GL_INFO_LOG_LENGTH, &length);
313 	GLU_EXPECT_NO_ERROR(gl.getError(), "glGetShaderiv()");
314 
315 	infoLog.resize(length, '\0');
316 
317 	gl.getShaderInfoLog(shader, (glw::GLsizei)infoLog.length(), DE_NULL, &(infoLog[0]));
318 	GLU_EXPECT_NO_ERROR(gl.getError(), "glGetShaderInfoLog()");
319 
320 	return infoLog;
321 }
322 
getShaderCompileStatus(const glw::Functions & gl,deUint32 shader)323 bool getShaderCompileStatus (const glw::Functions& gl, deUint32 shader)
324 {
325 	deInt32 status;
326 
327 	gl.getShaderiv(shader, GL_COMPILE_STATUS, &status);
328 	GLU_EXPECT_NO_ERROR(gl.getError(), "glGetShaderiv()");
329 
330 	return status == GL_TRUE;
331 }
332 
getProgramInfoLog(const glw::Functions & gl,deUint32 program)333 string getProgramInfoLog (const glw::Functions& gl, deUint32 program)
334 {
335 	deInt32	length = 0;
336 	string	infoLog;
337 
338 	gl.getProgramiv(program, GL_INFO_LOG_LENGTH, &length);
339 	GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramiv()");
340 
341 	infoLog.resize(length, '\0');
342 
343 	gl.getProgramInfoLog(program, (glw::GLsizei)infoLog.length(), DE_NULL, &(infoLog[0]));
344 	GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramInfoLog()");
345 
346 	return infoLog;
347 }
348 
getProgramLinkStatus(const glw::Functions & gl,deUint32 program)349 bool getProgramLinkStatus (const glw::Functions& gl, deUint32 program)
350 {
351 	deInt32 status;
352 
353 	gl.getProgramiv(program, GL_LINK_STATUS, &status);
354 	GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramiv()");
355 
356 	return status == GL_TRUE;
357 }
358 
logProgram(TestLog & log,const glw::Functions & gl,deUint32 program)359 void logProgram (TestLog& log, const glw::Functions& gl, deUint32 program)
360 {
361 	const bool				programLinkOk	= getProgramLinkStatus(gl, program);
362 	const string			programInfoLog	= getProgramInfoLog(gl, program);
363 	tcu::ScopedLogSection	linkInfo		(log, "Program Link Info", "Program Link Info");
364 
365 	{
366 		tcu::ScopedLogSection infoLogSection(log, "Info Log", "Info Log");
367 
368 		log << TestLog::Message << programInfoLog << TestLog::EndMessage;
369 	}
370 
371 	log << TestLog::Message << "Link result: " << (programLinkOk ? "Ok" : "Fail") << TestLog::EndMessage;
372 }
373 
logShaders(TestLog & log,const string & vertexShaderSource,const string & vertexShaderInfoLog,bool vertexCompileOk,const string & fragmentShaderSource,const string & fragmentShaderInfoLog,bool fragmentCompileOk)374 void logShaders (TestLog&		log,
375 				const string&	vertexShaderSource,
376 				const string&	vertexShaderInfoLog,
377 				bool			vertexCompileOk,
378 				const string&	fragmentShaderSource,
379 				const string&	fragmentShaderInfoLog,
380 				bool			fragmentCompileOk)
381 {
382 	// \todo [mika] Log as real shader elements. Currently not supported by TestLog.
383 	{
384 		tcu::ScopedLogSection shaderSection(log, "Vertex Shader Info", "Vertex Shader Info");
385 
386 		log << TestLog::KernelSource(vertexShaderSource);
387 
388 		{
389 			tcu::ScopedLogSection infoLogSection(log, "Info Log", "Info Log");
390 
391 			log << TestLog::Message << vertexShaderInfoLog << TestLog::EndMessage;
392 		}
393 
394 		log << TestLog::Message << "Compilation result: " << (vertexCompileOk ? "Ok" : "Failed") << TestLog::EndMessage;
395 	}
396 
397 	{
398 		tcu::ScopedLogSection shaderSection(log, "Fragment Shader Info", "Fragment Shader Info");
399 
400 		log << TestLog::KernelSource(fragmentShaderSource);
401 
402 		{
403 			tcu::ScopedLogSection infoLogSection(log, "Info Log", "Info Log");
404 
405 			log << TestLog::Message << fragmentShaderInfoLog << TestLog::EndMessage;
406 		}
407 
408 		log << TestLog::Message << "Compilation result: " << (fragmentCompileOk ? "Ok" : "Failed") << TestLog::EndMessage;
409 	}
410 }
411 
createAndAttachShaders(TestLog & log,glu::RenderContext & renderCtx,deUint32 program,const vector<Attribute> & attributes,bool attributeAliasing)412 pair<deUint32, deUint32> createAndAttachShaders (TestLog& log, glu::RenderContext& renderCtx, deUint32 program, const vector<Attribute>& attributes, bool attributeAliasing)
413 {
414 	const glw::Functions&	gl						= renderCtx.getFunctions();
415 	const string			vertexShaderSource		= createVertexShaderSource(renderCtx, attributes, attributeAliasing);
416 	const string			fragmentShaderSource	= createFragmentShaderSource(renderCtx, attributeAliasing);
417 
418 	const deUint32			vertexShader			= gl.createShader(GL_VERTEX_SHADER);
419 	const deUint32			fragmentShader			= gl.createShader(GL_FRAGMENT_SHADER);
420 
421 	try
422 	{
423 		GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShader()");
424 
425 		{
426 			const char* const vertexShaderString	= vertexShaderSource.c_str();
427 			const char* const fragmentShaderString	= fragmentShaderSource.c_str();
428 
429 			gl.shaderSource(vertexShader, 1, &vertexShaderString, DE_NULL);
430 			gl.shaderSource(fragmentShader, 1, &fragmentShaderString, DE_NULL);
431 
432 			GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource()");
433 		}
434 
435 		gl.compileShader(vertexShader);
436 		gl.compileShader(fragmentShader);
437 		GLU_EXPECT_NO_ERROR(gl.getError(), "glCompileShader()");
438 
439 		gl.attachShader(program, vertexShader);
440 		gl.attachShader(program, fragmentShader);
441 		GLU_EXPECT_NO_ERROR(gl.getError(), "glAttachShader()");
442 
443 		{
444 			const bool		vertexCompileOk			= getShaderCompileStatus(gl, vertexShader);
445 			const bool		fragmentCompileOk		= getShaderCompileStatus(gl, fragmentShader);
446 
447 			const string	vertexShaderInfoLog		= getShaderInfoLog(gl, vertexShader);
448 			const string	fragmentShaderInfoLog	= getShaderInfoLog(gl, fragmentShader);
449 
450 			logShaders(log, vertexShaderSource, vertexShaderInfoLog, vertexCompileOk, fragmentShaderSource, fragmentShaderInfoLog, fragmentCompileOk);
451 
452 			TCU_CHECK_MSG(vertexCompileOk, "Vertex shader compilation failed");
453 			TCU_CHECK_MSG(fragmentCompileOk, "Fragment shader compilation failed");
454 		}
455 
456 		gl.deleteShader(vertexShader);
457 		gl.deleteShader(fragmentShader);
458 
459 		return pair<deUint32, deUint32>(vertexShader, fragmentShader);
460 	}
461 	catch (...)
462 	{
463 		if (vertexShader != 0)
464 			gl.deleteShader(vertexShader);
465 
466 		if (fragmentShader != 0)
467 			gl.deleteShader(fragmentShader);
468 
469 		throw;
470 	}
471 }
472 
bindAttributes(TestLog & log,const glw::Functions & gl,deUint32 program,const vector<Bind> & binds)473 void bindAttributes (TestLog& log, const glw::Functions& gl, deUint32 program, const vector<Bind>& binds)
474 {
475 	for (vector<Bind>::const_iterator iter = binds.begin(); iter != binds.end(); ++iter)
476 	{
477 		log << TestLog::Message << "Bind attribute: '" << iter->getAttributeName() << "' to " << iter->getLocation() << TestLog::EndMessage;
478 		gl.bindAttribLocation(program, iter->getLocation(), iter->getAttributeName().c_str());
479 		GLU_EXPECT_NO_ERROR(gl.getError(), "glBindAttribLocation()");
480 	}
481 }
482 
logAttributes(TestLog & log,const vector<Attribute> & attributes)483 void logAttributes (TestLog& log, const vector<Attribute>& attributes)
484 {
485 	for (int attribNdx = 0; attribNdx < (int)attributes.size(); attribNdx++)
486 	{
487 		const Attribute& attrib = attributes[attribNdx];
488 
489 		log << TestLog::Message
490 			<< "Type: " << attrib.getType().getName()
491 			<< ", Name: " << attrib.getName()
492 			<< (attrib.getLayoutLocation()	!= Attribute::LOC_UNDEF ? ", Layout location "	+ de::toString(attrib.getLayoutLocation()) : "")
493 			<< TestLog::EndMessage;
494 	}
495 }
496 
checkActiveAttribQuery(TestLog & log,const glw::Functions & gl,deUint32 program,const vector<Attribute> & attributes)497 bool checkActiveAttribQuery (TestLog& log, const glw::Functions& gl, deUint32 program, const vector<Attribute>& attributes)
498 {
499 	deInt32					activeAttribCount = 0;
500 	set<string>				activeAttributes;
501 	bool					isOk = true;
502 
503 	gl.getProgramiv(program, GL_ACTIVE_ATTRIBUTES, &activeAttribCount);
504 	GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramiv(program, GL_ACTIVE_ATTRIBUTES, &activeAttribCount)");
505 
506 	for (int activeAttribNdx = 0; activeAttribNdx < activeAttribCount; activeAttribNdx++)
507 	{
508 		char			name[128];
509 		const size_t	maxNameSize = DE_LENGTH_OF_ARRAY(name) - 1;
510 		deInt32			length = 0;
511 		deInt32			size = 0;
512 		deUint32		type = 0;
513 
514 		std::memset(name, 0, sizeof(name));
515 
516 		gl.getActiveAttrib(program, activeAttribNdx, maxNameSize, &length, &size, &type, name);
517 		GLU_EXPECT_NO_ERROR(gl.getError(), "glGetActiveAttrib()");
518 
519 		log << TestLog::Message
520 			<< "glGetActiveAttrib(program"
521 			<< ", index=" << activeAttribNdx
522 			<< ", bufSize=" << maxNameSize
523 			<< ", length=" << length
524 			<< ", size=" << size
525 			<< ", type=" << glu::getShaderVarTypeStr(type)
526 			<< ", name='" << name << "')" << TestLog::EndMessage;
527 
528 		{
529 			bool found = false;
530 
531 			for (int attribNdx = 0; attribNdx < (int)attributes.size(); attribNdx++)
532 			{
533 				const Attribute& attrib = attributes[attribNdx];
534 
535 				if (attrib.getName() == name)
536 				{
537 					if (type != attrib.getType().getGLTypeEnum())
538 					{
539 						log << TestLog::Message
540 							<< "Error: Wrong type " << glu::getShaderVarTypeStr(type)
541 							<< " expected " << glu::getShaderVarTypeStr(attrib.getType().getGLTypeEnum())
542 							<< TestLog::EndMessage;
543 
544 						isOk = false;
545 					}
546 
547 					if (attrib.getArraySize() == Attribute::NOT_ARRAY)
548 					{
549 						if (size != 1)
550 						{
551 							log << TestLog::Message << "Error: Wrong size " << size << " expected " << 1 << TestLog::EndMessage;
552 							isOk = false;
553 						}
554 					}
555 					else
556 					{
557 						if (size != attrib.getArraySize())
558 						{
559 							log << TestLog::Message << "Error: Wrong size " << size << " expected " << attrib.getArraySize() << TestLog::EndMessage;
560 							isOk = false;
561 						}
562 					}
563 
564 					found = true;
565 					break;
566 				}
567 			}
568 
569 			if (!found)
570 			{
571 				log << TestLog::Message << "Error: Unknown attribute '" << name << "' returned by glGetActiveAttrib()." << TestLog::EndMessage;
572 				isOk = false;
573 			}
574 		}
575 
576 		activeAttributes.insert(name);
577 	}
578 
579 	for (int attribNdx = 0; attribNdx < (int)attributes.size(); attribNdx++)
580 	{
581 		const Attribute&	attrib		= attributes[attribNdx];
582 		const bool			isActive	= attrib.getCondition() != Cond::COND_NEVER;
583 
584 		if (isActive)
585 		{
586 			if (activeAttributes.find(attrib.getName()) == activeAttributes.end())
587 			{
588 				log << TestLog::Message << "Error: Active attribute " << attrib.getName() << " wasn't returned by glGetActiveAttrib()." << TestLog::EndMessage;
589 				isOk = false;
590 			}
591 		}
592 		else
593 		{
594 			if (activeAttributes.find(attrib.getName()) != activeAttributes.end())
595 				log << TestLog::Message << "Note: Inactive attribute " << attrib.getName() << " was returned by glGetActiveAttrib()." << TestLog::EndMessage;
596 		}
597 	}
598 
599 	return isOk;
600 }
601 
checkAttribLocationQuery(TestLog & log,const glw::Functions & gl,deUint32 program,const vector<Attribute> & attributes,const map<string,deUint32> & bindings)602 bool checkAttribLocationQuery (TestLog& log, const glw::Functions& gl, deUint32 program, const vector<Attribute>& attributes, const map<string, deUint32>& bindings)
603 {
604 	bool isOk = true;
605 
606 	for (int attribNdx = 0; attribNdx < (int)attributes.size(); attribNdx++)
607 	{
608 		const Attribute&	attrib				= attributes[attribNdx];
609 		const deInt32		expectedLocation	= (attrib.getLayoutLocation() != Attribute::LOC_UNDEF ? attrib.getLayoutLocation() : getBoundLocation(bindings, attrib.getName()));
610 		const deInt32		location			= gl.getAttribLocation(program, attrib.getName().c_str());
611 
612 		GLU_EXPECT_NO_ERROR(gl.getError(), "glGetAttribLocation()");
613 
614 		log << TestLog::Message
615 			<< location << " = glGetAttribLocation(program, \"" << attrib.getName() << "\")"
616 			<< (attrib.getCondition() != Cond::COND_NEVER && expectedLocation != Attribute::LOC_UNDEF ? ", expected " + de::toString(expectedLocation) : "")
617 			<< "." << TestLog::EndMessage;
618 
619 		if (attrib.getCondition() == Cond::COND_NEVER && location != -1)
620 			log << TestLog::Message << "\tNote: Inactive attribute with location." << TestLog::EndMessage;
621 
622 		if (attrib.getCondition() != Cond::COND_NEVER && expectedLocation != Attribute::LOC_UNDEF && expectedLocation != location)
623 			log << TestLog::Message << "\tError: Invalid attribute location." << TestLog::EndMessage;
624 
625 		isOk &= (attrib.getCondition() == Cond::COND_NEVER || expectedLocation == Attribute::LOC_UNDEF || expectedLocation == location);
626 	}
627 
628 	return isOk;
629 }
630 
checkQuery(TestLog & log,const glw::Functions & gl,deUint32 program,const vector<Attribute> & attributes,const map<string,deUint32> & bindings)631 bool checkQuery (TestLog& log, const glw::Functions& gl, deUint32 program, const vector<Attribute>& attributes, const map<string, deUint32>& bindings)
632 {
633 	bool isOk = checkActiveAttribQuery(log, gl, program, attributes);
634 
635 	if (!checkAttribLocationQuery(log, gl, program, attributes, bindings))
636 		isOk = false;
637 
638 	return isOk;
639 }
640 
generateTestName(const AttribType & type,int arraySize)641 string generateTestName (const AttribType& type, int arraySize)
642 {
643 	return type.getName() + (arraySize != Attribute::NOT_ARRAY ? "_array_" + de::toString(arraySize) : "");
644 }
645 
646 } // anonymous
647 
648 namespace AttributeLocationTestUtil
649 {
650 
AttribType(const string & name,deUint32 localSize,deUint32 typeEnum)651 AttribType::AttribType (const string& name, deUint32 localSize, deUint32 typeEnum)
652 	: m_name			(name)
653 	, m_locationSize	(localSize)
654 	, m_glTypeEnum		(typeEnum)
655 {
656 }
657 
Cond(const string & name,bool negate)658 Cond::Cond (const string& name, bool negate)
659 	: m_negate	(negate)
660 	, m_name	(name)
661 {
662 }
663 
Cond(ConstCond cond)664 Cond::Cond (ConstCond cond)
665 	: m_negate	(cond != COND_NEVER)
666 	, m_name	("__always__")
667 {
668 	DE_ASSERT(cond == COND_ALWAYS || cond == COND_NEVER);
669 }
670 
Attribute(const AttribType & type,const string & name,deInt32 layoutLocation,const Cond & cond,int arraySize)671 Attribute::Attribute (const AttribType& type, const string& name, deInt32 layoutLocation, const Cond& cond, int arraySize)
672 	: m_type			(type)
673 	, m_name			(name)
674 	, m_layoutLocation	(layoutLocation)
675 	, m_cond			(cond)
676 	, m_arraySize		(arraySize)
677 {
678 }
679 
Bind(const std::string & attribute,deUint32 location)680 Bind::Bind (const std::string& attribute, deUint32 location)
681 	: m_attribute	(attribute)
682 	, m_location	(location)
683 {
684 }
685 
runTest(tcu::TestContext & testCtx,glu::RenderContext & renderCtx,const vector<Attribute> & attributes,const vector<Bind> & preAttachBind,const vector<Bind> & preLinkBind,const vector<Bind> & postLinkBind,bool relink,bool reattach=false,const vector<Attribute> & reattachAttributes=vector<Attribute> ())686 void runTest (tcu::TestContext&			testCtx,
687 			glu::RenderContext&			renderCtx,
688 			const vector<Attribute>&	attributes,
689 			const vector<Bind>&			preAttachBind,
690 			const vector<Bind>&			preLinkBind,
691 			const vector<Bind>&			postLinkBind,
692 			bool						relink,
693 			bool						reattach = false,
694 			const vector<Attribute>&	reattachAttributes = vector<Attribute>())
695 {
696 	TestLog&					log			= testCtx.getLog();
697 	const glw::Functions&		gl			= renderCtx.getFunctions();
698 	deUint32					program 	= 0;
699 	pair<deUint32, deUint32>	shaders;
700 
701 	try
702 	{
703 		bool					isOk			= true;
704 		map<string, deUint32>	activeBindings;
705 
706 		for (int bindNdx = 0; bindNdx < (int)preAttachBind.size(); bindNdx++)
707 			activeBindings[preAttachBind[bindNdx].getAttributeName()] = preAttachBind[bindNdx].getLocation();
708 
709 		for (int bindNdx = 0; bindNdx < (int)preLinkBind.size(); bindNdx++)
710 			activeBindings[preLinkBind[bindNdx].getAttributeName()] = preLinkBind[bindNdx].getLocation();
711 
712 		{
713 			tcu::ScopedLogSection section(log, "Attributes", "Attribute information");
714 			logAttributes(testCtx.getLog(), attributes);
715 		}
716 
717 		log << TestLog::Message << "Create program." << TestLog::EndMessage;
718 		program = gl.createProgram();
719 		GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateProgram()");
720 
721 		if (!preAttachBind.empty())
722 			bindAttributes(log, gl, program, preAttachBind);
723 
724 		log << TestLog::Message << "Create and attach shaders to program." << TestLog::EndMessage;
725 		shaders = createAndAttachShaders(log, renderCtx, program, attributes, hasAttributeAliasing(attributes, activeBindings));
726 
727 		if (!preLinkBind.empty())
728 			bindAttributes(log, gl, program, preLinkBind);
729 
730 		log << TestLog::Message << "Link program." << TestLog::EndMessage;
731 
732 		gl.linkProgram(program);
733 		GLU_EXPECT_NO_ERROR(gl.getError(), "glLinkProgram()");
734 
735 		logProgram(log, gl, program);
736 		TCU_CHECK_MSG(getProgramLinkStatus(gl, program), "Program link failed");
737 
738 		if (!checkQuery(log, gl, program, attributes, activeBindings))
739 			isOk = false;
740 
741 		if (!postLinkBind.empty())
742 		{
743 			bindAttributes(log, gl, program, postLinkBind);
744 
745 			if (!checkQuery(log, gl, program, attributes, activeBindings))
746 				isOk = false;
747 		}
748 
749 		if (relink)
750 		{
751 			log << TestLog::Message << "Relink program." << TestLog::EndMessage;
752 			gl.linkProgram(program);
753 			GLU_EXPECT_NO_ERROR(gl.getError(), "glLinkProgram()");
754 
755 			logProgram(log, gl, program);
756 			TCU_CHECK_MSG(getProgramLinkStatus(gl, program), "Program link failed");
757 
758 			for (int bindNdx = 0; bindNdx < (int)postLinkBind.size(); bindNdx++)
759 				activeBindings[postLinkBind[bindNdx].getAttributeName()] = postLinkBind[bindNdx].getLocation();
760 
761 			if (!checkQuery(log, gl, program, attributes, activeBindings))
762 				isOk = false;
763 		}
764 
765 		if (reattach)
766 		{
767 			gl.detachShader(program, shaders.first);
768 			gl.detachShader(program, shaders.second);
769 			GLU_EXPECT_NO_ERROR(gl.getError(), "glDetachShader()");
770 
771 			log << TestLog::Message << "Create and attach shaders to program." << TestLog::EndMessage;
772 			createAndAttachShaders(log, renderCtx, program, reattachAttributes, hasAttributeAliasing(reattachAttributes, activeBindings));
773 
774 			log << TestLog::Message << "Relink program." << TestLog::EndMessage;
775 			gl.linkProgram(program);
776 			GLU_EXPECT_NO_ERROR(gl.getError(), "glLinkProgram()");
777 
778 			logProgram(log, gl, program);
779 			TCU_CHECK_MSG(getProgramLinkStatus(gl, program), "Program link failed");
780 
781 			if (!checkQuery(log, gl, program, reattachAttributes, activeBindings))
782 				isOk = false;
783 		}
784 
785 		gl.deleteProgram(program);
786 		GLU_EXPECT_NO_ERROR(gl.getError(), "glDeleteProgram()");
787 
788 		if (isOk)
789 			testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
790 		else
791 			testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
792 	}
793 	catch (...)
794 	{
795 		if (program)
796 			gl.deleteProgram(program);
797 
798 		throw;
799 	}
800 }
801 
802 } // AttributeLocationTestUtil
803 
BindAttributeTest(tcu::TestContext & testCtx,glu::RenderContext & renderCtx,const AttribType & type,int arraySize)804 BindAttributeTest::BindAttributeTest (tcu::TestContext&		testCtx,
805 									  glu::RenderContext&	renderCtx,
806 									  const AttribType&		type,
807 									  int					arraySize)
808 	: TestCase		(testCtx, generateTestName(type, arraySize).c_str(), generateTestName(type, arraySize).c_str())
809 	, m_renderCtx	(renderCtx)
810 	, m_type		(type)
811 	, m_arraySize	(arraySize)
812 {
813 }
814 
iterate(void)815 tcu::TestCase::IterateResult BindAttributeTest::iterate (void)
816 {
817 	const vector<Bind>	noBindings;
818 
819 	vector<Attribute>	attributes;
820 	vector<Bind>		bindings;
821 
822 	attributes.push_back(Attribute(m_type, "a_0", Attribute::LOC_UNDEF, Cond::COND_ALWAYS, m_arraySize));
823 	bindings.push_back(Bind("a_0", 3));
824 
825 	runTest(m_testCtx, m_renderCtx, attributes, noBindings, bindings, noBindings, false);
826 	return STOP;
827 }
828 
BindMaxAttributesTest(tcu::TestContext & testCtx,glu::RenderContext & renderCtx,const AttribType & type,int arraySize)829 BindMaxAttributesTest::BindMaxAttributesTest (tcu::TestContext&		testCtx,
830 											  glu::RenderContext&	renderCtx,
831 											  const AttribType&		type,
832 											  int					arraySize)
833 	: TestCase		(testCtx,  generateTestName(type, arraySize).c_str(), generateTestName(type, arraySize).c_str())
834 	, m_renderCtx	(renderCtx)
835 	, m_type		(type)
836 	, m_arraySize	(arraySize)
837 {
838 }
839 
iterate(void)840 tcu::TestCase::IterateResult BindMaxAttributesTest::iterate (void)
841 {
842 	const vector<Bind>	noBindings;
843 	const deInt32		maxAttributes		= getMaxAttributeLocations(m_renderCtx);
844 	const int			arrayElementCount	= (m_arraySize != Attribute::NOT_ARRAY ? m_arraySize : 1);
845 
846 	vector<Attribute>	attributes;
847 	vector<Bind>		bindings;
848 	int					ndx = 0;
849 
850 	m_testCtx.getLog() << TestLog::Message << "GL_MAX_VERTEX_ATTRIBS: " << maxAttributes << TestLog::EndMessage;
851 
852 	for (int loc = maxAttributes - (arrayElementCount * m_type.getLocationSize()); loc >= 0; loc -= (arrayElementCount * m_type.getLocationSize()))
853 	{
854 		attributes.push_back(Attribute(m_type, "a_" + de::toString(ndx), Attribute::LOC_UNDEF, Cond::COND_ALWAYS, m_arraySize));
855 		bindings.push_back(Bind("a_" + de::toString(ndx), loc));
856 		ndx++;
857 	}
858 
859 	runTest(m_testCtx, m_renderCtx, attributes, noBindings, bindings, noBindings, false);
860 	return STOP;
861 }
862 
BindAliasingAttributeTest(tcu::TestContext & testCtx,glu::RenderContext & renderCtx,const AttribType & type,int offset,int arraySize)863 BindAliasingAttributeTest::BindAliasingAttributeTest (tcu::TestContext&		testCtx,
864 													  glu::RenderContext&	renderCtx,
865 													  const AttribType&		type,
866 													  int					offset,
867 													  int					arraySize)
868 	: TestCase		(testCtx,	("cond_" + generateTestName(type, arraySize) + (offset != 0 ? "_offset_" + de::toString(offset) : "")).c_str(),
869 								("cond_" + generateTestName(type, arraySize) + (offset != 0 ? "_offset_" + de::toString(offset) : "")).c_str())
870 	, m_renderCtx	(renderCtx)
871 	, m_type		(type)
872 	, m_offset		(offset)
873 	, m_arraySize	(arraySize)
874 {
875 }
876 
iterate(void)877 tcu::TestCase::IterateResult BindAliasingAttributeTest::iterate (void)
878 {
879 	const vector<Bind>	noBindings;
880 
881 	vector<Attribute>	attributes;
882 	vector<Bind>		bindings;
883 
884 	attributes.push_back(Attribute(m_type, "a_0", Attribute::LOC_UNDEF, Cond("A", true), m_arraySize));
885 	attributes.push_back(Attribute(AttribType("vec4", 1, GL_FLOAT_VEC4), "a_1", Attribute::LOC_UNDEF, Cond("A", false)));
886 	bindings.push_back(Bind("a_0", 1));
887 	bindings.push_back(Bind("a_1", 1 + m_offset));
888 
889 	runTest(m_testCtx, m_renderCtx, attributes, noBindings, bindings, noBindings, false);
890 	return STOP;
891 }
892 
BindMaxAliasingAttributeTest(tcu::TestContext & testCtx,glu::RenderContext & renderCtx,const AttribType & type,int arraySize)893 BindMaxAliasingAttributeTest::BindMaxAliasingAttributeTest (tcu::TestContext&	testCtx,
894 															glu::RenderContext&	renderCtx,
895 															const AttribType&	type,
896 															int					arraySize)
897 	: TestCase		(testCtx, ("max_cond_" + generateTestName(type, arraySize)).c_str(), ("max_cond_" + generateTestName(type, arraySize)).c_str())
898 	, m_renderCtx	(renderCtx)
899 	, m_type		(type)
900 	, m_arraySize	(arraySize)
901 {
902 }
903 
iterate(void)904 tcu::TestCase::IterateResult BindMaxAliasingAttributeTest::iterate (void)
905 {
906 	const vector<Bind>	noBindings;
907 	const deInt32		maxAttributes		= getMaxAttributeLocations(m_renderCtx);
908 	const int			arrayElementCount	= (m_arraySize != Attribute::NOT_ARRAY ? m_arraySize : 1);
909 
910 	vector<Attribute>	attributes;
911 	vector<Bind>		bindings;
912 	int					ndx = 0;
913 
914 	m_testCtx.getLog() << TestLog::Message << "GL_MAX_VERTEX_ATTRIBS: " << maxAttributes << TestLog::EndMessage;
915 
916 	for (int loc = maxAttributes - arrayElementCount * m_type.getLocationSize(); loc >= 0; loc -= m_type.getLocationSize() * arrayElementCount)
917 	{
918 		attributes.push_back(Attribute(m_type, "a_" + de::toString(ndx), Attribute::LOC_UNDEF, Cond("A", true)));
919 		bindings.push_back(Bind("a_" + de::toString(ndx), loc));
920 
921 		attributes.push_back(Attribute(m_type, "a_" + de::toString(ndx + maxAttributes), Attribute::LOC_UNDEF, Cond("A", false)));
922 		bindings.push_back(Bind("a_" + de::toString(ndx + maxAttributes), loc));
923 		ndx++;
924 	}
925 
926 	runTest(m_testCtx, m_renderCtx, attributes, noBindings, bindings, noBindings, false);
927 	return STOP;
928 }
929 
BindHoleAttributeTest(tcu::TestContext & testCtx,glu::RenderContext & renderCtx,const AttribType & type,int arraySize)930 BindHoleAttributeTest::BindHoleAttributeTest (tcu::TestContext&		testCtx,
931 											  glu::RenderContext&	renderCtx,
932 											  const AttribType&		type,
933 											  int					arraySize)
934 	: TestCase		(testCtx, generateTestName(type, arraySize).c_str(), generateTestName(type, arraySize).c_str())
935 	, m_renderCtx	(renderCtx)
936 	, m_type		(type)
937 	, m_arraySize	(arraySize)
938 {
939 }
940 
iterate(void)941 tcu::TestCase::IterateResult BindHoleAttributeTest::iterate (void)
942 {
943 	const vector<Bind>	noBindings;
944 	const deInt32		maxAttributes = getMaxAttributeLocations(m_renderCtx);
945 	const AttribType	vec4("vec4", 1, GL_FLOAT_VEC4);
946 	const int			arrayElementCount	= (m_arraySize != Attribute::NOT_ARRAY ? m_arraySize : 1);
947 
948 	vector<Attribute>	attributes;
949 	vector<Bind>		bindings;
950 	int					ndx;
951 
952 	attributes.push_back(Attribute(vec4, "a_0"));
953 	bindings.push_back(Bind("a_0", 0));
954 
955 	attributes.push_back(Attribute(m_type, "a_1", Attribute::LOC_UNDEF, Cond::COND_ALWAYS, m_arraySize));
956 
957 	ndx = 2;
958 	for (int loc = 1 + m_type.getLocationSize() * arrayElementCount; loc < maxAttributes; loc++)
959 	{
960 		attributes.push_back(Attribute(vec4, "a_" + de::toString(ndx)));
961 		bindings.push_back(Bind("a_" + de::toString(ndx), loc));
962 
963 		ndx++;
964 	}
965 
966 	runTest(m_testCtx, m_renderCtx, attributes, noBindings, bindings, noBindings, false);
967 	return STOP;
968 }
969 
BindInactiveAliasingAttributeTest(tcu::TestContext & testCtx,glu::RenderContext & renderCtx,const AttribType & type,int arraySize)970 BindInactiveAliasingAttributeTest::BindInactiveAliasingAttributeTest (tcu::TestContext&		testCtx,
971 																	  glu::RenderContext&	renderCtx,
972 																	  const AttribType&		type,
973 																	  int					arraySize)
974 	: TestCase		(testCtx,	("max_inactive_" + generateTestName(type, arraySize)).c_str(),
975 								("max_inactive_" + generateTestName(type, arraySize)).c_str())
976 	, m_renderCtx	(renderCtx)
977 	, m_type		(type)
978 	, m_arraySize	(arraySize)
979 {
980 }
981 
iterate(void)982 tcu::TestCase::IterateResult BindInactiveAliasingAttributeTest::iterate (void)
983 {
984 	const vector<Bind>	noBindings;
985 	const deInt32		maxAttributes		= getMaxAttributeLocations(m_renderCtx);
986 	const int			arrayElementCount	= (m_arraySize != Attribute::NOT_ARRAY ? m_arraySize : 1);
987 
988 	vector<Attribute>	attributes;
989 	vector<Bind>		bindings;
990 	int					ndx = 0;
991 
992 	m_testCtx.getLog() << TestLog::Message << "GL_MAX_VERTEX_ATTRIBS: " << maxAttributes << TestLog::EndMessage;
993 
994 	for (int loc = maxAttributes - arrayElementCount * m_type.getLocationSize(); loc >= 0; loc -= m_type.getLocationSize() * arrayElementCount)
995 	{
996 		attributes.push_back(Attribute(m_type, "a_" + de::toString(ndx), Attribute::LOC_UNDEF, Cond("A")));
997 		bindings.push_back(Bind("a_" + de::toString(ndx), loc));
998 
999 		attributes.push_back(Attribute(m_type, "a_" + de::toString(ndx + maxAttributes), Attribute::LOC_UNDEF, Cond::COND_NEVER));
1000 		bindings.push_back(Bind("a_" + de::toString(ndx + maxAttributes), loc));
1001 		ndx++;
1002 	}
1003 
1004 	runTest(m_testCtx, m_renderCtx, attributes, noBindings, bindings, noBindings, false);
1005 	return STOP;
1006 }
1007 
PreAttachBindAttributeTest(tcu::TestContext & testCtx,glu::RenderContext & renderCtx)1008 PreAttachBindAttributeTest::PreAttachBindAttributeTest (tcu::TestContext&	testCtx,
1009 														glu::RenderContext&	renderCtx)
1010 	: TestCase		(testCtx, "pre_attach", "pre_attach")
1011 	, m_renderCtx	(renderCtx)
1012 {
1013 }
1014 
iterate(void)1015 tcu::TestCase::IterateResult PreAttachBindAttributeTest::iterate (void)
1016 {
1017 	const vector<Bind>	noBindings;
1018 
1019 	vector<Attribute>	attributes;
1020 	vector<Bind>		bindings;
1021 
1022 	attributes.push_back(Attribute(AttribType("vec4", 1, GL_FLOAT_VEC4), "a_0"));
1023 	bindings.push_back(Bind("a_0", 3));
1024 
1025 	runTest(m_testCtx, m_renderCtx, attributes, bindings, noBindings, noBindings, false);
1026 	return STOP;
1027 }
1028 
PreLinkBindAttributeTest(tcu::TestContext & testCtx,glu::RenderContext & renderCtx)1029 PreLinkBindAttributeTest::PreLinkBindAttributeTest (tcu::TestContext&	testCtx,
1030 													glu::RenderContext&	renderCtx)
1031 	: TestCase		(testCtx, "pre_link", "pre_link")
1032 	, m_renderCtx	(renderCtx)
1033 {
1034 }
1035 
iterate(void)1036 tcu::TestCase::IterateResult PreLinkBindAttributeTest::iterate (void)
1037 {
1038 	const vector<Bind>	noBindings;
1039 
1040 	vector<Attribute>	attributes;
1041 	vector<Bind>		bindings;
1042 
1043 	attributes.push_back(Attribute(AttribType("vec4", 1, GL_FLOAT_VEC4), "a_0"));
1044 	bindings.push_back(Bind("a_0", 3));
1045 
1046 	runTest(m_testCtx, m_renderCtx, attributes, noBindings, bindings, noBindings, false);
1047 	return STOP;
1048 }
1049 
PostLinkBindAttributeTest(tcu::TestContext & testCtx,glu::RenderContext & renderCtx)1050 PostLinkBindAttributeTest::PostLinkBindAttributeTest (tcu::TestContext&		testCtx,
1051 													  glu::RenderContext&	renderCtx)
1052 	: TestCase		(testCtx, "post_link", "post_link")
1053 	, m_renderCtx	(renderCtx)
1054 {
1055 }
1056 
iterate(void)1057 tcu::TestCase::IterateResult PostLinkBindAttributeTest::iterate (void)
1058 {
1059 	const vector<Bind>	noBindings;
1060 
1061 	vector<Attribute>	attributes;
1062 	vector<Bind>		bindings;
1063 
1064 	attributes.push_back(Attribute(AttribType("vec4", 1, GL_FLOAT_VEC4), "a_0"));
1065 	bindings.push_back(Bind("a_0", 3));
1066 
1067 	runTest(m_testCtx, m_renderCtx, attributes, noBindings, noBindings, bindings, false);
1068 	return STOP;
1069 }
1070 
LocationAttributeTest(tcu::TestContext & testCtx,glu::RenderContext & renderCtx,const AttribType & type,int arraySize)1071 LocationAttributeTest::LocationAttributeTest (tcu::TestContext&		testCtx,
1072 											  glu::RenderContext&	renderCtx,
1073 											  const AttribType&		type,
1074 											  int					arraySize)
1075 	: TestCase		(testCtx, generateTestName(type, arraySize).c_str(), generateTestName(type, arraySize).c_str())
1076 	, m_renderCtx	(renderCtx)
1077 	, m_type		(type)
1078 	, m_arraySize	(arraySize)
1079 {
1080 }
1081 
iterate(void)1082 tcu::TestCase::IterateResult LocationAttributeTest::iterate (void)
1083 {
1084 	const vector<Bind>	noBindings;
1085 
1086 	vector<Attribute>	attributes;
1087 
1088 	attributes.push_back(Attribute(m_type, "a_0", 3, Cond::COND_ALWAYS, m_arraySize));
1089 
1090 	runTest(m_testCtx, m_renderCtx, attributes, noBindings, noBindings, noBindings, false);
1091 	return STOP;
1092 }
1093 
LocationMaxAttributesTest(tcu::TestContext & testCtx,glu::RenderContext & renderCtx,const AttribType & type,int arraySize)1094 LocationMaxAttributesTest::LocationMaxAttributesTest (tcu::TestContext&		testCtx,
1095 													  glu::RenderContext&	renderCtx,
1096 													  const AttribType&		type,
1097 													  int					arraySize)
1098 	: TestCase		(testCtx, generateTestName(type, arraySize).c_str(), generateTestName(type, arraySize).c_str())
1099 	, m_renderCtx	(renderCtx)
1100 	, m_type		(type)
1101 	, m_arraySize	(arraySize)
1102 {
1103 }
1104 
iterate(void)1105 tcu::TestCase::IterateResult LocationMaxAttributesTest::iterate (void)
1106 {
1107 	const vector<Bind>	noBindings;
1108 	const deInt32		maxAttributes		= getMaxAttributeLocations(m_renderCtx);
1109 	const int			arrayElementCount	= (m_arraySize != Attribute::NOT_ARRAY ? m_arraySize : 1);
1110 
1111 	vector<Attribute>	attributes;
1112 	int					ndx = 0;
1113 
1114 	m_testCtx.getLog() << TestLog::Message << "GL_MAX_VERTEX_ATTRIBS: " << maxAttributes << TestLog::EndMessage;
1115 
1116 	for (int loc = maxAttributes - (arrayElementCount * m_type.getLocationSize()); loc >= 0; loc -= (arrayElementCount * m_type.getLocationSize()))
1117 	{
1118 		attributes.push_back(Attribute(m_type, "a_" + de::toString(ndx), loc, Cond::COND_ALWAYS, m_arraySize));
1119 		ndx++;
1120 	}
1121 
1122 	runTest(m_testCtx, m_renderCtx, attributes, noBindings, noBindings, noBindings, false);
1123 	return STOP;
1124 }
1125 
LocationHoleAttributeTest(tcu::TestContext & testCtx,glu::RenderContext & renderCtx,const AttribType & type,int arraySize)1126 LocationHoleAttributeTest::LocationHoleAttributeTest (tcu::TestContext&		testCtx,
1127 													  glu::RenderContext&	renderCtx,
1128 													  const AttribType&		type,
1129 													  int					arraySize)
1130 	: TestCase		(testCtx, generateTestName(type, arraySize).c_str(), generateTestName(type, arraySize).c_str())
1131 	, m_renderCtx	(renderCtx)
1132 	, m_type		(type)
1133 	, m_arraySize	(arraySize)
1134 {
1135 }
1136 
iterate(void)1137 tcu::TestCase::IterateResult LocationHoleAttributeTest::iterate (void)
1138 {
1139 	const vector<Bind>	noBindings;
1140 	const deInt32		maxAttributes = getMaxAttributeLocations(m_renderCtx);
1141 	const AttribType	vec4("vec4", 1, GL_FLOAT_VEC4);
1142 	const int			arrayElementCount	= (m_arraySize != Attribute::NOT_ARRAY ? m_arraySize : 1);
1143 
1144 	vector<Attribute>	attributes;
1145 	int					ndx;
1146 
1147 	attributes.push_back(Attribute(vec4, "a_0", 0));
1148 
1149 	attributes.push_back(Attribute(m_type, "a_1", Attribute::LOC_UNDEF, Cond::COND_ALWAYS, m_arraySize));
1150 
1151 	ndx = 2;
1152 	for (int loc = 1 + m_type.getLocationSize() * arrayElementCount; loc < maxAttributes; loc++)
1153 	{
1154 		attributes.push_back(Attribute(vec4, "a_" + de::toString(ndx), loc));
1155 		ndx++;
1156 	}
1157 
1158 	runTest(m_testCtx, m_renderCtx, attributes, noBindings, noBindings, noBindings, false);
1159 	return STOP;
1160 }
1161 
MixedAttributeTest(tcu::TestContext & testCtx,glu::RenderContext & renderCtx,const AttribType & type,int arraySize)1162 MixedAttributeTest::MixedAttributeTest (tcu::TestContext&	testCtx,
1163 										glu::RenderContext&	renderCtx,
1164 										const AttribType&	type,
1165 										int					arraySize)
1166 	: TestCase		(testCtx, generateTestName(type, arraySize).c_str(), generateTestName(type, arraySize).c_str())
1167 	, m_renderCtx	(renderCtx)
1168 	, m_type		(type)
1169 	, m_arraySize	(arraySize)
1170 {
1171 }
1172 
iterate(void)1173 tcu::TestCase::IterateResult MixedAttributeTest::iterate (void)
1174 {
1175 	const vector<Bind>	noBindings;
1176 
1177 	vector<Bind>		bindings;
1178 	vector<Attribute>	attributes;
1179 
1180 	attributes.push_back(Attribute(m_type, "a_0", 3, Cond::COND_ALWAYS, m_arraySize));
1181 	bindings.push_back(Bind("a_0", 4));
1182 
1183 	runTest(m_testCtx, m_renderCtx, attributes, noBindings, bindings, noBindings, false);
1184 	return STOP;
1185 }
1186 
MixedMaxAttributesTest(tcu::TestContext & testCtx,glu::RenderContext & renderCtx,const AttribType & type,int arraySize)1187 MixedMaxAttributesTest::MixedMaxAttributesTest (tcu::TestContext&	testCtx,
1188 												glu::RenderContext&	renderCtx,
1189 												const AttribType&	type,
1190 												int					arraySize)
1191 	: TestCase		(testCtx, generateTestName(type, arraySize).c_str(), generateTestName(type, arraySize).c_str())
1192 	, m_renderCtx	(renderCtx)
1193 	, m_type		(type)
1194 	, m_arraySize	(arraySize)
1195 {
1196 }
1197 
iterate(void)1198 tcu::TestCase::IterateResult MixedMaxAttributesTest::iterate (void)
1199 {
1200 	const vector<Bind>	noBindings;
1201 	const deInt32		maxAttributes		= getMaxAttributeLocations(m_renderCtx);
1202 	const int			arrayElementCount	= (m_arraySize != Attribute::NOT_ARRAY ? m_arraySize : 1);
1203 
1204 	vector<Bind>		bindings;
1205 	vector<Attribute>	attributes;
1206 	int					ndx = 0;
1207 
1208 	m_testCtx.getLog() << TestLog::Message << "GL_MAX_VERTEX_ATTRIBS: " << maxAttributes << TestLog::EndMessage;
1209 
1210 	for (int loc = maxAttributes - (arrayElementCount * m_type.getLocationSize()); loc >= 0; loc -= (arrayElementCount * m_type.getLocationSize()))
1211 	{
1212 		if ((ndx % 2) != 0)
1213 			attributes.push_back(Attribute(m_type, "a_" + de::toString(ndx), loc, Cond::COND_ALWAYS, m_arraySize));
1214 		else
1215 		{
1216 			attributes.push_back(Attribute(m_type, "a_" + de::toString(ndx), Attribute::LOC_UNDEF, Cond::COND_ALWAYS, m_arraySize));
1217 			bindings.push_back(Bind("a_" + de::toString(ndx), loc));
1218 
1219 		}
1220 		ndx++;
1221 	}
1222 
1223 	runTest(m_testCtx, m_renderCtx, attributes, noBindings, bindings, noBindings, false);
1224 	return STOP;
1225 }
1226 
MixedHoleAttributeTest(tcu::TestContext & testCtx,glu::RenderContext & renderCtx,const AttribType & type,int arraySize)1227 MixedHoleAttributeTest::MixedHoleAttributeTest (tcu::TestContext&		testCtx,
1228 												glu::RenderContext&		renderCtx,
1229 												const AttribType&		type,
1230 												int						arraySize)
1231 	: TestCase		(testCtx, generateTestName(type, arraySize).c_str(), generateTestName(type, arraySize).c_str())
1232 	, m_renderCtx	(renderCtx)
1233 	, m_type		(type)
1234 	, m_arraySize	(arraySize)
1235 {
1236 }
1237 
iterate(void)1238 tcu::TestCase::IterateResult MixedHoleAttributeTest::iterate (void)
1239 {
1240 	const vector<Bind>	noBindings;
1241 	const deInt32		maxAttributes = getMaxAttributeLocations(m_renderCtx);
1242 	const AttribType	vec4("vec4", 1, GL_FLOAT_VEC4);
1243 	const int			arrayElementCount	= (m_arraySize != Attribute::NOT_ARRAY ? m_arraySize : 1);
1244 
1245 	vector<Bind>		bindings;
1246 	vector<Attribute>	attributes;
1247 	int					ndx;
1248 
1249 	attributes.push_back(Attribute(vec4, "a_0"));
1250 	bindings.push_back(Bind("a_0", 0));
1251 
1252 	attributes.push_back(Attribute(m_type, "a_1", Attribute::LOC_UNDEF, Cond::COND_ALWAYS, m_arraySize));
1253 
1254 	ndx = 2;
1255 	for (int loc = 1 + m_type.getLocationSize() * arrayElementCount; loc < maxAttributes; loc++)
1256 	{
1257 		if ((ndx % 2) != 0)
1258 			attributes.push_back(Attribute(vec4, "a_" + de::toString(ndx), loc));
1259 		else
1260 		{
1261 			attributes.push_back(Attribute(vec4, "a_" + de::toString(ndx), loc));
1262 			bindings.push_back(Bind("a_" + de::toString(ndx), loc));
1263 
1264 		}
1265 		ndx++;
1266 	}
1267 
1268 	runTest(m_testCtx, m_renderCtx, attributes, noBindings, bindings, noBindings, false);
1269 	return STOP;
1270 }
1271 
BindRelinkAttributeTest(tcu::TestContext & testCtx,glu::RenderContext & renderCtx)1272 BindRelinkAttributeTest::BindRelinkAttributeTest (tcu::TestContext&		testCtx,
1273 												  glu::RenderContext&	renderCtx)
1274 	: TestCase		(testCtx, "relink", "relink")
1275 	, m_renderCtx	(renderCtx)
1276 {
1277 }
1278 
iterate(void)1279 tcu::TestCase::IterateResult BindRelinkAttributeTest::iterate (void)
1280 {
1281 	const vector<Bind>	noBindings;
1282 	const AttribType	vec4("vec4", 1, GL_FLOAT_VEC4);
1283 
1284 	vector<Attribute>	attributes;
1285 	vector<Bind>		preLinkBindings;
1286 	vector<Bind>		postLinkBindings;
1287 
1288 	attributes.push_back(Attribute(vec4, "a_0"));
1289 	attributes.push_back(Attribute(vec4, "a_1"));
1290 
1291 	preLinkBindings.push_back(Bind("a_0", 3));
1292 	preLinkBindings.push_back(Bind("a_0", 5));
1293 
1294 	postLinkBindings.push_back(Bind("a_0", 6));
1295 
1296 	runTest(m_testCtx, m_renderCtx, attributes, noBindings, preLinkBindings, postLinkBindings, true);
1297 	return STOP;
1298 }
1299 
BindRelinkHoleAttributeTest(tcu::TestContext & testCtx,glu::RenderContext & renderCtx,const AttribType & type,int arraySize)1300 BindRelinkHoleAttributeTest::BindRelinkHoleAttributeTest (tcu::TestContext&		testCtx,
1301 														  glu::RenderContext&	renderCtx,
1302 														  const AttribType&		type,
1303 														  int					arraySize)
1304 	: TestCase		(testCtx, generateTestName(type, arraySize).c_str(), generateTestName(type, arraySize).c_str())
1305 	, m_renderCtx	(renderCtx)
1306 	, m_type		(type)
1307 	, m_arraySize	(arraySize)
1308 {
1309 }
1310 
iterate(void)1311 tcu::TestCase::IterateResult BindRelinkHoleAttributeTest::iterate (void)
1312 {
1313 	const vector<Bind>	noBindings;
1314 	const deInt32		maxAttributes		= getMaxAttributeLocations(m_renderCtx);
1315 	const AttribType	vec4				("vec4", 1, GL_FLOAT_VEC4);
1316 	const int			arrayElementCount	= (m_arraySize != Attribute::NOT_ARRAY ? m_arraySize : 1);
1317 
1318 	vector<Attribute>	attributes;
1319 	vector<Bind>		preLinkBindings;
1320 	vector<Bind>		postLinkBindings;
1321 	int					ndx;
1322 
1323 	attributes.push_back(Attribute(vec4, "a_0"));
1324 	preLinkBindings.push_back(Bind("a_0", 0));
1325 
1326 	attributes.push_back(Attribute(m_type, "a_1", Attribute::LOC_UNDEF, Cond::COND_ALWAYS, m_arraySize));
1327 
1328 	ndx = 2;
1329 	for (int loc = 1 + m_type.getLocationSize() * arrayElementCount; loc < maxAttributes; loc++)
1330 	{
1331 		attributes.push_back(Attribute(vec4, "a_" + de::toString(ndx)));
1332 		preLinkBindings.push_back(Bind("a_" + de::toString(ndx), loc));
1333 
1334 		ndx++;
1335 	}
1336 
1337 	postLinkBindings.push_back(Bind("a_2", 1));
1338 
1339 	runTest(m_testCtx, m_renderCtx, attributes, noBindings, preLinkBindings, postLinkBindings, true);
1340 	return STOP;
1341 }
1342 
MixedRelinkHoleAttributeTest(tcu::TestContext & testCtx,glu::RenderContext & renderCtx,const AttribType & type,int arraySize)1343 MixedRelinkHoleAttributeTest::MixedRelinkHoleAttributeTest (tcu::TestContext&		testCtx,
1344 															glu::RenderContext&		renderCtx,
1345 															const AttribType&		type,
1346 															int						arraySize)
1347 	: TestCase		(testCtx, generateTestName(type, arraySize).c_str(), generateTestName(type, arraySize).c_str())
1348 	, m_renderCtx	(renderCtx)
1349 	, m_type		(type)
1350 	, m_arraySize	(arraySize)
1351 {
1352 }
1353 
iterate(void)1354 tcu::TestCase::IterateResult MixedRelinkHoleAttributeTest::iterate (void)
1355 {
1356 	const vector<Bind>	noBindings;
1357 	const deInt32		maxAttributes		= getMaxAttributeLocations(m_renderCtx);
1358 	const AttribType	vec4				("vec4", 1, GL_FLOAT_VEC4);
1359 	const int			arrayElementCount	= (m_arraySize != Attribute::NOT_ARRAY ? m_arraySize : 1);
1360 
1361 	vector<Bind>		preLinkBindings;
1362 	vector<Bind>		postLinkBindings;
1363 	vector<Attribute>	attributes;
1364 	int					ndx;
1365 
1366 	attributes.push_back(Attribute(vec4, "a_0"));
1367 	preLinkBindings.push_back(Bind("a_0", 0));
1368 
1369 	attributes.push_back(Attribute(m_type, "a_1", Attribute::LOC_UNDEF, Cond::COND_ALWAYS, m_arraySize));
1370 
1371 	ndx = 2;
1372 	for (int loc = 1 + m_type.getLocationSize() * arrayElementCount; loc < maxAttributes; loc++)
1373 	{
1374 		if ((ndx % 2) != 0)
1375 			attributes.push_back(Attribute(vec4, "a_" + de::toString(ndx), loc));
1376 		else
1377 		{
1378 			attributes.push_back(Attribute(vec4, "a_" + de::toString(ndx)));
1379 			preLinkBindings.push_back(Bind("a_" + de::toString(ndx), loc));
1380 
1381 		}
1382 		ndx++;
1383 	}
1384 
1385 	postLinkBindings.push_back(Bind("a_2", 1));
1386 
1387 	runTest(m_testCtx, m_renderCtx, attributes, noBindings, preLinkBindings, postLinkBindings, true);
1388 	return STOP;
1389 }
1390 
BindReattachAttributeTest(tcu::TestContext & testCtx,glu::RenderContext & renderCtx)1391 BindReattachAttributeTest::BindReattachAttributeTest (tcu::TestContext&		testCtx,
1392 													  glu::RenderContext&	renderCtx)
1393 	: TestCase		(testCtx, "reattach", "reattach")
1394 	, m_renderCtx	(renderCtx)
1395 {
1396 }
1397 
iterate(void)1398 tcu::TestCase::IterateResult BindReattachAttributeTest::iterate (void)
1399 {
1400 	const vector<Bind>	noBindings;
1401 	const AttribType	vec4("vec4", 1, GL_FLOAT_VEC4);
1402 	const AttribType	vec2("vec2", 1, GL_FLOAT_VEC2);
1403 
1404 	vector<Bind>		bindings;
1405 	vector<Attribute>	attributes;
1406 	vector<Attribute>	reattachAttributes;
1407 
1408 	attributes.push_back(Attribute(vec4, "a_0"));
1409 	bindings.push_back(Bind("a_0", 1));
1410 	bindings.push_back(Bind("a_1", 1));
1411 
1412 	reattachAttributes.push_back(Attribute(vec2, "a_1"));
1413 
1414 	runTest(m_testCtx, m_renderCtx, attributes, noBindings, bindings, noBindings, false, true, reattachAttributes);
1415 	return STOP;
1416 }
1417 
PreAttachMixedAttributeTest(tcu::TestContext & testCtx,glu::RenderContext & renderCtx)1418 PreAttachMixedAttributeTest::PreAttachMixedAttributeTest (tcu::TestContext&	testCtx,
1419 														glu::RenderContext&	renderCtx)
1420 	: TestCase		(testCtx, "pre_attach", "pre_attach")
1421 	, m_renderCtx	(renderCtx)
1422 {
1423 }
1424 
iterate(void)1425 tcu::TestCase::IterateResult PreAttachMixedAttributeTest::iterate (void)
1426 {
1427 	const vector<Bind>	noBindings;
1428 
1429 	vector<Attribute>	attributes;
1430 	vector<Bind>		bindings;
1431 
1432 	attributes.push_back(Attribute(AttribType("vec4", 1, GL_FLOAT_VEC4), "a_0", 1));
1433 	bindings.push_back(Bind("a_0", 3));
1434 
1435 	runTest(m_testCtx, m_renderCtx, attributes, bindings, noBindings, noBindings, false);
1436 	return STOP;
1437 }
1438 
PreLinkMixedAttributeTest(tcu::TestContext & testCtx,glu::RenderContext & renderCtx)1439 PreLinkMixedAttributeTest::PreLinkMixedAttributeTest (tcu::TestContext&	testCtx,
1440 													glu::RenderContext&	renderCtx)
1441 	: TestCase		(testCtx, "pre_link", "pre_link")
1442 	, m_renderCtx	(renderCtx)
1443 {
1444 }
1445 
iterate(void)1446 tcu::TestCase::IterateResult PreLinkMixedAttributeTest::iterate (void)
1447 {
1448 	const vector<Bind>	noBindings;
1449 
1450 	vector<Attribute>	attributes;
1451 	vector<Bind>		bindings;
1452 
1453 	attributes.push_back(Attribute(AttribType("vec4", 1, GL_FLOAT_VEC4), "a_0", 1));
1454 	bindings.push_back(Bind("a_0", 3));
1455 
1456 	runTest(m_testCtx, m_renderCtx, attributes, noBindings, bindings, noBindings, false);
1457 	return STOP;
1458 }
1459 
PostLinkMixedAttributeTest(tcu::TestContext & testCtx,glu::RenderContext & renderCtx)1460 PostLinkMixedAttributeTest::PostLinkMixedAttributeTest (tcu::TestContext&	testCtx,
1461 														glu::RenderContext&	renderCtx)
1462 	: TestCase		(testCtx, "post_link", "post_link")
1463 	, m_renderCtx	(renderCtx)
1464 {
1465 }
1466 
iterate(void)1467 tcu::TestCase::IterateResult PostLinkMixedAttributeTest::iterate (void)
1468 {
1469 	const vector<Bind>	noBindings;
1470 
1471 	vector<Attribute>	attributes;
1472 	vector<Bind>		bindings;
1473 
1474 	attributes.push_back(Attribute(AttribType("vec4", 1, GL_FLOAT_VEC4), "a_0", 1));
1475 	bindings.push_back(Bind("a_0", 3));
1476 
1477 	runTest(m_testCtx, m_renderCtx, attributes, noBindings, noBindings, bindings, false);
1478 	return STOP;
1479 }
1480 
MixedReattachAttributeTest(tcu::TestContext & testCtx,glu::RenderContext & renderCtx)1481 MixedReattachAttributeTest::MixedReattachAttributeTest (tcu::TestContext&	testCtx,
1482 														glu::RenderContext&	renderCtx)
1483 	: TestCase		(testCtx, "reattach", "reattach")
1484 	, m_renderCtx	(renderCtx)
1485 {
1486 }
1487 
iterate(void)1488 tcu::TestCase::IterateResult MixedReattachAttributeTest::iterate (void)
1489 {
1490 	const vector<Bind>	noBindings;
1491 	const AttribType	vec4("vec4", 1, GL_FLOAT_VEC4);
1492 	const AttribType	vec2("vec2", 1, GL_FLOAT_VEC2);
1493 
1494 	vector<Bind>		bindings;
1495 	vector<Attribute>	attributes;
1496 	vector<Attribute>	reattachAttributes;
1497 
1498 	attributes.push_back(Attribute(vec4, "a_0", 2));
1499 	bindings.push_back(Bind("a_0", 1));
1500 	bindings.push_back(Bind("a_1", 1));
1501 
1502 	reattachAttributes.push_back(Attribute(vec2, "a_1"));
1503 
1504 	runTest(m_testCtx, m_renderCtx, attributes, noBindings, bindings, noBindings, false, true, reattachAttributes);
1505 	return STOP;
1506 }
1507 
MixedRelinkAttributeTest(tcu::TestContext & testCtx,glu::RenderContext & renderCtx)1508 MixedRelinkAttributeTest::MixedRelinkAttributeTest (tcu::TestContext&	testCtx,
1509 													glu::RenderContext&	renderCtx)
1510 	: TestCase		(testCtx, "relink", "relink")
1511 	, m_renderCtx	(renderCtx)
1512 {
1513 }
1514 
iterate(void)1515 tcu::TestCase::IterateResult MixedRelinkAttributeTest::iterate (void)
1516 {
1517 	const vector<Bind>	noBindings;
1518 	const AttribType	vec4("vec4", 1, GL_FLOAT_VEC4);
1519 
1520 	vector<Attribute>	attributes;
1521 	vector<Bind>		preLinkBindings;
1522 	vector<Bind>		postLinkBindings;
1523 
1524 	attributes.push_back(Attribute(vec4, "a_0", 1));
1525 	attributes.push_back(Attribute(vec4, "a_1"));
1526 
1527 	preLinkBindings.push_back(Bind("a_0", 3));
1528 	preLinkBindings.push_back(Bind("a_0", 5));
1529 
1530 	postLinkBindings.push_back(Bind("a_0", 6));
1531 
1532 	runTest(m_testCtx, m_renderCtx, attributes, noBindings, preLinkBindings, postLinkBindings, true);
1533 	return STOP;
1534 }
1535 
1536 } // gls
1537 } // deqp
1538