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::__anonac4205910111::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_ASSERT(!"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 (hash%255)/255.0f;
208 	else if (glu::isDataTypeBoolOrBVec(adjustedType))
209 		return float(hash%2);
210 	else
211 		DE_ASSERT(!"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 
244 	if (!verifyResult(rendered.getAccess()))
245 	{
246 		m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Shader produced incorrect result");
247 		return STOP;
248 	}
249 
250 	m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
251 	return STOP;
252 }
253 
genShaderSources(const vector<UniformInfo> & uniformList)254 glu::ProgramSources UniformLocationCase::genShaderSources (const vector<UniformInfo>& uniformList)
255 {
256 	std::ostringstream	vertDecl, vertMain, fragDecl, fragMain;
257 
258 	vertDecl << "#version 310 es\n"
259 			 << "precision highp float;\n"
260 			 << "precision highp int;\n"
261 			 << "float verify(float val, float ref) { return float(abs(val-ref) < 0.05); }\n\n"
262 			 << "in highp vec4 a_position;\n"
263 			 << "out highp vec4 v_color;\n";
264 	fragDecl << "#version 310 es\n\n"
265 			 << "precision highp float;\n"
266 			 << "precision highp int;\n"
267 			 << "float verify(float val, float ref) { return float(abs(val-ref) < 0.05); }\n\n"
268 			 << "in highp vec4 v_color;\n"
269 			 << "layout(location = 0) out mediump vec4 o_color;\n\n";
270 
271 	vertMain << "void main()\n{\n"
272 			 << "	gl_Position = a_position;\n"
273 			 << "	v_color = vec4(1.0);\n";
274 
275 	fragMain << "void main()\n{\n"
276 			 << "	o_color = v_color;\n";
277 
278 	std::set<const glu::StructType*> declaredStructs;
279 
280 	// Declare uniforms
281 	for (int uniformNdx = 0; uniformNdx < int(uniformList.size()); uniformNdx++)
282 	{
283 		const UniformInfo&	uniformInfo = uniformList[uniformNdx];
284 
285 		const bool			declareInVert	= (uniformInfo.declareLocation & UniformInfo::SHADERSTAGE_VERTEX)   != 0;
286 		const bool			declareInFrag	= (uniformInfo.declareLocation & UniformInfo::SHADERSTAGE_FRAGMENT) != 0;
287 		const bool			layoutInVert    = (uniformInfo.layoutLocation  & UniformInfo::SHADERSTAGE_VERTEX)   != 0;
288 		const bool			layoutInFrag    = (uniformInfo.layoutLocation  & UniformInfo::SHADERSTAGE_FRAGMENT) != 0;
289 		const bool			checkInVert		= (uniformInfo.checkLocation   & UniformInfo::SHADERSTAGE_VERTEX)   != 0;
290 		const bool			checkInFrag		= (uniformInfo.checkLocation   & UniformInfo::SHADERSTAGE_FRAGMENT) != 0;
291 
292 		const string		layout			= uniformInfo.location >= 0 ? "layout(location = " + de::toString(uniformInfo.location) + ") " : "";
293 		const string		uniName			= "uni" + de::toString(uniformNdx);
294 
295 		int					location		= uniformInfo.location;
296 		int					subTypeIndex	= 0;
297 
298 		DE_ASSERT((declareInVert && layoutInVert) || !layoutInVert); // Cannot have layout without declaration
299 		DE_ASSERT((declareInFrag && layoutInFrag) || !layoutInFrag);
300 		DE_ASSERT(location<0 || (layoutInVert || layoutInFrag)); // Cannot have location without layout
301 
302 		// struct definitions
303 		if (uniformInfo.type.isStructType())
304 		{
305 			const glu::StructType* const structType = uniformInfo.type.getStructPtr();
306 			if (!declaredStructs.count(structType))
307 			{
308 				if (declareInVert)
309 					vertDecl << glu::declare(structType, 0) << ";\n";
310 
311 				if (declareInFrag)
312 					fragDecl << glu::declare(structType, 0) << ";\n";
313 
314 				declaredStructs.insert(structType);
315 			}
316 		}
317 
318 		if (declareInVert)
319 			vertDecl << "uniform " << (layoutInVert ? layout : "") << glu::declare(uniformInfo.type, uniName) << ";\n";
320 
321 		if (declareInFrag)
322 			fragDecl << "uniform " << (layoutInFrag ? layout : "") << glu::declare(uniformInfo.type, uniName) << ";\n";
323 
324 		// Anything that needs to be done for each enclosed primitive type
325 		for (glu::BasicTypeIterator subTypeIter = glu::BasicTypeIterator::begin(&uniformInfo.type); subTypeIter != glu::BasicTypeIterator::end(&uniformInfo.type); subTypeIter++, subTypeIndex++)
326 		{
327 			const glu::VarType	subType		= glu::getVarType(uniformInfo.type, subTypeIter.getPath());
328 			const glu::DataType	scalarType	= glu::getDataTypeScalarType(subType.getBasicType());
329 			const char* const	typeName	= glu::getDataTypeName(scalarType);
330 			const string		expectValue	= de::floatToString(getExpectedValue(scalarType, location >= 0 ? location+subTypeIndex : -1, typeName), 3);
331 
332 			if (glu::isDataTypeSampler(scalarType))
333 			{
334 				if (checkInVert)
335 					vertMain << "	v_color.rgb *= verify(float( texture(" << uniName
336 							 << glu::TypeAccessFormat(uniformInfo.type, subTypeIter.getPath())
337 							 << ", vec2(0.5)).r), " << expectValue << ");\n";
338 				if (checkInFrag)
339 					fragMain << "	o_color.rgb *= verify(float( texture(" << uniName
340 							 << glu::TypeAccessFormat(uniformInfo.type, subTypeIter.getPath())
341 							 << ", vec2(0.5)).r), " << expectValue << ");\n";
342 			}
343 			else
344 			{
345 				if (checkInVert)
346 					vertMain << "	v_color.rgb *= verify(float(" << uniName
347 							 << glu::TypeAccessFormat(uniformInfo.type, subTypeIter.getPath())
348 							 << getFirstComponentName(subType) << "), " << expectValue << ");\n";
349 				if (checkInFrag)
350 					fragMain << "	o_color.rgb *= verify(float(" << uniName
351 							 << glu::TypeAccessFormat(uniformInfo.type, subTypeIter.getPath())
352 							 << getFirstComponentName(subType) << "), " << expectValue << ");\n";
353 			}
354 		}
355 	}
356 
357 	vertMain << "}\n";
358 	fragMain << "}\n";
359 
360 	return glu::makeVtxFragSources(vertDecl.str() + vertMain.str(), fragDecl.str() + fragMain.str());
361 }
362 
verifyLocations(const glu::ShaderProgram & program,const vector<UniformInfo> & uniformList)363 bool UniformLocationCase::verifyLocations (const glu::ShaderProgram& program, const vector<UniformInfo>& uniformList)
364 {
365 	using tcu::TestLog;
366 
367 	const glw::Functions&	gl			= m_renderCtx.getFunctions();
368 	const bool				vertexOk	= program.getShaderInfo(glu::SHADERTYPE_VERTEX).compileOk;
369 	const bool				fragmentOk	= program.getShaderInfo(glu::SHADERTYPE_FRAGMENT).compileOk;
370 	const bool				linkOk		= program.getProgramInfo().linkOk;
371 	const deUint32			programID	= program.getProgram();
372 
373 	TestLog&				log			= m_testCtx.getLog();
374 	std::set<int>			usedLocations;
375 
376 	log << program;
377 
378 	if (!vertexOk || !fragmentOk || !linkOk)
379 	{
380 		log << TestLog::Message << "ERROR: shader failed to compile/link" << TestLog::EndMessage;
381 		m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Shader failed to compile/link");
382 		return false;
383 	}
384 
385 	for (int uniformNdx = 0; uniformNdx < int(uniformList.size()); uniformNdx++)
386 	{
387 		const UniformInfo&	uniformInfo		= uniformList[uniformNdx];
388 		int					subTypeIndex	= 0;
389 
390 		for (glu::BasicTypeIterator subTypeIter = glu::BasicTypeIterator::begin(&uniformInfo.type); subTypeIter != glu::BasicTypeIterator::end(&uniformInfo.type); subTypeIter++, subTypeIndex++)
391 		{
392 			const string		name		= getUniformName(uniformNdx, uniformInfo.type, subTypeIter.getPath());
393 			const int			gotLoc		= gl.getUniformLocation(programID, name.c_str());
394 			const int			expectLoc	= uniformInfo.location >= 0 ? uniformInfo.location+subTypeIndex : -1;
395 
396 			if (expectLoc >= 0)
397 			{
398 				if (uniformInfo.checkLocation == 0 && gotLoc == -1)
399 					continue;
400 
401 				if (gotLoc != expectLoc)
402 				{
403 					log << TestLog::Message << "ERROR: found uniform " << name << " in location " << gotLoc << " when it should have been in " << expectLoc << TestLog::EndMessage;
404 					m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Incorrect uniform location");
405 					return false;
406 				}
407 
408 				if (usedLocations.find(expectLoc) != usedLocations.end())
409 				{
410 					log << TestLog::Message << "ERROR: expected uniform " << name << " in location " << gotLoc << " but it has already been used" << TestLog::EndMessage;
411 					m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Overlapping uniform location");
412 					return false;
413 				}
414 
415 				usedLocations.insert(expectLoc);
416 			}
417 			else if (gotLoc >= 0)
418 			{
419 				if (usedLocations.count(gotLoc))
420 				{
421 					log << TestLog::Message << "ERROR: found uniform " << name << " in location " << gotLoc << " which has already been used" << TestLog::EndMessage;
422 					m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Overlapping uniform location");
423 					return false;
424 				}
425 
426 				usedLocations.insert(gotLoc);
427 			}
428 		}
429 	}
430 
431 	return true;
432 }
433 
434 // Check that shader output is white (or very close to it)
verifyResult(const tcu::ConstPixelBufferAccess & access)435 bool UniformLocationCase::verifyResult (const tcu::ConstPixelBufferAccess& access)
436 {
437 	using tcu::Vec4;
438 
439 	const Vec4 threshold (0.1f, 0.1f, 0.1f, 0.1f);
440 	const Vec4 reference (1.0f, 1.0f, 1.0f, 1.0f);
441 
442 	for (int y = 0; y < access.getHeight(); y++)
443 	{
444 		for (int x = 0; x < access.getWidth(); x++)
445 		{
446 			const Vec4 diff = abs(access.getPixel(x, y) - reference);
447 
448 			if (!boolAll(lessThanEqual(diff, threshold)))
449 				return false;
450 		}
451 	}
452 
453 	return true;
454 }
455 
456 // get a 4 channel 8 bits each texture format that is usable by the given sampler type
getTextureFormat(glu::DataType samplerType)457 deUint32 getTextureFormat (glu::DataType samplerType)
458 {
459 	using namespace glu;
460 
461 	switch (samplerType)
462 	{
463 		case TYPE_SAMPLER_1D:
464 		case TYPE_SAMPLER_2D:
465 		case TYPE_SAMPLER_CUBE:
466 		case TYPE_SAMPLER_2D_ARRAY:
467 		case TYPE_SAMPLER_3D:
468 			return GL_RGBA8;
469 
470 		case TYPE_INT_SAMPLER_1D:
471 		case TYPE_INT_SAMPLER_2D:
472 		case TYPE_INT_SAMPLER_CUBE:
473 		case TYPE_INT_SAMPLER_2D_ARRAY:
474 		case TYPE_INT_SAMPLER_3D:
475 			return GL_RGBA8I;
476 
477 		case TYPE_UINT_SAMPLER_1D:
478 		case TYPE_UINT_SAMPLER_2D:
479 		case TYPE_UINT_SAMPLER_CUBE:
480 		case TYPE_UINT_SAMPLER_2D_ARRAY:
481 		case TYPE_UINT_SAMPLER_3D:
482 			return GL_RGBA8UI;
483 
484 		default:
485 			DE_ASSERT(!"Unsupported (sampler) type");
486 			return 0;
487 	}
488 }
489 
490 // create a texture suitable for sampling by the given sampler type and bind it
createTexture(glu::DataType samplerType,float redChannelValue,int binding)491 de::MovePtr<glu::Texture2D> UniformLocationCase::createTexture (glu::DataType samplerType, float redChannelValue, int binding)
492 {
493 	using namespace glu;
494 
495 	const glw::Functions&	gl		 = m_renderCtx.getFunctions();
496 
497 	const deUint32			format	 = getTextureFormat(samplerType);
498 	de::MovePtr<Texture2D>	tex;
499 
500 	tex = de::MovePtr<Texture2D>(new Texture2D(m_renderCtx, format, 16, 16));
501 
502 	tex->getRefTexture().allocLevel(0);
503 
504 	if (format == GL_RGBA8I || format == GL_RGBA8UI)
505 		tcu::clear(tex->getRefTexture().getLevel(0), tcu::IVec4(int(redChannelValue), 0, 0, 0));
506 	else
507 		tcu::clear(tex->getRefTexture().getLevel(0), tcu::Vec4(redChannelValue, 0.0f, 0.0f, 1.0f));
508 
509 	gl.activeTexture(GL_TEXTURE0 + binding);
510 	tex->upload();
511 
512 	gl.bindTexture(GL_TEXTURE_2D, tex->getGLTexture());
513 	gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
514 	gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
515 
516 	GLU_EXPECT_NO_ERROR(gl.getError(), "UniformLocationCase: texture upload");
517 
518 	return tex;
519 }
520 
render(const glu::ShaderProgram & program,const vector<UniformInfo> & uniformList)521 void UniformLocationCase::render (const glu::ShaderProgram& program, const vector<UniformInfo>& uniformList)
522 {
523 	using glu::Texture2D;
524 	using de::MovePtr;
525 	typedef vector<Texture2D*> TextureList;
526 
527 	const glw::Functions&	gl				= m_renderCtx.getFunctions();
528 	const deUint32			programID		= program.getProgram();
529 	const deInt32			posLoc			= gl.getAttribLocation(programID, "a_position");
530 
531 	// Vertex data.
532 	const float position[] =
533 	{
534 		-1.0f, -1.0f, 0.1f,	1.0f,
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 	};
539 	const deUint16			indices[]		= { 0, 1, 2, 2, 1, 3 };
540 
541 	// some buffers to feed to the GPU, only the first element is relevant since the others are never verified
542 	float					floatBuf[16]	= {0.0f};
543 	deInt32					intBuf[4]		= {0};
544 	deUint32				uintBuf[4]		= {0};
545 
546 	TextureList				texList;
547 
548 	TCU_CHECK(posLoc >= 0);
549 	gl.useProgram(programID);
550 
551 	try
552 	{
553 
554 		// Set uniforms
555 		for (unsigned int uniformNdx = 0; uniformNdx < uniformList.size(); uniformNdx++)
556 		{
557 			const UniformInfo&	uniformInfo			= uniformList[uniformNdx];
558 			int					expectedLocation	= uniformInfo.location;
559 
560 			for (glu::BasicTypeIterator subTypeIter = glu::BasicTypeIterator::begin(&uniformInfo.type); subTypeIter != glu::BasicTypeIterator::end(&uniformInfo.type); subTypeIter++)
561 			{
562 				const glu::VarType	type			= glu::getVarType(uniformInfo.type, subTypeIter.getPath());
563 				const string		name			= getUniformName(uniformNdx, uniformInfo.type, subTypeIter.getPath());
564 				const int			gotLoc			= gl.getUniformLocation(programID, name.c_str());
565 				const glu::DataType	scalarType		= glu::getDataTypeScalarType(type.getBasicType());
566 				const char*	const	typeName		= glu::getDataTypeName(scalarType);
567 				const float			expectedValue	= getExpectedValue(scalarType, expectedLocation, typeName);
568 
569 				if (glu::isDataTypeSampler(scalarType))
570 				{
571 					const int binding = (int)texList.size();
572 
573 					texList.push_back(createTexture(scalarType, expectedValue, binding).release());
574 					gl.uniform1i(gotLoc, binding);
575 				}
576 				else if(gotLoc >= 0)
577 				{
578 					floatBuf[0] = expectedValue;
579 					intBuf[0]   = int(expectedValue);
580 					uintBuf[0]  = deUint32(expectedValue);
581 
582 					m_testCtx.getLog() << tcu::TestLog::Message << "Set uniform " << name << " in location " << gotLoc << " to " << expectedValue << tcu::TestLog::EndMessage;
583 
584 					switch (type.getBasicType())
585 					{
586 						case glu::TYPE_FLOAT:			gl.uniform1fv(gotLoc, 1, floatBuf);					break;
587 						case glu::TYPE_FLOAT_VEC2:		gl.uniform2fv(gotLoc, 1, floatBuf);					break;
588 						case glu::TYPE_FLOAT_VEC3:		gl.uniform3fv(gotLoc, 1, floatBuf);					break;
589 						case glu::TYPE_FLOAT_VEC4:		gl.uniform4fv(gotLoc, 1, floatBuf);					break;
590 
591 						case glu::TYPE_INT:				gl.uniform1iv(gotLoc, 1, intBuf);					break;
592 						case glu::TYPE_INT_VEC2:		gl.uniform2iv(gotLoc, 1, intBuf);					break;
593 						case glu::TYPE_INT_VEC3:		gl.uniform3iv(gotLoc, 1, intBuf);					break;
594 						case glu::TYPE_INT_VEC4:		gl.uniform4iv(gotLoc, 1, intBuf);					break;
595 
596 						case glu::TYPE_UINT:			gl.uniform1uiv(gotLoc, 1, uintBuf);					break;
597 						case glu::TYPE_UINT_VEC2:		gl.uniform2uiv(gotLoc, 1, uintBuf);					break;
598 						case glu::TYPE_UINT_VEC3:		gl.uniform3uiv(gotLoc, 1, uintBuf);					break;
599 						case glu::TYPE_UINT_VEC4:		gl.uniform4uiv(gotLoc, 1, uintBuf);					break;
600 
601 						case glu::TYPE_BOOL:			gl.uniform1iv(gotLoc, 1, intBuf);					break;
602 						case glu::TYPE_BOOL_VEC2:		gl.uniform2iv(gotLoc, 1, intBuf);					break;
603 						case glu::TYPE_BOOL_VEC3:		gl.uniform3iv(gotLoc, 1, intBuf);					break;
604 						case glu::TYPE_BOOL_VEC4:		gl.uniform4iv(gotLoc, 1, intBuf);					break;
605 
606 						case glu::TYPE_FLOAT_MAT2:		gl.uniformMatrix2fv(gotLoc, 1, false, floatBuf);	break;
607 						case glu::TYPE_FLOAT_MAT2X3:	gl.uniformMatrix2x3fv(gotLoc, 1, false, floatBuf);	break;
608 						case glu::TYPE_FLOAT_MAT2X4:	gl.uniformMatrix2x4fv(gotLoc, 1, false, floatBuf);	break;
609 
610 						case glu::TYPE_FLOAT_MAT3X2:	gl.uniformMatrix3x2fv(gotLoc, 1, false, floatBuf);	break;
611 						case glu::TYPE_FLOAT_MAT3:		gl.uniformMatrix3fv(gotLoc, 1, false, floatBuf);	break;
612 						case glu::TYPE_FLOAT_MAT3X4:	gl.uniformMatrix3x4fv(gotLoc, 1, false, floatBuf);	break;
613 
614 						case glu::TYPE_FLOAT_MAT4X2:	gl.uniformMatrix4x2fv(gotLoc, 1, false, floatBuf);	break;
615 						case glu::TYPE_FLOAT_MAT4X3:	gl.uniformMatrix4x3fv(gotLoc, 1, false, floatBuf);	break;
616 						case glu::TYPE_FLOAT_MAT4:		gl.uniformMatrix4fv(gotLoc, 1, false, floatBuf);	break;
617 						default:
618 							DE_ASSERT(false);
619 					}
620 				}
621 
622 				expectedLocation += expectedLocation>=0;
623 			}
624 		}
625 
626 		gl.enableVertexAttribArray(posLoc);
627 		gl.vertexAttribPointer(posLoc, 4, GL_FLOAT, GL_FALSE, 0, &position[0]);
628 
629 		gl.drawElements(GL_TRIANGLES, DE_LENGTH_OF_ARRAY(indices), GL_UNSIGNED_SHORT, &indices[0]);
630 
631 		gl.disableVertexAttribArray(posLoc);
632 	}
633 	catch(...)
634 	{
635 		for (int i = 0; i < int(texList.size()); i++)
636 			delete texList[i];
637 
638 		throw;
639 	}
640 
641 	for (int i = 0; i < int(texList.size()); i++)
642 		delete texList[i];
643 }
644 
645 class MaxUniformLocationCase : public UniformLocationCase
646 {
647 public:
648 								MaxUniformLocationCase		(tcu::TestContext&			context,
649 															 glu::RenderContext&		renderContext,
650 															 const char*				name,
651 															 const char*				desc,
652 															 const vector<UniformInfo>&	uniformInfo);
~MaxUniformLocationCase(void)653 	virtual 					~MaxUniformLocationCase		(void) {}
654 	virtual IterateResult		iterate						(void);
655 };
656 
MaxUniformLocationCase(tcu::TestContext & context,glu::RenderContext & renderContext,const char * name,const char * desc,const vector<UniformInfo> & uniformInfo)657 MaxUniformLocationCase::MaxUniformLocationCase (tcu::TestContext&			context,
658 												glu::RenderContext&			renderContext,
659 												const char*					name,
660 												const char*					desc,
661 												const vector<UniformInfo>&	uniformInfo)
662 	: UniformLocationCase(context, renderContext, name, desc, uniformInfo)
663 {
664 	DE_ASSERT(!uniformInfo.empty());
665 }
666 
iterate(void)667 UniformLocationCase::IterateResult MaxUniformLocationCase::iterate (void)
668 {
669 	int					maxLocation = 1024;
670 	vector<UniformInfo>	uniformInfo = m_uniformInfo;
671 
672 	m_renderCtx.getFunctions().getIntegerv(GL_MAX_UNIFORM_LOCATIONS, &maxLocation);
673 
674 	uniformInfo[0].location = maxLocation-1;
675 
676 	return UniformLocationCase::run(uniformInfo);
677 }
678 
679 } // Anonymous
680 
UniformLocationTests(Context & context)681 UniformLocationTests::UniformLocationTests (Context& context)
682 	: TestCaseGroup(context, "uniform_location", "Explicit uniform locations")
683 {
684 }
685 
~UniformLocationTests(void)686 UniformLocationTests::~UniformLocationTests (void)
687 {
688 	for (int i = 0; i < int(structTypes.size()); i++)
689 		delete structTypes[i];
690 }
691 
createVarType(glu::DataType type)692 glu::VarType createVarType (glu::DataType type)
693 {
694 	return glu::VarType(type, glu::isDataTypeBoolOrBVec(type) ? glu::PRECISION_LAST : glu::PRECISION_HIGHP);
695 }
696 
init(void)697 void UniformLocationTests::init (void)
698 {
699 	using namespace glu;
700 
701 	const UniformInfo::ShaderStage checkStages[]	= { UniformInfo::SHADERSTAGE_VERTEX, UniformInfo::SHADERSTAGE_FRAGMENT };
702 	const char*						stageNames[]	= {"vertex", "fragment"};
703 	const int						maxLocations	= 1024;
704 	const int						baseSeed		= m_context.getTestContext().getCommandLine().getBaseSeed();
705 
706 	const DataType					primitiveTypes[] =
707 	{
708 		TYPE_FLOAT,
709 		TYPE_FLOAT_VEC2,
710 		TYPE_FLOAT_VEC3,
711 		TYPE_FLOAT_VEC4,
712 
713 		TYPE_INT,
714 		TYPE_INT_VEC2,
715 		TYPE_INT_VEC3,
716 		TYPE_INT_VEC4,
717 
718 		TYPE_UINT,
719 		TYPE_UINT_VEC2,
720 		TYPE_UINT_VEC3,
721 		TYPE_UINT_VEC4,
722 
723 		TYPE_BOOL,
724 		TYPE_BOOL_VEC2,
725 		TYPE_BOOL_VEC3,
726 		TYPE_BOOL_VEC4,
727 
728 		TYPE_FLOAT_MAT2,
729 		TYPE_FLOAT_MAT2X3,
730 		TYPE_FLOAT_MAT2X4,
731 		TYPE_FLOAT_MAT3X2,
732 		TYPE_FLOAT_MAT3,
733 		TYPE_FLOAT_MAT3X4,
734 		TYPE_FLOAT_MAT4X2,
735 		TYPE_FLOAT_MAT4X3,
736 		TYPE_FLOAT_MAT4,
737 
738 		TYPE_SAMPLER_2D,
739 		TYPE_INT_SAMPLER_2D,
740 		TYPE_UINT_SAMPLER_2D,
741 	};
742 
743 	const int maxPrimitiveTypeNdx = DE_LENGTH_OF_ARRAY(primitiveTypes) - 4;
744 	DE_ASSERT(primitiveTypes[maxPrimitiveTypeNdx] == TYPE_FLOAT_MAT4);
745 
746 	// Primitive type cases with trivial linkage
747 	{
748 		tcu::TestCaseGroup* const	group	= new tcu::TestCaseGroup(m_testCtx, "basic", "Location specified with use, single shader stage");
749 		de::Random					rng		(baseSeed + 0x1001);
750 		addChild(group);
751 
752 		for (int primitiveNdx = 0; primitiveNdx < DE_LENGTH_OF_ARRAY(primitiveTypes); primitiveNdx++)
753 		{
754 			const DataType		type	= primitiveTypes[primitiveNdx];
755 
756 			for (int stageNdx = 0; stageNdx < DE_LENGTH_OF_ARRAY(checkStages); stageNdx++)
757 			{
758 				const string		name		= string(getDataTypeName(type)) + "_" + stageNames[stageNdx];
759 
760 				vector<UniformInfo> config;
761 
762 				UniformInfo			uniform	(createVarType(type),
763 											 checkStages[stageNdx],
764 											 checkStages[stageNdx],
765 											 checkStages[stageNdx],
766 											 rng.getInt(0, maxLocations-1));
767 
768 				config.push_back(uniform);
769 				group->addChild(new UniformLocationCase (m_testCtx, m_context.getRenderContext(), name.c_str(), name.c_str(), config));
770 			}
771 		}
772 	}
773 
774 	// Arrays
775 	{
776 		tcu::TestCaseGroup* const	group	= new tcu::TestCaseGroup(m_testCtx, "array", "Array location specified with use, single shader stage");
777 		de::Random					rng		(baseSeed + 0x2001);
778 		addChild(group);
779 
780 		for (int primitiveNdx = 0; primitiveNdx < DE_LENGTH_OF_ARRAY(primitiveTypes); primitiveNdx++)
781 		{
782 			const DataType		type	= primitiveTypes[primitiveNdx];
783 
784 			for (int stageNdx = 0; stageNdx < DE_LENGTH_OF_ARRAY(checkStages); stageNdx++)
785 			{
786 
787 				const string		name	= string(getDataTypeName(type)) + "_" + stageNames[stageNdx];
788 
789 				vector<UniformInfo> config;
790 
791 				UniformInfo			uniform	(VarType(createVarType(type), 8),
792 												checkStages[stageNdx],
793 												checkStages[stageNdx],
794 												checkStages[stageNdx],
795 												rng.getInt(0, maxLocations-1-8));
796 
797 				config.push_back(uniform);
798 				group->addChild(new UniformLocationCase (m_testCtx, m_context.getRenderContext(), name.c_str(), name.c_str(), config));
799 			}
800 		}
801 	}
802 
803 	// Nested Arrays
804 	{
805 		tcu::TestCaseGroup* const	group	= new tcu::TestCaseGroup(m_testCtx, "nested_array", "Array location specified with use, single shader stage");
806 		de::Random					rng		(baseSeed + 0x3001);
807 		addChild(group);
808 
809 		for (int primitiveNdx = 0; primitiveNdx < DE_LENGTH_OF_ARRAY(primitiveTypes); primitiveNdx++)
810 		{
811 			const DataType		type	= primitiveTypes[primitiveNdx];
812 
813 			for (int stageNdx = 0; stageNdx < DE_LENGTH_OF_ARRAY(checkStages); stageNdx++)
814 			{
815 				const string		name		= string(getDataTypeName(type)) + "_" + stageNames[stageNdx];
816 				// stay comfortably within minimum max uniform component count (896 in fragment) and sampler count with all types
817 				const int			arraySize	= (getDataTypeScalarSize(type) > 4 || isDataTypeSampler(type)) ? 3 : 7;
818 
819 				vector<UniformInfo> config;
820 
821 				UniformInfo			uniform	(VarType(VarType(createVarType(type), arraySize), arraySize),
822 											 checkStages[stageNdx],
823 											 checkStages[stageNdx],
824 											 checkStages[stageNdx],
825 											 rng.getInt(0, maxLocations-1-arraySize*arraySize));
826 
827 				config.push_back(uniform);
828 				group->addChild(new UniformLocationCase (m_testCtx, m_context.getRenderContext(), name.c_str(), name.c_str(), config));
829 			}
830 		}
831 	}
832 
833 	// Structs
834 	{
835 		tcu::TestCaseGroup* const	group	= new tcu::TestCaseGroup(m_testCtx, "struct", "Struct location, random contents & declaration location");
836 		de::Random					rng		(baseSeed + 0x4001);
837 		addChild(group);
838 
839 		for (int caseNdx = 0; caseNdx < 16; caseNdx++)
840 		{
841 			typedef UniformInfo::ShaderStage Stage;
842 
843 			const string	name		= "case_" + de::toString(caseNdx);
844 
845 			const Stage		layoutLoc	= Stage(rng.getUint32()&0x3);
846 			const Stage		declareLoc	= Stage((rng.getUint32()&0x3) | layoutLoc);
847 			const Stage		verifyLoc	= Stage((rng.getUint32()&0x3) & declareLoc);
848 			const int		location	= layoutLoc ? rng.getInt(0, maxLocations-1-5) : -1;
849 
850 			StructType*		structProto = new StructType("S");
851 
852 			structTypes.push_back(structProto);
853 
854 			structProto->addMember("a", createVarType(primitiveTypes[rng.getInt(0, maxPrimitiveTypeNdx)]));
855 			structProto->addMember("b", createVarType(primitiveTypes[rng.getInt(0, maxPrimitiveTypeNdx)]));
856 			structProto->addMember("c", createVarType(primitiveTypes[rng.getInt(0, maxPrimitiveTypeNdx)]));
857 			structProto->addMember("d", createVarType(primitiveTypes[rng.getInt(0, maxPrimitiveTypeNdx)]));
858 			structProto->addMember("e", createVarType(primitiveTypes[rng.getInt(0, maxPrimitiveTypeNdx)]));
859 
860 			{
861 				vector<UniformInfo> config;
862 
863 				config.push_back(UniformInfo(VarType(structProto),
864 											 declareLoc,
865 											 layoutLoc,
866 											 verifyLoc,
867 											 location));
868 				group->addChild(new UniformLocationCase (m_testCtx, m_context.getRenderContext(), name.c_str(), name.c_str(), config));
869 			}
870 		}
871 	}
872 
873 	// Nested Structs
874 	{
875 		tcu::TestCaseGroup* const	group	= new tcu::TestCaseGroup(m_testCtx, "nested_struct", "Struct location specified with use, single shader stage");
876 		de::Random					rng		(baseSeed + 0x5001);
877 
878 		addChild(group);
879 
880 		for (int caseNdx = 0; caseNdx < 16; caseNdx++)
881 		{
882 			typedef UniformInfo::ShaderStage Stage;
883 
884 			const string	name		= "case_" + de::toString(caseNdx);
885 			const int		baseLoc		= rng.getInt(0, maxLocations-1-60);
886 
887 			// Structs need to be added in the order of their declaration
888 			const Stage		layoutLocs[]=
889 			{
890 				Stage(rng.getUint32()&0x3),
891 				Stage(rng.getUint32()&0x3),
892 				Stage(rng.getUint32()&0x3),
893 				Stage(rng.getUint32()&0x3),
894 			};
895 
896 			const deUint32	tempDecl[] =
897 			{
898 				(rng.getUint32()&0x3) | layoutLocs[0],
899 				(rng.getUint32()&0x3) | layoutLocs[1],
900 				(rng.getUint32()&0x3) | layoutLocs[2],
901 				(rng.getUint32()&0x3) | layoutLocs[3],
902 			};
903 
904 			// Component structs need to be declared if anything using them is declared
905 			const Stage		declareLocs[] =
906 			{
907 				Stage(tempDecl[0] | tempDecl[1] | tempDecl[2] | tempDecl[3]),
908 				Stage(tempDecl[1] | tempDecl[2] | tempDecl[3]),
909 				Stage(tempDecl[2] | tempDecl[3]),
910 				Stage(tempDecl[3]),
911 			};
912 
913 			const Stage		verifyLocs[] =
914 			{
915 				Stage(rng.getUint32()&0x3 & declareLocs[0]),
916 				Stage(rng.getUint32()&0x3 & declareLocs[1]),
917 				Stage(rng.getUint32()&0x3 & declareLocs[2]),
918 				Stage(rng.getUint32()&0x3 & declareLocs[3]),
919 			};
920 
921 			StructType*		testTypes[]	=
922 			{
923 				new StructType("Type0"),
924 				new StructType("Type1"),
925 				new StructType("Type2"),
926 				new StructType("Type3"),
927 			};
928 
929 			structTypes.push_back(testTypes[0]);
930 			structTypes.push_back(testTypes[1]);
931 			structTypes.push_back(testTypes[2]);
932 			structTypes.push_back(testTypes[3]);
933 
934 			testTypes[0]->addMember("a", createVarType(primitiveTypes[rng.getInt(0, maxPrimitiveTypeNdx)]));
935 			testTypes[0]->addMember("b", createVarType(primitiveTypes[rng.getInt(0, maxPrimitiveTypeNdx)]));
936 			testTypes[0]->addMember("c", createVarType(primitiveTypes[rng.getInt(0, maxPrimitiveTypeNdx)]));
937 			testTypes[0]->addMember("d", createVarType(primitiveTypes[rng.getInt(0, maxPrimitiveTypeNdx)]));
938 			testTypes[0]->addMember("e", createVarType(primitiveTypes[rng.getInt(0, maxPrimitiveTypeNdx)]));
939 
940 			testTypes[1]->addMember("a", createVarType(primitiveTypes[rng.getInt(0, maxPrimitiveTypeNdx)]));
941 			testTypes[1]->addMember("b", createVarType(primitiveTypes[rng.getInt(0, maxPrimitiveTypeNdx)]));
942 			testTypes[1]->addMember("c", createVarType(primitiveTypes[rng.getInt(0, maxPrimitiveTypeNdx)]));
943 			testTypes[1]->addMember("d", createVarType(primitiveTypes[rng.getInt(0, maxPrimitiveTypeNdx)]));
944 			testTypes[1]->addMember("e", createVarType(primitiveTypes[rng.getInt(0, maxPrimitiveTypeNdx)]));
945 
946 			testTypes[2]->addMember("a", VarType(testTypes[0]));
947 			testTypes[2]->addMember("b", VarType(testTypes[1]));
948 			testTypes[2]->addMember("c", createVarType(primitiveTypes[rng.getInt(0, maxPrimitiveTypeNdx)]));
949 
950 			testTypes[3]->addMember("a", VarType(testTypes[2]));
951 
952 			{
953 				vector<UniformInfo> config;
954 
955 				config.push_back(UniformInfo(VarType(testTypes[0]),
956 											 declareLocs[0],
957 											 layoutLocs[0],
958 											 verifyLocs[0],
959 											 layoutLocs[0] ? baseLoc : -1));
960 
961 				config.push_back(UniformInfo(VarType(testTypes[1]),
962 											 declareLocs[1],
963 											 layoutLocs[1],
964 											 verifyLocs[1],
965 											 layoutLocs[1] ? baseLoc+5 : -1));
966 
967 				config.push_back(UniformInfo(VarType(testTypes[2]),
968 											 declareLocs[2],
969 											 layoutLocs[2],
970 											 verifyLocs[2],
971 											 layoutLocs[2] ? baseLoc+16 : -1));
972 
973 				config.push_back(UniformInfo(VarType(testTypes[3]),
974 											 declareLocs[3],
975 											 layoutLocs[3],
976 											 verifyLocs[3],
977 											 layoutLocs[3] ? baseLoc+27 : -1));
978 
979 				group->addChild(new UniformLocationCase (m_testCtx, m_context.getRenderContext(), name.c_str(), name.c_str(), config));
980 			}
981 		}
982 	}
983 
984 	// Min/Max location
985 	{
986 		tcu::TestCaseGroup* const	group		= new tcu::TestCaseGroup(m_testCtx, "min_max", "Maximum & minimum location");
987 
988 		addChild(group);
989 
990 		for (int primitiveNdx = 0; primitiveNdx < DE_LENGTH_OF_ARRAY(primitiveTypes); primitiveNdx++)
991 		{
992 			const DataType		type	= primitiveTypes[primitiveNdx];
993 
994 			for (int stageNdx = 0; stageNdx < DE_LENGTH_OF_ARRAY(checkStages); stageNdx++)
995 			{
996 				const string		name		= string(getDataTypeName(type)) + "_" + stageNames[stageNdx];
997 				vector<UniformInfo> config;
998 
999 				config.push_back(UniformInfo(createVarType(type),
1000 											 checkStages[stageNdx],
1001 											 checkStages[stageNdx],
1002 											 checkStages[stageNdx],
1003 											 0));
1004 
1005 				group->addChild(new UniformLocationCase (m_testCtx, m_context.getRenderContext(), (name+"_min").c_str(), (name+"_min").c_str(), config));
1006 
1007 				group->addChild(new MaxUniformLocationCase (m_testCtx, m_context.getRenderContext(), (name+"_max").c_str(), (name+"_max").c_str(), config));
1008 			}
1009 		}
1010 	}
1011 
1012 	// Link
1013 	{
1014 		tcu::TestCaseGroup* const	group	= new tcu::TestCaseGroup(m_testCtx, "link", "Location specified independently from use");
1015 		de::Random					rng		(baseSeed + 0x82e1);
1016 
1017 		addChild(group);
1018 
1019 		for (int caseNdx = 0; caseNdx < 10; caseNdx++)
1020 		{
1021 			const string		name		= "case_" + de::toString(caseNdx);
1022 			vector<UniformInfo> config;
1023 
1024 			vector<int>			locations	= shuffledRange(0, maxLocations, 0x1234 + caseNdx*100);
1025 
1026 			for (int count = 0; count < 32; count++)
1027 			{
1028 				typedef UniformInfo::ShaderStage Stage;
1029 
1030 				const Stage			layoutLoc	= Stage(rng.getUint32()&0x3);
1031 				const Stage			declareLoc	= Stage((rng.getUint32()&0x3) | layoutLoc);
1032 				const Stage			verifyLoc	= Stage((rng.getUint32()&0x3) & declareLoc);
1033 
1034 				const UniformInfo	uniform		(createVarType(primitiveTypes[rng.getInt(0, maxPrimitiveTypeNdx)]),
1035 												 declareLoc,
1036 												 layoutLoc,
1037 												 verifyLoc,
1038 												 (layoutLoc!=0) ? locations.back() : -1);
1039 
1040 				config.push_back(uniform);
1041 				locations.pop_back();
1042 			}
1043 			group->addChild(new UniformLocationCase (m_testCtx, m_context.getRenderContext(), name.c_str(), name.c_str(), config));
1044 		}
1045 	}
1046 
1047 	// Negative
1048 	{
1049 		gls::ShaderLibrary			shaderLibrary    (m_testCtx, m_context.getRenderContext(), m_context.getContextInfo());
1050 		const vector<TestNode*>     negativeCases    = shaderLibrary.loadShaderFile("shaders/uniform_location.test");
1051 		tcu::TestCaseGroup* const	group			 = new tcu::TestCaseGroup(m_testCtx, "negative", "Negative tests");
1052 
1053 		addChild(group);
1054 
1055 		for (int ndx = 0; ndx < int(negativeCases.size()); ndx++)
1056 			group->addChild(negativeCases[ndx]);
1057 	}
1058 }
1059 
1060 } // Functional
1061 } // gles31
1062 } // deqp
1063