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
53namespace deqp
54{
55namespace gles31
56{
57namespace Functional
58{
59namespace
60{
61
62using std::string;
63using std::vector;
64using std::map;
65using de::UniquePtr;
66using glu::VarType;
67
68struct 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
84	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
94class UniformLocationCase : public tcu::TestCase
95{
96public:
97								UniformLocationCase		(tcu::TestContext&			context,
98														 glu::RenderContext&		renderContext,
99														 const char*				name,
100														 const char*				desc,
101														 const vector<UniformInfo>&	uniformInfo);
102	virtual 					~UniformLocationCase	(void) {}
103
104	virtual IterateResult		iterate					(void);
105
106protected:
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
127string 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
135string 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
146UniformLocationCase::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]
158std::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
174glu::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.
193float 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
216UniformLocationCase::IterateResult UniformLocationCase::iterate (void)
217{
218	return run(m_uniformInfo);
219}
220
221UniformLocationCase::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
254glu::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
363bool 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)
436bool 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
458deUint32 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
492de::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
522void 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
646class MaxUniformLocationCase : public UniformLocationCase
647{
648public:
649								MaxUniformLocationCase		(tcu::TestContext&			context,
650															 glu::RenderContext&		renderContext,
651															 const char*				name,
652															 const char*				desc,
653															 const vector<UniformInfo>&	uniformInfo);
654	virtual 					~MaxUniformLocationCase		(void) {}
655	virtual IterateResult		iterate						(void);
656};
657
658MaxUniformLocationCase::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
668UniformLocationCase::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
682UniformLocationTests::UniformLocationTests (Context& context)
683	: TestCaseGroup(context, "uniform_location", "Explicit uniform locations")
684{
685}
686
687UniformLocationTests::~UniformLocationTests (void)
688{
689	for (int i = 0; i < int(structTypes.size()); i++)
690		delete structTypes[i];
691}
692
693glu::VarType createVarType (glu::DataType type)
694{
695	return glu::VarType(type, glu::isDataTypeBoolOrBVec(type) ? glu::PRECISION_LAST : glu::PRECISION_HIGHP);
696}
697
698void 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