Home | History | Annotate | Download | only in functional
      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 
     37 namespace deqp
     38 {
     39 namespace gles31
     40 {
     41 namespace Functional
     42 {
     43 namespace
     44 {
     45 
     46 using ProgramInterfaceDefinition::VariablePathComponent;
     47 using ProgramInterfaceDefinition::VariableSearchFilter;
     48 
     49 static 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 
     70 static bool isBufferBackedInterfaceBlockStorage (glu::Storage storage)
     71 {
     72 	return storage == glu::STORAGE_BUFFER || storage == glu::STORAGE_UNIFORM;
     73 }
     74 
     75 const 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 
     97 static 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 
    110 static 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 
    139 static 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 
    167 class PropValidator
    168 {
    169 public:
    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 
    178 protected:
    179 	void							setError						(const std::string& err) const;
    180 
    181 	tcu::TestContext&				m_testCtx;
    182 	const glu::RenderContext&		m_renderContext;
    183 
    184 private:
    185 	const glu::ContextInfo&			m_contextInfo;
    186 	const char*						m_extension;
    187 	const ProgramResourcePropFlags	m_validationProp;
    188 };
    189 
    190 PropValidator::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 
    199 std::string PropValidator::getHumanReadablePropertyString (glw::GLint propVal) const
    200 {
    201 	return de::toString(propVal);
    202 }
    203 
    204 bool PropValidator::isSupported (void) const
    205 {
    206 	return m_extension == DE_NULL || m_contextInfo.isExtensionSupported(m_extension);
    207 }
    208 
    209 bool PropValidator::isSelected (deUint32 caseFlags) const
    210 {
    211 	return (caseFlags & (deUint32)m_validationProp) != 0;
    212 }
    213 
    214 void 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 
    221 class SingleVariableValidator : public PropValidator
    222 {
    223 public:
    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 
    230 protected:
    231 	const VariableSearchFilter	m_filter;
    232 	const glw::GLuint			m_programID;
    233 };
    234 
    235 SingleVariableValidator::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 
    242 void 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 
    273 void 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 
    281 class SingleBlockValidator : public PropValidator
    282 {
    283 public:
    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 
    289 protected:
    290 	const VariableSearchFilter	m_filter;
    291 	const glw::GLuint			m_programID;
    292 };
    293 
    294 SingleBlockValidator::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 
    301 void 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 
    352 class TypeValidator : public SingleVariableValidator
    353 {
    354 public:
    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 
    362 TypeValidator::TypeValidator (Context& context, glw::GLuint programID, const VariableSearchFilter& filter)
    363 	: SingleVariableValidator(context, PROGRAMRESOURCEPROP_TYPE, programID, filter, DE_NULL)
    364 {
    365 }
    366 
    367 std::string TypeValidator::getHumanReadablePropertyString (glw::GLint propVal) const
    368 {
    369 	return de::toString(glu::getShaderVarTypeStr(propVal));
    370 }
    371 
    372 void 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 
    388 void 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 
    427 class ArraySizeValidator : public SingleVariableValidator
    428 {
    429 public:
    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 
    435 private:
    436 	const int	m_unsizedArraySize;
    437 };
    438 
    439 ArraySizeValidator::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 
    445 void 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 
    467 void 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 
    506 class ArrayStrideValidator : public SingleVariableValidator
    507 {
    508 public:
    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 
    514 ArrayStrideValidator::ArrayStrideValidator (Context& context, glw::GLuint programID, const VariableSearchFilter& filter)
    515 	: SingleVariableValidator(context, PROGRAMRESOURCEPROP_ARRAY_STRIDE, programID, filter, DE_NULL)
    516 {
    517 }
    518 
    519 void 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 
    560 class BlockIndexValidator : public SingleVariableValidator
    561 {
    562 public:
    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 
    568 BlockIndexValidator::BlockIndexValidator (Context& context, glw::GLuint programID, const VariableSearchFilter& filter)
    569 	: SingleVariableValidator(context, PROGRAMRESOURCEPROP_BLOCK_INDEX, programID, filter, DE_NULL)
    570 {
    571 }
    572 
    573 void 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 
    632 class IsRowMajorValidator : public SingleVariableValidator
    633 {
    634 public:
    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 
    641 IsRowMajorValidator::IsRowMajorValidator (Context& context, glw::GLuint programID, const VariableSearchFilter& filter)
    642 	: SingleVariableValidator(context, PROGRAMRESOURCEPROP_MATRIX_ROW_MAJOR, programID, filter, DE_NULL)
    643 {
    644 }
    645 
    646 std::string IsRowMajorValidator::getHumanReadablePropertyString (glw::GLint propVal) const
    647 {
    648 	return de::toString(glu::getBooleanStr(propVal));
    649 }
    650 
    651 void 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 
    672 class MatrixStrideValidator : public SingleVariableValidator
    673 {
    674 public:
    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 
    680 MatrixStrideValidator::MatrixStrideValidator (Context& context, glw::GLuint programID, const VariableSearchFilter& filter)
    681 	: SingleVariableValidator(context, PROGRAMRESOURCEPROP_MATRIX_STRIDE, programID, filter, DE_NULL)
    682 {
    683 }
    684 
    685 void 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 
    725 class AtomicCounterBufferIndexVerifier : public SingleVariableValidator
    726 {
    727 public:
    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 
    733 AtomicCounterBufferIndexVerifier::AtomicCounterBufferIndexVerifier (Context& context, glw::GLuint programID, const VariableSearchFilter& filter)
    734 	: SingleVariableValidator(context, PROGRAMRESOURCEPROP_ATOMIC_COUNTER_BUFFER_INDEX, programID, filter, DE_NULL)
    735 {
    736 }
    737 
    738 void 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 
    779 class LocationValidator : public SingleVariableValidator
    780 {
    781 public:
    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 
    788 LocationValidator::LocationValidator (Context& context, glw::GLuint programID, const VariableSearchFilter& filter)
    789 	: SingleVariableValidator(context, PROGRAMRESOURCEPROP_LOCATION, programID, filter, DE_NULL)
    790 {
    791 }
    792 
    793 static 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 
    818 static 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 
    849 static 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 
    872 static 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 
    909 void 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 
   1029 void 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 
   1045 class VariableNameLengthValidator : public SingleVariableValidator
   1046 {
   1047 public:
   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 
   1055 VariableNameLengthValidator::VariableNameLengthValidator (Context& context, glw::GLuint programID, const VariableSearchFilter& filter)
   1056 	: SingleVariableValidator(context, PROGRAMRESOURCEPROP_NAME_LENGTH, programID, filter, DE_NULL)
   1057 {
   1058 }
   1059 
   1060 void 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 
   1067 void 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 
   1073 void 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 
   1085 class OffsetValidator : public SingleVariableValidator
   1086 {
   1087 public:
   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 
   1093 OffsetValidator::OffsetValidator (Context& context, glw::GLuint programID, const VariableSearchFilter& filter)
   1094 	: SingleVariableValidator(context, PROGRAMRESOURCEPROP_OFFSET, programID, filter, DE_NULL)
   1095 {
   1096 }
   1097 
   1098 void 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 
   1130 class VariableReferencedByShaderValidator : public PropValidator
   1131 {
   1132 public:
   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 
   1138 private:
   1139 	const VariableSearchFilter	m_filter;
   1140 	const glu::ShaderType		m_shaderType;
   1141 };
   1142 
   1143 VariableReferencedByShaderValidator::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 
   1151 std::string VariableReferencedByShaderValidator::getHumanReadablePropertyString (glw::GLint propVal) const
   1152 {
   1153 	return de::toString(glu::getBooleanStr(propVal));
   1154 }
   1155 
   1156 void 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 
   1176 class BlockNameLengthValidator : public SingleBlockValidator
   1177 {
   1178 public:
   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 
   1184 BlockNameLengthValidator::BlockNameLengthValidator (Context& context, const glw::GLuint programID, const VariableSearchFilter& filter)
   1185 	: SingleBlockValidator(context, PROGRAMRESOURCEPROP_NAME_LENGTH, programID, filter, DE_NULL)
   1186 {
   1187 }
   1188 
   1189 void 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 
   1205 class BufferBindingValidator : public SingleBlockValidator
   1206 {
   1207 public:
   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 
   1213 BufferBindingValidator::BufferBindingValidator (Context& context, const glw::GLuint programID, const VariableSearchFilter& filter)
   1214 	: SingleBlockValidator(context, PROGRAMRESOURCEPROP_BUFFER_BINDING, programID, filter, DE_NULL)
   1215 {
   1216 }
   1217 
   1218 void 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 
   1255 class BlockReferencedByShaderValidator : public PropValidator
   1256 {
   1257 public:
   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 
   1263 private:
   1264 	const VariableSearchFilter	m_filter;
   1265 	const glu::ShaderType		m_shaderType;
   1266 };
   1267 
   1268 BlockReferencedByShaderValidator::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 
   1276 std::string BlockReferencedByShaderValidator::getHumanReadablePropertyString (glw::GLint propVal) const
   1277 {
   1278 	return de::toString(glu::getBooleanStr(propVal));
   1279 }
   1280 
   1281 void 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 
   1316 class TopLevelArraySizeValidator : public SingleVariableValidator
   1317 {
   1318 public:
   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 
   1324 TopLevelArraySizeValidator::TopLevelArraySizeValidator (Context& context, glw::GLuint programID, const VariableSearchFilter& filter)
   1325 	: SingleVariableValidator(context, PROGRAMRESOURCEPROP_TOP_LEVEL_ARRAY_SIZE, programID, filter, DE_NULL)
   1326 {
   1327 }
   1328 
   1329 void 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 
   1368 class TopLevelArrayStrideValidator : public SingleVariableValidator
   1369 {
   1370 public:
   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 
   1376 TopLevelArrayStrideValidator::TopLevelArrayStrideValidator (Context& context, glw::GLuint programID, const VariableSearchFilter& filter)
   1377 	: SingleVariableValidator(context, PROGRAMRESOURCEPROP_TOP_LEVEL_ARRAY_STRIDE, programID, filter, DE_NULL)
   1378 {
   1379 }
   1380 
   1381 void 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 
   1421 class TransformFeedbackResourceValidator : public PropValidator
   1422 {
   1423 public:
   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 
   1428 private:
   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 
   1434 TransformFeedbackResourceValidator::TransformFeedbackResourceValidator (Context& context, ProgramResourcePropFlags validationProp)
   1435 	: PropValidator(context, validationProp, DE_NULL)
   1436 {
   1437 }
   1438 
   1439 void 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 
   1491 class TransformFeedbackArraySizeValidator : public TransformFeedbackResourceValidator
   1492 {
   1493 public:
   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 
   1500 TransformFeedbackArraySizeValidator::TransformFeedbackArraySizeValidator (Context& context)
   1501 	: TransformFeedbackResourceValidator(context, PROGRAMRESOURCEPROP_ARRAY_SIZE)
   1502 {
   1503 }
   1504 
   1505 void 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 
   1524 void 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 
   1539 class TransformFeedbackNameLengthValidator : public TransformFeedbackResourceValidator
   1540 {
   1541 public:
   1542 				TransformFeedbackNameLengthValidator	(Context& context);
   1543 
   1544 private:
   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 
   1550 TransformFeedbackNameLengthValidator::TransformFeedbackNameLengthValidator (Context& context)
   1551 	: TransformFeedbackResourceValidator(context, PROGRAMRESOURCEPROP_NAME_LENGTH)
   1552 {
   1553 }
   1554 
   1555 void 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 
   1561 void 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 
   1568 void 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 
   1580 class TransformFeedbackTypeValidator : public TransformFeedbackResourceValidator
   1581 {
   1582 public:
   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 
   1589 TransformFeedbackTypeValidator::TransformFeedbackTypeValidator (Context& context)
   1590 	: TransformFeedbackResourceValidator(context, PROGRAMRESOURCEPROP_TYPE)
   1591 {
   1592 }
   1593 
   1594 void 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 
   1614 void 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 
   1634 class PerPatchValidator : public SingleVariableValidator
   1635 {
   1636 public:
   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 
   1644 PerPatchValidator::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 
   1649 std::string PerPatchValidator::getHumanReadablePropertyString (glw::GLint propVal) const
   1650 {
   1651 	return de::toString(glu::getBooleanStr(propVal));
   1652 }
   1653 
   1654 void 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 
   1671 void 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 
   1708 ProgramResourceQueryTestTarget::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 
   1727 ProgramInterfaceQueryTestCase::ProgramInterfaceQueryTestCase (Context& context, const char* name, const char* description, ProgramResourceQueryTestTarget queryTarget)
   1728 	: TestCase		(context, name, description)
   1729 	, m_queryTarget	(queryTarget)
   1730 {
   1731 }
   1732 
   1733 ProgramInterfaceQueryTestCase::~ProgramInterfaceQueryTestCase (void)
   1734 {
   1735 }
   1736 
   1737 ProgramInterface ProgramInterfaceQueryTestCase::getTargetInterface (void) const
   1738 {
   1739 	return m_queryTarget.interface;
   1740 }
   1741 
   1742 static 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 
   1760 static 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 
   1825 static 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 
   1893 static 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 
   2082 const 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 
   2117 int 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 
   2127 ProgramInterfaceQueryTestCase::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 
   2472 static 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 
   2492 static 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_IMAGE_UNIFORMS,					usage.numImages											},
   2635 				{ GL_MAX_TESS_CONTROL_SHADER_STORAGE_BLOCKS,			usage.numShaderStorageBlocks							},
   2636 			};
   2637 
   2638 			bool allOk = true;
   2639 
   2640 			log << tcu::TestLog::Message << "Tessellation control shader:" << tcu::TestLog::EndMessage;
   2641 			for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(restrictions); ++ndx)
   2642 				allOk &= checkLimit(restrictions[ndx].pname, restrictions[ndx].usage, gl, log);
   2643 
   2644 			return allOk;
   2645 		}
   2646 
   2647 		case glu::SHADERTYPE_TESSELLATION_EVALUATION:
   2648 		{
   2649 			const struct
   2650 			{
   2651 				glw::GLenum	pname;
   2652 				int			usage;
   2653 			} restrictions[] =
   2654 			{
   2655 				{ GL_MAX_PATCH_VERTICES,								(int)program->getTessellationNumOutputPatchVertices()	},
   2656 				{ GL_MAX_TESS_PATCH_COMPONENTS,							usage.numPatchInputComponents							},
   2657 				{ GL_MAX_TESS_EVALUATION_UNIFORM_COMPONENTS,			usage.numDefaultBlockUniformComponents					},
   2658 				{ GL_MAX_TESS_EVALUATION_UNIFORM_BLOCKS,				usage.numUniformBlocks									},
   2659 				{ GL_MAX_TESS_EVALUATION_INPUT_COMPONENTS,				usage.numInputComponents								},
   2660 				{ GL_MAX_TESS_EVALUATION_OUTPUT_COMPONENTS,				usage.numOutputComponents								},
   2661 				{ GL_MAX_TESS_EVALUATION_TEXTURE_IMAGE_UNITS,			usage.numSamplers										},
   2662 				{ GL_MAX_TESS_EVALUATION_ATOMIC_COUNTER_BUFFERS,		usage.numAtomicCounterBuffers							},
   2663 				{ GL_MAX_TESS_EVALUATION_ATOMIC_COUNTERS,				usage.numAtomicCounters									},
   2664 				{ GL_MAX_TESS_EVALUATION_IMAGE_UNIFORMS,				usage.numImages											},
   2665 				{ GL_MAX_TESS_EVALUATION_SHADER_STORAGE_BLOCKS,			usage.numShaderStorageBlocks							},
   2666 			};
   2667 
   2668 			bool allOk = true;
   2669 
   2670 			log << tcu::TestLog::Message << "Tessellation evaluation shader:" << tcu::TestLog::EndMessage;
   2671 			for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(restrictions); ++ndx)
   2672 				allOk &= checkLimit(restrictions[ndx].pname, restrictions[ndx].usage, gl, log);
   2673 
   2674 			return allOk;
   2675 		}
   2676 
   2677 		default:
   2678 			DE_ASSERT(false);
   2679 			return false;
   2680 	}
   2681 }
   2682 
   2683 static bool checkProgramCombinedResourceUsage (const ProgramInterfaceDefinition::Program* program, const glw::Functions& gl, tcu::TestLog& log)
   2684 {
   2685 	const ProgramInterfaceDefinition::ProgramResourceUsage usage = getCombinedProgramResourceUsage(program);
   2686 
   2687 	const struct
   2688 	{
   2689 		glw::GLenum	pname;
   2690 		int			usage;
   2691 	} restrictions[] =
   2692 	{
   2693 		{ GL_MAX_UNIFORM_BUFFER_BINDINGS,						usage.uniformBufferMaxBinding+1					},
   2694 		{ GL_MAX_UNIFORM_BLOCK_SIZE,							usage.uniformBufferMaxSize						},
   2695 		{ GL_MAX_COMBINED_UNIFORM_BLOCKS,						usage.numUniformBlocks							},
   2696 		{ GL_MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS,			usage.numCombinedVertexUniformComponents		},
   2697 		{ GL_MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS,			usage.numCombinedFragmentUniformComponents		},
   2698 		{ GL_MAX_COMBINED_GEOMETRY_UNIFORM_COMPONENTS,			usage.numCombinedGeometryUniformComponents		},
   2699 		{ GL_MAX_COMBINED_TESS_CONTROL_UNIFORM_COMPONENTS,		usage.numCombinedTessControlUniformComponents	},
   2700 		{ GL_MAX_COMBINED_TESS_EVALUATION_UNIFORM_COMPONENTS,	usage.numCombinedTessEvalUniformComponents		},
   2701 		{ GL_MAX_VARYING_COMPONENTS,							usage.numVaryingComponents						},
   2702 		{ GL_MAX_VARYING_VECTORS,								usage.numVaryingVectors							},
   2703 		{ GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS,					usage.numCombinedSamplers						},
   2704 		{ GL_MAX_COMBINED_SHADER_OUTPUT_RESOURCES,				usage.numCombinedOutputResources				},
   2705 		{ GL_MAX_ATOMIC_COUNTER_BUFFER_BINDINGS,				usage.atomicCounterBufferMaxBinding+1			},
   2706 		{ GL_MAX_ATOMIC_COUNTER_BUFFER_SIZE,					usage.atomicCounterBufferMaxSize				},
   2707 		{ GL_MAX_COMBINED_ATOMIC_COUNTER_BUFFERS,				usage.numAtomicCounterBuffers					},
   2708 		{ GL_MAX_COMBINED_ATOMIC_COUNTERS,						usage.numAtomicCounters							},
   2709 		{ GL_MAX_IMAGE_UNITS,									usage.maxImageBinding+1							},
   2710 		{ GL_MAX_COMBINED_IMAGE_UNIFORMS,						usage.numCombinedImages							},
   2711 		{ GL_MAX_SHADER_STORAGE_BUFFER_BINDINGS,				usage.shaderStorageBufferMaxBinding+1			},
   2712 		{ GL_MAX_SHADER_STORAGE_BLOCK_SIZE,						usage.shaderStorageBufferMaxSize				},
   2713 		{ GL_MAX_COMBINED_SHADER_STORAGE_BLOCKS,				usage.numShaderStorageBlocks					},
   2714 		{ GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS,		usage.numXFBInterleavedComponents				},
   2715 		{ GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS,			usage.numXFBSeparateAttribs						},
   2716 		{ GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS,		usage.numXFBSeparateComponents					},
   2717 		{ GL_MAX_DRAW_BUFFERS,									usage.fragmentOutputMaxBinding+1				},
   2718 	};
   2719 
   2720 	bool allOk = true;
   2721 
   2722 	log << tcu::TestLog::Message << "Program combined:" << tcu::TestLog::EndMessage;
   2723 	for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(restrictions); ++ndx)
   2724 		allOk &= checkLimit(restrictions[ndx].pname, restrictions[ndx].usage, gl, log);
   2725 
   2726 	return allOk;
   2727 }
   2728 
   2729 void checkProgramResourceUsage (const ProgramInterfaceDefinition::Program* program, const glw::Functions& gl, tcu::TestLog& log)
   2730 {
   2731 	bool limitExceeded = false;
   2732 
   2733 	for (int shaderNdx = 0; shaderNdx < (int)program->getShaders().size(); ++shaderNdx)
   2734 		limitExceeded |= !checkShaderResourceUsage(program, program->getShaders()[shaderNdx], gl, log);
   2735 
   2736 	limitExceeded |= !checkProgramCombinedResourceUsage(program, gl, log);
   2737 
   2738 	if (limitExceeded)
   2739 	{
   2740 		log << tcu::TestLog::Message << "One or more resource limits exceeded" << tcu::TestLog::EndMessage;
   2741 		throw tcu::NotSupportedError("one or more resource limits exceeded");
   2742 	}
   2743 }
   2744 
   2745 } // Functional
   2746 } // gles31
   2747 } // deqp
   2748