es31fProgramInterfaceQueryTestCase.cpp revision 6a1979c5e502d1403cbccf122b6dab8dd05b3c63
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 Program interface query test case
22 *//*--------------------------------------------------------------------*/
23
24#include "es31fProgramInterfaceQueryTestCase.hpp"
25#include "es31fProgramInterfaceDefinitionUtil.hpp"
26#include "tcuTestLog.hpp"
27#include "gluVarTypeUtil.hpp"
28#include "gluStrUtil.hpp"
29#include "gluContextInfo.hpp"
30#include "gluShaderProgram.hpp"
31#include "glwFunctions.hpp"
32#include "glwEnums.hpp"
33#include "deString.h"
34#include "deStringUtil.hpp"
35#include "deSTLUtil.hpp"
36
37namespace deqp
38{
39namespace gles31
40{
41namespace Functional
42{
43namespace
44{
45
46using ProgramInterfaceDefinition::VariablePathComponent;
47using ProgramInterfaceDefinition::VariableSearchFilter;
48
49static glw::GLenum getProgramDefaultBlockInterfaceFromStorage (glu::Storage storage)
50{
51	switch (storage)
52	{
53		case glu::STORAGE_IN:
54		case glu::STORAGE_PATCH_IN:
55			return GL_PROGRAM_INPUT;
56
57		case glu::STORAGE_OUT:
58		case glu::STORAGE_PATCH_OUT:
59			return GL_PROGRAM_OUTPUT;
60
61		case glu::STORAGE_UNIFORM:
62			return GL_UNIFORM;
63
64		default:
65			DE_ASSERT(false);
66			return 0;
67	}
68}
69
70static bool isBufferBackedInterfaceBlockStorage (glu::Storage storage)
71{
72	return storage == glu::STORAGE_BUFFER || storage == glu::STORAGE_UNIFORM;
73}
74
75const char* getRequiredExtensionForStage (glu::ShaderType stage)
76{
77	switch (stage)
78	{
79		case glu::SHADERTYPE_COMPUTE:
80		case glu::SHADERTYPE_VERTEX:
81		case glu::SHADERTYPE_FRAGMENT:
82			return DE_NULL;
83
84		case glu::SHADERTYPE_GEOMETRY:
85			return "GL_EXT_geometry_shader";
86
87		case glu::SHADERTYPE_TESSELLATION_CONTROL:
88		case glu::SHADERTYPE_TESSELLATION_EVALUATION:
89			return "GL_EXT_tessellation_shader";
90
91		default:
92			DE_ASSERT(false);
93			return DE_NULL;
94	}
95}
96
97static int getTypeSize (glu::DataType type)
98{
99	if (type == glu::TYPE_FLOAT)
100		return 4;
101	else if (type == glu::TYPE_INT || type == glu::TYPE_UINT)
102		return 4;
103	else if (type == glu::TYPE_BOOL)
104		return 4; // uint
105
106	DE_ASSERT(false);
107	return 0;
108}
109
110static int getVarTypeSize (const glu::VarType& type)
111{
112	if (type.isBasicType())
113	{
114		// return in basic machine units
115		return glu::getDataTypeScalarSize(type.getBasicType()) * getTypeSize(glu::getDataTypeScalarType(type.getBasicType()));
116	}
117	else if (type.isStructType())
118	{
119		int size = 0;
120		for (int ndx = 0; ndx < type.getStructPtr()->getNumMembers(); ++ndx)
121			size += getVarTypeSize(type.getStructPtr()->getMember(ndx).getType());
122		return size;
123	}
124	else if (type.isArrayType())
125	{
126		// unsized arrays are handled as if they had only one element
127		if (type.getArraySize() == glu::VarType::UNSIZED_ARRAY)
128			return getVarTypeSize(type.getElementType());
129		else
130			return type.getArraySize() * getVarTypeSize(type.getElementType());
131	}
132	else
133	{
134		DE_ASSERT(false);
135		return 0;
136	}
137}
138
139static glu::MatrixOrder getMatrixOrderFromPath (const std::vector<VariablePathComponent>& path)
140{
141	glu::MatrixOrder order = glu::MATRIXORDER_LAST;
142
143	// inherit majority
144	for (int pathNdx = 0; pathNdx < (int)path.size(); ++pathNdx)
145	{
146		glu::MatrixOrder matOrder;
147
148		if (path[pathNdx].isInterfaceBlock())
149			matOrder = path[pathNdx].getInterfaceBlock()->layout.matrixOrder;
150		else if (path[pathNdx].isDeclaration())
151			matOrder = path[pathNdx].getDeclaration()->layout.matrixOrder;
152		else if (path[pathNdx].isVariableType())
153			matOrder = glu::MATRIXORDER_LAST;
154		else
155		{
156			DE_ASSERT(false);
157			return glu::MATRIXORDER_LAST;
158		}
159
160		if (matOrder != glu::MATRIXORDER_LAST)
161			order = matOrder;
162	}
163
164	return order;
165}
166
167class PropValidator
168{
169public:
170									PropValidator					(Context& context, ProgramResourcePropFlags validationProp, const char* requiredExtension);
171
172	virtual std::string				getHumanReadablePropertyString	(glw::GLint propVal) const;
173	virtual void					validate						(const ProgramInterfaceDefinition::Program* program, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const = 0;
174
175	bool							isSupported						(void) const;
176	bool							isSelected						(deUint32 caseFlags) const;
177
178protected:
179	void							setError						(const std::string& err) const;
180
181	tcu::TestContext&				m_testCtx;
182	const glu::RenderContext&		m_renderContext;
183
184private:
185	const glu::ContextInfo&			m_contextInfo;
186	const char*						m_extension;
187	const ProgramResourcePropFlags	m_validationProp;
188};
189
190PropValidator::PropValidator (Context& context, ProgramResourcePropFlags validationProp, const char* requiredExtension)
191	: m_testCtx			(context.getTestContext())
192	, m_renderContext	(context.getRenderContext())
193	, m_contextInfo		(context.getContextInfo())
194	, m_extension		(requiredExtension)
195	, m_validationProp	(validationProp)
196{
197}
198
199std::string PropValidator::getHumanReadablePropertyString (glw::GLint propVal) const
200{
201	return de::toString(propVal);
202}
203
204bool PropValidator::isSupported (void) const
205{
206	return m_extension == DE_NULL || m_contextInfo.isExtensionSupported(m_extension);
207}
208
209bool PropValidator::isSelected (deUint32 caseFlags) const
210{
211	return (caseFlags & (deUint32)m_validationProp) != 0;
212}
213
214void PropValidator::setError (const std::string& err) const
215{
216	// don't overwrite earlier errors
217	if (m_testCtx.getTestResult() == QP_TEST_RESULT_PASS)
218		m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, err.c_str());
219}
220
221class SingleVariableValidator : public PropValidator
222{
223public:
224					SingleVariableValidator	(Context& context, ProgramResourcePropFlags validationProp, glw::GLuint programID, const VariableSearchFilter& filter, const char* requiredExtension);
225
226	void			validate				(const ProgramInterfaceDefinition::Program* program, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const;
227	virtual void	validateSingleVariable	(const std::vector<VariablePathComponent>& path, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const = 0;
228	virtual void	validateBuiltinVariable	(const std::string& resource, glw::GLint propValue, const std::string& implementationName) const;
229
230protected:
231	const VariableSearchFilter	m_filter;
232	const glw::GLuint			m_programID;
233};
234
235SingleVariableValidator::SingleVariableValidator (Context& context, ProgramResourcePropFlags validationProp, glw::GLuint programID, const VariableSearchFilter& filter, const char* requiredExtension)
236	: PropValidator	(context, validationProp, requiredExtension)
237	, m_filter		(filter)
238	, m_programID	(programID)
239{
240}
241
242void SingleVariableValidator::validate (const ProgramInterfaceDefinition::Program* program, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const
243{
244	std::vector<VariablePathComponent> path;
245
246	if (findProgramVariablePathByPathName(path, program, resource, m_filter))
247	{
248		const glu::VarType* variable = (path.back().isVariableType()) ? (path.back().getVariableType()) : (DE_NULL);
249
250		if (!variable || !variable->isBasicType())
251		{
252			m_testCtx.getLog() << tcu::TestLog::Message << "Error, resource name \"" << resource << "\" refers to a non-basic type." << tcu::TestLog::EndMessage;
253			setError("resource not basic type");
254		}
255		else
256			validateSingleVariable(path, resource, propValue, implementationName);
257
258		// finding matching variable in any shader is sufficient
259		return;
260	}
261	else if (deStringBeginsWith(resource.c_str(), "gl_"))
262	{
263		// special case for builtins
264		validateBuiltinVariable(resource, propValue, implementationName);
265		return;
266	}
267
268	// we are only supplied good names, generated by ourselves
269	DE_ASSERT(false);
270	throw tcu::InternalError("Resource name consistency error");
271}
272
273void SingleVariableValidator::validateBuiltinVariable (const std::string& resource, glw::GLint propValue, const std::string& implementationName) const
274{
275	DE_UNREF(resource);
276	DE_UNREF(propValue);
277	DE_UNREF(implementationName);
278	DE_ASSERT(false);
279}
280
281class SingleBlockValidator : public PropValidator
282{
283public:
284								SingleBlockValidator	(Context& context, ProgramResourcePropFlags validationProp, glw::GLuint programID, const VariableSearchFilter& filter, const char* requiredExtension);
285
286	void						validate				(const ProgramInterfaceDefinition::Program* program, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const;
287	virtual void				validateSingleBlock		(const glu::InterfaceBlock& block, const std::vector<int>& instanceIndex, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const = 0;
288
289protected:
290	const VariableSearchFilter	m_filter;
291	const glw::GLuint			m_programID;
292};
293
294SingleBlockValidator::SingleBlockValidator (Context& context, ProgramResourcePropFlags validationProp, glw::GLuint programID, const VariableSearchFilter& filter, const char* requiredExtension)
295	: PropValidator	(context, validationProp, requiredExtension)
296	, m_filter		(filter)
297	, m_programID	(programID)
298{
299}
300
301void SingleBlockValidator::validate (const ProgramInterfaceDefinition::Program* program, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const
302{
303	glu::VarTokenizer	tokenizer		(resource.c_str());
304	const std::string	blockName		= tokenizer.getIdentifier();
305	std::vector<int>	instanceIndex;
306
307	tokenizer.advance();
308
309	// array index
310	while (tokenizer.getToken() == glu::VarTokenizer::TOKEN_LEFT_BRACKET)
311	{
312		tokenizer.advance();
313		DE_ASSERT(tokenizer.getToken() == glu::VarTokenizer::TOKEN_NUMBER);
314
315		instanceIndex.push_back(tokenizer.getNumber());
316
317		tokenizer.advance();
318		DE_ASSERT(tokenizer.getToken() == glu::VarTokenizer::TOKEN_RIGHT_BRACKET);
319
320		tokenizer.advance();
321	}
322
323	// no trailing garbage
324	DE_ASSERT(tokenizer.getToken() == glu::VarTokenizer::TOKEN_END);
325
326	for (int shaderNdx = 0; shaderNdx < (int)program->getShaders().size(); ++shaderNdx)
327	{
328		const ProgramInterfaceDefinition::Shader* const shader = program->getShaders()[shaderNdx];
329		if (!m_filter.matchesFilter(shader))
330			continue;
331
332		for (int blockNdx = 0; blockNdx < (int)shader->getDefaultBlock().interfaceBlocks.size(); ++blockNdx)
333		{
334			const glu::InterfaceBlock& block = shader->getDefaultBlock().interfaceBlocks[blockNdx];
335
336			if (m_filter.matchesFilter(block) && block.interfaceName == blockName)
337			{
338				// dimensions match
339				DE_ASSERT(instanceIndex.size() == block.dimensions.size());
340
341				validateSingleBlock(block, instanceIndex, resource, propValue, implementationName);
342				return;
343			}
344		}
345	}
346
347	// we are only supplied good names, generated by ourselves
348	DE_ASSERT(false);
349	throw tcu::InternalError("Resource name consistency error");
350}
351
352class TypeValidator : public SingleVariableValidator
353{
354public:
355				TypeValidator					(Context& context, glw::GLuint programID, const VariableSearchFilter& filter);
356
357	std::string	getHumanReadablePropertyString	(glw::GLint propVal) const;
358	void		validateSingleVariable			(const std::vector<VariablePathComponent>& path, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const;
359	void		validateBuiltinVariable			(const std::string& resource, glw::GLint propValue, const std::string& implementationName) const;
360};
361
362TypeValidator::TypeValidator (Context& context, glw::GLuint programID, const VariableSearchFilter& filter)
363	: SingleVariableValidator(context, PROGRAMRESOURCEPROP_TYPE, programID, filter, DE_NULL)
364{
365}
366
367std::string TypeValidator::getHumanReadablePropertyString (glw::GLint propVal) const
368{
369	return de::toString(glu::getShaderVarTypeStr(propVal));
370}
371
372void TypeValidator::validateSingleVariable (const std::vector<VariablePathComponent>& path, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const
373{
374	const glu::VarType* variable = path.back().getVariableType();
375
376	DE_UNREF(resource);
377	DE_UNREF(implementationName);
378
379	m_testCtx.getLog() << tcu::TestLog::Message << "Verifying type, expecting " << glu::getDataTypeName(variable->getBasicType()) << tcu::TestLog::EndMessage;
380
381	if (variable->getBasicType() != glu::getDataTypeFromGLType(propValue))
382	{
383		m_testCtx.getLog() << tcu::TestLog::Message << "\tError, got " << glu::getDataTypeName(glu::getDataTypeFromGLType(propValue)) << tcu::TestLog::EndMessage;
384		setError("resource type invalid");
385	}
386}
387
388void TypeValidator::validateBuiltinVariable (const std::string& resource, glw::GLint propValue, const std::string& implementationName) const
389{
390	DE_UNREF(implementationName);
391
392	static const struct
393	{
394		const char*		name;
395		glu::DataType	type;
396	} builtins[] =
397	{
398		{ "gl_Position",				glu::TYPE_FLOAT_VEC4	},
399		{ "gl_FragCoord",				glu::TYPE_FLOAT_VEC4	},
400		{ "gl_PerVertex.gl_Position",	glu::TYPE_FLOAT_VEC4	},
401		{ "gl_VertexID",				glu::TYPE_INT			},
402		{ "gl_InvocationID",			glu::TYPE_INT			},
403		{ "gl_NumWorkGroups",			glu::TYPE_UINT_VEC3		},
404		{ "gl_FragDepth",				glu::TYPE_FLOAT			},
405		{ "gl_TessLevelOuter[0]",		glu::TYPE_FLOAT			},
406		{ "gl_TessLevelInner[0]",		glu::TYPE_FLOAT			},
407	};
408
409	for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(builtins); ++ndx)
410	{
411		if (resource == builtins[ndx].name)
412		{
413			m_testCtx.getLog() << tcu::TestLog::Message << "Verifying type, expecting " << glu::getDataTypeName(builtins[ndx].type) << tcu::TestLog::EndMessage;
414
415			if (glu::getDataTypeFromGLType(propValue) != builtins[ndx].type)
416			{
417				m_testCtx.getLog() << tcu::TestLog::Message << "\tError, got " << glu::getDataTypeName(glu::getDataTypeFromGLType(propValue)) << tcu::TestLog::EndMessage;
418				setError("resource type invalid");
419			}
420			return;
421		}
422	}
423
424	DE_ASSERT(false);
425}
426
427class ArraySizeValidator : public SingleVariableValidator
428{
429public:
430				ArraySizeValidator				(Context& context, glw::GLuint programID, int unsizedArraySize, const VariableSearchFilter& filter);
431
432	void		validateSingleVariable			(const std::vector<VariablePathComponent>& path, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const;
433	void		validateBuiltinVariable			(const std::string& resource, glw::GLint propValue, const std::string& implementationName) const;
434
435private:
436	const int	m_unsizedArraySize;
437};
438
439ArraySizeValidator::ArraySizeValidator (Context& context, glw::GLuint programID, int unsizedArraySize, const VariableSearchFilter& filter)
440	: SingleVariableValidator	(context, PROGRAMRESOURCEPROP_ARRAY_SIZE, programID, filter, DE_NULL)
441	, m_unsizedArraySize		(unsizedArraySize)
442{
443}
444
445void ArraySizeValidator::validateSingleVariable (const std::vector<VariablePathComponent>& path, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const
446{
447	const VariablePathComponent		nullComponent;
448	const VariablePathComponent&	enclosingcomponent	= (path.size() > 1) ? (path[path.size()-2]) : (nullComponent);
449
450	const bool						isArray				= enclosingcomponent.isVariableType() && enclosingcomponent.getVariableType()->isArrayType();
451	const bool						inUnsizedArray		= isArray && (enclosingcomponent.getVariableType()->getArraySize() == glu::VarType::UNSIZED_ARRAY);
452	const int						arraySize			= (!isArray) ? (1) : (inUnsizedArray) ? (m_unsizedArraySize) : (enclosingcomponent.getVariableType()->getArraySize());
453
454	DE_ASSERT(arraySize >= 0);
455	DE_UNREF(resource);
456	DE_UNREF(implementationName);
457
458	m_testCtx.getLog() << tcu::TestLog::Message << "Verifying array size, expecting " << arraySize << tcu::TestLog::EndMessage;
459
460	if (arraySize != propValue)
461	{
462		m_testCtx.getLog() << tcu::TestLog::Message << "\tError, got " << propValue << tcu::TestLog::EndMessage;
463		setError("resource array size invalid");
464	}
465}
466
467void ArraySizeValidator::validateBuiltinVariable (const std::string& resource, glw::GLint propValue, const std::string& implementationName) const
468{
469	DE_UNREF(implementationName);
470
471	static const struct
472	{
473		const char*		name;
474		int				arraySize;
475	} builtins[] =
476	{
477		{ "gl_Position",				1	},
478		{ "gl_VertexID",				1	},
479		{ "gl_FragCoord",				1	},
480		{ "gl_PerVertex.gl_Position",	1	},
481		{ "gl_InvocationID",			1	},
482		{ "gl_NumWorkGroups",			1	},
483		{ "gl_FragDepth",				1	},
484		{ "gl_TessLevelOuter[0]",		4	},
485		{ "gl_TessLevelInner[0]",		2	},
486	};
487
488	for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(builtins); ++ndx)
489	{
490		if (resource == builtins[ndx].name)
491		{
492			m_testCtx.getLog() << tcu::TestLog::Message << "Verifying array size, expecting " << builtins[ndx].arraySize << tcu::TestLog::EndMessage;
493
494			if (propValue != builtins[ndx].arraySize)
495			{
496				m_testCtx.getLog() << tcu::TestLog::Message << "\tError, got " << propValue << tcu::TestLog::EndMessage;
497				setError("resource array size invalid");
498			}
499			return;
500		}
501	}
502
503	DE_ASSERT(false);
504}
505
506class ArrayStrideValidator : public SingleVariableValidator
507{
508public:
509				ArrayStrideValidator			(Context& context, glw::GLuint programID, const VariableSearchFilter& filter);
510
511	void		validateSingleVariable			(const std::vector<VariablePathComponent>& path, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const;
512};
513
514ArrayStrideValidator::ArrayStrideValidator (Context& context, glw::GLuint programID, const VariableSearchFilter& filter)
515	: SingleVariableValidator(context, PROGRAMRESOURCEPROP_ARRAY_STRIDE, programID, filter, DE_NULL)
516{
517}
518
519void ArrayStrideValidator::validateSingleVariable (const std::vector<VariablePathComponent>& path, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const
520{
521	const VariablePathComponent		nullComponent;
522	const VariablePathComponent&	component			= path.back();
523	const VariablePathComponent&	enclosingcomponent	= (path.size() > 1) ? (path[path.size()-2]) : (nullComponent);
524	const VariablePathComponent&	firstComponent		= path.front();
525
526	const bool						isBufferBlock		= firstComponent.isInterfaceBlock() && isBufferBackedInterfaceBlockStorage(firstComponent.getInterfaceBlock()->storage);
527	const bool						isArray				= enclosingcomponent.isVariableType() && enclosingcomponent.getVariableType()->isArrayType();
528	const bool						isAtomicCounter		= glu::isDataTypeAtomicCounter(component.getVariableType()->getBasicType()); // atomic counters are buffer backed with a stride of 4 basic machine units
529
530	DE_UNREF(resource);
531	DE_UNREF(implementationName);
532
533	// Layout tests will verify layouts of buffer backed arrays properly. Here we just check values are greater or equal to the element size
534	if (isBufferBlock && isArray)
535	{
536		const int elementSize = glu::getDataTypeScalarSize(component.getVariableType()->getBasicType()) * getTypeSize(glu::getDataTypeScalarType(component.getVariableType()->getBasicType()));
537		m_testCtx.getLog() << tcu::TestLog::Message << "Verifying array stride, expecting greater or equal to " << elementSize << tcu::TestLog::EndMessage;
538
539		if (propValue < elementSize)
540		{
541			m_testCtx.getLog() << tcu::TestLog::Message << "\tError, got " << propValue << tcu::TestLog::EndMessage;
542			setError("resource array stride invalid");
543		}
544	}
545	else
546	{
547		// Atomics are buffer backed with stride of 4 even though they are not in an interface block
548		const int arrayStride = (isAtomicCounter && isArray) ? (4) : (!isBufferBlock && !isAtomicCounter) ? (-1) : (0);
549
550		m_testCtx.getLog() << tcu::TestLog::Message << "Verifying array stride, expecting " << arrayStride << tcu::TestLog::EndMessage;
551
552		if (arrayStride != propValue)
553		{
554			m_testCtx.getLog() << tcu::TestLog::Message << "\tError, got " << propValue << tcu::TestLog::EndMessage;
555			setError("resource array stride invalid");
556		}
557	}
558}
559
560class BlockIndexValidator : public SingleVariableValidator
561{
562public:
563				BlockIndexValidator				(Context& context, glw::GLuint programID, const VariableSearchFilter& filter);
564
565	void		validateSingleVariable			(const std::vector<VariablePathComponent>& path, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const;
566};
567
568BlockIndexValidator::BlockIndexValidator (Context& context, glw::GLuint programID, const VariableSearchFilter& filter)
569	: SingleVariableValidator(context, PROGRAMRESOURCEPROP_BLOCK_INDEX, programID, filter, DE_NULL)
570{
571}
572
573void BlockIndexValidator::validateSingleVariable (const std::vector<VariablePathComponent>& path, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const
574{
575	const VariablePathComponent& firstComponent = path.front();
576
577	DE_UNREF(resource);
578	DE_UNREF(implementationName);
579
580	if (!firstComponent.isInterfaceBlock())
581	{
582		m_testCtx.getLog() << tcu::TestLog::Message << "Verifying block index, expecting -1" << tcu::TestLog::EndMessage;
583
584		if (propValue != -1)
585		{
586			m_testCtx.getLog() << tcu::TestLog::Message << "\tError, got " << propValue << tcu::TestLog::EndMessage;
587			setError("resource block index invalid");
588		}
589	}
590	else
591	{
592		m_testCtx.getLog() << tcu::TestLog::Message << "Verifying block index, expecting a valid block index" << tcu::TestLog::EndMessage;
593
594		if (propValue == -1)
595		{
596			m_testCtx.getLog() << tcu::TestLog::Message << "\tError, got " << propValue << tcu::TestLog::EndMessage;
597			setError("resource block index invalid");
598		}
599		else
600		{
601			const glw::Functions&	gl			= m_renderContext.getFunctions();
602			const glw::GLenum		interface	= (firstComponent.getInterfaceBlock()->storage == glu::STORAGE_UNIFORM) ? (GL_UNIFORM_BLOCK) :
603												  (firstComponent.getInterfaceBlock()->storage == glu::STORAGE_BUFFER) ? (GL_SHADER_STORAGE_BLOCK) :
604												  (0);
605			glw::GLint				written		= 0;
606			std::vector<char>		nameBuffer	(firstComponent.getInterfaceBlock()->interfaceName.size() + 3 * firstComponent.getInterfaceBlock()->dimensions.size() + 2, '\0'); // +3 for appended "[N]", +1 for '\0' and +1 just for safety
607
608			gl.getProgramResourceName(m_programID, interface, propValue, (int)nameBuffer.size() - 1, &written, &nameBuffer[0]);
609			GLU_EXPECT_NO_ERROR(gl.getError(), "query block name");
610			TCU_CHECK(written < (int)nameBuffer.size());
611			TCU_CHECK(nameBuffer.back() == '\0');
612
613			{
614				const std::string	blockName		(&nameBuffer[0], written);
615				std::ostringstream	expectedName;
616
617				expectedName << firstComponent.getInterfaceBlock()->interfaceName;
618				for (int dimensionNdx = 0; dimensionNdx < (int)firstComponent.getInterfaceBlock()->dimensions.size(); ++dimensionNdx)
619					expectedName << "[0]";
620
621				m_testCtx.getLog() << tcu::TestLog::Message << "Block name with index " << propValue << " is \"" << blockName << "\"" << tcu::TestLog::EndMessage;
622				if (blockName != expectedName.str())
623				{
624					m_testCtx.getLog() << tcu::TestLog::Message << "\tError, expected " << expectedName.str() << tcu::TestLog::EndMessage;
625					setError("resource block index invalid");
626				}
627			}
628		}
629	}
630}
631
632class IsRowMajorValidator : public SingleVariableValidator
633{
634public:
635				IsRowMajorValidator				(Context& context, glw::GLuint programID, const VariableSearchFilter& filter);
636
637	std::string getHumanReadablePropertyString	(glw::GLint propVal) const;
638	void		validateSingleVariable			(const std::vector<VariablePathComponent>& path, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const;
639};
640
641IsRowMajorValidator::IsRowMajorValidator (Context& context, glw::GLuint programID, const VariableSearchFilter& filter)
642	: SingleVariableValidator(context, PROGRAMRESOURCEPROP_MATRIX_ROW_MAJOR, programID, filter, DE_NULL)
643{
644}
645
646std::string IsRowMajorValidator::getHumanReadablePropertyString (glw::GLint propVal) const
647{
648	return de::toString(glu::getBooleanStr(propVal));
649}
650
651void IsRowMajorValidator::validateSingleVariable (const std::vector<VariablePathComponent>& path, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const
652{
653	const VariablePathComponent&	component			= path.back();
654	const VariablePathComponent&	firstComponent		= path.front();
655
656	const bool						isBufferBlock		= firstComponent.isInterfaceBlock() && isBufferBackedInterfaceBlockStorage(firstComponent.getInterfaceBlock()->storage);
657	const bool						isMatrix			= glu::isDataTypeMatrix(component.getVariableType()->getBasicType());
658	const int						expected			= (isBufferBlock && isMatrix && getMatrixOrderFromPath(path) == glu::MATRIXORDER_ROW_MAJOR) ? (1) : (0);
659
660	DE_UNREF(resource);
661	DE_UNREF(implementationName);
662
663	m_testCtx.getLog() << tcu::TestLog::Message << "Verifying matrix order, expecting IS_ROW_MAJOR = " << expected << tcu::TestLog::EndMessage;
664
665	if (propValue != expected)
666	{
667		m_testCtx.getLog() << tcu::TestLog::Message << "\tError, got " << propValue << tcu::TestLog::EndMessage;
668		setError("resource matrix order invalid");
669	}
670}
671
672class MatrixStrideValidator : public SingleVariableValidator
673{
674public:
675				MatrixStrideValidator			(Context& context, glw::GLuint programID, const VariableSearchFilter& filter);
676
677	void		validateSingleVariable			(const std::vector<VariablePathComponent>& path, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const;
678};
679
680MatrixStrideValidator::MatrixStrideValidator (Context& context, glw::GLuint programID, const VariableSearchFilter& filter)
681	: SingleVariableValidator(context, PROGRAMRESOURCEPROP_MATRIX_STRIDE, programID, filter, DE_NULL)
682{
683}
684
685void MatrixStrideValidator::validateSingleVariable (const std::vector<VariablePathComponent>& path, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const
686{
687	const VariablePathComponent&	component			= path.back();
688	const VariablePathComponent&	firstComponent		= path.front();
689
690	const bool						isBufferBlock		= firstComponent.isInterfaceBlock() && isBufferBackedInterfaceBlockStorage(firstComponent.getInterfaceBlock()->storage);
691	const bool						isMatrix			= glu::isDataTypeMatrix(component.getVariableType()->getBasicType());
692
693	DE_UNREF(resource);
694	DE_UNREF(implementationName);
695
696	// Layout tests will verify layouts of buffer backed arrays properly. Here we just check the stride is is greater or equal to the row/column size
697	if (isBufferBlock && isMatrix)
698	{
699		const bool	columnMajor			= getMatrixOrderFromPath(path) != glu::MATRIXORDER_ROW_MAJOR;
700		const int	numMajorElements	= (columnMajor) ? (glu::getDataTypeMatrixNumRows(component.getVariableType()->getBasicType())) : (glu::getDataTypeMatrixNumColumns(component.getVariableType()->getBasicType()));
701		const int	majorSize			= numMajorElements * getTypeSize(glu::getDataTypeScalarType(component.getVariableType()->getBasicType()));
702
703		m_testCtx.getLog() << tcu::TestLog::Message << "Verifying matrix stride, expecting greater or equal to " << majorSize << tcu::TestLog::EndMessage;
704
705		if (propValue < majorSize)
706		{
707			m_testCtx.getLog() << tcu::TestLog::Message << "\tError, got " << propValue << tcu::TestLog::EndMessage;
708			setError("resource matrix stride invalid");
709		}
710	}
711	else
712	{
713		const int matrixStride = (!isBufferBlock && !glu::isDataTypeAtomicCounter(component.getVariableType()->getBasicType())) ? (-1) : (0);
714
715		m_testCtx.getLog() << tcu::TestLog::Message << "Verifying matrix stride, expecting " << matrixStride << tcu::TestLog::EndMessage;
716
717		if (matrixStride != propValue)
718		{
719			m_testCtx.getLog() << tcu::TestLog::Message << "\tError, got " << propValue << tcu::TestLog::EndMessage;
720			setError("resource matrix stride invalid");
721		}
722	}
723}
724
725class AtomicCounterBufferIndexVerifier : public SingleVariableValidator
726{
727public:
728				AtomicCounterBufferIndexVerifier	(Context& context, glw::GLuint programID, const VariableSearchFilter& filter);
729
730	void		validateSingleVariable				(const std::vector<VariablePathComponent>& path, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const;
731};
732
733AtomicCounterBufferIndexVerifier::AtomicCounterBufferIndexVerifier (Context& context, glw::GLuint programID, const VariableSearchFilter& filter)
734	: SingleVariableValidator(context, PROGRAMRESOURCEPROP_ATOMIC_COUNTER_BUFFER_INDEX, programID, filter, DE_NULL)
735{
736}
737
738void AtomicCounterBufferIndexVerifier::validateSingleVariable (const std::vector<VariablePathComponent>& path, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const
739{
740	DE_UNREF(resource);
741	DE_UNREF(implementationName);
742
743	if (!glu::isDataTypeAtomicCounter(path.back().getVariableType()->getBasicType()))
744	{
745		m_testCtx.getLog() << tcu::TestLog::Message << "Verifying atomic counter buffer index, expecting -1" << tcu::TestLog::EndMessage;
746
747		if (propValue != -1)
748		{
749			m_testCtx.getLog() << tcu::TestLog::Message << "\tError, got " << propValue << tcu::TestLog::EndMessage;
750			setError("resource atomic counter buffer index invalid");
751		}
752	}
753	else
754	{
755		m_testCtx.getLog() << tcu::TestLog::Message << "Verifying atomic counter buffer index, expecting a valid index" << tcu::TestLog::EndMessage;
756
757		if (propValue == -1)
758		{
759			m_testCtx.getLog() << tcu::TestLog::Message << "\tError, got " << propValue << tcu::TestLog::EndMessage;
760			setError("resource atomic counter buffer index invalid");
761		}
762		else
763		{
764			const glw::Functions&	gl					= m_renderContext.getFunctions();
765			glw::GLint				numActiveResources	= 0;
766
767			gl.getProgramInterfaceiv(m_programID, GL_ATOMIC_COUNTER_BUFFER, GL_ACTIVE_RESOURCES, &numActiveResources);
768			GLU_EXPECT_NO_ERROR(gl.getError(), "getProgramInterfaceiv(..., GL_ATOMIC_COUNTER_BUFFER, GL_ACTIVE_RESOURCES, ...)");
769
770			if (propValue >= numActiveResources)
771			{
772				m_testCtx.getLog() << tcu::TestLog::Message << "\tError, got " << propValue << ", GL_ACTIVE_RESOURCES = " << numActiveResources << tcu::TestLog::EndMessage;
773				setError("resource atomic counter buffer index invalid");
774			}
775		}
776	}
777}
778
779class LocationValidator : public SingleVariableValidator
780{
781public:
782				LocationValidator		(Context& context, glw::GLuint programID, const VariableSearchFilter& filter);
783
784	void		validateSingleVariable	(const std::vector<VariablePathComponent>& path, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const;
785	void		validateBuiltinVariable	(const std::string& resource, glw::GLint propValue, const std::string& implementationName) const;
786};
787
788LocationValidator::LocationValidator (Context& context, glw::GLuint programID, const VariableSearchFilter& filter)
789	: SingleVariableValidator(context, PROGRAMRESOURCEPROP_LOCATION, programID, filter, DE_NULL)
790{
791}
792
793static int getVariableLocationLength (const glu::VarType& type)
794{
795	if (type.isBasicType())
796	{
797		if (glu::isDataTypeMatrix(type.getBasicType()))
798			return glu::getDataTypeMatrixNumColumns(type.getBasicType());
799		else
800			return 1;
801	}
802	else if (type.isStructType())
803	{
804		int size = 0;
805		for (int ndx = 0; ndx < type.getStructPtr()->getNumMembers(); ++ndx)
806			size += getVariableLocationLength(type.getStructPtr()->getMember(ndx).getType());
807		return size;
808	}
809	else if (type.isArrayType())
810		return type.getArraySize() * getVariableLocationLength(type.getElementType());
811	else
812	{
813		DE_ASSERT(false);
814		return 0;
815	}
816}
817
818static int getIOSubVariableLocation (const std::vector<VariablePathComponent>& path, int startNdx, int currentLocation)
819{
820	if (currentLocation == -1)
821		return -1;
822
823	if (path[startNdx].getVariableType()->isBasicType())
824		return currentLocation;
825	else if (path[startNdx].getVariableType()->isArrayType())
826		return getIOSubVariableLocation(path, startNdx+1, currentLocation);
827	else if (path[startNdx].getVariableType()->isStructType())
828	{
829		for (int ndx = 0; ndx < path[startNdx].getVariableType()->getStructPtr()->getNumMembers(); ++ndx)
830		{
831			if (&path[startNdx].getVariableType()->getStructPtr()->getMember(ndx).getType() == path[startNdx + 1].getVariableType())
832				return getIOSubVariableLocation(path, startNdx + 1, currentLocation);
833
834			if (currentLocation != -1)
835				currentLocation += getVariableLocationLength(path[startNdx].getVariableType()->getStructPtr()->getMember(ndx).getType());
836		}
837
838		// could not find member, never happens
839		DE_ASSERT(false);
840		return -1;
841	}
842	else
843	{
844		DE_ASSERT(false);
845		return -1;
846	}
847}
848
849static int getIOBlockVariableLocation (const std::vector<VariablePathComponent>& path)
850{
851	const glu::InterfaceBlock*	block			= path.front().getInterfaceBlock();
852	int							currentLocation	= block->layout.location;
853
854	// Find the block member
855	for (int memberNdx = 0; memberNdx < (int)block->variables.size(); ++memberNdx)
856	{
857		if (block->variables[memberNdx].layout.location != -1)
858			currentLocation = block->variables[memberNdx].layout.location;
859
860		if (&block->variables[memberNdx] == path[1].getDeclaration())
861			break;
862
863		// unspecified + unspecified = unspecified
864		if (currentLocation != -1)
865			currentLocation += getVariableLocationLength(block->variables[memberNdx].varType);
866	}
867
868	// Find subtype location in the complex type
869	return getIOSubVariableLocation(path, 2, currentLocation);
870}
871
872static int getExplicitLocationFromPath (const std::vector<VariablePathComponent>& path)
873{
874	const glu::VariableDeclaration* varDecl = (path[0].isInterfaceBlock()) ? (path[1].getDeclaration()) : (path[0].getDeclaration());
875
876	if (path.front().isInterfaceBlock() && path.front().getInterfaceBlock()->storage == glu::STORAGE_UNIFORM)
877	{
878		// inside uniform block
879		return -1;
880	}
881	else if (path.front().isInterfaceBlock() && (path.front().getInterfaceBlock()->storage == glu::STORAGE_IN		||
882												 path.front().getInterfaceBlock()->storage == glu::STORAGE_OUT		||
883												 path.front().getInterfaceBlock()->storage == glu::STORAGE_PATCH_IN	||
884												 path.front().getInterfaceBlock()->storage == glu::STORAGE_PATCH_OUT))
885	{
886		// inside ioblock
887		return getIOBlockVariableLocation(path);
888	}
889	else if (varDecl->storage == glu::STORAGE_UNIFORM)
890	{
891		// default block uniform
892		return varDecl->layout.location;
893	}
894	else if (varDecl->storage == glu::STORAGE_IN		||
895			 varDecl->storage == glu::STORAGE_OUT		||
896			 varDecl->storage == glu::STORAGE_PATCH_IN	||
897			 varDecl->storage == glu::STORAGE_PATCH_OUT)
898	{
899		// default block input/output
900		return getIOSubVariableLocation(path, 1, varDecl->layout.location);
901	}
902	else
903	{
904		DE_ASSERT(false);
905		return -1;
906	}
907}
908
909void LocationValidator::validateSingleVariable (const std::vector<VariablePathComponent>& path, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const
910{
911	const bool			isAtomicCounterUniform	= glu::isDataTypeAtomicCounter(path.back().getVariableType()->getBasicType());
912	const bool			isUniformBlockVariable	= path.front().isInterfaceBlock() && path.front().getInterfaceBlock()->storage == glu::STORAGE_UNIFORM;
913	const bool			isVertexShader			= m_filter.getShaderTypeBits() == (1u << glu::SHADERTYPE_VERTEX);
914	const bool			isFragmentShader		= m_filter.getShaderTypeBits() == (1u << glu::SHADERTYPE_FRAGMENT);
915	const glu::Storage	storage					= (path.front().isInterfaceBlock()) ? (path.front().getInterfaceBlock()->storage) : (path.front().getDeclaration()->storage);
916	const bool			isInputVariable			= (storage == glu::STORAGE_IN || storage == glu::STORAGE_PATCH_IN);
917	const bool			isOutputVariable		= (storage == glu::STORAGE_OUT || storage == glu::STORAGE_PATCH_OUT);
918	const int			explicitLayoutLocation	= getExplicitLocationFromPath(path);
919
920	bool				expectLocation;
921	std::string			reasonStr;
922
923	DE_UNREF(resource);
924
925	if (isAtomicCounterUniform)
926	{
927		expectLocation = false;
928		reasonStr = "Atomic counter uniforms have effective location of -1";
929	}
930	else if (isUniformBlockVariable)
931	{
932		expectLocation = false;
933		reasonStr = "Uniform block variables have effective location of -1";
934	}
935	else if (isInputVariable && !isVertexShader && explicitLayoutLocation == -1)
936	{
937		expectLocation = false;
938		reasonStr = "Inputs (except for vertex shader inputs) not declared with a location layout qualifier have effective location of -1";
939	}
940	else if (isOutputVariable && !isFragmentShader && explicitLayoutLocation == -1)
941	{
942		expectLocation = false;
943		reasonStr = "Outputs (except for fragment shader outputs) not declared with a location layout qualifier have effective location of -1";
944	}
945	else
946	{
947		expectLocation = true;
948	}
949
950	if (!expectLocation)
951	{
952		m_testCtx.getLog() << tcu::TestLog::Message << "Verifying uniform location, expecting -1. (" << reasonStr << ")" << tcu::TestLog::EndMessage;
953
954		if (propValue != -1)
955		{
956			m_testCtx.getLog() << tcu::TestLog::Message << "\tError, got " << propValue << tcu::TestLog::EndMessage;
957			setError("resource location invalid");
958		}
959	}
960	else
961	{
962		bool locationOk;
963
964		if (explicitLayoutLocation == -1)
965		{
966			m_testCtx.getLog() << tcu::TestLog::Message << "Verifying location, expecting a valid location" << tcu::TestLog::EndMessage;
967			locationOk = (propValue != -1);
968		}
969		else
970		{
971			m_testCtx.getLog() << tcu::TestLog::Message << "Verifying location, expecting " << explicitLayoutLocation << tcu::TestLog::EndMessage;
972			locationOk = (propValue == explicitLayoutLocation);
973		}
974
975		if (!locationOk)
976		{
977			m_testCtx.getLog() << tcu::TestLog::Message << "\tError, got " << propValue << tcu::TestLog::EndMessage;
978			setError("resource location invalid");
979		}
980		else
981		{
982			const VariablePathComponent		nullComponent;
983			const VariablePathComponent&	enclosingcomponent	= (path.size() > 1) ? (path[path.size()-2]) : (nullComponent);
984			const bool						isArray				= enclosingcomponent.isVariableType() && enclosingcomponent.getVariableType()->isArrayType();
985
986			const glw::Functions&			gl					= m_renderContext.getFunctions();
987			const glw::GLenum				interface			= getProgramDefaultBlockInterfaceFromStorage(storage);
988
989			m_testCtx.getLog() << tcu::TestLog::Message << "Comparing location to the values returned by GetProgramResourceLocation" << tcu::TestLog::EndMessage;
990
991			// Test all bottom-level array elements
992			if (isArray)
993			{
994				const std::string arrayResourceName = (implementationName.size() > 3) ? (implementationName.substr(0, implementationName.size() - 3)) : (""); // chop "[0]"
995
996				for (int arrayElementNdx = 0; arrayElementNdx < enclosingcomponent.getVariableType()->getArraySize(); ++arrayElementNdx)
997				{
998					const std::string	elementResourceName	= arrayResourceName + "[" + de::toString(arrayElementNdx) + "]";
999					const glw::GLint	location			= gl.getProgramResourceLocation(m_programID, interface, elementResourceName.c_str());
1000
1001					if (location != propValue+arrayElementNdx)
1002					{
1003						m_testCtx.getLog()
1004							<< tcu::TestLog::Message
1005							<< "\tError, getProgramResourceLocation (resource=\"" << elementResourceName << "\") returned location " << location
1006							<< ", expected " << (propValue+arrayElementNdx)
1007							<< tcu::TestLog::EndMessage;
1008						setError("resource location invalid");
1009					}
1010					else
1011						m_testCtx.getLog() << tcu::TestLog::Message << "\tLocation of \"" << elementResourceName << "\":\t" << location << tcu::TestLog::EndMessage;
1012				}
1013			}
1014			else
1015			{
1016				const glw::GLint location = gl.getProgramResourceLocation(m_programID, interface, implementationName.c_str());
1017
1018				if (location != propValue)
1019				{
1020					m_testCtx.getLog() << tcu::TestLog::Message << "\tError, getProgramResourceLocation returned location " << location << ", expected " << propValue << tcu::TestLog::EndMessage;
1021					setError("resource location invalid");
1022				}
1023			}
1024
1025		}
1026	}
1027}
1028
1029void LocationValidator::validateBuiltinVariable (const std::string& resource, glw::GLint propValue, const std::string& implementationName) const
1030{
1031	DE_UNREF(resource);
1032	DE_UNREF(implementationName);
1033
1034	// built-ins have no location
1035
1036	m_testCtx.getLog() << tcu::TestLog::Message << "Verifying location, expecting -1" << tcu::TestLog::EndMessage;
1037
1038	if (propValue != -1)
1039	{
1040		m_testCtx.getLog() << tcu::TestLog::Message << "\tError, got " << propValue << tcu::TestLog::EndMessage;
1041		setError("resource location invalid");
1042	}
1043}
1044
1045class VariableNameLengthValidator : public SingleVariableValidator
1046{
1047public:
1048				VariableNameLengthValidator	(Context& context, glw::GLuint programID, const VariableSearchFilter& filter);
1049
1050	void		validateSingleVariable		(const std::vector<VariablePathComponent>& path, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const;
1051	void		validateBuiltinVariable		(const std::string& resource, glw::GLint propValue, const std::string& implementationName) const;
1052	void		validateNameLength			(const std::string& implementationName, glw::GLint propValue) const;
1053};
1054
1055VariableNameLengthValidator::VariableNameLengthValidator (Context& context, glw::GLuint programID, const VariableSearchFilter& filter)
1056	: SingleVariableValidator(context, PROGRAMRESOURCEPROP_NAME_LENGTH, programID, filter, DE_NULL)
1057{
1058}
1059
1060void VariableNameLengthValidator::validateSingleVariable (const std::vector<VariablePathComponent>& path, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const
1061{
1062	DE_UNREF(path);
1063	DE_UNREF(resource);
1064	validateNameLength(implementationName, propValue);
1065}
1066
1067void VariableNameLengthValidator::validateBuiltinVariable (const std::string& resource, glw::GLint propValue, const std::string& implementationName) const
1068{
1069	DE_UNREF(resource);
1070	validateNameLength(implementationName, propValue);
1071}
1072
1073void VariableNameLengthValidator::validateNameLength (const std::string& implementationName, glw::GLint propValue) const
1074{
1075	const int expected = (int)implementationName.length() + 1; // includes null byte
1076	m_testCtx.getLog() << tcu::TestLog::Message << "Verifying name length, expecting " << expected << " (" << (int)implementationName.length() << " for \"" << implementationName << "\" + 1 byte for terminating null character)" << tcu::TestLog::EndMessage;
1077
1078	if (propValue != expected)
1079	{
1080		m_testCtx.getLog() << tcu::TestLog::Message << "\tError, invalid name length, got " << propValue << tcu::TestLog::EndMessage;
1081		setError("name length invalid");
1082	}
1083}
1084
1085class OffsetValidator : public SingleVariableValidator
1086{
1087public:
1088				OffsetValidator			(Context& context, glw::GLuint programID, const VariableSearchFilter& filter);
1089
1090	void		validateSingleVariable	(const std::vector<VariablePathComponent>& path, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const;
1091};
1092
1093OffsetValidator::OffsetValidator (Context& context, glw::GLuint programID, const VariableSearchFilter& filter)
1094	: SingleVariableValidator(context, PROGRAMRESOURCEPROP_OFFSET, programID, filter, DE_NULL)
1095{
1096}
1097
1098void OffsetValidator::validateSingleVariable (const std::vector<VariablePathComponent>& path, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const
1099{
1100	const bool isAtomicCounterUniform		= glu::isDataTypeAtomicCounter(path.back().getVariableType()->getBasicType());
1101	const bool isBufferBackedBlockStorage	= path.front().isInterfaceBlock() && isBufferBackedInterfaceBlockStorage(path.front().getInterfaceBlock()->storage);
1102
1103	DE_UNREF(resource);
1104	DE_UNREF(implementationName);
1105
1106	if (!isAtomicCounterUniform && !isBufferBackedBlockStorage)
1107	{
1108		// Not buffer backed
1109		m_testCtx.getLog() << tcu::TestLog::Message << "Verifying offset, expecting -1" << tcu::TestLog::EndMessage;
1110
1111		if (propValue != -1)
1112		{
1113			m_testCtx.getLog() << tcu::TestLog::Message << "\tError, invalid offset, got " << propValue << tcu::TestLog::EndMessage;
1114			setError("offset invalid");
1115		}
1116	}
1117	else
1118	{
1119		// Expect a valid offset
1120		m_testCtx.getLog() << tcu::TestLog::Message << "Verifying offset, expecting a valid offset" << tcu::TestLog::EndMessage;
1121
1122		if (propValue < 0)
1123		{
1124			m_testCtx.getLog() << tcu::TestLog::Message << "\tError, invalid offset, got " << propValue << tcu::TestLog::EndMessage;
1125			setError("offset invalid");
1126		}
1127	}
1128}
1129
1130class VariableReferencedByShaderValidator : public PropValidator
1131{
1132public:
1133								VariableReferencedByShaderValidator	(Context& context, glu::ShaderType shaderType, const VariableSearchFilter& searchFilter);
1134
1135	std::string					getHumanReadablePropertyString		(glw::GLint propVal) const;
1136	void						validate							(const ProgramInterfaceDefinition::Program* program, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const;
1137
1138private:
1139	const VariableSearchFilter	m_filter;
1140	const glu::ShaderType		m_shaderType;
1141};
1142
1143VariableReferencedByShaderValidator::VariableReferencedByShaderValidator (Context& context, glu::ShaderType shaderType, const VariableSearchFilter& searchFilter)
1144	: PropValidator	(context, PROGRAMRESOURCEPROP_REFERENCED_BY_SHADER, getRequiredExtensionForStage(shaderType))
1145	, m_filter		(VariableSearchFilter::logicalAnd(VariableSearchFilter::createShaderTypeFilter(shaderType), searchFilter))
1146	, m_shaderType	(shaderType)
1147{
1148	DE_ASSERT(m_shaderType < glu::SHADERTYPE_LAST);
1149}
1150
1151std::string VariableReferencedByShaderValidator::getHumanReadablePropertyString (glw::GLint propVal) const
1152{
1153	return de::toString(glu::getBooleanStr(propVal));
1154}
1155
1156void VariableReferencedByShaderValidator::validate (const ProgramInterfaceDefinition::Program* program, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const
1157{
1158	DE_UNREF(implementationName);
1159
1160	std::vector<VariablePathComponent>	dummyPath;
1161	const bool							referencedByShader = findProgramVariablePathByPathName(dummyPath, program, resource, m_filter);
1162
1163	m_testCtx.getLog()
1164		<< tcu::TestLog::Message
1165		<< "Verifying referenced by " << glu::getShaderTypeName(m_shaderType) << " shader, expecting "
1166		<< ((referencedByShader) ? ("GL_TRUE") : ("GL_FALSE"))
1167		<< tcu::TestLog::EndMessage;
1168
1169	if (propValue != ((referencedByShader) ? (1) : (0)))
1170	{
1171		m_testCtx.getLog() << tcu::TestLog::Message << "\tError, invalid referenced_by_" << glu::getShaderTypeName(m_shaderType) << ", got " << propValue << tcu::TestLog::EndMessage;
1172		setError("referenced_by_" + std::string(glu::getShaderTypeName(m_shaderType)) + " invalid");
1173	}
1174}
1175
1176class BlockNameLengthValidator : public SingleBlockValidator
1177{
1178public:
1179			BlockNameLengthValidator	(Context& context, const glw::GLuint programID, const VariableSearchFilter& filter);
1180
1181	void	validateSingleBlock			(const glu::InterfaceBlock& block, const std::vector<int>& instanceIndex, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const;
1182};
1183
1184BlockNameLengthValidator::BlockNameLengthValidator (Context& context, const glw::GLuint programID, const VariableSearchFilter& filter)
1185	: SingleBlockValidator(context, PROGRAMRESOURCEPROP_NAME_LENGTH, programID, filter, DE_NULL)
1186{
1187}
1188
1189void BlockNameLengthValidator::validateSingleBlock (const glu::InterfaceBlock& block, const std::vector<int>& instanceIndex, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const
1190{
1191	DE_UNREF(instanceIndex);
1192	DE_UNREF(block);
1193	DE_UNREF(resource);
1194
1195	const int expected = (int)implementationName.length() + 1; // includes null byte
1196	m_testCtx.getLog() << tcu::TestLog::Message << "Verifying name length, expecting " << expected << " (" << (int)implementationName.length() << " for \"" << implementationName << "\" + 1 byte for terminating null character)" << tcu::TestLog::EndMessage;
1197
1198	if (propValue != expected)
1199	{
1200		m_testCtx.getLog() << tcu::TestLog::Message << "\tError, invalid name length, got " << propValue << tcu::TestLog::EndMessage;
1201		setError("name length invalid");
1202	}
1203}
1204
1205class BufferBindingValidator : public SingleBlockValidator
1206{
1207public:
1208			BufferBindingValidator	(Context& context, const glw::GLuint programID, const VariableSearchFilter& filter);
1209
1210	void	validateSingleBlock		(const glu::InterfaceBlock& block, const std::vector<int>& instanceIndex, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const;
1211};
1212
1213BufferBindingValidator::BufferBindingValidator (Context& context, const glw::GLuint programID, const VariableSearchFilter& filter)
1214	: SingleBlockValidator(context, PROGRAMRESOURCEPROP_BUFFER_BINDING, programID, filter, DE_NULL)
1215{
1216}
1217
1218void BufferBindingValidator::validateSingleBlock (const glu::InterfaceBlock& block, const std::vector<int>& instanceIndex, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const
1219{
1220	DE_UNREF(resource);
1221	DE_UNREF(implementationName);
1222
1223	if (block.layout.binding != -1)
1224	{
1225		int flatIndex		= 0;
1226		int dimensionSize	= 1;
1227
1228		for (int dimensionNdx = (int)(block.dimensions.size()) - 1; dimensionNdx >= 0; --dimensionNdx)
1229		{
1230			flatIndex += dimensionSize * instanceIndex[dimensionNdx];
1231			dimensionSize *= block.dimensions[dimensionNdx];
1232		}
1233
1234		const int expected = (block.dimensions.empty()) ? (block.layout.binding) : (block.layout.binding + flatIndex);
1235		m_testCtx.getLog() << tcu::TestLog::Message << "Verifying block binding, expecting " << expected << tcu::TestLog::EndMessage;
1236
1237		if (propValue != expected)
1238		{
1239			m_testCtx.getLog() << tcu::TestLog::Message << "\tError, invalid buffer binding, got " << propValue << tcu::TestLog::EndMessage;
1240			setError("buffer binding invalid");
1241		}
1242	}
1243	else
1244	{
1245		m_testCtx.getLog() << tcu::TestLog::Message << "Verifying buffer binding, expecting a valid binding" << tcu::TestLog::EndMessage;
1246
1247		if (propValue < 0)
1248		{
1249			m_testCtx.getLog() << tcu::TestLog::Message << "\tError, invalid buffer binding, got " << propValue << tcu::TestLog::EndMessage;
1250			setError("buffer binding invalid");
1251		}
1252	}
1253}
1254
1255class BlockReferencedByShaderValidator : public PropValidator
1256{
1257public:
1258								BlockReferencedByShaderValidator	(Context& context, glu::ShaderType shaderType, const VariableSearchFilter& searchFilter);
1259
1260	std::string					getHumanReadablePropertyString		(glw::GLint propVal) const;
1261	void						validate							(const ProgramInterfaceDefinition::Program* program, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const;
1262
1263private:
1264	const VariableSearchFilter	m_filter;
1265	const glu::ShaderType		m_shaderType;
1266};
1267
1268BlockReferencedByShaderValidator::BlockReferencedByShaderValidator (Context& context, glu::ShaderType shaderType, const VariableSearchFilter& searchFilter)
1269	: PropValidator	(context, PROGRAMRESOURCEPROP_REFERENCED_BY_SHADER, getRequiredExtensionForStage(shaderType))
1270	, m_filter		(VariableSearchFilter::logicalAnd(VariableSearchFilter::createShaderTypeFilter(shaderType), searchFilter))
1271	, m_shaderType	(shaderType)
1272{
1273	DE_ASSERT(m_shaderType < glu::SHADERTYPE_LAST);
1274}
1275
1276std::string BlockReferencedByShaderValidator::getHumanReadablePropertyString (glw::GLint propVal) const
1277{
1278	return de::toString(glu::getBooleanStr(propVal));
1279}
1280
1281void BlockReferencedByShaderValidator::validate (const ProgramInterfaceDefinition::Program* program, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const
1282{
1283	const std::string	blockName			= glu::parseVariableName(resource.c_str());
1284	bool				referencedByShader	= false;
1285
1286	DE_UNREF(implementationName);
1287
1288	for (int shaderNdx = 0; shaderNdx < (int)program->getShaders().size(); ++shaderNdx)
1289	{
1290		const ProgramInterfaceDefinition::Shader* const shader = program->getShaders()[shaderNdx];
1291		if (!m_filter.matchesFilter(shader))
1292			continue;
1293
1294		for (int blockNdx = 0; blockNdx < (int)shader->getDefaultBlock().interfaceBlocks.size(); ++blockNdx)
1295		{
1296			const glu::InterfaceBlock& block = shader->getDefaultBlock().interfaceBlocks[blockNdx];
1297
1298			if (m_filter.matchesFilter(block) && block.interfaceName == blockName)
1299				referencedByShader = true;
1300		}
1301	}
1302
1303	m_testCtx.getLog()
1304		<< tcu::TestLog::Message
1305		<< "Verifying referenced by " << glu::getShaderTypeName(m_shaderType) << " shader, expecting "
1306		<< ((referencedByShader) ? ("GL_TRUE") : ("GL_FALSE"))
1307		<< tcu::TestLog::EndMessage;
1308
1309	if (propValue != ((referencedByShader) ? (1) : (0)))
1310	{
1311		m_testCtx.getLog() << tcu::TestLog::Message << "\tError, invalid referenced_by_" << glu::getShaderTypeName(m_shaderType) << ", got " << propValue << tcu::TestLog::EndMessage;
1312		setError("referenced_by_" + std::string(glu::getShaderTypeName(m_shaderType)) + " invalid");
1313	}
1314}
1315
1316class TopLevelArraySizeValidator : public SingleVariableValidator
1317{
1318public:
1319				TopLevelArraySizeValidator	(Context& context, glw::GLuint programID, const VariableSearchFilter& filter);
1320
1321	void		validateSingleVariable		(const std::vector<VariablePathComponent>& path, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const;
1322};
1323
1324TopLevelArraySizeValidator::TopLevelArraySizeValidator (Context& context, glw::GLuint programID, const VariableSearchFilter& filter)
1325	: SingleVariableValidator(context, PROGRAMRESOURCEPROP_TOP_LEVEL_ARRAY_SIZE, programID, filter, DE_NULL)
1326{
1327}
1328
1329void TopLevelArraySizeValidator::validateSingleVariable (const std::vector<VariablePathComponent>& path, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const
1330{
1331	int			expected;
1332	std::string	reason;
1333
1334	DE_ASSERT(path.front().isInterfaceBlock() && path.front().getInterfaceBlock()->storage == glu::STORAGE_BUFFER);
1335	DE_UNREF(resource);
1336	DE_UNREF(implementationName);
1337
1338	if (!path[1].getDeclaration()->varType.isArrayType())
1339	{
1340		expected = 1;
1341		reason = "Top-level block member is not an array";
1342	}
1343	else if (path[1].getDeclaration()->varType.getElementType().isBasicType())
1344	{
1345		expected = 1;
1346		reason = "Top-level block member is not an array of an aggregate type";
1347	}
1348	else if (path[1].getDeclaration()->varType.getArraySize() == glu::VarType::UNSIZED_ARRAY)
1349	{
1350		expected = 0;
1351		reason = "Top-level block member is an unsized top-level array";
1352	}
1353	else
1354	{
1355		expected = path[1].getDeclaration()->varType.getArraySize();
1356		reason = "Top-level block member is a sized top-level array";
1357	}
1358
1359	m_testCtx.getLog() << tcu::TestLog::Message << "Verifying top level array size, expecting " << expected << ". (" << reason << ")." << tcu::TestLog::EndMessage;
1360
1361	if (propValue != expected)
1362	{
1363		m_testCtx.getLog() << tcu::TestLog::Message << "\tError, invalid top level array size, got " << propValue << tcu::TestLog::EndMessage;
1364		setError("top level array size invalid");
1365	}
1366}
1367
1368class TopLevelArrayStrideValidator : public SingleVariableValidator
1369{
1370public:
1371				TopLevelArrayStrideValidator	(Context& context, glw::GLuint programID, const VariableSearchFilter& filter);
1372
1373	void		validateSingleVariable			(const std::vector<VariablePathComponent>& path, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const;
1374};
1375
1376TopLevelArrayStrideValidator::TopLevelArrayStrideValidator (Context& context, glw::GLuint programID, const VariableSearchFilter& filter)
1377	: SingleVariableValidator(context, PROGRAMRESOURCEPROP_TOP_LEVEL_ARRAY_STRIDE, programID, filter, DE_NULL)
1378{
1379}
1380
1381void TopLevelArrayStrideValidator::validateSingleVariable (const std::vector<VariablePathComponent>& path, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const
1382{
1383	DE_ASSERT(path.front().isInterfaceBlock() && path.front().getInterfaceBlock()->storage == glu::STORAGE_BUFFER);
1384	DE_UNREF(resource);
1385	DE_UNREF(implementationName);
1386
1387	if (!path[1].getDeclaration()->varType.isArrayType())
1388	{
1389		m_testCtx.getLog() << tcu::TestLog::Message << "Verifying top level array stride, expecting 0. (Top-level block member is not an array)." << tcu::TestLog::EndMessage;
1390
1391		if (propValue != 0)
1392		{
1393			m_testCtx.getLog() << tcu::TestLog::Message << "\tError, top level array stride, got " << propValue << tcu::TestLog::EndMessage;
1394			setError("top level array stride invalid");
1395		}
1396	}
1397	else if (path[1].getDeclaration()->varType.getElementType().isBasicType())
1398	{
1399		m_testCtx.getLog() << tcu::TestLog::Message << "Verifying top level array stride, expecting 0. (Top-level block member is not an array of an aggregate type)." << tcu::TestLog::EndMessage;
1400
1401		if (propValue != 0)
1402		{
1403			m_testCtx.getLog() << tcu::TestLog::Message << "\tError, top level array stride, got " << propValue << tcu::TestLog::EndMessage;
1404			setError("top level array stride invalid");
1405		}
1406	}
1407	else
1408	{
1409		const int minimumStride = getVarTypeSize(path[1].getDeclaration()->varType.getElementType());
1410
1411		m_testCtx.getLog() << tcu::TestLog::Message << "Verifying top level array stride, expecting greater or equal to " << minimumStride << "." << tcu::TestLog::EndMessage;
1412
1413		if (propValue < minimumStride)
1414		{
1415			m_testCtx.getLog() << tcu::TestLog::Message << "\tError, invalid top level array stride, got " << propValue << tcu::TestLog::EndMessage;
1416			setError("top level array stride invalid");
1417		}
1418	}
1419}
1420
1421class TransformFeedbackResourceValidator : public PropValidator
1422{
1423public:
1424					TransformFeedbackResourceValidator	(Context& context, ProgramResourcePropFlags validationProp);
1425
1426	void			validate							(const ProgramInterfaceDefinition::Program* program, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const;
1427
1428private:
1429	virtual void	validateBuiltinVariable				(const std::string& resource, glw::GLint propValue, const std::string& implementationName) const = 0;
1430	virtual void	validateSingleVariable				(const std::vector<VariablePathComponent>& path, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const = 0;
1431};
1432
1433
1434TransformFeedbackResourceValidator::TransformFeedbackResourceValidator (Context& context, ProgramResourcePropFlags validationProp)
1435	: PropValidator(context, validationProp, DE_NULL)
1436{
1437}
1438
1439void TransformFeedbackResourceValidator::validate (const ProgramInterfaceDefinition::Program* program, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const
1440{
1441	if (deStringBeginsWith(resource.c_str(), "gl_"))
1442	{
1443		validateBuiltinVariable(resource, propValue, implementationName);
1444	}
1445	else
1446	{
1447		// Check resource name is a xfb output. (sanity check)
1448#if defined(DE_DEBUG)
1449		bool generatorFound = false;
1450
1451		// Check the resource name is a valid transform feedback resource and find the name generating resource
1452		for (int varyingNdx = 0; varyingNdx < (int)program->getTransformFeedbackVaryings().size(); ++varyingNdx)
1453		{
1454			const std::string					varyingName = program->getTransformFeedbackVaryings()[varyingNdx];
1455			std::vector<VariablePathComponent>	path;
1456			std::vector<std::string>			resources;
1457
1458			if (!findProgramVariablePathByPathName(path, program, varyingName, VariableSearchFilter::createShaderTypeStorageFilter(getProgramTransformFeedbackStage(program), glu::STORAGE_OUT)))
1459			{
1460				// program does not contain feedback varying, not valid program
1461				DE_ASSERT(false);
1462				return;
1463			}
1464
1465			generateVariableTypeResourceNames(resources, varyingName, *path.back().getVariableType(), RESOURCE_NAME_GENERATION_FLAG_TRANSFORM_FEEDBACK_VARIABLE);
1466
1467			if (de::contains(resources.begin(), resources.end(), resource))
1468			{
1469				generatorFound = true;
1470				break;
1471			}
1472		}
1473
1474		// resource name was not found, should never happen
1475		DE_ASSERT(generatorFound);
1476		DE_UNREF(generatorFound);
1477#endif
1478
1479		// verify resource
1480		{
1481			std::vector<VariablePathComponent> path;
1482
1483			if (!findProgramVariablePathByPathName(path, program, resource, VariableSearchFilter::createShaderTypeStorageFilter(getProgramTransformFeedbackStage(program), glu::STORAGE_OUT)))
1484				DE_ASSERT(false);
1485
1486			validateSingleVariable(path, resource, propValue, implementationName);
1487		}
1488	}
1489}
1490
1491class TransformFeedbackArraySizeValidator : public TransformFeedbackResourceValidator
1492{
1493public:
1494				TransformFeedbackArraySizeValidator	(Context& context);
1495
1496	void		validateBuiltinVariable				(const std::string& resource, glw::GLint propValue, const std::string& implementationName) const;
1497	void		validateSingleVariable				(const std::vector<VariablePathComponent>& path, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const;
1498};
1499
1500TransformFeedbackArraySizeValidator::TransformFeedbackArraySizeValidator (Context& context)
1501	: TransformFeedbackResourceValidator(context, PROGRAMRESOURCEPROP_ARRAY_SIZE)
1502{
1503}
1504
1505void TransformFeedbackArraySizeValidator::validateBuiltinVariable (const std::string& resource, glw::GLint propValue, const std::string& implementationName) const
1506{
1507	DE_UNREF(implementationName);
1508
1509	int arraySize = 0;
1510
1511	if (resource == "gl_Position")
1512		arraySize = 1;
1513	else
1514		DE_ASSERT(false);
1515
1516	m_testCtx.getLog() << tcu::TestLog::Message << "Verifying array size, expecting " << arraySize << tcu::TestLog::EndMessage;
1517	if (arraySize != propValue)
1518	{
1519		m_testCtx.getLog() << tcu::TestLog::Message << "\tError, got " << propValue << tcu::TestLog::EndMessage;
1520		setError("resource array size invalid");
1521	}
1522}
1523
1524void TransformFeedbackArraySizeValidator::validateSingleVariable (const std::vector<VariablePathComponent>& path, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const
1525{
1526	DE_UNREF(resource);
1527	DE_UNREF(implementationName);
1528
1529	const int arraySize = (path.back().getVariableType()->isArrayType()) ? (path.back().getVariableType()->getArraySize()) : (1);
1530
1531	m_testCtx.getLog() << tcu::TestLog::Message << "Verifying array size, expecting " << arraySize << tcu::TestLog::EndMessage;
1532	if (arraySize != propValue)
1533	{
1534		m_testCtx.getLog() << tcu::TestLog::Message << "\tError, got " << propValue << tcu::TestLog::EndMessage;
1535		setError("resource array size invalid");
1536	}
1537}
1538
1539class TransformFeedbackNameLengthValidator : public TransformFeedbackResourceValidator
1540{
1541public:
1542				TransformFeedbackNameLengthValidator	(Context& context);
1543
1544private:
1545	void		validateBuiltinVariable					(const std::string& resource, glw::GLint propValue, const std::string& implementationName) const;
1546	void		validateSingleVariable					(const std::vector<VariablePathComponent>& path, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const;
1547	void		validateVariable						(const std::string& implementationName, glw::GLint propValue) const;
1548};
1549
1550TransformFeedbackNameLengthValidator::TransformFeedbackNameLengthValidator (Context& context)
1551	: TransformFeedbackResourceValidator(context, PROGRAMRESOURCEPROP_NAME_LENGTH)
1552{
1553}
1554
1555void TransformFeedbackNameLengthValidator::validateBuiltinVariable (const std::string& resource, glw::GLint propValue, const std::string& implementationName) const
1556{
1557	DE_UNREF(resource);
1558	validateVariable(implementationName, propValue);
1559}
1560
1561void TransformFeedbackNameLengthValidator::validateSingleVariable (const std::vector<VariablePathComponent>& path, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const
1562{
1563	DE_UNREF(path);
1564	DE_UNREF(resource);
1565	validateVariable(implementationName, propValue);
1566}
1567
1568void TransformFeedbackNameLengthValidator::validateVariable (const std::string& implementationName, glw::GLint propValue) const
1569{
1570	const int expected = (int)implementationName.length() + 1; // includes null byte
1571	m_testCtx.getLog() << tcu::TestLog::Message << "Verifying name length, expecting " << expected << " (" << (int)implementationName.length() << " for \"" << implementationName << "\" + 1 byte for terminating null character)" << tcu::TestLog::EndMessage;
1572
1573	if (propValue != expected)
1574	{
1575		m_testCtx.getLog() << tcu::TestLog::Message << "\tError, invalid name length, got " << propValue << tcu::TestLog::EndMessage;
1576		setError("name length invalid");
1577	}
1578}
1579
1580class TransformFeedbackTypeValidator : public TransformFeedbackResourceValidator
1581{
1582public:
1583				TransformFeedbackTypeValidator		(Context& context);
1584
1585	void		validateBuiltinVariable				(const std::string& resource, glw::GLint propValue, const std::string& implementationName) const;
1586	void		validateSingleVariable				(const std::vector<VariablePathComponent>& path, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const;
1587};
1588
1589TransformFeedbackTypeValidator::TransformFeedbackTypeValidator (Context& context)
1590	: TransformFeedbackResourceValidator(context, PROGRAMRESOURCEPROP_TYPE)
1591{
1592}
1593
1594void TransformFeedbackTypeValidator::validateBuiltinVariable (const std::string& resource, glw::GLint propValue, const std::string& implementationName) const
1595{
1596	DE_UNREF(implementationName);
1597
1598	glu::DataType varType = glu::TYPE_INVALID;
1599
1600	if (resource == "gl_Position")
1601		varType = glu::TYPE_FLOAT_VEC4;
1602	else
1603		DE_ASSERT(false);
1604
1605	m_testCtx.getLog() << tcu::TestLog::Message << "Verifying type, expecting " << glu::getDataTypeName(varType) << tcu::TestLog::EndMessage;
1606	if (glu::getDataTypeFromGLType(propValue) != varType)
1607	{
1608		m_testCtx.getLog() << tcu::TestLog::Message << "\tError, got " << glu::getDataTypeName(glu::getDataTypeFromGLType(propValue)) << tcu::TestLog::EndMessage;
1609		setError("resource type invalid");
1610	}
1611	return;
1612}
1613
1614void TransformFeedbackTypeValidator::validateSingleVariable (const std::vector<VariablePathComponent>& path, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const
1615{
1616	DE_UNREF(resource);
1617	DE_UNREF(implementationName);
1618
1619	// Unlike other interfaces, xfb program interface uses just variable name to refer to arrays of basic types. (Others use "variable[0]")
1620	// Thus we might end up querying a type for an array. In this case, return the type of an array element.
1621	const glu::VarType& variable    = *path.back().getVariableType();
1622	const glu::VarType& elementType = (variable.isArrayType()) ? (variable.getElementType()) : (variable);
1623
1624	DE_ASSERT(elementType.isBasicType());
1625
1626	m_testCtx.getLog() << tcu::TestLog::Message << "Verifying type, expecting " << glu::getDataTypeName(elementType.getBasicType()) << tcu::TestLog::EndMessage;
1627	if (elementType.getBasicType() != glu::getDataTypeFromGLType(propValue))
1628	{
1629		m_testCtx.getLog() << tcu::TestLog::Message << "\tError, got " << glu::getDataTypeName(glu::getDataTypeFromGLType(propValue)) << tcu::TestLog::EndMessage;
1630		setError("resource type invalid");
1631	}
1632}
1633
1634class PerPatchValidator : public SingleVariableValidator
1635{
1636public:
1637				PerPatchValidator				(Context& context, glw::GLuint programID, const VariableSearchFilter& filter);
1638
1639	std::string getHumanReadablePropertyString	(glw::GLint propVal) const;
1640	void		validateSingleVariable			(const std::vector<VariablePathComponent>& path, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const;
1641	void		validateBuiltinVariable			(const std::string& resource, glw::GLint propValue, const std::string& implementationName) const;
1642};
1643
1644PerPatchValidator::PerPatchValidator (Context& context, glw::GLuint programID, const VariableSearchFilter& filter)
1645	: SingleVariableValidator(context, PROGRAMRESOURCEPROP_IS_PER_PATCH, programID, filter, "GL_EXT_tessellation_shader")
1646{
1647}
1648
1649std::string PerPatchValidator::getHumanReadablePropertyString (glw::GLint propVal) const
1650{
1651	return de::toString(glu::getBooleanStr(propVal));
1652}
1653
1654void PerPatchValidator::validateSingleVariable (const std::vector<VariablePathComponent>& path, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const
1655{
1656	const glu::Storage	storage		= (path.front().isInterfaceBlock()) ? (path.front().getInterfaceBlock()->storage) : (path.front().getDeclaration()->storage);
1657	const int			expected	= (storage == glu::STORAGE_PATCH_IN || storage == glu::STORAGE_PATCH_OUT) ? (1) : (0);
1658
1659	DE_UNREF(resource);
1660	DE_UNREF(implementationName);
1661
1662	m_testCtx.getLog() << tcu::TestLog::Message << "Verifying if is per patch, expecting IS_PER_PATCH = " << expected << tcu::TestLog::EndMessage;
1663
1664	if (propValue != expected)
1665	{
1666		m_testCtx.getLog() << tcu::TestLog::Message << "\tError, got " << propValue << tcu::TestLog::EndMessage;
1667		setError("resource is per patch invalid");
1668	}
1669}
1670
1671void PerPatchValidator::validateBuiltinVariable (const std::string& resource, glw::GLint propValue, const std::string& implementationName) const
1672{
1673	DE_UNREF(implementationName);
1674
1675	static const struct
1676	{
1677		const char*		name;
1678		int				isPerPatch;
1679	} builtins[] =
1680	{
1681		{ "gl_Position",				0	},
1682		{ "gl_PerVertex.gl_Position",	0	},
1683		{ "gl_InvocationID",			0	},
1684		{ "gl_TessLevelOuter[0]",		1	},
1685		{ "gl_TessLevelInner[0]",		1	},
1686	};
1687
1688	for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(builtins); ++ndx)
1689	{
1690		if (resource == builtins[ndx].name)
1691		{
1692			m_testCtx.getLog() << tcu::TestLog::Message << "Verifying if is per patch, expecting IS_PER_PATCH = " << builtins[ndx].isPerPatch << tcu::TestLog::EndMessage;
1693
1694			if (propValue != builtins[ndx].isPerPatch)
1695			{
1696				m_testCtx.getLog() << tcu::TestLog::Message << "\tError, got " << propValue << tcu::TestLog::EndMessage;
1697				setError("resource is per patch invalid");
1698			}
1699			return;
1700		}
1701	}
1702
1703	DE_ASSERT(false);
1704}
1705
1706} // anonymous
1707
1708ProgramResourceQueryTestTarget::ProgramResourceQueryTestTarget (ProgramInterface interface_, deUint32 propFlags_)
1709	: interface(interface_)
1710	, propFlags(propFlags_)
1711{
1712	switch (interface)
1713	{
1714		case PROGRAMINTERFACE_UNIFORM:						DE_ASSERT((propFlags & PROGRAMRESOURCEPROP_UNIFORM_INTERFACE_MASK)			== propFlags);	break;
1715		case PROGRAMINTERFACE_UNIFORM_BLOCK:				DE_ASSERT((propFlags & PROGRAMRESOURCEPROP_UNIFORM_BLOCK_INTERFACE_MASK)	== propFlags);	break;
1716		case PROGRAMINTERFACE_SHADER_STORAGE_BLOCK:			DE_ASSERT((propFlags & PROGRAMRESOURCEPROP_SHADER_STORAGE_BLOCK_MASK)		== propFlags);	break;
1717		case PROGRAMINTERFACE_PROGRAM_INPUT:				DE_ASSERT((propFlags & PROGRAMRESOURCEPROP_PROGRAM_INPUT_MASK)				== propFlags);	break;
1718		case PROGRAMINTERFACE_PROGRAM_OUTPUT:				DE_ASSERT((propFlags & PROGRAMRESOURCEPROP_PROGRAM_OUTPUT_MASK)				== propFlags);	break;
1719		case PROGRAMINTERFACE_BUFFER_VARIABLE:				DE_ASSERT((propFlags & PROGRAMRESOURCEPROP_BUFFER_VARIABLE_MASK)			== propFlags);	break;
1720		case PROGRAMINTERFACE_TRANSFORM_FEEDBACK_VARYING:	DE_ASSERT((propFlags & PROGRAMRESOURCEPROP_TRANSFORM_FEEDBACK_VARYING_MASK)	== propFlags);	break;
1721
1722		default:
1723			DE_ASSERT(false);
1724	}
1725}
1726
1727ProgramInterfaceQueryTestCase::ProgramInterfaceQueryTestCase (Context& context, const char* name, const char* description, ProgramResourceQueryTestTarget queryTarget)
1728	: TestCase		(context, name, description)
1729	, m_queryTarget	(queryTarget)
1730{
1731}
1732
1733ProgramInterfaceQueryTestCase::~ProgramInterfaceQueryTestCase (void)
1734{
1735}
1736
1737ProgramInterface ProgramInterfaceQueryTestCase::getTargetInterface (void) const
1738{
1739	return m_queryTarget.interface;
1740}
1741
1742static glw::GLenum getGLInterfaceEnumValue (ProgramInterface interface)
1743{
1744	switch (interface)
1745	{
1746		case PROGRAMINTERFACE_UNIFORM:						return GL_UNIFORM;
1747		case PROGRAMINTERFACE_UNIFORM_BLOCK:				return GL_UNIFORM_BLOCK;
1748		case PROGRAMINTERFACE_ATOMIC_COUNTER_BUFFER:		return GL_ATOMIC_COUNTER_BUFFER;
1749		case PROGRAMINTERFACE_PROGRAM_INPUT:				return GL_PROGRAM_INPUT;
1750		case PROGRAMINTERFACE_PROGRAM_OUTPUT:				return GL_PROGRAM_OUTPUT;
1751		case PROGRAMINTERFACE_TRANSFORM_FEEDBACK_VARYING:	return GL_TRANSFORM_FEEDBACK_VARYING;
1752		case PROGRAMINTERFACE_BUFFER_VARIABLE:				return GL_BUFFER_VARIABLE;
1753		case PROGRAMINTERFACE_SHADER_STORAGE_BLOCK:			return GL_SHADER_STORAGE_BLOCK;
1754		default:
1755			DE_ASSERT(false);
1756			return 0;
1757	};
1758}
1759
1760static bool isInterfaceBlockInterfaceName (const ProgramInterfaceDefinition::Program* program, ProgramInterface interface, const std::string& blockInterfaceName)
1761{
1762	deUint32 validStorageBits;
1763	deUint32 searchStageBits;
1764
1765	DE_STATIC_ASSERT(glu::STORAGE_LAST < 32);
1766	DE_STATIC_ASSERT(glu::SHADERTYPE_LAST < 32);
1767
1768	switch (interface)
1769	{
1770		case PROGRAMINTERFACE_UNIFORM_BLOCK:
1771		case PROGRAMINTERFACE_SHADER_STORAGE_BLOCK:
1772		case PROGRAMINTERFACE_ATOMIC_COUNTER_BUFFER:
1773			return false;
1774
1775		case PROGRAMINTERFACE_PROGRAM_INPUT:
1776			validStorageBits = (1u << glu::STORAGE_IN) | (1u << glu::STORAGE_PATCH_IN);
1777			searchStageBits = (1u << program->getFirstStage());
1778			break;
1779
1780		case PROGRAMINTERFACE_PROGRAM_OUTPUT:
1781			validStorageBits = (1u << glu::STORAGE_OUT) | (1u << glu::STORAGE_PATCH_OUT);
1782			searchStageBits = (1u << program->getLastStage());
1783			break;
1784
1785		case PROGRAMINTERFACE_TRANSFORM_FEEDBACK_VARYING:
1786			validStorageBits = (1u << glu::STORAGE_OUT);
1787			searchStageBits = (1u << getProgramTransformFeedbackStage(program));
1788			break;
1789
1790		case PROGRAMINTERFACE_UNIFORM:
1791			validStorageBits = (1u << glu::STORAGE_UNIFORM);
1792			searchStageBits = 0xFFFFFFFFu;
1793			break;
1794
1795		case PROGRAMINTERFACE_BUFFER_VARIABLE:
1796			validStorageBits = (1u << glu::STORAGE_BUFFER);
1797			searchStageBits = 0xFFFFFFFFu;
1798			break;
1799
1800		default:
1801			DE_ASSERT(false);
1802			return false;
1803	}
1804
1805	for (int shaderNdx = 0; shaderNdx < (int)program->getShaders().size(); ++shaderNdx)
1806	{
1807		const ProgramInterfaceDefinition::Shader* const shader = program->getShaders()[shaderNdx];
1808		if (((1u << shader->getType()) & searchStageBits) == 0)
1809			continue;
1810
1811		for (int blockNdx = 0; blockNdx < (int)shader->getDefaultBlock().interfaceBlocks.size(); ++blockNdx)
1812		{
1813			const glu::InterfaceBlock& block = shader->getDefaultBlock().interfaceBlocks[blockNdx];
1814
1815			if (((1u << block.storage) & validStorageBits) == 0)
1816				continue;
1817
1818			if (block.interfaceName == blockInterfaceName)
1819				return true;
1820		}
1821	}
1822	return false;
1823}
1824
1825static std::string getInterfaceBlockInteraceNameByMember (const ProgramInterfaceDefinition::Program* program, ProgramInterface interface, const std::string& memberName)
1826{
1827	deUint32 validStorageBits;
1828	deUint32 searchStageBits;
1829
1830	DE_STATIC_ASSERT(glu::STORAGE_LAST < 32);
1831	DE_STATIC_ASSERT(glu::SHADERTYPE_LAST < 32);
1832
1833	switch (interface)
1834	{
1835		case PROGRAMINTERFACE_UNIFORM_BLOCK:
1836		case PROGRAMINTERFACE_SHADER_STORAGE_BLOCK:
1837		case PROGRAMINTERFACE_ATOMIC_COUNTER_BUFFER:
1838			return "";
1839
1840		case PROGRAMINTERFACE_PROGRAM_INPUT:
1841			validStorageBits = (1u << glu::STORAGE_IN) | (1u << glu::STORAGE_PATCH_IN);
1842			searchStageBits = (1u << program->getFirstStage());
1843			break;
1844
1845		case PROGRAMINTERFACE_PROGRAM_OUTPUT:
1846			validStorageBits = (1u << glu::STORAGE_OUT) | (1u << glu::STORAGE_PATCH_OUT);
1847			searchStageBits = (1u << program->getLastStage());
1848			break;
1849
1850		case PROGRAMINTERFACE_TRANSFORM_FEEDBACK_VARYING:
1851			validStorageBits = (1u << glu::STORAGE_OUT);
1852			searchStageBits = (1u << getProgramTransformFeedbackStage(program));
1853			break;
1854
1855		case PROGRAMINTERFACE_UNIFORM:
1856			validStorageBits = (1u << glu::STORAGE_UNIFORM);
1857			searchStageBits = 0xFFFFFFFFu;
1858			break;
1859
1860		case PROGRAMINTERFACE_BUFFER_VARIABLE:
1861			validStorageBits = (1u << glu::STORAGE_BUFFER);
1862			searchStageBits = 0xFFFFFFFFu;
1863			break;
1864
1865		default:
1866			DE_ASSERT(false);
1867			return "";
1868	}
1869
1870	for (int shaderNdx = 0; shaderNdx < (int)program->getShaders().size(); ++shaderNdx)
1871	{
1872		const ProgramInterfaceDefinition::Shader* const shader = program->getShaders()[shaderNdx];
1873		if (((1u << shader->getType()) & searchStageBits) == 0)
1874			continue;
1875
1876		for (int blockNdx = 0; blockNdx < (int)shader->getDefaultBlock().interfaceBlocks.size(); ++blockNdx)
1877		{
1878			const glu::InterfaceBlock& block = shader->getDefaultBlock().interfaceBlocks[blockNdx];
1879
1880			if (((1u << block.storage) & validStorageBits) == 0)
1881				continue;
1882
1883			for (int varNdx = 0; varNdx < (int)block.variables.size(); ++varNdx)
1884			{
1885				if (block.variables[varNdx].name == memberName)
1886					return block.interfaceName;
1887			}
1888		}
1889	}
1890	return "";
1891}
1892
1893static void queryAndValidateProps (tcu::TestContext&							testCtx,
1894								   const glw::Functions&						gl,
1895								   glw::GLuint									programID,
1896								   ProgramInterface								interface,
1897								   const char*									targetResourceName,
1898								   const ProgramInterfaceDefinition::Program*	programDefinition,
1899								   const std::vector<glw::GLenum>&				props,
1900								   const std::vector<const PropValidator*>&		validators)
1901{
1902	const glw::GLenum			glInterface					= getGLInterfaceEnumValue(interface);
1903	std::string					implementationResourceName	= targetResourceName;
1904	glw::GLuint					resourceNdx;
1905	glw::GLint					written						= -1;
1906
1907	// prefill result buffer with an invalid value. -1 might be valid sometimes, avoid it. Make buffer one larger
1908	// to allow detection of too many return values
1909	std::vector<glw::GLint>		propValues		(props.size() + 1, -2);
1910
1911	DE_ASSERT(props.size() == validators.size());
1912
1913	// query
1914
1915	resourceNdx = gl.getProgramResourceIndex(programID, glInterface, targetResourceName);
1916	GLU_EXPECT_NO_ERROR(gl.getError(), "get resource index");
1917
1918	if (resourceNdx == GL_INVALID_INDEX)
1919	{
1920		static const struct
1921		{
1922			bool removeTrailingArray;	// convert from "target[0]" -> "target"
1923			bool removeTrailingMember;	// convert from "target.member" -> "target"
1924			bool removeIOBlock;			// convert from "InterfaceName.target" -> "target"
1925			bool addIOBlock;			// convert from "target" -> "InterfaceName.target"
1926			bool addIOBlockArray;		// convert from "target" -> "InterfaceName[0].target"
1927		} recoveryStrategies[] =
1928		{
1929			// try one patch
1930			{ true,		false,	false,	false,	false	},
1931			{ false,	true,	false,	false,	false	},
1932			{ false,	false,	true,	false,	false	},
1933			{ false,	false,	false,	true,	false	},
1934			{ false,	false,	false,	false,	true	},
1935			// patch both ends
1936			{ true,		false,	true,	false,	false	},
1937			{ true,		false,	false,	true,	false	},
1938			{ true,		false,	false,	false,	true	},
1939			{ false,	true,	true,	false,	false	},
1940			{ false,	true,	false,	true,	false	},
1941			{ false,	true,	false,	false,	true	},
1942		};
1943
1944		// The resource name generation in the GL implementations is very commonly broken. Try to
1945		// keep the tests producing useful data even in these cases by attempting to recover from
1946		// common naming bugs. Set test result to failure even if recovery succeeded to signal
1947		// incorrect name generation.
1948
1949		testCtx.getLog() << tcu::TestLog::Message << "getProgramResourceIndex returned GL_INVALID_INDEX for \"" << targetResourceName << "\"" << tcu::TestLog::EndMessage;
1950		testCtx.setTestResult(QP_TEST_RESULT_FAIL, "could not find target resource");
1951
1952		for (int strategyNdx = 0; strategyNdx < DE_LENGTH_OF_ARRAY(recoveryStrategies); ++strategyNdx)
1953		{
1954			const std::string	resourceName			= std::string(targetResourceName);
1955			const size_t		rootNameEnd				= resourceName.find_first_of(".[");
1956			const std::string	rootName				= resourceName.substr(0, rootNameEnd);
1957			std::string			simplifiedResourceName;
1958
1959			if (recoveryStrategies[strategyNdx].removeTrailingArray)
1960			{
1961				if (de::endsWith(resourceName, "[0]"))
1962					simplifiedResourceName = resourceName.substr(0, resourceName.length() - 3);
1963				else
1964					continue;
1965			}
1966
1967			if (recoveryStrategies[strategyNdx].removeTrailingMember)
1968			{
1969				const size_t lastMember = resourceName.find_last_of('.');
1970				if (lastMember != std::string::npos)
1971					simplifiedResourceName = resourceName.substr(0, lastMember);
1972				else
1973					continue;
1974			}
1975
1976			if (recoveryStrategies[strategyNdx].removeIOBlock)
1977			{
1978				if (deStringBeginsWith(resourceName.c_str(), "gl_PerVertex."))
1979				{
1980					// builtin interface bock, remove block name
1981					simplifiedResourceName = resourceName.substr(13);
1982				}
1983				else if (isInterfaceBlockInterfaceName(programDefinition, interface, rootName))
1984				{
1985					// user-defined inteface block, remove name
1986					const size_t accessorEnd = resourceName.find('.'); // includes potential array accessor
1987
1988					if (accessorEnd != std::string::npos)
1989						simplifiedResourceName = resourceName.substr(0, accessorEnd+1);
1990					else
1991						continue;
1992				}
1993				else
1994				{
1995					// recovery not applicable
1996					continue;
1997				}
1998			}
1999
2000			if (recoveryStrategies[strategyNdx].addIOBlock || recoveryStrategies[strategyNdx].addIOBlockArray)
2001			{
2002				const std::string arrayAccessor = (recoveryStrategies[strategyNdx].addIOBlockArray) ? ("[0]") : ("");
2003
2004				if (deStringBeginsWith(resourceName.c_str(), "gl_") && resourceName.find('.') == std::string::npos)
2005				{
2006					// free builtin variable, add block name
2007					simplifiedResourceName = "gl_PerVertex" + arrayAccessor + "." + resourceName;
2008				}
2009				else
2010				{
2011					const std::string interafaceName = getInterfaceBlockInteraceNameByMember(programDefinition, interface, rootName);
2012
2013					if (!interafaceName.empty())
2014					{
2015						// free user variable, add block name
2016						simplifiedResourceName = interafaceName + arrayAccessor + "." + resourceName;
2017					}
2018					else
2019					{
2020						// recovery not applicable
2021						continue;
2022					}
2023				}
2024			}
2025
2026			if (simplifiedResourceName.empty())
2027				continue;
2028
2029			resourceNdx = gl.getProgramResourceIndex(programID, glInterface, simplifiedResourceName.c_str());
2030			GLU_EXPECT_NO_ERROR(gl.getError(), "get resource index");
2031
2032			// recovery succeeded
2033			if (resourceNdx != GL_INVALID_INDEX)
2034			{
2035				implementationResourceName = simplifiedResourceName;
2036				testCtx.getLog() << tcu::TestLog::Message << "\tResource not found, continuing anyway using index obtained for resource \"" << simplifiedResourceName << "\"" << tcu::TestLog::EndMessage;
2037				break;
2038			}
2039		}
2040
2041		if (resourceNdx == GL_INVALID_INDEX)
2042			return;
2043	}
2044
2045	gl.getProgramResourceiv(programID, glInterface, resourceNdx, (int)props.size(), &props[0], (int)propValues.size(), &written, &propValues[0]);
2046	GLU_EXPECT_NO_ERROR(gl.getError(), "get props");
2047
2048	if (written != (int)props.size())
2049	{
2050		testCtx.getLog() << tcu::TestLog::Message << "getProgramResourceiv returned unexpected number of values, expected " << (int)props.size() << ", got " << written << tcu::TestLog::EndMessage;
2051		testCtx.setTestResult(QP_TEST_RESULT_FAIL, "getProgramResourceiv returned unexpected number of values");
2052		return;
2053	}
2054
2055	if (propValues.back() != -2)
2056	{
2057		testCtx.getLog() << tcu::TestLog::Message << "getProgramResourceiv post write buffer guard value was modified, too many return values" << tcu::TestLog::EndMessage;
2058		testCtx.setTestResult(QP_TEST_RESULT_FAIL, "getProgramResourceiv returned unexpected number of values");
2059		return;
2060	}
2061	propValues.pop_back();
2062	DE_ASSERT(validators.size() == propValues.size());
2063
2064	// log
2065
2066	{
2067		tcu::MessageBuilder message(&testCtx.getLog());
2068		message << "For resource index " << resourceNdx << " (\"" << targetResourceName << "\") got following properties:\n";
2069
2070		for (int propNdx = 0; propNdx < (int)propValues.size(); ++propNdx)
2071			message << "\t" << glu::getProgramResourcePropertyName(props[propNdx]) << ":\t" << validators[propNdx]->getHumanReadablePropertyString(propValues[propNdx]) << "\n";
2072
2073		message << tcu::TestLog::EndMessage;
2074	}
2075
2076	// validate
2077
2078	for (int propNdx = 0; propNdx < (int)propValues.size(); ++propNdx)
2079		validators[propNdx]->validate(programDefinition, targetResourceName, propValues[propNdx], implementationResourceName);
2080}
2081
2082const ProgramInterfaceDefinition::Program* ProgramInterfaceQueryTestCase::getAndCheckProgramDefinition (void)
2083{
2084	const ProgramInterfaceDefinition::Program* programDefinition = getProgramDefinition();
2085	DE_ASSERT(programDefinition->isValid());
2086
2087	if (programDefinition->hasStage(glu::SHADERTYPE_TESSELLATION_CONTROL) ||
2088		programDefinition->hasStage(glu::SHADERTYPE_TESSELLATION_EVALUATION))
2089	{
2090		if (!m_context.getContextInfo().isExtensionSupported("GL_EXT_tessellation_shader"))
2091			throw tcu::NotSupportedError("Test requires GL_EXT_tessellation_shader extension");
2092	}
2093
2094	// Testing IS_PER_PATCH as a part of a larger set is ok, since the extension is checked
2095	// before query. However, we don't want IS_PER_PATCH-specific tests to become noop and pass.
2096	if (m_queryTarget.propFlags == PROGRAMRESOURCEPROP_IS_PER_PATCH)
2097	{
2098		if (!m_context.getContextInfo().isExtensionSupported("GL_EXT_tessellation_shader"))
2099			throw tcu::NotSupportedError("Test requires GL_EXT_tessellation_shader extension");
2100	}
2101
2102	if (programDefinition->hasStage(glu::SHADERTYPE_GEOMETRY))
2103	{
2104		if (!m_context.getContextInfo().isExtensionSupported("GL_EXT_geometry_shader"))
2105			throw tcu::NotSupportedError("Test requires GL_EXT_geometry_shader extension");
2106	}
2107
2108	if (programContainsIOBlocks(programDefinition))
2109	{
2110		if (!m_context.getContextInfo().isExtensionSupported("GL_EXT_shader_io_blocks"))
2111			throw tcu::NotSupportedError("Test requires GL_EXT_shader_io_blocks extension");
2112	}
2113
2114	return programDefinition;
2115}
2116
2117int ProgramInterfaceQueryTestCase::getMaxPatchVertices (void)
2118{
2119	const glw::Functions&	gl					= m_context.getRenderContext().getFunctions();
2120	glw::GLint				maxPatchVertices	= 0;
2121
2122	gl.getIntegerv(GL_MAX_PATCH_VERTICES, &maxPatchVertices);
2123	GLU_EXPECT_NO_ERROR(gl.getError(), "getIntegerv(GL_MAX_PATCH_VERTICES)");
2124	return maxPatchVertices;
2125}
2126
2127ProgramInterfaceQueryTestCase::IterateResult ProgramInterfaceQueryTestCase::iterate (void)
2128{
2129	struct TestProperty
2130	{
2131		glw::GLenum				prop;
2132		const PropValidator*	validator;
2133	};
2134
2135	const ProgramInterfaceDefinition::Program*	programDefinition	= getAndCheckProgramDefinition();
2136	const std::vector<std::string>				targetResources		= getQueryTargetResources();
2137	glu::ShaderProgram							program				(m_context.getRenderContext(), generateProgramInterfaceProgramSources(programDefinition));
2138
2139	m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
2140
2141	// Log program
2142	{
2143		const tcu::ScopedLogSection section(m_testCtx.getLog(), "Program", "Program");
2144
2145		// Feedback varyings
2146		if (!programDefinition->getTransformFeedbackVaryings().empty())
2147		{
2148			tcu::MessageBuilder builder(&m_testCtx.getLog());
2149			builder << "Transform feedback varyings: {";
2150			for (int ndx = 0; ndx < (int)programDefinition->getTransformFeedbackVaryings().size(); ++ndx)
2151			{
2152				if (ndx)
2153					builder << ", ";
2154				builder << "\"" << programDefinition->getTransformFeedbackVaryings()[ndx] << "\"";
2155			}
2156			builder << "}" << tcu::TestLog::EndMessage;
2157		}
2158
2159		m_testCtx.getLog() << program;
2160		if (!program.isOk())
2161		{
2162			m_testCtx.getLog() << tcu::TestLog::Message << "Program build failed, checking if program exceeded implementation limits" << tcu::TestLog::EndMessage;
2163			checkProgramResourceUsage(programDefinition, m_context.getRenderContext().getFunctions(), m_testCtx.getLog());
2164
2165			// within limits
2166			throw tcu::TestError("could not build program");
2167		}
2168	}
2169
2170	// Check interface props
2171
2172	switch (m_queryTarget.interface)
2173	{
2174		case PROGRAMINTERFACE_UNIFORM:
2175		{
2176			const VariableSearchFilter					uniformFilter						= VariableSearchFilter::createStorageFilter(glu::STORAGE_UNIFORM);
2177
2178			const TypeValidator							typeValidator						(m_context, program.getProgram(),						uniformFilter);
2179			const ArraySizeValidator					arraySizeValidator					(m_context, program.getProgram(),						-1,					uniformFilter);
2180			const ArrayStrideValidator					arrayStrideValidator				(m_context, program.getProgram(),						uniformFilter);
2181			const BlockIndexValidator					blockIndexValidator					(m_context, program.getProgram(),						uniformFilter);
2182			const IsRowMajorValidator					isRowMajorValidator					(m_context, program.getProgram(),						uniformFilter);
2183			const MatrixStrideValidator					matrixStrideValidator				(m_context, program.getProgram(),						uniformFilter);
2184			const AtomicCounterBufferIndexVerifier		atomicCounterBufferIndexVerifier	(m_context, program.getProgram(),						uniformFilter);
2185			const LocationValidator						locationValidator					(m_context, program.getProgram(),						uniformFilter);
2186			const VariableNameLengthValidator			nameLengthValidator					(m_context, program.getProgram(),						uniformFilter);
2187			const OffsetValidator						offsetVerifier						(m_context, program.getProgram(),						uniformFilter);
2188			const VariableReferencedByShaderValidator	referencedByVertexVerifier			(m_context, glu::SHADERTYPE_VERTEX,						uniformFilter);
2189			const VariableReferencedByShaderValidator	referencedByFragmentVerifier		(m_context, glu::SHADERTYPE_FRAGMENT,					uniformFilter);
2190			const VariableReferencedByShaderValidator	referencedByComputeVerifier			(m_context, glu::SHADERTYPE_COMPUTE,					uniformFilter);
2191			const VariableReferencedByShaderValidator	referencedByGeometryVerifier		(m_context, glu::SHADERTYPE_GEOMETRY,					uniformFilter);
2192			const VariableReferencedByShaderValidator	referencedByTessControlVerifier		(m_context, glu::SHADERTYPE_TESSELLATION_CONTROL,		uniformFilter);
2193			const VariableReferencedByShaderValidator	referencedByTessEvaluationVerifier	(m_context, glu::SHADERTYPE_TESSELLATION_EVALUATION,	uniformFilter);
2194
2195			const TestProperty allProperties[] =
2196			{
2197				{ GL_ARRAY_SIZE,							&arraySizeValidator					},
2198				{ GL_ARRAY_STRIDE,							&arrayStrideValidator				},
2199				{ GL_ATOMIC_COUNTER_BUFFER_INDEX,			&atomicCounterBufferIndexVerifier	},
2200				{ GL_BLOCK_INDEX,							&blockIndexValidator				},
2201				{ GL_IS_ROW_MAJOR,							&isRowMajorValidator				},
2202				{ GL_LOCATION,								&locationValidator					},
2203				{ GL_MATRIX_STRIDE,							&matrixStrideValidator				},
2204				{ GL_NAME_LENGTH,							&nameLengthValidator				},
2205				{ GL_OFFSET,								&offsetVerifier						},
2206				{ GL_REFERENCED_BY_VERTEX_SHADER,			&referencedByVertexVerifier			},
2207				{ GL_REFERENCED_BY_FRAGMENT_SHADER,			&referencedByFragmentVerifier		},
2208				{ GL_REFERENCED_BY_COMPUTE_SHADER,			&referencedByComputeVerifier		},
2209				{ GL_REFERENCED_BY_GEOMETRY_SHADER,			&referencedByGeometryVerifier		},
2210				{ GL_REFERENCED_BY_TESS_CONTROL_SHADER,		&referencedByTessControlVerifier	},
2211				{ GL_REFERENCED_BY_TESS_EVALUATION_SHADER,	&referencedByTessEvaluationVerifier	},
2212				{ GL_TYPE,									&typeValidator						},
2213			};
2214
2215			for (int targetResourceNdx = 0; targetResourceNdx < (int)targetResources.size(); ++targetResourceNdx)
2216			{
2217				const tcu::ScopedLogSection			section			(m_testCtx.getLog(), "UniformResource", "Uniform resource \"" +  targetResources[targetResourceNdx] + "\"");
2218				const glw::Functions&				gl				= m_context.getRenderContext().getFunctions();
2219				std::vector<glw::GLenum>			props;
2220				std::vector<const PropValidator*>	validators;
2221
2222				for (int propNdx = 0; propNdx < DE_LENGTH_OF_ARRAY(allProperties); ++propNdx)
2223				{
2224					if (allProperties[propNdx].validator->isSelected(m_queryTarget.propFlags) &&
2225						allProperties[propNdx].validator->isSupported())
2226					{
2227						props.push_back(allProperties[propNdx].prop);
2228						validators.push_back(allProperties[propNdx].validator);
2229					}
2230				}
2231
2232				DE_ASSERT(!props.empty());
2233
2234				queryAndValidateProps(m_testCtx, gl, program.getProgram(), m_queryTarget.interface, targetResources[targetResourceNdx].c_str(), programDefinition, props, validators);
2235			}
2236
2237			break;
2238		}
2239
2240		case PROGRAMINTERFACE_UNIFORM_BLOCK:
2241		case PROGRAMINTERFACE_SHADER_STORAGE_BLOCK:
2242		{
2243			const glu::Storage						storage								= (m_queryTarget.interface == PROGRAMINTERFACE_UNIFORM_BLOCK) ? (glu::STORAGE_UNIFORM) : (glu::STORAGE_BUFFER);
2244			const VariableSearchFilter				blockFilter							= VariableSearchFilter::createStorageFilter(storage);
2245
2246			const BlockNameLengthValidator			nameLengthValidator					(m_context, program.getProgram(),						blockFilter);
2247			const BlockReferencedByShaderValidator	referencedByVertexVerifier			(m_context, glu::SHADERTYPE_VERTEX,						blockFilter);
2248			const BlockReferencedByShaderValidator	referencedByFragmentVerifier		(m_context, glu::SHADERTYPE_FRAGMENT,					blockFilter);
2249			const BlockReferencedByShaderValidator	referencedByComputeVerifier			(m_context, glu::SHADERTYPE_COMPUTE,					blockFilter);
2250			const BlockReferencedByShaderValidator	referencedByGeometryVerifier		(m_context, glu::SHADERTYPE_GEOMETRY,					blockFilter);
2251			const BlockReferencedByShaderValidator	referencedByTessControlVerifier		(m_context, glu::SHADERTYPE_TESSELLATION_CONTROL,		blockFilter);
2252			const BlockReferencedByShaderValidator	referencedByTessEvaluationVerifier	(m_context, glu::SHADERTYPE_TESSELLATION_EVALUATION,	blockFilter);
2253			const BufferBindingValidator			bufferBindingValidator				(m_context, program.getProgram(),						blockFilter);
2254
2255			const TestProperty allProperties[] =
2256			{
2257				{ GL_NAME_LENGTH,							&nameLengthValidator				},
2258				{ GL_REFERENCED_BY_VERTEX_SHADER,			&referencedByVertexVerifier			},
2259				{ GL_REFERENCED_BY_FRAGMENT_SHADER,			&referencedByFragmentVerifier		},
2260				{ GL_REFERENCED_BY_COMPUTE_SHADER,			&referencedByComputeVerifier		},
2261				{ GL_REFERENCED_BY_GEOMETRY_SHADER,			&referencedByGeometryVerifier		},
2262				{ GL_REFERENCED_BY_TESS_CONTROL_SHADER,		&referencedByTessControlVerifier	},
2263				{ GL_REFERENCED_BY_TESS_EVALUATION_SHADER,	&referencedByTessEvaluationVerifier	},
2264				{ GL_BUFFER_BINDING,						&bufferBindingValidator				},
2265			};
2266
2267			for (int targetResourceNdx = 0; targetResourceNdx < (int)targetResources.size(); ++targetResourceNdx)
2268			{
2269				const tcu::ScopedLogSection			section			(m_testCtx.getLog(), "BlockResource", "Interface block \"" +  targetResources[targetResourceNdx] + "\"");
2270				const glw::Functions&				gl				= m_context.getRenderContext().getFunctions();
2271				std::vector<glw::GLenum>			props;
2272				std::vector<const PropValidator*>	validators;
2273
2274				for (int propNdx = 0; propNdx < DE_LENGTH_OF_ARRAY(allProperties); ++propNdx)
2275				{
2276					if (allProperties[propNdx].validator->isSelected(m_queryTarget.propFlags) &&
2277						allProperties[propNdx].validator->isSupported())
2278					{
2279						props.push_back(allProperties[propNdx].prop);
2280						validators.push_back(allProperties[propNdx].validator);
2281					}
2282				}
2283
2284				DE_ASSERT(!props.empty());
2285
2286				queryAndValidateProps(m_testCtx, gl, program.getProgram(), m_queryTarget.interface, targetResources[targetResourceNdx].c_str(), programDefinition, props, validators);
2287			}
2288
2289			break;
2290		}
2291
2292		case PROGRAMINTERFACE_PROGRAM_INPUT:
2293		case PROGRAMINTERFACE_PROGRAM_OUTPUT:
2294		{
2295			const bool									isInputCase							= (m_queryTarget.interface == PROGRAMINTERFACE_PROGRAM_INPUT);
2296			const glu::Storage							varyingStorage						= (isInputCase) ? (glu::STORAGE_IN) : (glu::STORAGE_OUT);
2297			const glu::Storage							patchStorage						= (isInputCase) ? (glu::STORAGE_PATCH_IN) : (glu::STORAGE_PATCH_OUT);
2298			const glu::ShaderType						shaderType							= (isInputCase) ? (programDefinition->getFirstStage()) : (programDefinition->getLastStage());
2299			const int									unsizedArraySize					= (isInputCase && shaderType == glu::SHADERTYPE_GEOMETRY)					? (1)															// input points
2300																							: (isInputCase && shaderType == glu::SHADERTYPE_TESSELLATION_CONTROL)		? (getMaxPatchVertices())										// input batch size
2301																							: (!isInputCase && shaderType == glu::SHADERTYPE_TESSELLATION_CONTROL)		? (programDefinition->getTessellationNumOutputPatchVertices())	// output batch size
2302																							: (isInputCase && shaderType == glu::SHADERTYPE_TESSELLATION_EVALUATION)	? (getMaxPatchVertices())										// input batch size
2303																							: (-1);
2304			const VariableSearchFilter					variableFilter						= VariableSearchFilter::logicalAnd(VariableSearchFilter::createShaderTypeFilter(shaderType),
2305																															   VariableSearchFilter::logicalOr(VariableSearchFilter::createStorageFilter(varyingStorage),
2306																																							   VariableSearchFilter::createStorageFilter(patchStorage)));
2307
2308			const TypeValidator							typeValidator						(m_context, program.getProgram(),						variableFilter);
2309			const ArraySizeValidator					arraySizeValidator					(m_context, program.getProgram(),						unsizedArraySize,		variableFilter);
2310			const LocationValidator						locationValidator					(m_context, program.getProgram(),						variableFilter);
2311			const VariableNameLengthValidator			nameLengthValidator					(m_context, program.getProgram(),						variableFilter);
2312			const VariableReferencedByShaderValidator	referencedByVertexVerifier			(m_context, glu::SHADERTYPE_VERTEX,						variableFilter);
2313			const VariableReferencedByShaderValidator	referencedByFragmentVerifier		(m_context, glu::SHADERTYPE_FRAGMENT,					variableFilter);
2314			const VariableReferencedByShaderValidator	referencedByComputeVerifier			(m_context, glu::SHADERTYPE_COMPUTE,					variableFilter);
2315			const VariableReferencedByShaderValidator	referencedByGeometryVerifier		(m_context, glu::SHADERTYPE_GEOMETRY,					variableFilter);
2316			const VariableReferencedByShaderValidator	referencedByTessControlVerifier		(m_context, glu::SHADERTYPE_TESSELLATION_CONTROL,		variableFilter);
2317			const VariableReferencedByShaderValidator	referencedByTessEvaluationVerifier	(m_context, glu::SHADERTYPE_TESSELLATION_EVALUATION,	variableFilter);
2318			const PerPatchValidator						perPatchValidator					(m_context, program.getProgram(),						variableFilter);
2319
2320			const TestProperty allProperties[] =
2321			{
2322				{ GL_ARRAY_SIZE,							&arraySizeValidator					},
2323				{ GL_LOCATION,								&locationValidator					},
2324				{ GL_NAME_LENGTH,							&nameLengthValidator				},
2325				{ GL_REFERENCED_BY_VERTEX_SHADER,			&referencedByVertexVerifier			},
2326				{ GL_REFERENCED_BY_FRAGMENT_SHADER,			&referencedByFragmentVerifier		},
2327				{ GL_REFERENCED_BY_COMPUTE_SHADER,			&referencedByComputeVerifier		},
2328				{ GL_REFERENCED_BY_GEOMETRY_SHADER,			&referencedByGeometryVerifier		},
2329				{ GL_REFERENCED_BY_TESS_CONTROL_SHADER,		&referencedByTessControlVerifier	},
2330				{ GL_REFERENCED_BY_TESS_EVALUATION_SHADER,	&referencedByTessEvaluationVerifier	},
2331				{ GL_TYPE,									&typeValidator						},
2332				{ GL_IS_PER_PATCH,							&perPatchValidator					},
2333			};
2334
2335			for (int targetResourceNdx = 0; targetResourceNdx < (int)targetResources.size(); ++targetResourceNdx)
2336			{
2337				const std::string					resourceInterfaceName	= (m_queryTarget.interface == PROGRAMINTERFACE_PROGRAM_INPUT) ? ("Input") : ("Output");
2338				const tcu::ScopedLogSection			section					(m_testCtx.getLog(), "BlockResource", resourceInterfaceName + " resource \"" +  targetResources[targetResourceNdx] + "\"");
2339				const glw::Functions&				gl						= m_context.getRenderContext().getFunctions();
2340				std::vector<glw::GLenum>			props;
2341				std::vector<const PropValidator*>	validators;
2342
2343				for (int propNdx = 0; propNdx < DE_LENGTH_OF_ARRAY(allProperties); ++propNdx)
2344				{
2345					if (allProperties[propNdx].validator->isSelected(m_queryTarget.propFlags) &&
2346						allProperties[propNdx].validator->isSupported())
2347					{
2348						props.push_back(allProperties[propNdx].prop);
2349						validators.push_back(allProperties[propNdx].validator);
2350					}
2351				}
2352
2353				DE_ASSERT(!props.empty());
2354
2355				queryAndValidateProps(m_testCtx, gl, program.getProgram(), m_queryTarget.interface, targetResources[targetResourceNdx].c_str(), programDefinition, props, validators);
2356			}
2357
2358			break;
2359		}
2360
2361		case PROGRAMINTERFACE_BUFFER_VARIABLE:
2362		{
2363			const VariableSearchFilter					variableFilter						= VariableSearchFilter::createStorageFilter(glu::STORAGE_BUFFER);
2364
2365			const TypeValidator							typeValidator						(m_context, program.getProgram(),						variableFilter);
2366			const ArraySizeValidator					arraySizeValidator					(m_context, program.getProgram(),						0,					variableFilter);
2367			const ArrayStrideValidator					arrayStrideValidator				(m_context, program.getProgram(),						variableFilter);
2368			const BlockIndexValidator					blockIndexValidator					(m_context, program.getProgram(),						variableFilter);
2369			const IsRowMajorValidator					isRowMajorValidator					(m_context, program.getProgram(),						variableFilter);
2370			const MatrixStrideValidator					matrixStrideValidator				(m_context, program.getProgram(),						variableFilter);
2371			const OffsetValidator						offsetValidator						(m_context, program.getProgram(),						variableFilter);
2372			const VariableNameLengthValidator			nameLengthValidator					(m_context, program.getProgram(),						variableFilter);
2373			const VariableReferencedByShaderValidator	referencedByVertexVerifier			(m_context, glu::SHADERTYPE_VERTEX,						variableFilter);
2374			const VariableReferencedByShaderValidator	referencedByFragmentVerifier		(m_context, glu::SHADERTYPE_FRAGMENT,					variableFilter);
2375			const VariableReferencedByShaderValidator	referencedByComputeVerifier			(m_context, glu::SHADERTYPE_COMPUTE,					variableFilter);
2376			const VariableReferencedByShaderValidator	referencedByGeometryVerifier		(m_context, glu::SHADERTYPE_GEOMETRY,					variableFilter);
2377			const VariableReferencedByShaderValidator	referencedByTessControlVerifier		(m_context, glu::SHADERTYPE_TESSELLATION_CONTROL,		variableFilter);
2378			const VariableReferencedByShaderValidator	referencedByTessEvaluationVerifier	(m_context, glu::SHADERTYPE_TESSELLATION_EVALUATION,	variableFilter);
2379			const TopLevelArraySizeValidator			topLevelArraySizeValidator			(m_context, program.getProgram(),						variableFilter);
2380			const TopLevelArrayStrideValidator			topLevelArrayStrideValidator		(m_context, program.getProgram(),						variableFilter);
2381
2382			const TestProperty allProperties[] =
2383			{
2384				{ GL_ARRAY_SIZE,							&arraySizeValidator					},
2385				{ GL_ARRAY_STRIDE,							&arrayStrideValidator				},
2386				{ GL_BLOCK_INDEX,							&blockIndexValidator				},
2387				{ GL_IS_ROW_MAJOR,							&isRowMajorValidator				},
2388				{ GL_MATRIX_STRIDE,							&matrixStrideValidator				},
2389				{ GL_NAME_LENGTH,							&nameLengthValidator				},
2390				{ GL_OFFSET,								&offsetValidator					},
2391				{ GL_REFERENCED_BY_VERTEX_SHADER,			&referencedByVertexVerifier			},
2392				{ GL_REFERENCED_BY_FRAGMENT_SHADER,			&referencedByFragmentVerifier		},
2393				{ GL_REFERENCED_BY_COMPUTE_SHADER,			&referencedByComputeVerifier		},
2394				{ GL_REFERENCED_BY_GEOMETRY_SHADER,			&referencedByGeometryVerifier		},
2395				{ GL_REFERENCED_BY_TESS_CONTROL_SHADER,		&referencedByTessControlVerifier	},
2396				{ GL_REFERENCED_BY_TESS_EVALUATION_SHADER,	&referencedByTessEvaluationVerifier	},
2397				{ GL_TOP_LEVEL_ARRAY_SIZE,					&topLevelArraySizeValidator			},
2398				{ GL_TOP_LEVEL_ARRAY_STRIDE,				&topLevelArrayStrideValidator		},
2399				{ GL_TYPE,									&typeValidator						},
2400			};
2401
2402			for (int targetResourceNdx = 0; targetResourceNdx < (int)targetResources.size(); ++targetResourceNdx)
2403			{
2404				const tcu::ScopedLogSection			section			(m_testCtx.getLog(), "BufferVariableResource", "Buffer variable \"" +  targetResources[targetResourceNdx] + "\"");
2405				const glw::Functions&				gl				= m_context.getRenderContext().getFunctions();
2406				std::vector<glw::GLenum>			props;
2407				std::vector<const PropValidator*>	validators;
2408
2409				for (int propNdx = 0; propNdx < DE_LENGTH_OF_ARRAY(allProperties); ++propNdx)
2410				{
2411					if (allProperties[propNdx].validator->isSelected(m_queryTarget.propFlags) &&
2412						allProperties[propNdx].validator->isSupported())
2413					{
2414						props.push_back(allProperties[propNdx].prop);
2415						validators.push_back(allProperties[propNdx].validator);
2416					}
2417				}
2418
2419				DE_ASSERT(!props.empty());
2420
2421				queryAndValidateProps(m_testCtx, gl, program.getProgram(), m_queryTarget.interface, targetResources[targetResourceNdx].c_str(), programDefinition, props, validators);
2422			}
2423
2424			break;
2425		}
2426
2427		case PROGRAMINTERFACE_TRANSFORM_FEEDBACK_VARYING:
2428		{
2429			const TransformFeedbackTypeValidator		typeValidator			(m_context);
2430			const TransformFeedbackArraySizeValidator	arraySizeValidator		(m_context);
2431			const TransformFeedbackNameLengthValidator	nameLengthValidator		(m_context);
2432
2433			const TestProperty allProperties[] =
2434			{
2435				{ GL_ARRAY_SIZE,					&arraySizeValidator				},
2436				{ GL_NAME_LENGTH,					&nameLengthValidator			},
2437				{ GL_TYPE,							&typeValidator					},
2438			};
2439
2440			for (int targetResourceNdx = 0; targetResourceNdx < (int)targetResources.size(); ++targetResourceNdx)
2441			{
2442				const tcu::ScopedLogSection			section			(m_testCtx.getLog(), "XFBVariableResource", "Transform feedback varying \"" +  targetResources[targetResourceNdx] + "\"");
2443				const glw::Functions&				gl				= m_context.getRenderContext().getFunctions();
2444				std::vector<glw::GLenum>			props;
2445				std::vector<const PropValidator*>	validators;
2446
2447				for (int propNdx = 0; propNdx < DE_LENGTH_OF_ARRAY(allProperties); ++propNdx)
2448				{
2449					if (allProperties[propNdx].validator->isSelected(m_queryTarget.propFlags) &&
2450						allProperties[propNdx].validator->isSupported())
2451					{
2452						props.push_back(allProperties[propNdx].prop);
2453						validators.push_back(allProperties[propNdx].validator);
2454					}
2455				}
2456
2457				DE_ASSERT(!props.empty());
2458
2459				queryAndValidateProps(m_testCtx, gl, program.getProgram(), m_queryTarget.interface, targetResources[targetResourceNdx].c_str(), programDefinition, props, validators);
2460			}
2461
2462			break;
2463		}
2464
2465		default:
2466			DE_ASSERT(false);
2467	}
2468
2469	return STOP;
2470}
2471
2472static bool checkLimit (glw::GLenum pname, int usage, const glw::Functions& gl, tcu::TestLog& log)
2473{
2474	if (usage > 0)
2475	{
2476		glw::GLint limit = 0;
2477		gl.getIntegerv(pname, &limit);
2478		GLU_EXPECT_NO_ERROR(gl.getError(), "query limits");
2479
2480		log << tcu::TestLog::Message << "\t" << glu::getGettableStateStr(pname) << " = " << limit << ", test requires " << usage << tcu::TestLog::EndMessage;
2481
2482		if (limit < usage)
2483		{
2484			log << tcu::TestLog::Message << "\t\tLimit exceeded" << tcu::TestLog::EndMessage;
2485			return false;
2486		}
2487	}
2488
2489	return true;
2490}
2491
2492static bool checkShaderResourceUsage (const ProgramInterfaceDefinition::Program* program, const ProgramInterfaceDefinition::Shader* shader, const glw::Functions& gl, tcu::TestLog& log)
2493{
2494	const ProgramInterfaceDefinition::ShaderResourceUsage usage = getShaderResourceUsage(program, shader);
2495
2496	switch (shader->getType())
2497	{
2498		case glu::SHADERTYPE_VERTEX:
2499		{
2500			const struct
2501			{
2502				glw::GLenum	pname;
2503				int			usage;
2504			} restrictions[] =
2505			{
2506				{ GL_MAX_VERTEX_ATTRIBS,						usage.numInputVectors					},
2507				{ GL_MAX_VERTEX_UNIFORM_COMPONENTS,				usage.numDefaultBlockUniformComponents	},
2508				{ GL_MAX_VERTEX_UNIFORM_VECTORS,				usage.numUniformVectors					},
2509				{ GL_MAX_VERTEX_UNIFORM_BLOCKS,					usage.numUniformBlocks					},
2510				{ GL_MAX_VERTEX_OUTPUT_COMPONENTS,				usage.numOutputComponents				},
2511				{ GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS,			usage.numSamplers						},
2512				{ GL_MAX_VERTEX_ATOMIC_COUNTER_BUFFERS,			usage.numAtomicCounterBuffers			},
2513				{ GL_MAX_VERTEX_ATOMIC_COUNTERS,				usage.numAtomicCounters					},
2514				{ GL_MAX_VERTEX_IMAGE_UNIFORMS,					usage.numImages							},
2515				{ GL_MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS,	usage.numCombinedUniformComponents		},
2516				{ GL_MAX_VERTEX_SHADER_STORAGE_BLOCKS,			usage.numShaderStorageBlocks			},
2517			};
2518
2519			bool allOk = true;
2520
2521			log << tcu::TestLog::Message << "Vertex shader:" << tcu::TestLog::EndMessage;
2522			for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(restrictions); ++ndx)
2523				allOk &= checkLimit(restrictions[ndx].pname, restrictions[ndx].usage, gl, log);
2524
2525			return allOk;
2526		}
2527
2528		case glu::SHADERTYPE_FRAGMENT:
2529		{
2530			const struct
2531			{
2532				glw::GLenum	pname;
2533				int			usage;
2534			} restrictions[] =
2535			{
2536				{ GL_MAX_FRAGMENT_UNIFORM_COMPONENTS,			usage.numDefaultBlockUniformComponents		},
2537				{ GL_MAX_FRAGMENT_UNIFORM_VECTORS,				usage.numUniformVectors						},
2538				{ GL_MAX_FRAGMENT_UNIFORM_BLOCKS,				usage.numUniformBlocks						},
2539				{ GL_MAX_FRAGMENT_INPUT_COMPONENTS,				usage.numInputComponents					},
2540				{ GL_MAX_TEXTURE_IMAGE_UNITS,					usage.numSamplers							},
2541				{ GL_MAX_FRAGMENT_ATOMIC_COUNTER_BUFFERS,		usage.numAtomicCounterBuffers				},
2542				{ GL_MAX_FRAGMENT_ATOMIC_COUNTERS,				usage.numAtomicCounters						},
2543				{ GL_MAX_FRAGMENT_IMAGE_UNIFORMS,				usage.numImages								},
2544				{ GL_MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS,	usage.numCombinedUniformComponents			},
2545				{ GL_MAX_FRAGMENT_SHADER_STORAGE_BLOCKS,		usage.numShaderStorageBlocks				},
2546			};
2547
2548			bool allOk = true;
2549
2550			log << tcu::TestLog::Message << "Fragment shader:" << tcu::TestLog::EndMessage;
2551			for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(restrictions); ++ndx)
2552				allOk &= checkLimit(restrictions[ndx].pname, restrictions[ndx].usage, gl, log);
2553
2554			return allOk;
2555		}
2556
2557		case glu::SHADERTYPE_COMPUTE:
2558		{
2559			const struct
2560			{
2561				glw::GLenum	pname;
2562				int			usage;
2563			} restrictions[] =
2564			{
2565				{ GL_MAX_COMPUTE_UNIFORM_BLOCKS,				usage.numUniformBlocks					},
2566				{ GL_MAX_COMPUTE_TEXTURE_IMAGE_UNITS,			usage.numSamplers						},
2567				{ GL_MAX_COMPUTE_UNIFORM_COMPONENTS,			usage.numDefaultBlockUniformComponents	},
2568				{ GL_MAX_COMPUTE_ATOMIC_COUNTER_BUFFERS,		usage.numAtomicCounterBuffers			},
2569				{ GL_MAX_COMPUTE_ATOMIC_COUNTERS,				usage.numAtomicCounters					},
2570				{ GL_MAX_COMPUTE_IMAGE_UNIFORMS,				usage.numImages							},
2571				{ GL_MAX_COMBINED_COMPUTE_UNIFORM_COMPONENTS,	usage.numCombinedUniformComponents		},
2572				{ GL_MAX_COMPUTE_SHADER_STORAGE_BLOCKS,			usage.numShaderStorageBlocks			},
2573			};
2574
2575			bool allOk = true;
2576
2577			log << tcu::TestLog::Message << "Compute shader:" << tcu::TestLog::EndMessage;
2578			for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(restrictions); ++ndx)
2579				allOk &= checkLimit(restrictions[ndx].pname, restrictions[ndx].usage, gl, log);
2580
2581			return allOk;
2582		}
2583
2584		case glu::SHADERTYPE_GEOMETRY:
2585		{
2586			const int totalOutputComponents = program->getGeometryNumOutputVertices() * usage.numOutputComponents;
2587			const struct
2588			{
2589				glw::GLenum	pname;
2590				int			usage;
2591			} restrictions[] =
2592			{
2593				{ GL_MAX_GEOMETRY_UNIFORM_COMPONENTS,				usage.numDefaultBlockUniformComponents			},
2594				{ GL_MAX_GEOMETRY_UNIFORM_BLOCKS,					usage.numUniformBlocks							},
2595				{ GL_MAX_GEOMETRY_INPUT_COMPONENTS,					usage.numInputComponents						},
2596				{ GL_MAX_GEOMETRY_OUTPUT_COMPONENTS,				usage.numOutputComponents						},
2597				{ GL_MAX_GEOMETRY_OUTPUT_VERTICES,					(int)program->getGeometryNumOutputVertices()	},
2598				{ GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS,			totalOutputComponents							},
2599				{ GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS,				usage.numSamplers								},
2600				{ GL_MAX_GEOMETRY_ATOMIC_COUNTER_BUFFERS,			usage.numAtomicCounterBuffers					},
2601				{ GL_MAX_GEOMETRY_ATOMIC_COUNTERS,					usage.numAtomicCounters							},
2602				{ GL_MAX_GEOMETRY_IMAGE_UNIFORMS,					usage.numImages									},
2603				{ GL_MAX_GEOMETRY_SHADER_STORAGE_BLOCKS,			usage.numShaderStorageBlocks					},
2604			};
2605
2606			bool allOk = true;
2607
2608			log << tcu::TestLog::Message << "Geometry shader:" << tcu::TestLog::EndMessage;
2609			for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(restrictions); ++ndx)
2610				allOk &= checkLimit(restrictions[ndx].pname, restrictions[ndx].usage, gl, log);
2611
2612			return allOk;
2613		}
2614
2615		case glu::SHADERTYPE_TESSELLATION_CONTROL:
2616		{
2617			const int totalOutputComponents = program->getTessellationNumOutputPatchVertices() * usage.numOutputComponents + usage.numPatchOutputComponents;
2618			const struct
2619			{
2620				glw::GLenum	pname;
2621				int			usage;
2622			} restrictions[] =
2623			{
2624				{ GL_MAX_PATCH_VERTICES,								(int)program->getTessellationNumOutputPatchVertices()	},
2625				{ GL_MAX_TESS_PATCH_COMPONENTS,							usage.numPatchOutputComponents							},
2626				{ GL_MAX_TESS_CONTROL_UNIFORM_COMPONENTS,				usage.numDefaultBlockUniformComponents					},
2627				{ GL_MAX_TESS_CONTROL_UNIFORM_BLOCKS,					usage.numUniformBlocks									},
2628				{ GL_MAX_TESS_CONTROL_INPUT_COMPONENTS,					usage.numInputComponents								},
2629				{ GL_MAX_TESS_CONTROL_OUTPUT_COMPONENTS,				usage.numOutputComponents								},
2630				{ GL_MAX_TESS_CONTROL_TOTAL_OUTPUT_COMPONENTS,			totalOutputComponents									},
2631				{ GL_MAX_TESS_CONTROL_TEXTURE_IMAGE_UNITS,				usage.numSamplers										},
2632				{ GL_MAX_TESS_CONTROL_ATOMIC_COUNTER_BUFFERS,			usage.numAtomicCounterBuffers							},
2633				{ GL_MAX_TESS_CONTROL_ATOMIC_COUNTERS,					usage.numAtomicCounters									},
2634				{ GL_MAX_TESS_CONTROL_SHADER_STORAGE_BLOCKS,			usage.numShaderStorageBlocks							},
2635			};
2636
2637			bool allOk = true;
2638
2639			log << tcu::TestLog::Message << "Tessellation control shader:" << tcu::TestLog::EndMessage;
2640			for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(restrictions); ++ndx)
2641				allOk &= checkLimit(restrictions[ndx].pname, restrictions[ndx].usage, gl, log);
2642
2643			return allOk;
2644		}
2645
2646		case glu::SHADERTYPE_TESSELLATION_EVALUATION:
2647		{
2648			const struct
2649			{
2650				glw::GLenum	pname;
2651				int			usage;
2652			} restrictions[] =
2653			{
2654				{ GL_MAX_PATCH_VERTICES,								(int)program->getTessellationNumOutputPatchVertices()	},
2655				{ GL_MAX_TESS_PATCH_COMPONENTS,							usage.numPatchInputComponents							},
2656				{ GL_MAX_TESS_EVALUATION_UNIFORM_COMPONENTS,			usage.numDefaultBlockUniformComponents					},
2657				{ GL_MAX_TESS_EVALUATION_UNIFORM_BLOCKS,				usage.numUniformBlocks									},
2658				{ GL_MAX_TESS_EVALUATION_INPUT_COMPONENTS,				usage.numInputComponents								},
2659				{ GL_MAX_TESS_EVALUATION_OUTPUT_COMPONENTS,				usage.numOutputComponents								},
2660				{ GL_MAX_TESS_EVALUATION_TEXTURE_IMAGE_UNITS,			usage.numSamplers										},
2661				{ GL_MAX_TESS_EVALUATION_ATOMIC_COUNTER_BUFFERS,		usage.numAtomicCounterBuffers							},
2662				{ GL_MAX_TESS_EVALUATION_ATOMIC_COUNTERS,				usage.numAtomicCounters									},
2663				{ GL_MAX_TESS_EVALUATION_SHADER_STORAGE_BLOCKS,			usage.numShaderStorageBlocks							},
2664			};
2665
2666			bool allOk = true;
2667
2668			log << tcu::TestLog::Message << "Tessellation evaluation shader:" << tcu::TestLog::EndMessage;
2669			for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(restrictions); ++ndx)
2670				allOk &= checkLimit(restrictions[ndx].pname, restrictions[ndx].usage, gl, log);
2671
2672			return allOk;
2673		}
2674
2675		default:
2676			DE_ASSERT(false);
2677			return false;
2678	}
2679}
2680
2681static bool checkProgramCombinedResourceUsage (const ProgramInterfaceDefinition::Program* program, const glw::Functions& gl, tcu::TestLog& log)
2682{
2683	const ProgramInterfaceDefinition::ProgramResourceUsage usage = getCombinedProgramResourceUsage(program);
2684
2685	const struct
2686	{
2687		glw::GLenum	pname;
2688		int			usage;
2689	} restrictions[] =
2690	{
2691		{ GL_MAX_UNIFORM_BUFFER_BINDINGS,						usage.uniformBufferMaxBinding+1					},
2692		{ GL_MAX_UNIFORM_BLOCK_SIZE,							usage.uniformBufferMaxSize						},
2693		{ GL_MAX_COMBINED_UNIFORM_BLOCKS,						usage.numUniformBlocks							},
2694		{ GL_MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS,			usage.numCombinedVertexUniformComponents		},
2695		{ GL_MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS,			usage.numCombinedFragmentUniformComponents		},
2696		{ GL_MAX_COMBINED_GEOMETRY_UNIFORM_COMPONENTS,			usage.numCombinedGeometryUniformComponents		},
2697		{ GL_MAX_COMBINED_TESS_CONTROL_UNIFORM_COMPONENTS,		usage.numCombinedTessControlUniformComponents	},
2698		{ GL_MAX_COMBINED_TESS_EVALUATION_UNIFORM_COMPONENTS,	usage.numCombinedTessEvalUniformComponents		},
2699		{ GL_MAX_VARYING_COMPONENTS,							usage.numVaryingComponents						},
2700		{ GL_MAX_VARYING_VECTORS,								usage.numVaryingVectors							},
2701		{ GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS,					usage.numCombinedSamplers						},
2702		{ GL_MAX_COMBINED_SHADER_OUTPUT_RESOURCES,				usage.numCombinedOutputResources				},
2703		{ GL_MAX_ATOMIC_COUNTER_BUFFER_BINDINGS,				usage.atomicCounterBufferMaxBinding+1			},
2704		{ GL_MAX_ATOMIC_COUNTER_BUFFER_SIZE,					usage.atomicCounterBufferMaxSize				},
2705		{ GL_MAX_COMBINED_ATOMIC_COUNTER_BUFFERS,				usage.numAtomicCounterBuffers					},
2706		{ GL_MAX_COMBINED_ATOMIC_COUNTERS,						usage.numAtomicCounters							},
2707		{ GL_MAX_IMAGE_UNITS,									usage.maxImageBinding+1							},
2708		{ GL_MAX_COMBINED_IMAGE_UNIFORMS,						usage.numCombinedImages							},
2709		{ GL_MAX_SHADER_STORAGE_BUFFER_BINDINGS,				usage.shaderStorageBufferMaxBinding+1			},
2710		{ GL_MAX_SHADER_STORAGE_BLOCK_SIZE,						usage.shaderStorageBufferMaxSize				},
2711		{ GL_MAX_COMBINED_SHADER_STORAGE_BLOCKS,				usage.numShaderStorageBlocks					},
2712		{ GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS,		usage.numXFBInterleavedComponents				},
2713		{ GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS,			usage.numXFBSeparateAttribs						},
2714		{ GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS,		usage.numXFBSeparateComponents					},
2715		{ GL_MAX_DRAW_BUFFERS,									usage.fragmentOutputMaxBinding+1				},
2716	};
2717
2718	bool allOk = true;
2719
2720	log << tcu::TestLog::Message << "Program combined:" << tcu::TestLog::EndMessage;
2721	for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(restrictions); ++ndx)
2722		allOk &= checkLimit(restrictions[ndx].pname, restrictions[ndx].usage, gl, log);
2723
2724	return allOk;
2725}
2726
2727void checkProgramResourceUsage (const ProgramInterfaceDefinition::Program* program, const glw::Functions& gl, tcu::TestLog& log)
2728{
2729	bool limitExceeded = false;
2730
2731	for (int shaderNdx = 0; shaderNdx < (int)program->getShaders().size(); ++shaderNdx)
2732		limitExceeded |= !checkShaderResourceUsage(program, program->getShaders()[shaderNdx], gl, log);
2733
2734	limitExceeded |= !checkProgramCombinedResourceUsage(program, gl, log);
2735
2736	if (limitExceeded)
2737	{
2738		log << tcu::TestLog::Message << "One or more resource limits exceeded" << tcu::TestLog::EndMessage;
2739		throw tcu::NotSupportedError("one or more resource limits exceeded");
2740	}
2741}
2742
2743} // Functional
2744} // gles31
2745} // deqp
2746