• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*-------------------------------------------------------------------------
2  * drawElements Quality Program OpenGL ES 3.1 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 Explicit uniform location tests
22  *//*--------------------------------------------------------------------*/
23 
24 #include "es31fUniformLocationTests.hpp"
25 
26 #include "tcuTestLog.hpp"
27 #include "tcuTextureUtil.hpp"
28 #include "tcuVectorUtil.hpp"
29 #include "tcuCommandLine.hpp"
30 
31 #include "glsShaderLibrary.hpp"
32 #include "glsTextureTestUtil.hpp"
33 
34 #include "gluShaderProgram.hpp"
35 #include "gluTexture.hpp"
36 #include "gluPixelTransfer.hpp"
37 #include "gluVarType.hpp"
38 #include "gluVarTypeUtil.hpp"
39 
40 #include "glwFunctions.hpp"
41 #include "glwEnums.hpp"
42 #include "sglrContextUtil.hpp"
43 
44 #include "deStringUtil.hpp"
45 #include "deUniquePtr.hpp"
46 #include "deString.h"
47 #include "deRandom.hpp"
48 #include "deInt32.h"
49 
50 #include <set>
51 #include <map>
52 
53 namespace deqp
54 {
55 namespace gles31
56 {
57 namespace Functional
58 {
59 namespace
60 {
61 
62 using std::string;
63 using std::vector;
64 using std::map;
65 using de::UniquePtr;
66 using glu::VarType;
67 
68 struct UniformInfo
69 {
70 	enum ShaderStage
71 	{
72 		SHADERSTAGE_NONE	= 0,
73 		SHADERSTAGE_VERTEX	= (1<<0),
74 		SHADERSTAGE_FRAGMENT= (1<<1),
75 		SHADERSTAGE_BOTH	= (SHADERSTAGE_VERTEX | SHADERSTAGE_FRAGMENT),
76 	};
77 
78 	VarType			type;
79 	ShaderStage		declareLocation; // support declarations with/without layout qualifiers, needed for linkage testing
80 	ShaderStage		layoutLocation;
81 	ShaderStage		checkLocation;
82 	int				location; // -1 for unset
83 
UniformInfodeqp::gles31::Functional::__anon2611c92f0111::UniformInfo84 	UniformInfo (VarType type_, ShaderStage declareLocation_, ShaderStage layoutLocation_, ShaderStage checkLocation_, int location_ = -1)
85 		: type				(type_)
86 		, declareLocation	(declareLocation_)
87 		, layoutLocation	(layoutLocation_)
88 		, checkLocation		(checkLocation_)
89 		, location			(location_)
90 	{
91 	}
92 };
93 
94 class UniformLocationCase : public tcu::TestCase
95 {
96 public:
97 								UniformLocationCase		(tcu::TestContext&			context,
98 														 glu::RenderContext&		renderContext,
99 														 const char*				name,
100 														 const char*				desc,
101 														 const vector<UniformInfo>&	uniformInfo);
~UniformLocationCase(void)102 	virtual						~UniformLocationCase	(void) {}
103 
104 	virtual IterateResult		iterate					(void);
105 
106 protected:
107 	IterateResult				run						(const vector<UniformInfo>& uniformList);
108 	static glu::ProgramSources	genShaderSources		(const vector<UniformInfo>& uniformList);
109 	bool						verifyLocations			(const glu::ShaderProgram& program, const vector<UniformInfo>& uniformList);
110 	void						render					(const glu::ShaderProgram& program, const vector<UniformInfo>& uniformList);
111 	static bool					verifyResult			(const tcu::ConstPixelBufferAccess& access);
112 
113 	static float				getExpectedValue		(glu::DataType type, int id, const char* name);
114 
115 	de::MovePtr<glu::Texture2D>	createTexture			(glu::DataType samplerType, float redChannelValue, int binding);
116 
117 	glu::RenderContext&			m_renderCtx;
118 
119 	const vector<UniformInfo>	m_uniformInfo;
120 
121 	enum
122 	{
123 		RENDER_SIZE = 16
124 	};
125 };
126 
getUniformName(int ndx,const glu::VarType & type,const glu::TypeComponentVector & path)127 string getUniformName (int ndx, const glu::VarType& type, const glu::TypeComponentVector& path)
128 {
129 	std::ostringstream buff;
130 	buff << "uni" << ndx << glu::TypeAccessFormat(type, path);
131 
132 	return buff.str();
133 }
134 
getFirstComponentName(const glu::VarType & type)135 string getFirstComponentName (const glu::VarType& type)
136 {
137 	std::ostringstream buff;
138 	if (glu::isDataTypeVector(type.getBasicType()))
139 		buff << glu::TypeAccessFormat(type, glu::SubTypeAccess(type).component(0).getPath());
140 	else if (glu::isDataTypeMatrix(type.getBasicType()))
141 		buff << glu::TypeAccessFormat(type, glu::SubTypeAccess(type).column(0).component(0).getPath());
142 
143 	return buff.str();
144 }
145 
UniformLocationCase(tcu::TestContext & context,glu::RenderContext & renderContext,const char * name,const char * desc,const vector<UniformInfo> & uniformInfo)146 UniformLocationCase::UniformLocationCase (tcu::TestContext&				context,
147 										  glu::RenderContext&			renderContext,
148 										  const char*					name,
149 										  const char*					desc,
150 										  const vector<UniformInfo>&	uniformInfo)
151 	: TestCase			(context, name, desc)
152 	, m_renderCtx		(renderContext)
153 	, m_uniformInfo		(uniformInfo)
154 {
155 }
156 
157 // [from, to]
shuffledRange(int from,int to,int seed)158 std::vector<int> shuffledRange (int from, int to, int seed)
159 {
160 	const int	count	= to - from;
161 
162 	vector<int> retval	(count);
163 	de::Random	rng		(seed);
164 
165 	DE_ASSERT(count > 0);
166 
167 	for (int ndx = 0; ndx < count; ndx++)
168 		retval[ndx] = ndx + from;
169 
170 	rng.shuffle(retval.begin(), retval.end());
171 	return retval;
172 }
173 
getDataTypeSamplerSampleType(glu::DataType type)174 glu::DataType getDataTypeSamplerSampleType (glu::DataType type)
175 {
176 	using namespace glu;
177 
178 	if (type >= TYPE_SAMPLER_1D && type <= TYPE_SAMPLER_3D)
179 		return TYPE_FLOAT_VEC4;
180 	else if (type >= TYPE_INT_SAMPLER_1D && type <= TYPE_INT_SAMPLER_3D)
181 		return TYPE_INT_VEC4;
182 	else if (type >= TYPE_UINT_SAMPLER_1D && type <= TYPE_UINT_SAMPLER_3D)
183 		return TYPE_UINT_VEC4;
184 	else if (type >= TYPE_SAMPLER_1D_SHADOW && type <=	TYPE_SAMPLER_2D_ARRAY_SHADOW)
185 		return TYPE_FLOAT;
186 	else
187 		DE_FATAL("Unknown sampler type");
188 
189 	return TYPE_INVALID;
190 }
191 
192 // A (hopefully) unique value for a uniform. For multi-component types creates only one value. Values are in the range [0,1] for floats, [-128, 127] for ints, [0,255] for uints and 0/1 for booleans. Samplers are treated according to the types they return.
getExpectedValue(glu::DataType type,int id,const char * name)193 float UniformLocationCase::getExpectedValue (glu::DataType type, int id, const char* name)
194 {
195 	const deUint32	hash			= deStringHash(name) + deInt32Hash(id);
196 
197 	glu::DataType	adjustedType	= type;
198 
199 	if (glu::isDataTypeSampler(type))
200 		adjustedType = getDataTypeSamplerSampleType(type);
201 
202 	if (glu::isDataTypeIntOrIVec(adjustedType))
203 		return float(hash%128);
204 	else if (glu::isDataTypeUintOrUVec(adjustedType))
205 		return float(hash%255);
206 	else if (glu::isDataTypeFloatOrVec(adjustedType))
207 		return float(hash%255)/255.0f;
208 	else if (glu::isDataTypeBoolOrBVec(adjustedType))
209 		return float(hash%2);
210 	else
211 		DE_FATAL("Unkown primitive type");
212 
213 	return glu::TYPE_INVALID;
214 }
215 
iterate(void)216 UniformLocationCase::IterateResult UniformLocationCase::iterate (void)
217 {
218 	return run(m_uniformInfo);
219 }
220 
run(const vector<UniformInfo> & uniformList)221 UniformLocationCase::IterateResult UniformLocationCase::run (const vector<UniformInfo>& uniformList)
222 {
223 	using gls::TextureTestUtil::RandomViewport;
224 
225 	const glu::ProgramSources	sources		= genShaderSources(uniformList);
226 	const glu::ShaderProgram	program		(m_renderCtx, sources);
227 	const int					baseSeed	= m_testCtx.getCommandLine().getBaseSeed();
228 	const glw::Functions&		gl			= m_renderCtx.getFunctions();
229 	const RandomViewport		viewport	(m_renderCtx.getRenderTarget(), RENDER_SIZE, RENDER_SIZE, deStringHash(getName()) + baseSeed);
230 
231 	tcu::Surface				rendered	(RENDER_SIZE, RENDER_SIZE);
232 
233 	if (!verifyLocations(program, uniformList))
234 		return STOP;
235 
236 	gl.clearColor(0.0f, 0.0f, 0.0f, 1.0f);
237 	gl.clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
238 	gl.viewport(viewport.x, viewport.y, viewport.width, viewport.height);
239 
240 	render(program, uniformList);
241 
242 	glu::readPixels(m_renderCtx, viewport.x, viewport.y, rendered.getAccess());
243 	GLU_EXPECT_NO_ERROR(gl.getError(), "error in readPixels");
244 
245 	if (!verifyResult(rendered.getAccess()))
246 	{
247 		m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Shader produced incorrect result");
248 		return STOP;
249 	}
250 
251 	m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
252 	return STOP;
253 }
254 
genShaderSources(const vector<UniformInfo> & uniformList)255 glu::ProgramSources UniformLocationCase::genShaderSources (const vector<UniformInfo>& uniformList)
256 {
257 	std::ostringstream	vertDecl, vertMain, fragDecl, fragMain;
258 
259 	vertDecl << "#version 310 es\n"
260 			 << "precision highp float;\n"
261 			 << "precision highp int;\n"
262 			 << "float verify(float val, float ref) { return float(abs(val-ref) < 0.05); }\n\n"
263 			 << "in highp vec4 a_position;\n"
264 			 << "out highp vec4 v_color;\n";
265 	fragDecl << "#version 310 es\n\n"
266 			 << "precision highp float;\n"
267 			 << "precision highp int;\n"
268 			 << "float verify(float val, float ref) { return float(abs(val-ref) < 0.05); }\n\n"
269 			 << "in highp vec4 v_color;\n"
270 			 << "layout(location = 0) out mediump vec4 o_color;\n\n";
271 
272 	vertMain << "void main()\n{\n"
273 			 << "	gl_Position = a_position;\n"
274 			 << "	v_color = vec4(1.0);\n";
275 
276 	fragMain << "void main()\n{\n"
277 			 << "	o_color = v_color;\n";
278 
279 	std::set<const glu::StructType*> declaredStructs;
280 
281 	// Declare uniforms
282 	for (int uniformNdx = 0; uniformNdx < int(uniformList.size()); uniformNdx++)
283 	{
284 		const UniformInfo&	uniformInfo = uniformList[uniformNdx];
285 
286 		const bool			declareInVert	= (uniformInfo.declareLocation & UniformInfo::SHADERSTAGE_VERTEX)   != 0;
287 		const bool			declareInFrag	= (uniformInfo.declareLocation & UniformInfo::SHADERSTAGE_FRAGMENT) != 0;
288 		const bool			layoutInVert    = (uniformInfo.layoutLocation  & UniformInfo::SHADERSTAGE_VERTEX)   != 0;
289 		const bool			layoutInFrag    = (uniformInfo.layoutLocation  & UniformInfo::SHADERSTAGE_FRAGMENT) != 0;
290 		const bool			checkInVert		= (uniformInfo.checkLocation   & UniformInfo::SHADERSTAGE_VERTEX)   != 0;
291 		const bool			checkInFrag		= (uniformInfo.checkLocation   & UniformInfo::SHADERSTAGE_FRAGMENT) != 0;
292 
293 		const string		layout			= uniformInfo.location >= 0 ? "layout(location = " + de::toString(uniformInfo.location) + ") " : "";
294 		const string		uniName			= "uni" + de::toString(uniformNdx);
295 
296 		int					location		= uniformInfo.location;
297 		int					subTypeIndex	= 0;
298 
299 		DE_ASSERT((declareInVert && layoutInVert) || !layoutInVert); // Cannot have layout without declaration
300 		DE_ASSERT((declareInFrag && layoutInFrag) || !layoutInFrag);
301 		DE_ASSERT(location<0 || (layoutInVert || layoutInFrag)); // Cannot have location without layout
302 
303 		// struct definitions
304 		if (uniformInfo.type.isStructType())
305 		{
306 			const glu::StructType* const structType = uniformInfo.type.getStructPtr();
307 			if (!declaredStructs.count(structType))
308 			{
309 				if (declareInVert)
310 					vertDecl << glu::declare(structType, 0) << ";\n";
311 
312 				if (declareInFrag)
313 					fragDecl << glu::declare(structType, 0) << ";\n";
314 
315 				declaredStructs.insert(structType);
316 			}
317 		}
318 
319 		if (declareInVert)
320 			vertDecl << "uniform " << (layoutInVert ? layout : "") << glu::declare(uniformInfo.type, uniName) << ";\n";
321 
322 		if (declareInFrag)
323 			fragDecl << "uniform " << (layoutInFrag ? layout : "") << glu::declare(uniformInfo.type, uniName) << ";\n";
324 
325 		// Anything that needs to be done for each enclosed primitive type
326 		for (glu::BasicTypeIterator subTypeIter = glu::BasicTypeIterator::begin(&uniformInfo.type); subTypeIter != glu::BasicTypeIterator::end(&uniformInfo.type); subTypeIter++, subTypeIndex++)
327 		{
328 			const glu::VarType	subType		= glu::getVarType(uniformInfo.type, subTypeIter.getPath());
329 			const glu::DataType	scalarType	= glu::getDataTypeScalarType(subType.getBasicType());
330 			const char* const	typeName	= glu::getDataTypeName(scalarType);
331 			const string		expectValue	= de::floatToString(getExpectedValue(scalarType, location >= 0 ? location+subTypeIndex : -1, typeName), 3);
332 
333 			if (glu::isDataTypeSampler(scalarType))
334 			{
335 				if (checkInVert)
336 					vertMain << "	v_color.rgb *= verify(float( texture(" << uniName
337 							 << glu::TypeAccessFormat(uniformInfo.type, subTypeIter.getPath())
338 							 << ", vec2(0.5)).r), " << expectValue << ");\n";
339 				if (checkInFrag)
340 					fragMain << "	o_color.rgb *= verify(float( texture(" << uniName
341 							 << glu::TypeAccessFormat(uniformInfo.type, subTypeIter.getPath())
342 							 << ", vec2(0.5)).r), " << expectValue << ");\n";
343 			}
344 			else
345 			{
346 				if (checkInVert)
347 					vertMain << "	v_color.rgb *= verify(float(" << uniName
348 							 << glu::TypeAccessFormat(uniformInfo.type, subTypeIter.getPath())
349 							 << getFirstComponentName(subType) << "), " << expectValue << ");\n";
350 				if (checkInFrag)
351 					fragMain << "	o_color.rgb *= verify(float(" << uniName
352 							 << glu::TypeAccessFormat(uniformInfo.type, subTypeIter.getPath())
353 							 << getFirstComponentName(subType) << "), " << expectValue << ");\n";
354 			}
355 		}
356 	}
357 
358 	vertMain << "}\n";
359 	fragMain << "}\n";
360 
361 	return glu::makeVtxFragSources(vertDecl.str() + vertMain.str(), fragDecl.str() + fragMain.str());
362 }
363 
verifyLocations(const glu::ShaderProgram & program,const vector<UniformInfo> & uniformList)364 bool UniformLocationCase::verifyLocations (const glu::ShaderProgram& program, const vector<UniformInfo>& uniformList)
365 {
366 	using tcu::TestLog;
367 
368 	const glw::Functions&	gl			= m_renderCtx.getFunctions();
369 	const bool				vertexOk	= program.getShaderInfo(glu::SHADERTYPE_VERTEX).compileOk;
370 	const bool				fragmentOk	= program.getShaderInfo(glu::SHADERTYPE_FRAGMENT).compileOk;
371 	const bool				linkOk		= program.getProgramInfo().linkOk;
372 	const deUint32			programID	= program.getProgram();
373 
374 	TestLog&				log			= m_testCtx.getLog();
375 	std::set<int>			usedLocations;
376 
377 	log << program;
378 
379 	if (!vertexOk || !fragmentOk || !linkOk)
380 	{
381 		log << TestLog::Message << "ERROR: shader failed to compile/link" << TestLog::EndMessage;
382 		m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Shader failed to compile/link");
383 		return false;
384 	}
385 
386 	for (int uniformNdx = 0; uniformNdx < int(uniformList.size()); uniformNdx++)
387 	{
388 		const UniformInfo&	uniformInfo		= uniformList[uniformNdx];
389 		int					subTypeIndex	= 0;
390 
391 		for (glu::BasicTypeIterator subTypeIter = glu::BasicTypeIterator::begin(&uniformInfo.type); subTypeIter != glu::BasicTypeIterator::end(&uniformInfo.type); subTypeIter++, subTypeIndex++)
392 		{
393 			const string		name		= getUniformName(uniformNdx, uniformInfo.type, subTypeIter.getPath());
394 			const int			gotLoc		= gl.getUniformLocation(programID, name.c_str());
395 			const int			expectLoc	= uniformInfo.location >= 0 ? uniformInfo.location+subTypeIndex : -1;
396 
397 			if (expectLoc >= 0)
398 			{
399 				if (uniformInfo.checkLocation == 0 && gotLoc == -1)
400 					continue;
401 
402 				if (gotLoc != expectLoc)
403 				{
404 					log << TestLog::Message << "ERROR: found uniform " << name << " in location " << gotLoc << " when it should have been in " << expectLoc << TestLog::EndMessage;
405 					m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Incorrect uniform location");
406 					return false;
407 				}
408 
409 				if (usedLocations.find(expectLoc) != usedLocations.end())
410 				{
411 					log << TestLog::Message << "ERROR: expected uniform " << name << " in location " << gotLoc << " but it has already been used" << TestLog::EndMessage;
412 					m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Overlapping uniform location");
413 					return false;
414 				}
415 
416 				usedLocations.insert(expectLoc);
417 			}
418 			else if (gotLoc >= 0)
419 			{
420 				if (usedLocations.count(gotLoc))
421 				{
422 					log << TestLog::Message << "ERROR: found uniform " << name << " in location " << gotLoc << " which has already been used" << TestLog::EndMessage;
423 					m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Overlapping uniform location");
424 					return false;
425 				}
426 
427 				usedLocations.insert(gotLoc);
428 			}
429 		}
430 	}
431 
432 	return true;
433 }
434 
435 // Check that shader output is white (or very close to it)
verifyResult(const tcu::ConstPixelBufferAccess & access)436 bool UniformLocationCase::verifyResult (const tcu::ConstPixelBufferAccess& access)
437 {
438 	using tcu::Vec4;
439 
440 	const Vec4 threshold (0.1f, 0.1f, 0.1f, 0.1f);
441 	const Vec4 reference (1.0f, 1.0f, 1.0f, 1.0f);
442 
443 	for (int y = 0; y < access.getHeight(); y++)
444 	{
445 		for (int x = 0; x < access.getWidth(); x++)
446 		{
447 			const Vec4 diff = abs(access.getPixel(x, y) - reference);
448 
449 			if (!boolAll(lessThanEqual(diff, threshold)))
450 				return false;
451 		}
452 	}
453 
454 	return true;
455 }
456 
457 // get a 4 channel 8 bits each texture format that is usable by the given sampler type
getTextureFormat(glu::DataType samplerType)458 deUint32 getTextureFormat (glu::DataType samplerType)
459 {
460 	using namespace glu;
461 
462 	switch (samplerType)
463 	{
464 		case TYPE_SAMPLER_1D:
465 		case TYPE_SAMPLER_2D:
466 		case TYPE_SAMPLER_CUBE:
467 		case TYPE_SAMPLER_2D_ARRAY:
468 		case TYPE_SAMPLER_3D:
469 			return GL_RGBA8;
470 
471 		case TYPE_INT_SAMPLER_1D:
472 		case TYPE_INT_SAMPLER_2D:
473 		case TYPE_INT_SAMPLER_CUBE:
474 		case TYPE_INT_SAMPLER_2D_ARRAY:
475 		case TYPE_INT_SAMPLER_3D:
476 			return GL_RGBA8I;
477 
478 		case TYPE_UINT_SAMPLER_1D:
479 		case TYPE_UINT_SAMPLER_2D:
480 		case TYPE_UINT_SAMPLER_CUBE:
481 		case TYPE_UINT_SAMPLER_2D_ARRAY:
482 		case TYPE_UINT_SAMPLER_3D:
483 			return GL_RGBA8UI;
484 
485 		default:
486 			DE_FATAL("Unsupported (sampler) type");
487 			return 0;
488 	}
489 }
490 
491 // create a texture suitable for sampling by the given sampler type and bind it
createTexture(glu::DataType samplerType,float redChannelValue,int binding)492 de::MovePtr<glu::Texture2D> UniformLocationCase::createTexture (glu::DataType samplerType, float redChannelValue, int binding)
493 {
494 	using namespace glu;
495 
496 	const glw::Functions&	gl		 = m_renderCtx.getFunctions();
497 
498 	const deUint32			format	 = getTextureFormat(samplerType);
499 	de::MovePtr<Texture2D>	tex;
500 
501 	tex = de::MovePtr<Texture2D>(new Texture2D(m_renderCtx, format, 16, 16));
502 
503 	tex->getRefTexture().allocLevel(0);
504 
505 	if (format == GL_RGBA8I || format == GL_RGBA8UI)
506 		tcu::clear(tex->getRefTexture().getLevel(0), tcu::IVec4(int(redChannelValue), 0, 0, 0));
507 	else
508 		tcu::clear(tex->getRefTexture().getLevel(0), tcu::Vec4(redChannelValue, 0.0f, 0.0f, 1.0f));
509 
510 	gl.activeTexture(GL_TEXTURE0 + binding);
511 	tex->upload();
512 
513 	gl.bindTexture(GL_TEXTURE_2D, tex->getGLTexture());
514 	gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
515 	gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
516 
517 	GLU_EXPECT_NO_ERROR(gl.getError(), "UniformLocationCase: texture upload");
518 
519 	return tex;
520 }
521 
render(const glu::ShaderProgram & program,const vector<UniformInfo> & uniformList)522 void UniformLocationCase::render (const glu::ShaderProgram& program, const vector<UniformInfo>& uniformList)
523 {
524 	using glu::Texture2D;
525 	using de::MovePtr;
526 	typedef vector<Texture2D*> TextureList;
527 
528 	const glw::Functions&	gl				= m_renderCtx.getFunctions();
529 	const deUint32			programID		= program.getProgram();
530 	const deInt32			posLoc			= gl.getAttribLocation(programID, "a_position");
531 
532 	// Vertex data.
533 	const float position[] =
534 	{
535 		-1.0f, -1.0f, 0.1f,	1.0f,
536 		-1.0f,  1.0f, 0.1f,	1.0f,
537 		 1.0f, -1.0f, 0.1f,	1.0f,
538 		 1.0f,  1.0f, 0.1f,	1.0f
539 	};
540 	const void *			positionPtr		= &position[0];
541 	const deUint16			indices[]		= { 0, 1, 2, 2, 1, 3 };
542 	const void *			indicesPtr		= &indices[0];
543 
544 	// some buffers to feed to the GPU, only the first element is relevant since the others are never verified
545 	float					floatBuf[16]	= {0.0f};
546 	deInt32					intBuf[4]		= {0};
547 	deUint32				uintBuf[4]		= {0};
548 	deUint32				vao				= 0;
549 	deUint32				attribVbo		= 0;
550 	deUint32				elementVbo		= 0;
551 
552 	TextureList				texList;
553 
554 	bool isGL45 = glu::contextSupports(m_renderCtx.getType(), glu::ApiType::core(4, 5));
555 	if (isGL45)
556 	{
557 		gl.genVertexArrays(1, &vao);
558 		gl.bindVertexArray(vao);
559 
560 		gl.genBuffers(1, &attribVbo);
561 		gl.genBuffers(1, &elementVbo);
562 
563 		gl.bindBuffer(GL_ARRAY_BUFFER, attribVbo);
564 		gl.bufferData(GL_ARRAY_BUFFER, (glw::GLsizeiptr)(DE_LENGTH_OF_ARRAY(position) * sizeof(float)), position, GL_STATIC_DRAW);
565 		GLU_EXPECT_NO_ERROR(gl.getError(), "UniformLocationCase::render");
566 
567 		gl.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, elementVbo);
568 		gl.bufferData(GL_ELEMENT_ARRAY_BUFFER, (glw::GLsizeiptr)(DE_LENGTH_OF_ARRAY(indices) * sizeof(deUint16)), indices, GL_STATIC_DRAW);
569 		GLU_EXPECT_NO_ERROR(gl.getError(), "UniformLocationCase::render");
570 
571 		positionPtr = 0;
572 		indicesPtr = 0;
573 	}
574 
575 	TCU_CHECK(posLoc >= 0);
576 	gl.useProgram(programID);
577 
578 	try
579 	{
580 
581 		// Set uniforms
582 		for (unsigned int uniformNdx = 0; uniformNdx < uniformList.size(); uniformNdx++)
583 		{
584 			const UniformInfo&	uniformInfo			= uniformList[uniformNdx];
585 			int					expectedLocation	= uniformInfo.location;
586 
587 			for (glu::BasicTypeIterator subTypeIter = glu::BasicTypeIterator::begin(&uniformInfo.type); subTypeIter != glu::BasicTypeIterator::end(&uniformInfo.type); subTypeIter++)
588 			{
589 				const glu::VarType	type			= glu::getVarType(uniformInfo.type, subTypeIter.getPath());
590 				const string		name			= getUniformName(uniformNdx, uniformInfo.type, subTypeIter.getPath());
591 				const int			gotLoc			= gl.getUniformLocation(programID, name.c_str());
592 				const glu::DataType	scalarType		= glu::getDataTypeScalarType(type.getBasicType());
593 				const char*	const	typeName		= glu::getDataTypeName(scalarType);
594 				const float			expectedValue	= getExpectedValue(scalarType, expectedLocation, typeName);
595 
596 				if (glu::isDataTypeSampler(scalarType))
597 				{
598 					const int binding = (int)texList.size();
599 
600 					texList.push_back(createTexture(scalarType, expectedValue, binding).release());
601 					gl.uniform1i(gotLoc, binding);
602 				}
603 				else if(gotLoc >= 0)
604 				{
605 					floatBuf[0] = expectedValue;
606 					intBuf[0]   = int(expectedValue);
607 					uintBuf[0]  = deUint32(expectedValue);
608 
609 					m_testCtx.getLog() << tcu::TestLog::Message << "Set uniform " << name << " in location " << gotLoc << " to " << expectedValue << tcu::TestLog::EndMessage;
610 
611 					switch (type.getBasicType())
612 					{
613 						case glu::TYPE_FLOAT:			gl.uniform1fv(gotLoc, 1, floatBuf);					break;
614 						case glu::TYPE_FLOAT_VEC2:		gl.uniform2fv(gotLoc, 1, floatBuf);					break;
615 						case glu::TYPE_FLOAT_VEC3:		gl.uniform3fv(gotLoc, 1, floatBuf);					break;
616 						case glu::TYPE_FLOAT_VEC4:		gl.uniform4fv(gotLoc, 1, floatBuf);					break;
617 
618 						case glu::TYPE_INT:				gl.uniform1iv(gotLoc, 1, intBuf);					break;
619 						case glu::TYPE_INT_VEC2:		gl.uniform2iv(gotLoc, 1, intBuf);					break;
620 						case glu::TYPE_INT_VEC3:		gl.uniform3iv(gotLoc, 1, intBuf);					break;
621 						case glu::TYPE_INT_VEC4:		gl.uniform4iv(gotLoc, 1, intBuf);					break;
622 
623 						case glu::TYPE_UINT:			gl.uniform1uiv(gotLoc, 1, uintBuf);					break;
624 						case glu::TYPE_UINT_VEC2:		gl.uniform2uiv(gotLoc, 1, uintBuf);					break;
625 						case glu::TYPE_UINT_VEC3:		gl.uniform3uiv(gotLoc, 1, uintBuf);					break;
626 						case glu::TYPE_UINT_VEC4:		gl.uniform4uiv(gotLoc, 1, uintBuf);					break;
627 
628 						case glu::TYPE_BOOL:			gl.uniform1iv(gotLoc, 1, intBuf);					break;
629 						case glu::TYPE_BOOL_VEC2:		gl.uniform2iv(gotLoc, 1, intBuf);					break;
630 						case glu::TYPE_BOOL_VEC3:		gl.uniform3iv(gotLoc, 1, intBuf);					break;
631 						case glu::TYPE_BOOL_VEC4:		gl.uniform4iv(gotLoc, 1, intBuf);					break;
632 
633 						case glu::TYPE_FLOAT_MAT2:		gl.uniformMatrix2fv(gotLoc, 1, false, floatBuf);	break;
634 						case glu::TYPE_FLOAT_MAT2X3:	gl.uniformMatrix2x3fv(gotLoc, 1, false, floatBuf);	break;
635 						case glu::TYPE_FLOAT_MAT2X4:	gl.uniformMatrix2x4fv(gotLoc, 1, false, floatBuf);	break;
636 
637 						case glu::TYPE_FLOAT_MAT3X2:	gl.uniformMatrix3x2fv(gotLoc, 1, false, floatBuf);	break;
638 						case glu::TYPE_FLOAT_MAT3:		gl.uniformMatrix3fv(gotLoc, 1, false, floatBuf);	break;
639 						case glu::TYPE_FLOAT_MAT3X4:	gl.uniformMatrix3x4fv(gotLoc, 1, false, floatBuf);	break;
640 
641 						case glu::TYPE_FLOAT_MAT4X2:	gl.uniformMatrix4x2fv(gotLoc, 1, false, floatBuf);	break;
642 						case glu::TYPE_FLOAT_MAT4X3:	gl.uniformMatrix4x3fv(gotLoc, 1, false, floatBuf);	break;
643 						case glu::TYPE_FLOAT_MAT4:		gl.uniformMatrix4fv(gotLoc, 1, false, floatBuf);	break;
644 						default:
645 							DE_ASSERT(false);
646 					}
647 				}
648 
649 				expectedLocation += expectedLocation>=0;
650 			}
651 		}
652 
653 		gl.enableVertexAttribArray(posLoc);
654 		GLU_EXPECT_NO_ERROR(gl.getError(), "error in glEnableVertexAttribArray");
655 		gl.vertexAttribPointer(posLoc, 4, GL_FLOAT, GL_FALSE, 0, positionPtr);
656 		GLU_EXPECT_NO_ERROR(gl.getError(), "error in glVertexAttribPointer");
657 
658 		gl.drawElements(GL_TRIANGLES, DE_LENGTH_OF_ARRAY(indices), GL_UNSIGNED_SHORT, indicesPtr);
659 		GLU_EXPECT_NO_ERROR(gl.getError(), "error in glDrawElements");
660 
661 		gl.disableVertexAttribArray(posLoc);
662 		GLU_EXPECT_NO_ERROR(gl.getError(), "error in glDisableVertexAttribArray");
663 
664 		if (isGL45)
665 		{
666 			gl.bindBuffer(GL_ARRAY_BUFFER, 0);
667 			gl.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
668 
669 			gl.deleteBuffers(1, &attribVbo);
670 			gl.deleteBuffers(1, &elementVbo);
671 			gl.deleteVertexArrays(1, &vao);
672 		}
673 	}
674 	catch(...)
675 	{
676 		for (int i = 0; i < int(texList.size()); i++)
677 			delete texList[i];
678 
679 		throw;
680 	}
681 
682 	for (int i = 0; i < int(texList.size()); i++)
683 		delete texList[i];
684 }
685 
686 class MaxUniformLocationCase : public UniformLocationCase
687 {
688 public:
689 								MaxUniformLocationCase		(tcu::TestContext&			context,
690 															 glu::RenderContext&		renderContext,
691 															 const char*				name,
692 															 const char*				desc,
693 															 const vector<UniformInfo>&	uniformInfo);
~MaxUniformLocationCase(void)694 	virtual						~MaxUniformLocationCase		(void) {}
695 	virtual IterateResult		iterate						(void);
696 };
697 
MaxUniformLocationCase(tcu::TestContext & context,glu::RenderContext & renderContext,const char * name,const char * desc,const vector<UniformInfo> & uniformInfo)698 MaxUniformLocationCase::MaxUniformLocationCase (tcu::TestContext&			context,
699 												glu::RenderContext&			renderContext,
700 												const char*					name,
701 												const char*					desc,
702 												const vector<UniformInfo>&	uniformInfo)
703 	: UniformLocationCase(context, renderContext, name, desc, uniformInfo)
704 {
705 	DE_ASSERT(!uniformInfo.empty());
706 }
707 
iterate(void)708 UniformLocationCase::IterateResult MaxUniformLocationCase::iterate (void)
709 {
710 	int					maxLocation = 1024;
711 	vector<UniformInfo>	uniformInfo = m_uniformInfo;
712 
713 	m_renderCtx.getFunctions().getIntegerv(GL_MAX_UNIFORM_LOCATIONS, &maxLocation);
714 
715 	uniformInfo[0].location = maxLocation-1;
716 
717 	return UniformLocationCase::run(uniformInfo);
718 }
719 
720 } // Anonymous
721 
UniformLocationTests(Context & context,bool isGL45)722 UniformLocationTests::UniformLocationTests (Context& context, bool isGL45)
723 	: TestCaseGroup(context, "uniform_location", "Explicit uniform locations")
724 	, m_isGL45(isGL45)
725 {
726 }
727 
~UniformLocationTests(void)728 UniformLocationTests::~UniformLocationTests (void)
729 {
730 	for (int i = 0; i < int(structTypes.size()); i++)
731 		delete structTypes[i];
732 }
733 
createVarType(glu::DataType type)734 glu::VarType createVarType (glu::DataType type)
735 {
736 	return glu::VarType(type, glu::isDataTypeBoolOrBVec(type) ? glu::PRECISION_LAST : glu::PRECISION_HIGHP);
737 }
738 
init(void)739 void UniformLocationTests::init (void)
740 {
741 	using namespace glu;
742 
743 	const UniformInfo::ShaderStage checkStages[]	= { UniformInfo::SHADERSTAGE_VERTEX, UniformInfo::SHADERSTAGE_FRAGMENT };
744 	const char*						stageNames[]	= {"vertex", "fragment"};
745 	const int						maxLocations	= 1024;
746 	const int						baseSeed		= m_context.getTestContext().getCommandLine().getBaseSeed();
747 
748 	const DataType					primitiveTypes[] =
749 	{
750 		TYPE_FLOAT,
751 		TYPE_FLOAT_VEC2,
752 		TYPE_FLOAT_VEC3,
753 		TYPE_FLOAT_VEC4,
754 
755 		TYPE_INT,
756 		TYPE_INT_VEC2,
757 		TYPE_INT_VEC3,
758 		TYPE_INT_VEC4,
759 
760 		TYPE_UINT,
761 		TYPE_UINT_VEC2,
762 		TYPE_UINT_VEC3,
763 		TYPE_UINT_VEC4,
764 
765 		TYPE_BOOL,
766 		TYPE_BOOL_VEC2,
767 		TYPE_BOOL_VEC3,
768 		TYPE_BOOL_VEC4,
769 
770 		TYPE_FLOAT_MAT2,
771 		TYPE_FLOAT_MAT2X3,
772 		TYPE_FLOAT_MAT2X4,
773 		TYPE_FLOAT_MAT3X2,
774 		TYPE_FLOAT_MAT3,
775 		TYPE_FLOAT_MAT3X4,
776 		TYPE_FLOAT_MAT4X2,
777 		TYPE_FLOAT_MAT4X3,
778 		TYPE_FLOAT_MAT4,
779 
780 		TYPE_SAMPLER_2D,
781 		TYPE_INT_SAMPLER_2D,
782 		TYPE_UINT_SAMPLER_2D,
783 	};
784 
785 	const int maxPrimitiveTypeNdx = DE_LENGTH_OF_ARRAY(primitiveTypes) - 4;
786 	DE_ASSERT(primitiveTypes[maxPrimitiveTypeNdx] == TYPE_FLOAT_MAT4);
787 
788 	// Primitive type cases with trivial linkage
789 	{
790 		tcu::TestCaseGroup* const	group	= new tcu::TestCaseGroup(m_testCtx, "basic", "Location specified with use, single shader stage");
791 		de::Random					rng		(baseSeed + 0x1001);
792 		addChild(group);
793 
794 		for (int primitiveNdx = 0; primitiveNdx < DE_LENGTH_OF_ARRAY(primitiveTypes); primitiveNdx++)
795 		{
796 			const DataType		type	= primitiveTypes[primitiveNdx];
797 
798 			for (int stageNdx = 0; stageNdx < DE_LENGTH_OF_ARRAY(checkStages); stageNdx++)
799 			{
800 				const string		name		= string(getDataTypeName(type)) + "_" + stageNames[stageNdx];
801 
802 				vector<UniformInfo> config;
803 
804 				UniformInfo			uniform	(createVarType(type),
805 											 checkStages[stageNdx],
806 											 checkStages[stageNdx],
807 											 checkStages[stageNdx],
808 											 rng.getInt(0, maxLocations-1));
809 
810 				config.push_back(uniform);
811 				group->addChild(new UniformLocationCase (m_testCtx, m_context.getRenderContext(), name.c_str(), name.c_str(), config));
812 			}
813 		}
814 	}
815 
816 	// Arrays
817 	{
818 		tcu::TestCaseGroup* const	group	= new tcu::TestCaseGroup(m_testCtx, "array", "Array location specified with use, single shader stage");
819 		de::Random					rng		(baseSeed + 0x2001);
820 		addChild(group);
821 
822 		for (int primitiveNdx = 0; primitiveNdx < DE_LENGTH_OF_ARRAY(primitiveTypes); primitiveNdx++)
823 		{
824 			const DataType		type	= primitiveTypes[primitiveNdx];
825 
826 			for (int stageNdx = 0; stageNdx < DE_LENGTH_OF_ARRAY(checkStages); stageNdx++)
827 			{
828 
829 				const string		name	= string(getDataTypeName(type)) + "_" + stageNames[stageNdx];
830 
831 				vector<UniformInfo> config;
832 
833 				UniformInfo			uniform	(VarType(createVarType(type), 8),
834 												checkStages[stageNdx],
835 												checkStages[stageNdx],
836 												checkStages[stageNdx],
837 												rng.getInt(0, maxLocations-1-8));
838 
839 				config.push_back(uniform);
840 				group->addChild(new UniformLocationCase (m_testCtx, m_context.getRenderContext(), name.c_str(), name.c_str(), config));
841 			}
842 		}
843 	}
844 
845 	// Nested Arrays
846 	{
847 		tcu::TestCaseGroup* const	group	= new tcu::TestCaseGroup(m_testCtx, "nested_array", "Array location specified with use, single shader stage");
848 		de::Random					rng		(baseSeed + 0x3001);
849 		addChild(group);
850 
851 		for (int primitiveNdx = 0; primitiveNdx < DE_LENGTH_OF_ARRAY(primitiveTypes); primitiveNdx++)
852 		{
853 			const DataType		type	= primitiveTypes[primitiveNdx];
854 
855 			for (int stageNdx = 0; stageNdx < DE_LENGTH_OF_ARRAY(checkStages); stageNdx++)
856 			{
857 				const string		name		= string(getDataTypeName(type)) + "_" + stageNames[stageNdx];
858 				// stay comfortably within minimum max uniform component count (896 in fragment) and sampler count with all types
859 				const int			arraySize	= (getDataTypeScalarSize(type) > 4 || isDataTypeSampler(type)) ? 3 : 7;
860 
861 				vector<UniformInfo> config;
862 
863 				UniformInfo			uniform	(VarType(VarType(createVarType(type), arraySize), arraySize),
864 											 checkStages[stageNdx],
865 											 checkStages[stageNdx],
866 											 checkStages[stageNdx],
867 											 rng.getInt(0, maxLocations-1-arraySize*arraySize));
868 
869 				config.push_back(uniform);
870 				group->addChild(new UniformLocationCase (m_testCtx, m_context.getRenderContext(), name.c_str(), name.c_str(), config));
871 			}
872 		}
873 	}
874 
875 	// Structs
876 	{
877 		tcu::TestCaseGroup* const	group	= new tcu::TestCaseGroup(m_testCtx, "struct", "Struct location, random contents & declaration location");
878 		de::Random					rng		(baseSeed + 0x4001);
879 		addChild(group);
880 
881 		for (int caseNdx = 0; caseNdx < 16; caseNdx++)
882 		{
883 			typedef UniformInfo::ShaderStage Stage;
884 
885 			const string	name		= "case_" + de::toString(caseNdx);
886 
887 			const Stage		layoutLoc	= Stage(rng.getUint32()&0x3);
888 			const Stage		declareLoc	= Stage((rng.getUint32()&0x3) | layoutLoc);
889 			const Stage		verifyLoc	= Stage((rng.getUint32()&0x3) & declareLoc);
890 			const int		location	= layoutLoc ? rng.getInt(0, maxLocations-1-5) : -1;
891 
892 			StructType*		structProto = new StructType("S");
893 
894 			structTypes.push_back(structProto);
895 
896 			structProto->addMember("a", createVarType(primitiveTypes[rng.getInt(0, maxPrimitiveTypeNdx)]));
897 			structProto->addMember("b", createVarType(primitiveTypes[rng.getInt(0, maxPrimitiveTypeNdx)]));
898 			structProto->addMember("c", createVarType(primitiveTypes[rng.getInt(0, maxPrimitiveTypeNdx)]));
899 			structProto->addMember("d", createVarType(primitiveTypes[rng.getInt(0, maxPrimitiveTypeNdx)]));
900 			structProto->addMember("e", createVarType(primitiveTypes[rng.getInt(0, maxPrimitiveTypeNdx)]));
901 
902 			{
903 				vector<UniformInfo> config;
904 
905 				config.push_back(UniformInfo(VarType(structProto),
906 											 declareLoc,
907 											 layoutLoc,
908 											 verifyLoc,
909 											 location));
910 				group->addChild(new UniformLocationCase (m_testCtx, m_context.getRenderContext(), name.c_str(), name.c_str(), config));
911 			}
912 		}
913 	}
914 
915 	// Nested Structs
916 	{
917 		tcu::TestCaseGroup* const	group	= new tcu::TestCaseGroup(m_testCtx, "nested_struct", "Struct location specified with use, single shader stage");
918 		de::Random					rng		(baseSeed + 0x5001);
919 
920 		addChild(group);
921 
922 		for (int caseNdx = 0; caseNdx < 16; caseNdx++)
923 		{
924 			typedef UniformInfo::ShaderStage Stage;
925 
926 			const string	name		= "case_" + de::toString(caseNdx);
927 			const int		baseLoc		= rng.getInt(0, maxLocations-1-60);
928 
929 			// Structs need to be added in the order of their declaration
930 			const Stage		layoutLocs[]=
931 			{
932 				Stage(rng.getUint32()&0x3),
933 				Stage(rng.getUint32()&0x3),
934 				Stage(rng.getUint32()&0x3),
935 				Stage(rng.getUint32()&0x3),
936 			};
937 
938 			const deUint32	tempDecl[] =
939 			{
940 				(rng.getUint32()&0x3) | layoutLocs[0],
941 				(rng.getUint32()&0x3) | layoutLocs[1],
942 				(rng.getUint32()&0x3) | layoutLocs[2],
943 				(rng.getUint32()&0x3) | layoutLocs[3],
944 			};
945 
946 			// Component structs need to be declared if anything using them is declared
947 			const Stage		declareLocs[] =
948 			{
949 				Stage(tempDecl[0] | tempDecl[1] | tempDecl[2] | tempDecl[3]),
950 				Stage(tempDecl[1] | tempDecl[2] | tempDecl[3]),
951 				Stage(tempDecl[2] | tempDecl[3]),
952 				Stage(tempDecl[3]),
953 			};
954 
955 			const Stage		verifyLocs[] =
956 			{
957 				Stage(rng.getUint32()&0x3 & declareLocs[0]),
958 				Stage(rng.getUint32()&0x3 & declareLocs[1]),
959 				Stage(rng.getUint32()&0x3 & declareLocs[2]),
960 				Stage(rng.getUint32()&0x3 & declareLocs[3]),
961 			};
962 
963 			StructType*		testTypes[]	=
964 			{
965 				new StructType("Type0"),
966 				new StructType("Type1"),
967 				new StructType("Type2"),
968 				new StructType("Type3"),
969 			};
970 
971 			structTypes.push_back(testTypes[0]);
972 			structTypes.push_back(testTypes[1]);
973 			structTypes.push_back(testTypes[2]);
974 			structTypes.push_back(testTypes[3]);
975 
976 			testTypes[0]->addMember("a", createVarType(primitiveTypes[rng.getInt(0, maxPrimitiveTypeNdx)]));
977 			testTypes[0]->addMember("b", createVarType(primitiveTypes[rng.getInt(0, maxPrimitiveTypeNdx)]));
978 			testTypes[0]->addMember("c", createVarType(primitiveTypes[rng.getInt(0, maxPrimitiveTypeNdx)]));
979 			testTypes[0]->addMember("d", createVarType(primitiveTypes[rng.getInt(0, maxPrimitiveTypeNdx)]));
980 			testTypes[0]->addMember("e", createVarType(primitiveTypes[rng.getInt(0, maxPrimitiveTypeNdx)]));
981 
982 			testTypes[1]->addMember("a", createVarType(primitiveTypes[rng.getInt(0, maxPrimitiveTypeNdx)]));
983 			testTypes[1]->addMember("b", createVarType(primitiveTypes[rng.getInt(0, maxPrimitiveTypeNdx)]));
984 			testTypes[1]->addMember("c", createVarType(primitiveTypes[rng.getInt(0, maxPrimitiveTypeNdx)]));
985 			testTypes[1]->addMember("d", createVarType(primitiveTypes[rng.getInt(0, maxPrimitiveTypeNdx)]));
986 			testTypes[1]->addMember("e", createVarType(primitiveTypes[rng.getInt(0, maxPrimitiveTypeNdx)]));
987 
988 			testTypes[2]->addMember("a", VarType(testTypes[0]));
989 			testTypes[2]->addMember("b", VarType(testTypes[1]));
990 			testTypes[2]->addMember("c", createVarType(primitiveTypes[rng.getInt(0, maxPrimitiveTypeNdx)]));
991 
992 			testTypes[3]->addMember("a", VarType(testTypes[2]));
993 
994 			{
995 				vector<UniformInfo> config;
996 
997 				config.push_back(UniformInfo(VarType(testTypes[0]),
998 											 declareLocs[0],
999 											 layoutLocs[0],
1000 											 verifyLocs[0],
1001 											 layoutLocs[0] ? baseLoc : -1));
1002 
1003 				config.push_back(UniformInfo(VarType(testTypes[1]),
1004 											 declareLocs[1],
1005 											 layoutLocs[1],
1006 											 verifyLocs[1],
1007 											 layoutLocs[1] ? baseLoc+5 : -1));
1008 
1009 				config.push_back(UniformInfo(VarType(testTypes[2]),
1010 											 declareLocs[2],
1011 											 layoutLocs[2],
1012 											 verifyLocs[2],
1013 											 layoutLocs[2] ? baseLoc+16 : -1));
1014 
1015 				config.push_back(UniformInfo(VarType(testTypes[3]),
1016 											 declareLocs[3],
1017 											 layoutLocs[3],
1018 											 verifyLocs[3],
1019 											 layoutLocs[3] ? baseLoc+27 : -1));
1020 
1021 				group->addChild(new UniformLocationCase (m_testCtx, m_context.getRenderContext(), name.c_str(), name.c_str(), config));
1022 			}
1023 		}
1024 	}
1025 
1026 	// Min/Max location
1027 	{
1028 		tcu::TestCaseGroup* const	group		= new tcu::TestCaseGroup(m_testCtx, "min_max", "Maximum & minimum location");
1029 
1030 		addChild(group);
1031 
1032 		for (int primitiveNdx = 0; primitiveNdx < DE_LENGTH_OF_ARRAY(primitiveTypes); primitiveNdx++)
1033 		{
1034 			const DataType		type	= primitiveTypes[primitiveNdx];
1035 
1036 			for (int stageNdx = 0; stageNdx < DE_LENGTH_OF_ARRAY(checkStages); stageNdx++)
1037 			{
1038 				const string		name		= string(getDataTypeName(type)) + "_" + stageNames[stageNdx];
1039 				vector<UniformInfo> config;
1040 
1041 				config.push_back(UniformInfo(createVarType(type),
1042 											 checkStages[stageNdx],
1043 											 checkStages[stageNdx],
1044 											 checkStages[stageNdx],
1045 											 0));
1046 
1047 				group->addChild(new UniformLocationCase (m_testCtx, m_context.getRenderContext(), (name+"_min").c_str(), (name+"_min").c_str(), config));
1048 
1049 				group->addChild(new MaxUniformLocationCase (m_testCtx, m_context.getRenderContext(), (name+"_max").c_str(), (name+"_max").c_str(), config));
1050 			}
1051 		}
1052 	}
1053 
1054 	// Link
1055 	{
1056 		tcu::TestCaseGroup* const	group	= new tcu::TestCaseGroup(m_testCtx, "link", "Location specified independently from use");
1057 		de::Random					rng		(baseSeed + 0x82e1);
1058 
1059 		addChild(group);
1060 
1061 		for (int caseNdx = 0; caseNdx < 10; caseNdx++)
1062 		{
1063 			const string		name		= "case_" + de::toString(caseNdx);
1064 			vector<UniformInfo> config;
1065 
1066 			vector<int>			locations	= shuffledRange(0, maxLocations, 0x1234 + caseNdx*100);
1067 
1068 			for (int count = 0; count < 32; count++)
1069 			{
1070 				typedef UniformInfo::ShaderStage Stage;
1071 
1072 				const Stage			layoutLoc	= Stage(rng.getUint32()&0x3);
1073 				const Stage			declareLoc	= Stage((rng.getUint32()&0x3) | layoutLoc);
1074 				const Stage			verifyLoc	= Stage((rng.getUint32()&0x3) & declareLoc);
1075 
1076 				const UniformInfo	uniform		(createVarType(primitiveTypes[rng.getInt(0, maxPrimitiveTypeNdx)]),
1077 												 declareLoc,
1078 												 layoutLoc,
1079 												 verifyLoc,
1080 												 (layoutLoc!=0) ? locations.back() : -1);
1081 
1082 				config.push_back(uniform);
1083 				locations.pop_back();
1084 			}
1085 			group->addChild(new UniformLocationCase (m_testCtx, m_context.getRenderContext(), name.c_str(), name.c_str(), config));
1086 		}
1087 	}
1088 
1089 	// Negative
1090 	{
1091 		de::MovePtr<tcu::TestCaseGroup>	negativeGroup			(new tcu::TestCaseGroup(m_testCtx, "negative", "Negative tests"));
1092 
1093 		{
1094 			de::MovePtr<tcu::TestCaseGroup>	es31Group		(new tcu::TestCaseGroup(m_testCtx, "es31", "GLSL ES 3.1 Negative tests"));
1095 			gls::ShaderLibrary				shaderLibrary   (m_testCtx, m_context.getRenderContext(), m_context.getContextInfo());
1096 			const vector<TestNode*>			negativeCases    = shaderLibrary.loadShaderFile("shaders/es31/uniform_location.test");
1097 
1098 			for (int ndx = 0; ndx < int(negativeCases.size()); ndx++)
1099 				es31Group->addChild(negativeCases[ndx]);
1100 
1101 			negativeGroup->addChild(es31Group.release());
1102 		}
1103 
1104 		// ES only
1105 		if (!m_isGL45)
1106 		{
1107 			de::MovePtr<tcu::TestCaseGroup>	es32Group		(new tcu::TestCaseGroup(m_testCtx, "es32", "GLSL ES 3.2 Negative tests"));
1108 			gls::ShaderLibrary				shaderLibrary   (m_testCtx, m_context.getRenderContext(), m_context.getContextInfo());
1109 			const vector<TestNode*>			negativeCases    = shaderLibrary.loadShaderFile("shaders/es32/uniform_location.test");
1110 
1111 			for (int ndx = 0; ndx < int(negativeCases.size()); ndx++)
1112 				es32Group->addChild(negativeCases[ndx]);
1113 
1114 			negativeGroup->addChild(es32Group.release());
1115 		}
1116 
1117 		addChild(negativeGroup.release());
1118 	}
1119 }
1120 
1121 } // Functional
1122 } // gles31
1123 } // deqp
1124