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
49using tcu::TestLog;
50
51using std::string;
52using std::vector;
53using std::set;
54using std::map;
55using std::pair;
56
57using namespace deqp::gls::AttributeLocationTestUtil;
58
59namespace deqp
60{
61namespace gls
62{
63namespace
64{
65
66deInt32 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
73bool 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
100deInt32 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
111string 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
129string 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
146string 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
173string 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
227string 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
254string 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
276string 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
307string 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
323bool 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
333string 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
349bool 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
359void 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
374void 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
412pair<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
473void 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
483void 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
497bool 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
602bool 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
631bool 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
641string generateTestName (const AttribType& type, int arraySize)
642{
643	return type.getName() + (arraySize != Attribute::NOT_ARRAY ? "_array_" + de::toString(arraySize) : "");
644}
645
646} // anonymous
647
648namespace AttributeLocationTestUtil
649{
650
651AttribType::AttribType (const string& name, deUint32 localSize, deUint32 typeEnum)
652	: m_name			(name)
653	, m_locationSize	(localSize)
654	, m_glTypeEnum		(typeEnum)
655{
656}
657
658Cond::Cond (const string& name, bool negate)
659	: m_negate	(negate)
660	, m_name	(name)
661{
662}
663
664Cond::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
671Attribute::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
680Bind::Bind (const std::string& attribute, deUint32 location)
681	: m_attribute	(attribute)
682	, m_location	(location)
683{
684}
685
686void 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
804BindAttributeTest::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
815tcu::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
829BindMaxAttributesTest::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
840tcu::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
863BindAliasingAttributeTest::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
877tcu::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
893BindMaxAliasingAttributeTest::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
904tcu::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
930BindHoleAttributeTest::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
941tcu::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
970BindInactiveAliasingAttributeTest::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
982tcu::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
1008PreAttachBindAttributeTest::PreAttachBindAttributeTest (tcu::TestContext&	testCtx,
1009														glu::RenderContext&	renderCtx)
1010	: TestCase		(testCtx, "pre_attach", "pre_attach")
1011	, m_renderCtx	(renderCtx)
1012{
1013}
1014
1015tcu::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
1029PreLinkBindAttributeTest::PreLinkBindAttributeTest (tcu::TestContext&	testCtx,
1030													glu::RenderContext&	renderCtx)
1031	: TestCase		(testCtx, "pre_link", "pre_link")
1032	, m_renderCtx	(renderCtx)
1033{
1034}
1035
1036tcu::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
1050PostLinkBindAttributeTest::PostLinkBindAttributeTest (tcu::TestContext&		testCtx,
1051													  glu::RenderContext&	renderCtx)
1052	: TestCase		(testCtx, "post_link", "post_link")
1053	, m_renderCtx	(renderCtx)
1054{
1055}
1056
1057tcu::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
1071LocationAttributeTest::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
1082tcu::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
1094LocationMaxAttributesTest::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
1105tcu::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
1126LocationHoleAttributeTest::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
1137tcu::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
1162MixedAttributeTest::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
1173tcu::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
1187MixedMaxAttributesTest::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
1198tcu::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
1227MixedHoleAttributeTest::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
1238tcu::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
1272BindRelinkAttributeTest::BindRelinkAttributeTest (tcu::TestContext&		testCtx,
1273												  glu::RenderContext&	renderCtx)
1274	: TestCase		(testCtx, "relink", "relink")
1275	, m_renderCtx	(renderCtx)
1276{
1277}
1278
1279tcu::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
1300BindRelinkHoleAttributeTest::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
1311tcu::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
1343MixedRelinkHoleAttributeTest::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
1354tcu::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
1391BindReattachAttributeTest::BindReattachAttributeTest (tcu::TestContext&		testCtx,
1392													  glu::RenderContext&	renderCtx)
1393	: TestCase		(testCtx, "reattach", "reattach")
1394	, m_renderCtx	(renderCtx)
1395{
1396}
1397
1398tcu::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
1418PreAttachMixedAttributeTest::PreAttachMixedAttributeTest (tcu::TestContext&	testCtx,
1419														glu::RenderContext&	renderCtx)
1420	: TestCase		(testCtx, "pre_attach", "pre_attach")
1421	, m_renderCtx	(renderCtx)
1422{
1423}
1424
1425tcu::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
1439PreLinkMixedAttributeTest::PreLinkMixedAttributeTest (tcu::TestContext&	testCtx,
1440													glu::RenderContext&	renderCtx)
1441	: TestCase		(testCtx, "pre_link", "pre_link")
1442	, m_renderCtx	(renderCtx)
1443{
1444}
1445
1446tcu::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
1460PostLinkMixedAttributeTest::PostLinkMixedAttributeTest (tcu::TestContext&	testCtx,
1461														glu::RenderContext&	renderCtx)
1462	: TestCase		(testCtx, "post_link", "post_link")
1463	, m_renderCtx	(renderCtx)
1464{
1465}
1466
1467tcu::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
1481MixedReattachAttributeTest::MixedReattachAttributeTest (tcu::TestContext&	testCtx,
1482														glu::RenderContext&	renderCtx)
1483	: TestCase		(testCtx, "reattach", "reattach")
1484	, m_renderCtx	(renderCtx)
1485{
1486}
1487
1488tcu::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
1508MixedRelinkAttributeTest::MixedRelinkAttributeTest (tcu::TestContext&	testCtx,
1509													glu::RenderContext&	renderCtx)
1510	: TestCase		(testCtx, "relink", "relink")
1511	, m_renderCtx	(renderCtx)
1512{
1513}
1514
1515tcu::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