• 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::__anon227711d50111::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 glu::VarType	type		= glu::getVarType(uniformInfo.type, subTypeIter.getPath());
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_ASSERT(!"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 deUint16			indices[]		= { 0, 1, 2, 2, 1, 3 };
541 
542 	// some buffers to feed to the GPU, only the first element is relevant since the others are never verified
543 	float					floatBuf[16]	= {0.0f};
544 	deInt32					intBuf[4]		= {0};
545 	deUint32				uintBuf[4]		= {0};
546 
547 	TextureList				texList;
548 
549 	TCU_CHECK(posLoc >= 0);
550 	gl.useProgram(programID);
551 
552 	try
553 	{
554 
555 		// Set uniforms
556 		for (unsigned int uniformNdx = 0; uniformNdx < uniformList.size(); uniformNdx++)
557 		{
558 			const UniformInfo&	uniformInfo			= uniformList[uniformNdx];
559 			int					expectedLocation	= uniformInfo.location;
560 
561 			for (glu::BasicTypeIterator subTypeIter = glu::BasicTypeIterator::begin(&uniformInfo.type); subTypeIter != glu::BasicTypeIterator::end(&uniformInfo.type); subTypeIter++)
562 			{
563 				const glu::VarType	type			= glu::getVarType(uniformInfo.type, subTypeIter.getPath());
564 				const string		name			= getUniformName(uniformNdx, uniformInfo.type, subTypeIter.getPath());
565 				const int			gotLoc			= gl.getUniformLocation(programID, name.c_str());
566 				const glu::DataType	scalarType		= glu::getDataTypeScalarType(type.getBasicType());
567 				const char*	const	typeName		= glu::getDataTypeName(scalarType);
568 				const float			expectedValue	= getExpectedValue(scalarType, expectedLocation, typeName);
569 
570 				if (glu::isDataTypeSampler(scalarType))
571 				{
572 					const int binding = (int)texList.size();
573 
574 					texList.push_back(createTexture(scalarType, expectedValue, binding).release());
575 					gl.uniform1i(gotLoc, binding);
576 				}
577 				else if(gotLoc >= 0)
578 				{
579 					floatBuf[0] = expectedValue;
580 					intBuf[0]   = int(expectedValue);
581 					uintBuf[0]  = deUint32(expectedValue);
582 
583 					m_testCtx.getLog() << tcu::TestLog::Message << "Set uniform " << name << " in location " << gotLoc << " to " << expectedValue << tcu::TestLog::EndMessage;
584 
585 					switch (type.getBasicType())
586 					{
587 						case glu::TYPE_FLOAT:			gl.uniform1fv(gotLoc, 1, floatBuf);					break;
588 						case glu::TYPE_FLOAT_VEC2:		gl.uniform2fv(gotLoc, 1, floatBuf);					break;
589 						case glu::TYPE_FLOAT_VEC3:		gl.uniform3fv(gotLoc, 1, floatBuf);					break;
590 						case glu::TYPE_FLOAT_VEC4:		gl.uniform4fv(gotLoc, 1, floatBuf);					break;
591 
592 						case glu::TYPE_INT:				gl.uniform1iv(gotLoc, 1, intBuf);					break;
593 						case glu::TYPE_INT_VEC2:		gl.uniform2iv(gotLoc, 1, intBuf);					break;
594 						case glu::TYPE_INT_VEC3:		gl.uniform3iv(gotLoc, 1, intBuf);					break;
595 						case glu::TYPE_INT_VEC4:		gl.uniform4iv(gotLoc, 1, intBuf);					break;
596 
597 						case glu::TYPE_UINT:			gl.uniform1uiv(gotLoc, 1, uintBuf);					break;
598 						case glu::TYPE_UINT_VEC2:		gl.uniform2uiv(gotLoc, 1, uintBuf);					break;
599 						case glu::TYPE_UINT_VEC3:		gl.uniform3uiv(gotLoc, 1, uintBuf);					break;
600 						case glu::TYPE_UINT_VEC4:		gl.uniform4uiv(gotLoc, 1, uintBuf);					break;
601 
602 						case glu::TYPE_BOOL:			gl.uniform1iv(gotLoc, 1, intBuf);					break;
603 						case glu::TYPE_BOOL_VEC2:		gl.uniform2iv(gotLoc, 1, intBuf);					break;
604 						case glu::TYPE_BOOL_VEC3:		gl.uniform3iv(gotLoc, 1, intBuf);					break;
605 						case glu::TYPE_BOOL_VEC4:		gl.uniform4iv(gotLoc, 1, intBuf);					break;
606 
607 						case glu::TYPE_FLOAT_MAT2:		gl.uniformMatrix2fv(gotLoc, 1, false, floatBuf);	break;
608 						case glu::TYPE_FLOAT_MAT2X3:	gl.uniformMatrix2x3fv(gotLoc, 1, false, floatBuf);	break;
609 						case glu::TYPE_FLOAT_MAT2X4:	gl.uniformMatrix2x4fv(gotLoc, 1, false, floatBuf);	break;
610 
611 						case glu::TYPE_FLOAT_MAT3X2:	gl.uniformMatrix3x2fv(gotLoc, 1, false, floatBuf);	break;
612 						case glu::TYPE_FLOAT_MAT3:		gl.uniformMatrix3fv(gotLoc, 1, false, floatBuf);	break;
613 						case glu::TYPE_FLOAT_MAT3X4:	gl.uniformMatrix3x4fv(gotLoc, 1, false, floatBuf);	break;
614 
615 						case glu::TYPE_FLOAT_MAT4X2:	gl.uniformMatrix4x2fv(gotLoc, 1, false, floatBuf);	break;
616 						case glu::TYPE_FLOAT_MAT4X3:	gl.uniformMatrix4x3fv(gotLoc, 1, false, floatBuf);	break;
617 						case glu::TYPE_FLOAT_MAT4:		gl.uniformMatrix4fv(gotLoc, 1, false, floatBuf);	break;
618 						default:
619 							DE_ASSERT(false);
620 					}
621 				}
622 
623 				expectedLocation += expectedLocation>=0;
624 			}
625 		}
626 
627 		gl.enableVertexAttribArray(posLoc);
628 		gl.vertexAttribPointer(posLoc, 4, GL_FLOAT, GL_FALSE, 0, &position[0]);
629 
630 		gl.drawElements(GL_TRIANGLES, DE_LENGTH_OF_ARRAY(indices), GL_UNSIGNED_SHORT, &indices[0]);
631 
632 		gl.disableVertexAttribArray(posLoc);
633 	}
634 	catch(...)
635 	{
636 		for (int i = 0; i < int(texList.size()); i++)
637 			delete texList[i];
638 
639 		throw;
640 	}
641 
642 	for (int i = 0; i < int(texList.size()); i++)
643 		delete texList[i];
644 }
645 
646 class MaxUniformLocationCase : public UniformLocationCase
647 {
648 public:
649 								MaxUniformLocationCase		(tcu::TestContext&			context,
650 															 glu::RenderContext&		renderContext,
651 															 const char*				name,
652 															 const char*				desc,
653 															 const vector<UniformInfo>&	uniformInfo);
~MaxUniformLocationCase(void)654 	virtual 					~MaxUniformLocationCase		(void) {}
655 	virtual IterateResult		iterate						(void);
656 };
657 
MaxUniformLocationCase(tcu::TestContext & context,glu::RenderContext & renderContext,const char * name,const char * desc,const vector<UniformInfo> & uniformInfo)658 MaxUniformLocationCase::MaxUniformLocationCase (tcu::TestContext&			context,
659 												glu::RenderContext&			renderContext,
660 												const char*					name,
661 												const char*					desc,
662 												const vector<UniformInfo>&	uniformInfo)
663 	: UniformLocationCase(context, renderContext, name, desc, uniformInfo)
664 {
665 	DE_ASSERT(!uniformInfo.empty());
666 }
667 
iterate(void)668 UniformLocationCase::IterateResult MaxUniformLocationCase::iterate (void)
669 {
670 	int					maxLocation = 1024;
671 	vector<UniformInfo>	uniformInfo = m_uniformInfo;
672 
673 	m_renderCtx.getFunctions().getIntegerv(GL_MAX_UNIFORM_LOCATIONS, &maxLocation);
674 
675 	uniformInfo[0].location = maxLocation-1;
676 
677 	return UniformLocationCase::run(uniformInfo);
678 }
679 
680 } // Anonymous
681 
UniformLocationTests(Context & context)682 UniformLocationTests::UniformLocationTests (Context& context)
683 	: TestCaseGroup(context, "uniform_location", "Explicit uniform locations")
684 {
685 }
686 
~UniformLocationTests(void)687 UniformLocationTests::~UniformLocationTests (void)
688 {
689 	for (int i = 0; i < int(structTypes.size()); i++)
690 		delete structTypes[i];
691 }
692 
createVarType(glu::DataType type)693 glu::VarType createVarType (glu::DataType type)
694 {
695 	return glu::VarType(type, glu::isDataTypeBoolOrBVec(type) ? glu::PRECISION_LAST : glu::PRECISION_HIGHP);
696 }
697 
init(void)698 void UniformLocationTests::init (void)
699 {
700 	using namespace glu;
701 
702 	const UniformInfo::ShaderStage checkStages[]	= { UniformInfo::SHADERSTAGE_VERTEX, UniformInfo::SHADERSTAGE_FRAGMENT };
703 	const char*						stageNames[]	= {"vertex", "fragment"};
704 	const int						maxLocations	= 1024;
705 	const int						baseSeed		= m_context.getTestContext().getCommandLine().getBaseSeed();
706 
707 	const DataType					primitiveTypes[] =
708 	{
709 		TYPE_FLOAT,
710 		TYPE_FLOAT_VEC2,
711 		TYPE_FLOAT_VEC3,
712 		TYPE_FLOAT_VEC4,
713 
714 		TYPE_INT,
715 		TYPE_INT_VEC2,
716 		TYPE_INT_VEC3,
717 		TYPE_INT_VEC4,
718 
719 		TYPE_UINT,
720 		TYPE_UINT_VEC2,
721 		TYPE_UINT_VEC3,
722 		TYPE_UINT_VEC4,
723 
724 		TYPE_BOOL,
725 		TYPE_BOOL_VEC2,
726 		TYPE_BOOL_VEC3,
727 		TYPE_BOOL_VEC4,
728 
729 		TYPE_FLOAT_MAT2,
730 		TYPE_FLOAT_MAT2X3,
731 		TYPE_FLOAT_MAT2X4,
732 		TYPE_FLOAT_MAT3X2,
733 		TYPE_FLOAT_MAT3,
734 		TYPE_FLOAT_MAT3X4,
735 		TYPE_FLOAT_MAT4X2,
736 		TYPE_FLOAT_MAT4X3,
737 		TYPE_FLOAT_MAT4,
738 
739 		TYPE_SAMPLER_2D,
740 		TYPE_INT_SAMPLER_2D,
741 		TYPE_UINT_SAMPLER_2D,
742 	};
743 
744 	const int maxPrimitiveTypeNdx = DE_LENGTH_OF_ARRAY(primitiveTypes) - 4;
745 	DE_ASSERT(primitiveTypes[maxPrimitiveTypeNdx] == TYPE_FLOAT_MAT4);
746 
747 	// Primitive type cases with trivial linkage
748 	{
749 		tcu::TestCaseGroup* const	group	= new tcu::TestCaseGroup(m_testCtx, "basic", "Location specified with use, single shader stage");
750 		de::Random					rng		(baseSeed + 0x1001);
751 		addChild(group);
752 
753 		for (int primitiveNdx = 0; primitiveNdx < DE_LENGTH_OF_ARRAY(primitiveTypes); primitiveNdx++)
754 		{
755 			const DataType		type	= primitiveTypes[primitiveNdx];
756 
757 			for (int stageNdx = 0; stageNdx < DE_LENGTH_OF_ARRAY(checkStages); stageNdx++)
758 			{
759 				const string		name		= string(getDataTypeName(type)) + "_" + stageNames[stageNdx];
760 
761 				vector<UniformInfo> config;
762 
763 				UniformInfo			uniform	(createVarType(type),
764 											 checkStages[stageNdx],
765 											 checkStages[stageNdx],
766 											 checkStages[stageNdx],
767 											 rng.getInt(0, maxLocations-1));
768 
769 				config.push_back(uniform);
770 				group->addChild(new UniformLocationCase (m_testCtx, m_context.getRenderContext(), name.c_str(), name.c_str(), config));
771 			}
772 		}
773 	}
774 
775 	// Arrays
776 	{
777 		tcu::TestCaseGroup* const	group	= new tcu::TestCaseGroup(m_testCtx, "array", "Array location specified with use, single shader stage");
778 		de::Random					rng		(baseSeed + 0x2001);
779 		addChild(group);
780 
781 		for (int primitiveNdx = 0; primitiveNdx < DE_LENGTH_OF_ARRAY(primitiveTypes); primitiveNdx++)
782 		{
783 			const DataType		type	= primitiveTypes[primitiveNdx];
784 
785 			for (int stageNdx = 0; stageNdx < DE_LENGTH_OF_ARRAY(checkStages); stageNdx++)
786 			{
787 
788 				const string		name	= string(getDataTypeName(type)) + "_" + stageNames[stageNdx];
789 
790 				vector<UniformInfo> config;
791 
792 				UniformInfo			uniform	(VarType(createVarType(type), 8),
793 												checkStages[stageNdx],
794 												checkStages[stageNdx],
795 												checkStages[stageNdx],
796 												rng.getInt(0, maxLocations-1-8));
797 
798 				config.push_back(uniform);
799 				group->addChild(new UniformLocationCase (m_testCtx, m_context.getRenderContext(), name.c_str(), name.c_str(), config));
800 			}
801 		}
802 	}
803 
804 	// Nested Arrays
805 	{
806 		tcu::TestCaseGroup* const	group	= new tcu::TestCaseGroup(m_testCtx, "nested_array", "Array location specified with use, single shader stage");
807 		de::Random					rng		(baseSeed + 0x3001);
808 		addChild(group);
809 
810 		for (int primitiveNdx = 0; primitiveNdx < DE_LENGTH_OF_ARRAY(primitiveTypes); primitiveNdx++)
811 		{
812 			const DataType		type	= primitiveTypes[primitiveNdx];
813 
814 			for (int stageNdx = 0; stageNdx < DE_LENGTH_OF_ARRAY(checkStages); stageNdx++)
815 			{
816 				const string		name		= string(getDataTypeName(type)) + "_" + stageNames[stageNdx];
817 				// stay comfortably within minimum max uniform component count (896 in fragment) and sampler count with all types
818 				const int			arraySize	= (getDataTypeScalarSize(type) > 4 || isDataTypeSampler(type)) ? 3 : 7;
819 
820 				vector<UniformInfo> config;
821 
822 				UniformInfo			uniform	(VarType(VarType(createVarType(type), arraySize), arraySize),
823 											 checkStages[stageNdx],
824 											 checkStages[stageNdx],
825 											 checkStages[stageNdx],
826 											 rng.getInt(0, maxLocations-1-arraySize*arraySize));
827 
828 				config.push_back(uniform);
829 				group->addChild(new UniformLocationCase (m_testCtx, m_context.getRenderContext(), name.c_str(), name.c_str(), config));
830 			}
831 		}
832 	}
833 
834 	// Structs
835 	{
836 		tcu::TestCaseGroup* const	group	= new tcu::TestCaseGroup(m_testCtx, "struct", "Struct location, random contents & declaration location");
837 		de::Random					rng		(baseSeed + 0x4001);
838 		addChild(group);
839 
840 		for (int caseNdx = 0; caseNdx < 16; caseNdx++)
841 		{
842 			typedef UniformInfo::ShaderStage Stage;
843 
844 			const string	name		= "case_" + de::toString(caseNdx);
845 
846 			const Stage		layoutLoc	= Stage(rng.getUint32()&0x3);
847 			const Stage		declareLoc	= Stage((rng.getUint32()&0x3) | layoutLoc);
848 			const Stage		verifyLoc	= Stage((rng.getUint32()&0x3) & declareLoc);
849 			const int		location	= layoutLoc ? rng.getInt(0, maxLocations-1-5) : -1;
850 
851 			StructType*		structProto = new StructType("S");
852 
853 			structTypes.push_back(structProto);
854 
855 			structProto->addMember("a", createVarType(primitiveTypes[rng.getInt(0, maxPrimitiveTypeNdx)]));
856 			structProto->addMember("b", createVarType(primitiveTypes[rng.getInt(0, maxPrimitiveTypeNdx)]));
857 			structProto->addMember("c", createVarType(primitiveTypes[rng.getInt(0, maxPrimitiveTypeNdx)]));
858 			structProto->addMember("d", createVarType(primitiveTypes[rng.getInt(0, maxPrimitiveTypeNdx)]));
859 			structProto->addMember("e", createVarType(primitiveTypes[rng.getInt(0, maxPrimitiveTypeNdx)]));
860 
861 			{
862 				vector<UniformInfo> config;
863 
864 				config.push_back(UniformInfo(VarType(structProto),
865 											 declareLoc,
866 											 layoutLoc,
867 											 verifyLoc,
868 											 location));
869 				group->addChild(new UniformLocationCase (m_testCtx, m_context.getRenderContext(), name.c_str(), name.c_str(), config));
870 			}
871 		}
872 	}
873 
874 	// Nested Structs
875 	{
876 		tcu::TestCaseGroup* const	group	= new tcu::TestCaseGroup(m_testCtx, "nested_struct", "Struct location specified with use, single shader stage");
877 		de::Random					rng		(baseSeed + 0x5001);
878 
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 			const int		baseLoc		= rng.getInt(0, maxLocations-1-60);
887 
888 			// Structs need to be added in the order of their declaration
889 			const Stage		layoutLocs[]=
890 			{
891 				Stage(rng.getUint32()&0x3),
892 				Stage(rng.getUint32()&0x3),
893 				Stage(rng.getUint32()&0x3),
894 				Stage(rng.getUint32()&0x3),
895 			};
896 
897 			const deUint32	tempDecl[] =
898 			{
899 				(rng.getUint32()&0x3) | layoutLocs[0],
900 				(rng.getUint32()&0x3) | layoutLocs[1],
901 				(rng.getUint32()&0x3) | layoutLocs[2],
902 				(rng.getUint32()&0x3) | layoutLocs[3],
903 			};
904 
905 			// Component structs need to be declared if anything using them is declared
906 			const Stage		declareLocs[] =
907 			{
908 				Stage(tempDecl[0] | tempDecl[1] | tempDecl[2] | tempDecl[3]),
909 				Stage(tempDecl[1] | tempDecl[2] | tempDecl[3]),
910 				Stage(tempDecl[2] | tempDecl[3]),
911 				Stage(tempDecl[3]),
912 			};
913 
914 			const Stage		verifyLocs[] =
915 			{
916 				Stage(rng.getUint32()&0x3 & declareLocs[0]),
917 				Stage(rng.getUint32()&0x3 & declareLocs[1]),
918 				Stage(rng.getUint32()&0x3 & declareLocs[2]),
919 				Stage(rng.getUint32()&0x3 & declareLocs[3]),
920 			};
921 
922 			StructType*		testTypes[]	=
923 			{
924 				new StructType("Type0"),
925 				new StructType("Type1"),
926 				new StructType("Type2"),
927 				new StructType("Type3"),
928 			};
929 
930 			structTypes.push_back(testTypes[0]);
931 			structTypes.push_back(testTypes[1]);
932 			structTypes.push_back(testTypes[2]);
933 			structTypes.push_back(testTypes[3]);
934 
935 			testTypes[0]->addMember("a", createVarType(primitiveTypes[rng.getInt(0, maxPrimitiveTypeNdx)]));
936 			testTypes[0]->addMember("b", createVarType(primitiveTypes[rng.getInt(0, maxPrimitiveTypeNdx)]));
937 			testTypes[0]->addMember("c", createVarType(primitiveTypes[rng.getInt(0, maxPrimitiveTypeNdx)]));
938 			testTypes[0]->addMember("d", createVarType(primitiveTypes[rng.getInt(0, maxPrimitiveTypeNdx)]));
939 			testTypes[0]->addMember("e", createVarType(primitiveTypes[rng.getInt(0, maxPrimitiveTypeNdx)]));
940 
941 			testTypes[1]->addMember("a", createVarType(primitiveTypes[rng.getInt(0, maxPrimitiveTypeNdx)]));
942 			testTypes[1]->addMember("b", createVarType(primitiveTypes[rng.getInt(0, maxPrimitiveTypeNdx)]));
943 			testTypes[1]->addMember("c", createVarType(primitiveTypes[rng.getInt(0, maxPrimitiveTypeNdx)]));
944 			testTypes[1]->addMember("d", createVarType(primitiveTypes[rng.getInt(0, maxPrimitiveTypeNdx)]));
945 			testTypes[1]->addMember("e", createVarType(primitiveTypes[rng.getInt(0, maxPrimitiveTypeNdx)]));
946 
947 			testTypes[2]->addMember("a", VarType(testTypes[0]));
948 			testTypes[2]->addMember("b", VarType(testTypes[1]));
949 			testTypes[2]->addMember("c", createVarType(primitiveTypes[rng.getInt(0, maxPrimitiveTypeNdx)]));
950 
951 			testTypes[3]->addMember("a", VarType(testTypes[2]));
952 
953 			{
954 				vector<UniformInfo> config;
955 
956 				config.push_back(UniformInfo(VarType(testTypes[0]),
957 											 declareLocs[0],
958 											 layoutLocs[0],
959 											 verifyLocs[0],
960 											 layoutLocs[0] ? baseLoc : -1));
961 
962 				config.push_back(UniformInfo(VarType(testTypes[1]),
963 											 declareLocs[1],
964 											 layoutLocs[1],
965 											 verifyLocs[1],
966 											 layoutLocs[1] ? baseLoc+5 : -1));
967 
968 				config.push_back(UniformInfo(VarType(testTypes[2]),
969 											 declareLocs[2],
970 											 layoutLocs[2],
971 											 verifyLocs[2],
972 											 layoutLocs[2] ? baseLoc+16 : -1));
973 
974 				config.push_back(UniformInfo(VarType(testTypes[3]),
975 											 declareLocs[3],
976 											 layoutLocs[3],
977 											 verifyLocs[3],
978 											 layoutLocs[3] ? baseLoc+27 : -1));
979 
980 				group->addChild(new UniformLocationCase (m_testCtx, m_context.getRenderContext(), name.c_str(), name.c_str(), config));
981 			}
982 		}
983 	}
984 
985 	// Min/Max location
986 	{
987 		tcu::TestCaseGroup* const	group		= new tcu::TestCaseGroup(m_testCtx, "min_max", "Maximum & minimum location");
988 		de::Random					rng			(baseSeed + 0x1f01);
989 
990 		addChild(group);
991 
992 		for (int primitiveNdx = 0; primitiveNdx < DE_LENGTH_OF_ARRAY(primitiveTypes); primitiveNdx++)
993 		{
994 			const DataType		type	= primitiveTypes[primitiveNdx];
995 
996 			for (int stageNdx = 0; stageNdx < DE_LENGTH_OF_ARRAY(checkStages); stageNdx++)
997 			{
998 				const string		name		= string(getDataTypeName(type)) + "_" + stageNames[stageNdx];
999 				vector<UniformInfo> config;
1000 
1001 				config.push_back(UniformInfo(createVarType(type),
1002 											 checkStages[stageNdx],
1003 											 checkStages[stageNdx],
1004 											 checkStages[stageNdx],
1005 											 0));
1006 
1007 				group->addChild(new UniformLocationCase (m_testCtx, m_context.getRenderContext(), (name+"_min").c_str(), (name+"_min").c_str(), config));
1008 
1009 				group->addChild(new MaxUniformLocationCase (m_testCtx, m_context.getRenderContext(), (name+"_max").c_str(), (name+"_max").c_str(), config));
1010 			}
1011 		}
1012 	}
1013 
1014 	// Link
1015 	{
1016 		tcu::TestCaseGroup* const	group	= new tcu::TestCaseGroup(m_testCtx, "link", "Location specified independently from use");
1017 		de::Random					rng		(baseSeed + 0x82e1);
1018 
1019 		addChild(group);
1020 
1021 		for (int caseNdx = 0; caseNdx < 10; caseNdx++)
1022 		{
1023 			const string		name		= "case_" + de::toString(caseNdx);
1024 			vector<UniformInfo> config;
1025 
1026 			vector<int>			locations	= shuffledRange(0, maxLocations, 0x1234 + caseNdx*100);
1027 
1028 			for (int count = 0; count < 32; count++)
1029 			{
1030 				typedef UniformInfo::ShaderStage Stage;
1031 
1032 				const Stage			layoutLoc	= Stage(rng.getUint32()&0x3);
1033 				const Stage			declareLoc	= Stage((rng.getUint32()&0x3) | layoutLoc);
1034 				const Stage			verifyLoc	= Stage((rng.getUint32()&0x3) & declareLoc);
1035 
1036 				const UniformInfo	uniform		(createVarType(primitiveTypes[rng.getInt(0, maxPrimitiveTypeNdx)]),
1037 												 declareLoc,
1038 												 layoutLoc,
1039 												 verifyLoc,
1040 												 (layoutLoc!=0) ? locations.back() : -1);
1041 
1042 				config.push_back(uniform);
1043 				locations.pop_back();
1044 			}
1045 			group->addChild(new UniformLocationCase (m_testCtx, m_context.getRenderContext(), name.c_str(), name.c_str(), config));
1046 		}
1047 	}
1048 
1049 	// Negative
1050 	{
1051 		gls::ShaderLibrary			shaderLibrary    (m_testCtx, m_context.getRenderContext(), m_context.getContextInfo());
1052 		const vector<TestNode*>     negativeCases    = shaderLibrary.loadShaderFile("shaders/uniform_location.test");
1053 		tcu::TestCaseGroup* const	group			 = new tcu::TestCaseGroup(m_testCtx, "negative", "Negative tests");
1054 
1055 		addChild(group);
1056 
1057 		for (int ndx = 0; ndx < int(negativeCases.size()); ndx++)
1058 			group->addChild(negativeCases[ndx]);
1059 	}
1060 }
1061 
1062 } // Functional
1063 } // gles31
1064 } // deqp
1065