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 utilities
     22  *//*--------------------------------------------------------------------*/
     23 
     24 #include "es31fProgramInterfaceDefinitionUtil.hpp"
     25 #include "es31fProgramInterfaceDefinition.hpp"
     26 #include "gluVarType.hpp"
     27 #include "gluVarTypeUtil.hpp"
     28 #include "gluShaderUtil.hpp"
     29 #include "deString.h"
     30 #include "deStringUtil.hpp"
     31 #include "glwEnums.hpp"
     32 
     33 #include <set>
     34 #include <map>
     35 #include <sstream>
     36 #include <vector>
     37 #include <algorithm>
     38 
     39 namespace deqp
     40 {
     41 namespace gles31
     42 {
     43 namespace Functional
     44 {
     45 namespace ProgramInterfaceDefinition
     46 {
     47 
     48 VariableSearchFilter VariableSearchFilter::intersection (const VariableSearchFilter& a, const VariableSearchFilter& b)
     49 {
     50 	const bool storageNonEmpty		= (a.m_storage == b.m_storage) || (a.m_storage == glu::STORAGE_LAST) || (b.m_storage == glu::STORAGE_LAST);
     51 	const bool shaderTypeNonEmpty	= (a.m_shaderType == b.m_shaderType) || (a.m_shaderType == glu::SHADERTYPE_LAST) || (b.m_shaderType == glu::SHADERTYPE_LAST);
     52 
     53 	return VariableSearchFilter((a.m_shaderType == glu::SHADERTYPE_LAST) ? (b.m_shaderType) : (a.m_shaderType),
     54 								(a.m_storage == glu::STORAGE_LAST) ? (b.m_storage) : (a.m_storage),
     55 								!storageNonEmpty || !shaderTypeNonEmpty || a.m_null || b.m_null);
     56 }
     57 
     58 } // ProgramInterfaceDefinition
     59 
     60 static bool incrementMultiDimensionIndex (std::vector<int>& index, const std::vector<int>& dimensions)
     61 {
     62 	int incrementDimensionNdx = (int)(index.size() - 1);
     63 
     64 	while (incrementDimensionNdx >= 0)
     65 	{
     66 		if (++index[incrementDimensionNdx] == dimensions[incrementDimensionNdx])
     67 			index[incrementDimensionNdx--] = 0;
     68 		else
     69 			break;
     70 	}
     71 
     72 	return (incrementDimensionNdx != -1);
     73 }
     74 
     75 void generateVariableTypeResourceNames (std::vector<std::string>& resources, const std::string& name, const glu::VarType& type, deUint32 resourceNameGenerationFlags)
     76 {
     77 	DE_ASSERT((resourceNameGenerationFlags & (~RESOURCE_NAME_GENERATION_FLAG_MASK)) == 0);
     78 
     79 	// remove top-level flag from children
     80 	const deUint32 childFlags = resourceNameGenerationFlags & ~((deUint32)RESOURCE_NAME_GENERATION_FLAG_TOP_LEVEL_BUFFER_VARIABLE);
     81 
     82 	if (type.isBasicType())
     83 		resources.push_back(name);
     84 	else if (type.isStructType())
     85 	{
     86 		const glu::StructType* structType = type.getStructPtr();
     87 		for (int ndx = 0; ndx < structType->getNumMembers(); ++ndx)
     88 			generateVariableTypeResourceNames(resources, name + "." + structType->getMember(ndx).getName(), structType->getMember(ndx).getType(), childFlags);
     89 	}
     90 	else if (type.isArrayType())
     91 	{
     92 		// Bottom-level arrays of basic types of a transform feedback variable will produce only the first
     93 		// element but without the trailing "[0]"
     94 		if (type.getElementType().isBasicType() &&
     95 			(resourceNameGenerationFlags & RESOURCE_NAME_GENERATION_FLAG_TRANSFORM_FEEDBACK_VARIABLE) != 0)
     96 		{
     97 			resources.push_back(name);
     98 		}
     99 		// Bottom-level arrays of basic types and SSBO top-level arrays of any type procude only first element
    100 		else if (type.getElementType().isBasicType() ||
    101 				 (resourceNameGenerationFlags & RESOURCE_NAME_GENERATION_FLAG_TOP_LEVEL_BUFFER_VARIABLE) != 0)
    102 		{
    103 			generateVariableTypeResourceNames(resources, name + "[0]", type.getElementType(), childFlags);
    104 		}
    105 		// Other arrays of aggregate types are expanded
    106 		else
    107 		{
    108 			for (int ndx = 0; ndx < type.getArraySize(); ++ndx)
    109 				generateVariableTypeResourceNames(resources, name + "[" + de::toString(ndx) + "]", type.getElementType(), childFlags);
    110 		}
    111 	}
    112 	else
    113 		DE_ASSERT(false);
    114 }
    115 
    116 // Program source generation
    117 
    118 namespace
    119 {
    120 
    121 using ProgramInterfaceDefinition::VariablePathComponent;
    122 using ProgramInterfaceDefinition::VariableSearchFilter;
    123 
    124 static const char* getShaderTypeDeclarations (glu::ShaderType type)
    125 {
    126 	switch (type)
    127 	{
    128 		case glu::SHADERTYPE_VERTEX:
    129 			return	"";
    130 
    131 		case glu::SHADERTYPE_FRAGMENT:
    132 			return	"";
    133 
    134 		case glu::SHADERTYPE_GEOMETRY:
    135 			return	"layout(points) in;\n"
    136 					"layout(points, max_vertices=3) out;\n";
    137 
    138 		case glu::SHADERTYPE_TESSELLATION_CONTROL:
    139 			return	"layout(vertices=1) out;\n";
    140 
    141 		case glu::SHADERTYPE_TESSELLATION_EVALUATION:
    142 			return	"layout(triangle, point_mode) in;\n";
    143 
    144 		case glu::SHADERTYPE_COMPUTE:
    145 			return	"layout(local_size_x=1) in;\n";
    146 
    147 		default:
    148 			DE_ASSERT(false);
    149 			return DE_NULL;
    150 	}
    151 }
    152 
    153 class StructNameEqualPredicate
    154 {
    155 public:
    156 				StructNameEqualPredicate	(const char* name) : m_name(name) { }
    157 	bool		operator()					(const glu::StructType* type) { return type->hasTypeName() && (deStringEqual(m_name, type->getTypeName()) == DE_TRUE); }
    158 private:
    159 	const char*	m_name;
    160 };
    161 
    162 static void collectNamedStructureDefinitions (std::vector<const glu::StructType*>& dst, const glu::VarType& type)
    163 {
    164 	if (type.isBasicType())
    165 		return;
    166 	else if (type.isArrayType())
    167 		return collectNamedStructureDefinitions(dst, type.getElementType());
    168 	else if (type.isStructType())
    169 	{
    170 		if (type.getStructPtr()->hasTypeName())
    171 		{
    172 			// must be unique (may share the the same struct)
    173 			std::vector<const glu::StructType*>::iterator where = std::find_if(dst.begin(), dst.end(), StructNameEqualPredicate(type.getStructPtr()->getTypeName()));
    174 			if (where != dst.end())
    175 			{
    176 				DE_ASSERT(**where == *type.getStructPtr());
    177 
    178 				// identical type has been added already, types of members must be added too
    179 				return;
    180 			}
    181 		}
    182 
    183 		// Add types of members first
    184 		for (int ndx = 0; ndx < type.getStructPtr()->getNumMembers(); ++ndx)
    185 			collectNamedStructureDefinitions(dst, type.getStructPtr()->getMember(ndx).getType());
    186 
    187 		dst.push_back(type.getStructPtr());
    188 	}
    189 	else
    190 		DE_ASSERT(false);
    191 }
    192 
    193 static void writeStructureDefinitions (std::ostringstream& buf, const ProgramInterfaceDefinition::DefaultBlock& defaultBlock)
    194 {
    195 	std::vector<const glu::StructType*> namedStructs;
    196 
    197 	// Collect all structs in post order
    198 
    199 	for (int ndx = 0; ndx < (int)defaultBlock.variables.size(); ++ndx)
    200 		collectNamedStructureDefinitions(namedStructs, defaultBlock.variables[ndx].varType);
    201 
    202 	for (int blockNdx = 0; blockNdx < (int)defaultBlock.interfaceBlocks.size(); ++blockNdx)
    203 		for (int ndx = 0; ndx < (int)defaultBlock.interfaceBlocks[blockNdx].variables.size(); ++ndx)
    204 			collectNamedStructureDefinitions(namedStructs, defaultBlock.interfaceBlocks[blockNdx].variables[ndx].varType);
    205 
    206 	// Write
    207 
    208 	for (int structNdx = 0; structNdx < (int)namedStructs.size(); ++structNdx)
    209 	{
    210 		buf <<	"struct " << namedStructs[structNdx]->getTypeName() << "\n"
    211 				"{\n";
    212 
    213 		for (int memberNdx = 0; memberNdx < namedStructs[structNdx]->getNumMembers(); ++memberNdx)
    214 			buf << glu::indent(1) << glu::declare(namedStructs[structNdx]->getMember(memberNdx).getType(), namedStructs[structNdx]->getMember(memberNdx).getName(), 1) << ";\n";
    215 
    216 		buf <<	"};\n";
    217 	}
    218 
    219 	if (!namedStructs.empty())
    220 		buf << "\n";
    221 }
    222 
    223 static void writeInterfaceBlock (std::ostringstream& buf, const glu::InterfaceBlock& interfaceBlock)
    224 {
    225 	buf << interfaceBlock.layout;
    226 
    227 	if (interfaceBlock.layout != glu::Layout())
    228 		buf << " ";
    229 
    230 	buf	<< glu::getStorageName(interfaceBlock.storage) << " " << interfaceBlock.interfaceName << "\n"
    231 		<< "{\n";
    232 
    233 	for (int ndx = 0; ndx < (int)interfaceBlock.variables.size(); ++ndx)
    234 		buf << glu::indent(1) << interfaceBlock.variables[ndx] << ";\n";
    235 
    236 	buf << "}";
    237 
    238 	if (!interfaceBlock.instanceName.empty())
    239 		buf << " " << interfaceBlock.instanceName;
    240 
    241 	for (int dimensionNdx = 0; dimensionNdx < (int)interfaceBlock.dimensions.size(); ++dimensionNdx)
    242 		buf << "[" << interfaceBlock.dimensions[dimensionNdx] << "]";
    243 
    244 	buf << ";\n\n";
    245 }
    246 
    247 static void writeVariableReadAccumulateExpression (std::ostringstream& buf, const std::string& accumulatorName, const std::string& name, const glu::VarType& varType)
    248 {
    249 	if (varType.isBasicType())
    250 	{
    251 		buf << "\t" << accumulatorName << " += ";
    252 
    253 		if (glu::isDataTypeScalar(varType.getBasicType()))
    254 			buf << "vec4(float(" << name << "))";
    255 		else if (glu::isDataTypeVector(varType.getBasicType()))
    256 			buf << "vec4(" << name << ".xyxy)";
    257 		else if (glu::isDataTypeMatrix(varType.getBasicType()))
    258 			buf << "vec4(float(" << name << "[0][0]))";
    259 		else if (glu::isDataTypeSamplerMultisample(varType.getBasicType()))
    260 			buf << "vec4(float(textureSize(" << name << ").x))";
    261 		else if (glu::isDataTypeSampler(varType.getBasicType()))
    262 			buf << "vec4(float(textureSize(" << name << ", 0).x))";
    263 		else if (glu::isDataTypeImage(varType.getBasicType()))
    264 			buf << "vec4(float(imageSize(" << name << ").x))";
    265 		else if (varType.getBasicType() == glu::TYPE_UINT_ATOMIC_COUNTER)
    266 			buf << "vec4(float(atomicCounterIncrement(" << name << ")))";
    267 		else
    268 			DE_ASSERT(false);
    269 
    270 		buf << ";\n";
    271 	}
    272 	else if (varType.isStructType())
    273 	{
    274 		for (int ndx = 0; ndx < varType.getStructPtr()->getNumMembers(); ++ndx)
    275 			writeVariableReadAccumulateExpression(buf, accumulatorName, name + "." + varType.getStructPtr()->getMember(ndx).getName(), varType.getStructPtr()->getMember(ndx).getType());
    276 	}
    277 	else if (varType.isArrayType())
    278 	{
    279 		if (varType.getArraySize() != glu::VarType::UNSIZED_ARRAY)
    280 			for (int ndx = 0; ndx < varType.getArraySize(); ++ndx)
    281 				writeVariableReadAccumulateExpression(buf, accumulatorName, name + "[" + de::toString(ndx) + "]", varType.getElementType());
    282 		else
    283 			writeVariableReadAccumulateExpression(buf, accumulatorName, name + "[8]", varType.getElementType());
    284 	}
    285 	else
    286 		DE_ASSERT(false);
    287 }
    288 
    289 static void writeInterfaceReadAccumulateExpression (std::ostringstream& buf, const std::string& accumulatorName, const glu::InterfaceBlock& block)
    290 {
    291 	if (block.dimensions.empty())
    292 	{
    293 		const std::string prefix = (block.instanceName.empty()) ? ("") : (block.instanceName + ".");
    294 
    295 		for (int ndx = 0; ndx < (int)block.variables.size(); ++ndx)
    296 			writeVariableReadAccumulateExpression(buf, accumulatorName, prefix + block.variables[ndx].name, block.variables[ndx].varType);
    297 	}
    298 	else
    299 	{
    300 		std::vector<int> index(block.dimensions.size(), 0);
    301 
    302 		for (;;)
    303 		{
    304 			// access element
    305 			{
    306 				std::ostringstream name;
    307 				name << block.instanceName;
    308 
    309 				for (int dimensionNdx = 0; dimensionNdx < (int)block.dimensions.size(); ++dimensionNdx)
    310 					name << "[" << index[dimensionNdx] << "]";
    311 
    312 				for (int ndx = 0; ndx < (int)block.variables.size(); ++ndx)
    313 					writeVariableReadAccumulateExpression(buf, accumulatorName, name.str() + "." + block.variables[ndx].name, block.variables[ndx].varType);
    314 			}
    315 
    316 			// increment index
    317 			if (!incrementMultiDimensionIndex(index, block.dimensions))
    318 				break;
    319 		}
    320 	}
    321 }
    322 
    323 static void writeVariableWriteExpression (std::ostringstream& buf, const std::string& sourceVec4Name, const std::string& name, const glu::VarType& varType)
    324 {
    325 	if (varType.isBasicType())
    326 	{
    327 		buf << "\t" << name << " = ";
    328 
    329 		if (glu::isDataTypeScalar(varType.getBasicType()))
    330 			buf << glu::getDataTypeName(varType.getBasicType()) << "(" << sourceVec4Name << ".y)";
    331 		else if (glu::isDataTypeVector(varType.getBasicType()) || glu::isDataTypeMatrix(varType.getBasicType()))
    332 			buf << glu::getDataTypeName(varType.getBasicType()) << "(" << glu::getDataTypeName(glu::getDataTypeScalarType(varType.getBasicType())) << "(" << sourceVec4Name << ".y))";
    333 		else
    334 			DE_ASSERT(false);
    335 
    336 		buf << ";\n";
    337 	}
    338 	else if (varType.isStructType())
    339 	{
    340 		for (int ndx = 0; ndx < varType.getStructPtr()->getNumMembers(); ++ndx)
    341 			writeVariableWriteExpression(buf, sourceVec4Name, name + "." + varType.getStructPtr()->getMember(ndx).getName(), varType.getStructPtr()->getMember(ndx).getType());
    342 	}
    343 	else if (varType.isArrayType())
    344 	{
    345 		if (varType.getArraySize() != glu::VarType::UNSIZED_ARRAY)
    346 			for (int ndx = 0; ndx < varType.getArraySize(); ++ndx)
    347 				writeVariableWriteExpression(buf, sourceVec4Name, name + "[" + de::toString(ndx) + "]", varType.getElementType());
    348 		else
    349 			writeVariableWriteExpression(buf, sourceVec4Name, name + "[9]", varType.getElementType());
    350 	}
    351 	else
    352 		DE_ASSERT(false);
    353 }
    354 
    355 static void writeInterfaceWriteExpression (std::ostringstream& buf, const std::string& sourceVec4Name, const glu::InterfaceBlock& block)
    356 {
    357 	if (block.dimensions.empty())
    358 	{
    359 		const std::string prefix = (block.instanceName.empty()) ? ("") : (block.instanceName + ".");
    360 
    361 		for (int ndx = 0; ndx < (int)block.variables.size(); ++ndx)
    362 			writeVariableWriteExpression(buf, sourceVec4Name, prefix + block.variables[ndx].name, block.variables[ndx].varType);
    363 	}
    364 	else
    365 	{
    366 		std::vector<int> index(block.dimensions.size(), 0);
    367 
    368 		for (;;)
    369 		{
    370 			// access element
    371 			{
    372 				std::ostringstream name;
    373 				name << block.instanceName;
    374 
    375 				for (int dimensionNdx = 0; dimensionNdx < (int)block.dimensions.size(); ++dimensionNdx)
    376 					name << "[" << index[dimensionNdx] << "]";
    377 
    378 				for (int ndx = 0; ndx < (int)block.variables.size(); ++ndx)
    379 					writeVariableWriteExpression(buf, sourceVec4Name, name.str() + "." + block.variables[ndx].name, block.variables[ndx].varType);
    380 			}
    381 
    382 			// increment index
    383 			if (!incrementMultiDimensionIndex(index, block.dimensions))
    384 				break;
    385 		}
    386 	}
    387 }
    388 
    389 static bool traverseVariablePath (std::vector<VariablePathComponent>& typePath, const char* subPath, const glu::VarType& type)
    390 {
    391 	glu::VarTokenizer tokenizer(subPath);
    392 
    393 	typePath.push_back(VariablePathComponent(&type));
    394 
    395 	if (tokenizer.getToken() == glu::VarTokenizer::TOKEN_END)
    396 		return true;
    397 
    398 	if (type.isStructType() && tokenizer.getToken() == glu::VarTokenizer::TOKEN_PERIOD)
    399 	{
    400 		tokenizer.advance();
    401 
    402 		// malformed path
    403 		if (tokenizer.getToken() != glu::VarTokenizer::TOKEN_IDENTIFIER)
    404 			return false;
    405 
    406 		for (int memberNdx = 0; memberNdx < type.getStructPtr()->getNumMembers(); ++memberNdx)
    407 			if (type.getStructPtr()->getMember(memberNdx).getName() == tokenizer.getIdentifier())
    408 				return traverseVariablePath(typePath, subPath + tokenizer.getCurrentTokenEndLocation(), type.getStructPtr()->getMember(memberNdx).getType());
    409 
    410 		// malformed path, no such member
    411 		return false;
    412 	}
    413 	else if (type.isArrayType() && tokenizer.getToken() == glu::VarTokenizer::TOKEN_LEFT_BRACKET)
    414 	{
    415 		tokenizer.advance();
    416 
    417 		// malformed path
    418 		if (tokenizer.getToken() != glu::VarTokenizer::TOKEN_NUMBER)
    419 			return false;
    420 
    421 		tokenizer.advance();
    422 		if (tokenizer.getToken() != glu::VarTokenizer::TOKEN_RIGHT_BRACKET)
    423 			return false;
    424 
    425 		return traverseVariablePath(typePath, subPath + tokenizer.getCurrentTokenEndLocation(), type.getElementType());
    426 	}
    427 
    428 	return false;
    429 }
    430 
    431 static bool traverseVariablePath (std::vector<VariablePathComponent>& typePath, const std::string& path, const glu::VariableDeclaration& var)
    432 {
    433 	if (glu::parseVariableName(path.c_str()) != var.name)
    434 		return false;
    435 
    436 	typePath.push_back(VariablePathComponent(&var));
    437 	return traverseVariablePath(typePath, path.c_str() + var.name.length(), var.varType);
    438 }
    439 
    440 static bool traverseShaderVariablePath (std::vector<VariablePathComponent>& typePath, const ProgramInterfaceDefinition::Shader* shader, const std::string& path, const VariableSearchFilter& filter)
    441 {
    442 	// Default block variable?
    443 	for (int varNdx = 0; varNdx < (int)shader->getDefaultBlock().variables.size(); ++varNdx)
    444 		if (filter.matchesFilter(shader->getDefaultBlock().variables[varNdx]))
    445 			if (traverseVariablePath(typePath, path, shader->getDefaultBlock().variables[varNdx]))
    446 				return true;
    447 
    448 	// is variable an interface block variable?
    449 	{
    450 		const std::string blockName = glu::parseVariableName(path.c_str());
    451 
    452 		for (int interfaceNdx = 0; interfaceNdx < (int)shader->getDefaultBlock().interfaceBlocks.size(); ++interfaceNdx)
    453 		{
    454 			if (!filter.matchesFilter(shader->getDefaultBlock().interfaceBlocks[interfaceNdx]))
    455 				continue;
    456 
    457 			if (shader->getDefaultBlock().interfaceBlocks[interfaceNdx].interfaceName == blockName)
    458 			{
    459 				// resource is a member of a named interface block
    460 				// \note there is no array index specifier even if the interface is declared as an array of instances
    461 				const std::string blockMemberPath = path.substr(blockName.size() + 1);
    462 				const std::string blockMemeberName = glu::parseVariableName(blockMemberPath.c_str());
    463 
    464 				for (int varNdx = 0; varNdx < (int)shader->getDefaultBlock().interfaceBlocks[interfaceNdx].variables.size(); ++varNdx)
    465 				{
    466 					if (shader->getDefaultBlock().interfaceBlocks[interfaceNdx].variables[varNdx].name == blockMemeberName)
    467 					{
    468 						typePath.push_back(VariablePathComponent(&shader->getDefaultBlock().interfaceBlocks[interfaceNdx]));
    469 						return traverseVariablePath(typePath, blockMemberPath, shader->getDefaultBlock().interfaceBlocks[interfaceNdx].variables[varNdx]);
    470 					}
    471 				}
    472 
    473 				// terminate search
    474 				return false;
    475 			}
    476 			else if (shader->getDefaultBlock().interfaceBlocks[interfaceNdx].instanceName.empty())
    477 			{
    478 				const std::string blockMemeberName = glu::parseVariableName(path.c_str());
    479 
    480 				// unnamed block contains such variable?
    481 				for (int varNdx = 0; varNdx < (int)shader->getDefaultBlock().interfaceBlocks[interfaceNdx].variables.size(); ++varNdx)
    482 				{
    483 					if (shader->getDefaultBlock().interfaceBlocks[interfaceNdx].variables[varNdx].name == blockMemeberName)
    484 					{
    485 						typePath.push_back(VariablePathComponent(&shader->getDefaultBlock().interfaceBlocks[interfaceNdx]));
    486 						return traverseVariablePath(typePath, path, shader->getDefaultBlock().interfaceBlocks[interfaceNdx].variables[varNdx]);
    487 					}
    488 				}
    489 
    490 				// continue search
    491 			}
    492 		}
    493 	}
    494 
    495 	return false;
    496 }
    497 
    498 static bool traverseProgramVariablePath (std::vector<VariablePathComponent>& typePath, const ProgramInterfaceDefinition::Program* program, const std::string& path, const VariableSearchFilter& filter)
    499 {
    500 	for (int shaderNdx = 0; shaderNdx < (int)program->getShaders().size(); ++shaderNdx)
    501 	{
    502 		const ProgramInterfaceDefinition::Shader* shader = program->getShaders()[shaderNdx];
    503 
    504 		if (filter.matchesFilter(shader))
    505 		{
    506 			// \note modifying output variable even when returning false
    507 			typePath.clear();
    508 			if (traverseShaderVariablePath(typePath, shader, path, filter))
    509 				return true;
    510 		}
    511 	}
    512 
    513 	return false;
    514 }
    515 
    516 static bool containsSubType (const glu::VarType& complexType, glu::DataType basicType)
    517 {
    518 	if (complexType.isBasicType())
    519 	{
    520 		return complexType.getBasicType() == basicType;
    521 	}
    522 	else if (complexType.isArrayType())
    523 	{
    524 		return containsSubType(complexType.getElementType(), basicType);
    525 	}
    526 	else if (complexType.isStructType())
    527 	{
    528 		for (int ndx = 0; ndx < complexType.getStructPtr()->getNumMembers(); ++ndx)
    529 			if (containsSubType(complexType.getStructPtr()->getMember(ndx).getType(), basicType))
    530 				return true;
    531 		return false;
    532 	}
    533 	else
    534 	{
    535 		DE_ASSERT(false);
    536 		return false;
    537 	}
    538 }
    539 
    540 static int getNumShaderBlocks (const ProgramInterfaceDefinition::Shader* shader, glu::Storage storage)
    541 {
    542 	int retVal = 0;
    543 
    544 	for (int ndx = 0; ndx < (int)shader->getDefaultBlock().interfaceBlocks.size(); ++ndx)
    545 	{
    546 		if (shader->getDefaultBlock().interfaceBlocks[ndx].storage == storage)
    547 		{
    548 			int numInstances = 1;
    549 
    550 			for (int dimensionNdx = 0; dimensionNdx < (int)shader->getDefaultBlock().interfaceBlocks[ndx].dimensions.size(); ++dimensionNdx)
    551 				numInstances *= shader->getDefaultBlock().interfaceBlocks[ndx].dimensions[dimensionNdx];
    552 
    553 			retVal += numInstances;
    554 		}
    555 	}
    556 
    557 	return retVal;
    558 }
    559 
    560 static int getNumAtomicCounterBuffers (const ProgramInterfaceDefinition::Shader* shader)
    561 {
    562 	std::set<int> buffers;
    563 
    564 	for (int ndx = 0; ndx < (int)shader->getDefaultBlock().variables.size(); ++ndx)
    565 	{
    566 		if (containsSubType(shader->getDefaultBlock().variables[ndx].varType, glu::TYPE_UINT_ATOMIC_COUNTER))
    567 		{
    568 			DE_ASSERT(shader->getDefaultBlock().variables[ndx].layout.binding != -1);
    569 			buffers.insert(shader->getDefaultBlock().variables[ndx].layout.binding);
    570 		}
    571 	}
    572 
    573 	return (int)buffers.size();
    574 }
    575 
    576 template <bool B>
    577 static bool dummyConstantTypeFilter (glu::DataType d)
    578 {
    579 	DE_UNREF(d);
    580 	return B;
    581 }
    582 
    583 static int getNumTypeInstances (const glu::VarType& complexType, bool (*predicate)(glu::DataType))
    584 {
    585 	if (complexType.isBasicType())
    586 	{
    587 		if (predicate(complexType.getBasicType()))
    588 			return 1;
    589 		else
    590 			return 0;
    591 	}
    592 	else if (complexType.isArrayType())
    593 	{
    594 		const int arraySize = (complexType.getArraySize() == glu::VarType::UNSIZED_ARRAY) ? (1) : (complexType.getArraySize());
    595 		return arraySize * getNumTypeInstances(complexType.getElementType(), predicate);
    596 	}
    597 	else if (complexType.isStructType())
    598 	{
    599 		int sum = 0;
    600 		for (int ndx = 0; ndx < complexType.getStructPtr()->getNumMembers(); ++ndx)
    601 			sum += getNumTypeInstances(complexType.getStructPtr()->getMember(ndx).getType(), predicate);
    602 		return sum;
    603 	}
    604 	else
    605 	{
    606 		DE_ASSERT(false);
    607 		return false;
    608 	}
    609 }
    610 
    611 static int getMappedBasicTypeSum (const glu::VarType& complexType, int (*typeMap)(glu::DataType))
    612 {
    613 	if (complexType.isBasicType())
    614 		return typeMap(complexType.getBasicType());
    615 	else if (complexType.isArrayType())
    616 	{
    617 		const int arraySize = (complexType.getArraySize() == glu::VarType::UNSIZED_ARRAY) ? (1) : (complexType.getArraySize());
    618 		return arraySize * getMappedBasicTypeSum(complexType.getElementType(), typeMap);
    619 	}
    620 	else if (complexType.isStructType())
    621 	{
    622 		int sum = 0;
    623 		for (int ndx = 0; ndx < complexType.getStructPtr()->getNumMembers(); ++ndx)
    624 			sum += getMappedBasicTypeSum(complexType.getStructPtr()->getMember(ndx).getType(), typeMap);
    625 		return sum;
    626 	}
    627 	else
    628 	{
    629 		DE_ASSERT(false);
    630 		return false;
    631 	}
    632 }
    633 
    634 static int getNumTypeInstances (const ProgramInterfaceDefinition::Shader* shader, glu::Storage storage, bool (*predicate)(glu::DataType))
    635 {
    636 	int retVal = 0;
    637 
    638 	for (int ndx = 0; ndx < (int)shader->getDefaultBlock().interfaceBlocks.size(); ++ndx)
    639 	{
    640 		if (shader->getDefaultBlock().interfaceBlocks[ndx].storage == storage)
    641 		{
    642 			int numInstances = 1;
    643 
    644 			for (int dimensionNdx = 0; dimensionNdx < (int)shader->getDefaultBlock().interfaceBlocks[ndx].dimensions.size(); ++dimensionNdx)
    645 				numInstances *= shader->getDefaultBlock().interfaceBlocks[ndx].dimensions[dimensionNdx];
    646 
    647 			for (int varNdx = 0; varNdx < (int)shader->getDefaultBlock().interfaceBlocks[ndx].variables.size(); ++varNdx)
    648 				retVal += numInstances * getNumTypeInstances(shader->getDefaultBlock().interfaceBlocks[ndx].variables[varNdx].varType, predicate);
    649 		}
    650 	}
    651 
    652 	for (int varNdx = 0; varNdx < (int)shader->getDefaultBlock().variables.size(); ++varNdx)
    653 		if (shader->getDefaultBlock().variables[varNdx].storage == storage)
    654 			retVal += getNumTypeInstances(shader->getDefaultBlock().variables[varNdx].varType, predicate);
    655 
    656 	return retVal;
    657 }
    658 
    659 static int getMappedBasicTypeSum (const ProgramInterfaceDefinition::Shader* shader, glu::Storage storage, int (*typeMap)(glu::DataType))
    660 {
    661 	int retVal = 0;
    662 
    663 	for (int ndx = 0; ndx < (int)shader->getDefaultBlock().interfaceBlocks.size(); ++ndx)
    664 	{
    665 		if (shader->getDefaultBlock().interfaceBlocks[ndx].storage == storage)
    666 		{
    667 			int numInstances = 1;
    668 
    669 			for (int dimensionNdx = 0; dimensionNdx < (int)shader->getDefaultBlock().interfaceBlocks[ndx].dimensions.size(); ++dimensionNdx)
    670 				numInstances *= shader->getDefaultBlock().interfaceBlocks[ndx].dimensions[dimensionNdx];
    671 
    672 			for (int varNdx = 0; varNdx < (int)shader->getDefaultBlock().interfaceBlocks[ndx].variables.size(); ++varNdx)
    673 				retVal += numInstances * getMappedBasicTypeSum(shader->getDefaultBlock().interfaceBlocks[ndx].variables[varNdx].varType, typeMap);
    674 		}
    675 	}
    676 
    677 	for (int varNdx = 0; varNdx < (int)shader->getDefaultBlock().variables.size(); ++varNdx)
    678 		if (shader->getDefaultBlock().variables[varNdx].storage == storage)
    679 			retVal += getMappedBasicTypeSum(shader->getDefaultBlock().variables[varNdx].varType, typeMap);
    680 
    681 	return retVal;
    682 }
    683 
    684 static int getNumDataTypeComponents (glu::DataType type)
    685 {
    686 	if (glu::isDataTypeScalarOrVector(type) || glu::isDataTypeMatrix(type))
    687 		return glu::getDataTypeScalarSize(type);
    688 	else
    689 		return 0;
    690 }
    691 
    692 static int getNumDataTypeVectors (glu::DataType type)
    693 {
    694 	if (glu::isDataTypeScalar(type))
    695 		return 1;
    696 	else if (glu::isDataTypeVector(type))
    697 		return 1;
    698 	else if (glu::isDataTypeMatrix(type))
    699 		return glu::getDataTypeMatrixNumColumns(type);
    700 	else
    701 		return 0;
    702 }
    703 
    704 static int getNumComponents (const ProgramInterfaceDefinition::Shader* shader, glu::Storage storage)
    705 {
    706 	return getMappedBasicTypeSum(shader, storage, getNumDataTypeComponents);
    707 }
    708 
    709 static int getNumVectors (const ProgramInterfaceDefinition::Shader* shader, glu::Storage storage)
    710 {
    711 	return getMappedBasicTypeSum(shader, storage, getNumDataTypeVectors);
    712 }
    713 
    714 static int getNumDefaultBlockComponents (const ProgramInterfaceDefinition::Shader* shader, glu::Storage storage)
    715 {
    716 	int retVal = 0;
    717 
    718 	for (int varNdx = 0; varNdx < (int)shader->getDefaultBlock().variables.size(); ++varNdx)
    719 		if (shader->getDefaultBlock().variables[varNdx].storage == storage)
    720 			retVal += getMappedBasicTypeSum(shader->getDefaultBlock().variables[varNdx].varType, getNumDataTypeComponents);
    721 
    722 	return retVal;
    723 }
    724 
    725 static int getMaxBufferBinding (const ProgramInterfaceDefinition::Shader* shader, glu::Storage storage)
    726 {
    727 	int maxBinding = -1;
    728 
    729 	for (int ndx = 0; ndx < (int)shader->getDefaultBlock().interfaceBlocks.size(); ++ndx)
    730 	{
    731 		if (shader->getDefaultBlock().interfaceBlocks[ndx].storage == storage)
    732 		{
    733 			const int	binding			= (shader->getDefaultBlock().interfaceBlocks[ndx].layout.binding == -1) ? (0) : (shader->getDefaultBlock().interfaceBlocks[ndx].layout.binding);
    734 			int			numInstances	= 1;
    735 
    736 			for (int dimensionNdx = 0; dimensionNdx < (int)shader->getDefaultBlock().interfaceBlocks[ndx].dimensions.size(); ++dimensionNdx)
    737 				numInstances *= shader->getDefaultBlock().interfaceBlocks[ndx].dimensions[dimensionNdx];
    738 
    739 			maxBinding = de::max(maxBinding, binding + numInstances - 1);
    740 		}
    741 	}
    742 
    743 	return (int)maxBinding;
    744 }
    745 
    746 static int getBufferTypeSize (glu::DataType type, glu::MatrixOrder order)
    747 {
    748 	// assume vec4 alignments, should produce values greater than or equal to the actual resource usage
    749 	int numVectors = 0;
    750 
    751 	if (glu::isDataTypeScalarOrVector(type))
    752 		numVectors = 1;
    753 	else if (glu::isDataTypeMatrix(type) && order == glu::MATRIXORDER_ROW_MAJOR)
    754 		numVectors = glu::getDataTypeMatrixNumRows(type);
    755 	else if (glu::isDataTypeMatrix(type) && order != glu::MATRIXORDER_ROW_MAJOR)
    756 		numVectors = glu::getDataTypeMatrixNumColumns(type);
    757 	else
    758 		DE_ASSERT(false);
    759 
    760 	return 4 * numVectors;
    761 }
    762 
    763 static int getBufferVariableSize (const glu::VarType& type, glu::MatrixOrder order)
    764 {
    765 	if (type.isBasicType())
    766 		return getBufferTypeSize(type.getBasicType(), order);
    767 	else if (type.isArrayType())
    768 	{
    769 		const int arraySize = (type.getArraySize() == glu::VarType::UNSIZED_ARRAY) ? (1) : (type.getArraySize());
    770 		return arraySize * getBufferVariableSize(type.getElementType(), order);
    771 	}
    772 	else if (type.isStructType())
    773 	{
    774 		int sum = 0;
    775 		for (int ndx = 0; ndx < type.getStructPtr()->getNumMembers(); ++ndx)
    776 			sum += getBufferVariableSize(type.getStructPtr()->getMember(ndx).getType(), order);
    777 		return sum;
    778 	}
    779 	else
    780 	{
    781 		DE_ASSERT(false);
    782 		return false;
    783 	}
    784 }
    785 
    786 static int getBufferSize (const glu::InterfaceBlock& block, glu::MatrixOrder blockOrder)
    787 {
    788 	int size = 0;
    789 
    790 	for (int ndx = 0; ndx < (int)block.variables.size(); ++ndx)
    791 		size += getBufferVariableSize(block.variables[ndx].varType, (block.variables[ndx].layout.matrixOrder == glu::MATRIXORDER_LAST) ? (blockOrder) : (block.variables[ndx].layout.matrixOrder));
    792 
    793 	return size;
    794 }
    795 
    796 static int getBufferMaxSize (const ProgramInterfaceDefinition::Shader* shader, glu::Storage storage)
    797 {
    798 	int maxSize = 0;
    799 
    800 	for (int ndx = 0; ndx < (int)shader->getDefaultBlock().interfaceBlocks.size(); ++ndx)
    801 		if (shader->getDefaultBlock().interfaceBlocks[ndx].storage == storage)
    802 			maxSize = de::max(maxSize, getBufferSize(shader->getDefaultBlock().interfaceBlocks[ndx], shader->getDefaultBlock().interfaceBlocks[ndx].layout.matrixOrder));
    803 
    804 	return (int)maxSize;
    805 }
    806 
    807 static int getAtomicCounterMaxBinding (const ProgramInterfaceDefinition::Shader* shader)
    808 {
    809 	int maxBinding = -1;
    810 
    811 	for (int ndx = 0; ndx < (int)shader->getDefaultBlock().variables.size(); ++ndx)
    812 	{
    813 		if (containsSubType(shader->getDefaultBlock().variables[ndx].varType, glu::TYPE_UINT_ATOMIC_COUNTER))
    814 		{
    815 			DE_ASSERT(shader->getDefaultBlock().variables[ndx].layout.binding != -1);
    816 			maxBinding = de::max(maxBinding, shader->getDefaultBlock().variables[ndx].layout.binding);
    817 		}
    818 	}
    819 
    820 	return (int)maxBinding;
    821 }
    822 
    823 static int getUniformMaxBinding (const ProgramInterfaceDefinition::Shader* shader, bool (*predicate)(glu::DataType))
    824 {
    825 	int maxBinding = -1;
    826 
    827 	for (int ndx = 0; ndx < (int)shader->getDefaultBlock().variables.size(); ++ndx)
    828 		maxBinding = de::max(maxBinding, shader->getDefaultBlock().variables[ndx].layout.binding + getNumTypeInstances(shader->getDefaultBlock().variables[ndx].varType, predicate));
    829 
    830 	return (int)maxBinding;
    831 }
    832 
    833 static int getAtomicCounterMaxBufferSize (const ProgramInterfaceDefinition::Shader* shader)
    834 {
    835 	std::map<int, int>	bufferSizes;
    836 	int					maxSize			= 0;
    837 
    838 	for (int ndx = 0; ndx < (int)shader->getDefaultBlock().variables.size(); ++ndx)
    839 	{
    840 		if (containsSubType(shader->getDefaultBlock().variables[ndx].varType, glu::TYPE_UINT_ATOMIC_COUNTER))
    841 		{
    842 			const int bufferBinding	= shader->getDefaultBlock().variables[ndx].layout.binding;
    843 			const int offset		= (shader->getDefaultBlock().variables[ndx].layout.offset == -1) ? (0) : (shader->getDefaultBlock().variables[ndx].layout.offset);
    844 			const int size			= offset + 4 * getNumTypeInstances(shader->getDefaultBlock().variables[ndx].varType, glu::isDataTypeAtomicCounter);
    845 
    846 			DE_ASSERT(shader->getDefaultBlock().variables[ndx].layout.binding != -1);
    847 
    848 			if (bufferSizes.find(bufferBinding) == bufferSizes.end())
    849 				bufferSizes[bufferBinding] = size;
    850 			else
    851 				bufferSizes[bufferBinding] = de::max<int>(bufferSizes[bufferBinding], size);
    852 		}
    853 	}
    854 
    855 	for (std::map<int, int>::iterator it = bufferSizes.begin(); it != bufferSizes.end(); ++it)
    856 		maxSize = de::max<int>(maxSize, it->second);
    857 
    858 	return maxSize;
    859 }
    860 
    861 static int getNumFeedbackVaryingComponents (const ProgramInterfaceDefinition::Program* program, const std::string& name)
    862 {
    863 	std::vector<VariablePathComponent> path;
    864 
    865 	if (name == "gl_Position")
    866 		return 4;
    867 
    868 	DE_ASSERT(deStringBeginsWith(name.c_str(), "gl_") == DE_FALSE);
    869 
    870 	if (!traverseProgramVariablePath(path, program, name, VariableSearchFilter(glu::SHADERTYPE_VERTEX, glu::STORAGE_OUT)))
    871 		DE_ASSERT(false); // Program failed validate, invalid operation
    872 
    873 	return getMappedBasicTypeSum(*path.back().getVariableType(), getNumDataTypeComponents);
    874 }
    875 
    876 static int getNumXFBComponents (const ProgramInterfaceDefinition::Program* program)
    877 {
    878 	int numComponents = 0;
    879 
    880 	for (int ndx = 0; ndx < (int)program->getTransformFeedbackVaryings().size(); ++ndx)
    881 		numComponents += getNumFeedbackVaryingComponents(program, program->getTransformFeedbackVaryings()[ndx]);
    882 
    883 	return numComponents;
    884 }
    885 
    886 static int getNumMaxXFBOutputComponents (const ProgramInterfaceDefinition::Program* program)
    887 {
    888 	int numComponents = 0;
    889 
    890 	for (int ndx = 0; ndx < (int)program->getTransformFeedbackVaryings().size(); ++ndx)
    891 		numComponents = de::max(numComponents, getNumFeedbackVaryingComponents(program, program->getTransformFeedbackVaryings()[ndx]));
    892 
    893 	return numComponents;
    894 }
    895 
    896 static int getFragmentOutputMaxLocation (const ProgramInterfaceDefinition::Shader* shader)
    897 {
    898 	DE_ASSERT(shader->getType() == glu::SHADERTYPE_FRAGMENT);
    899 
    900 	int maxOutputLocation = -1;
    901 
    902 	for (int ndx = 0; ndx < (int)shader->getDefaultBlock().variables.size(); ++ndx)
    903 	{
    904 		if (shader->getDefaultBlock().variables[ndx].storage == glu::STORAGE_OUT)
    905 		{
    906 			// missing location qualifier means location == 0
    907 			const int outputLocation 		= (shader->getDefaultBlock().variables[ndx].layout.location == -1)
    908 												? (0)
    909 												: (shader->getDefaultBlock().variables[ndx].layout.location);
    910 
    911 			// only basic types or arrays of basic types possible
    912 			DE_ASSERT(!shader->getDefaultBlock().variables[ndx].varType.isStructType());
    913 
    914 			const int locationSlotsTaken	= (shader->getDefaultBlock().variables[ndx].varType.isArrayType())
    915 												? (shader->getDefaultBlock().variables[ndx].varType.getArraySize())
    916 												: (1);
    917 
    918 			maxOutputLocation = de::max(maxOutputLocation, outputLocation + locationSlotsTaken - 1);
    919 		}
    920 	}
    921 
    922 	return maxOutputLocation;
    923 }
    924 
    925 } // anonymous
    926 
    927 std::vector<std::string> getProgramInterfaceBlockMemberResourceList (const glu::InterfaceBlock& interfaceBlock)
    928 {
    929 	const std::string			namePrefix					= (!interfaceBlock.instanceName.empty()) ? (interfaceBlock.interfaceName + ".") : ("");
    930 	const bool					isTopLevelBufferVariable	= (interfaceBlock.storage == glu::STORAGE_BUFFER);
    931 	std::vector<std::string>	resources;
    932 
    933 	for (int variableNdx = 0; variableNdx < (int)interfaceBlock.variables.size(); ++variableNdx)
    934 		generateVariableTypeResourceNames(resources,
    935 										  namePrefix + interfaceBlock.variables[variableNdx].name,
    936 										  interfaceBlock.variables[variableNdx].varType,
    937 										  (isTopLevelBufferVariable) ?
    938 											(RESOURCE_NAME_GENERATION_FLAG_TOP_LEVEL_BUFFER_VARIABLE) :
    939 											(RESOURCE_NAME_GENERATION_FLAG_DEFAULT));
    940 
    941 	return resources;
    942 }
    943 
    944 std::vector<std::string> getProgramInterfaceResourceList (const ProgramInterfaceDefinition::Program* program, ProgramInterface interface)
    945 {
    946 	// The same {uniform (block), buffer (variable)} can exist in multiple shaders, remove duplicates but keep order
    947 	const bool					removeDuplicated	= (interface == PROGRAMINTERFACE_UNIFORM)			||
    948 													  (interface == PROGRAMINTERFACE_UNIFORM_BLOCK)		||
    949 													  (interface == PROGRAMINTERFACE_BUFFER_VARIABLE)	||
    950 													  (interface == PROGRAMINTERFACE_SHADER_STORAGE_BLOCK);
    951 	std::vector<std::string>	resources;
    952 
    953 	switch (interface)
    954 	{
    955 		case PROGRAMINTERFACE_UNIFORM:
    956 		case PROGRAMINTERFACE_BUFFER_VARIABLE:
    957 		{
    958 			const glu::Storage storage = (interface == PROGRAMINTERFACE_UNIFORM) ? (glu::STORAGE_UNIFORM) : (glu::STORAGE_BUFFER);
    959 
    960 			for (int shaderNdx = 0; shaderNdx < (int)program->getShaders().size(); ++shaderNdx)
    961 			{
    962 				const ProgramInterfaceDefinition::Shader* shader = program->getShaders()[shaderNdx];
    963 
    964 				for (int variableNdx = 0; variableNdx < (int)shader->getDefaultBlock().variables.size(); ++variableNdx)
    965 					if (shader->getDefaultBlock().variables[variableNdx].storage == storage)
    966 						generateVariableTypeResourceNames(resources,
    967 														  shader->getDefaultBlock().variables[variableNdx].name,
    968 														  shader->getDefaultBlock().variables[variableNdx].varType,
    969 														  RESOURCE_NAME_GENERATION_FLAG_DEFAULT);
    970 
    971 				for (int interfaceNdx = 0; interfaceNdx < (int)shader->getDefaultBlock().interfaceBlocks.size(); ++interfaceNdx)
    972 				{
    973 					const glu::InterfaceBlock& interfaceBlock = shader->getDefaultBlock().interfaceBlocks[interfaceNdx];
    974 					if (interfaceBlock.storage == storage)
    975 					{
    976 						const std::vector<std::string> blockResources = getProgramInterfaceBlockMemberResourceList(interfaceBlock);
    977 						resources.insert(resources.end(), blockResources.begin(), blockResources.end());
    978 					}
    979 				}
    980 			}
    981 			break;
    982 		}
    983 
    984 		case PROGRAMINTERFACE_UNIFORM_BLOCK:
    985 		case PROGRAMINTERFACE_SHADER_STORAGE_BLOCK:
    986 		{
    987 			const glu::Storage storage = (interface == PROGRAMINTERFACE_UNIFORM_BLOCK) ? (glu::STORAGE_UNIFORM) : (glu::STORAGE_BUFFER);
    988 
    989 			for (int shaderNdx = 0; shaderNdx < (int)program->getShaders().size(); ++shaderNdx)
    990 			{
    991 				const ProgramInterfaceDefinition::Shader* shader = program->getShaders()[shaderNdx];
    992 				for (int interfaceNdx = 0; interfaceNdx < (int)shader->getDefaultBlock().interfaceBlocks.size(); ++interfaceNdx)
    993 				{
    994 					const glu::InterfaceBlock& interfaceBlock = shader->getDefaultBlock().interfaceBlocks[interfaceNdx];
    995 					if (interfaceBlock.storage == storage)
    996 					{
    997 						std::vector<int> index(interfaceBlock.dimensions.size(), 0);
    998 
    999 						for (;;)
   1000 						{
   1001 							// add resource string for each element
   1002 							{
   1003 								std::ostringstream name;
   1004 								name << interfaceBlock.interfaceName;
   1005 
   1006 								for (int dimensionNdx = 0; dimensionNdx < (int)interfaceBlock.dimensions.size(); ++dimensionNdx)
   1007 									name << "[" << index[dimensionNdx] << "]";
   1008 
   1009 								resources.push_back(name.str());
   1010 							}
   1011 
   1012 							// increment index
   1013 							if (!incrementMultiDimensionIndex(index, interfaceBlock.dimensions))
   1014 								break;
   1015 						}
   1016 					}
   1017 				}
   1018 			}
   1019 			break;
   1020 		}
   1021 
   1022 		case PROGRAMINTERFACE_PROGRAM_INPUT:
   1023 		case PROGRAMINTERFACE_PROGRAM_OUTPUT:
   1024 		{
   1025 			const glu::Storage		storage		= (interface == PROGRAMINTERFACE_PROGRAM_INPUT) ? (glu::STORAGE_IN) : (glu::STORAGE_OUT);
   1026 			const glu::ShaderType	shaderType	= (interface == PROGRAMINTERFACE_PROGRAM_INPUT) ? (program->getFirstStage()) : (program->getLastStage());
   1027 
   1028 			for (int shaderNdx = 0; shaderNdx < (int)program->getShaders().size(); ++shaderNdx)
   1029 			{
   1030 				const ProgramInterfaceDefinition::Shader* shader = program->getShaders()[shaderNdx];
   1031 
   1032 				if (shader->getType() != shaderType)
   1033 					continue;
   1034 
   1035 				for (int variableNdx = 0; variableNdx < (int)shader->getDefaultBlock().variables.size(); ++variableNdx)
   1036 					if (shader->getDefaultBlock().variables[variableNdx].storage == storage)
   1037 						generateVariableTypeResourceNames(resources,
   1038 														  shader->getDefaultBlock().variables[variableNdx].name,
   1039 														  shader->getDefaultBlock().variables[variableNdx].varType,
   1040 														  RESOURCE_NAME_GENERATION_FLAG_DEFAULT);
   1041 
   1042 				for (int interfaceNdx = 0; interfaceNdx < (int)shader->getDefaultBlock().interfaceBlocks.size(); ++interfaceNdx)
   1043 				{
   1044 					const glu::InterfaceBlock& interfaceBlock = shader->getDefaultBlock().interfaceBlocks[interfaceNdx];
   1045 					if (interfaceBlock.storage == storage)
   1046 					{
   1047 						const std::vector<std::string> blockResources = getProgramInterfaceBlockMemberResourceList(interfaceBlock);
   1048 						resources.insert(resources.end(), blockResources.begin(), blockResources.end());
   1049 					}
   1050 				}
   1051 			}
   1052 
   1053 			// built-ins
   1054 			if (interface == PROGRAMINTERFACE_PROGRAM_INPUT)
   1055 			{
   1056 				if (shaderType == glu::SHADERTYPE_VERTEX && resources.empty())
   1057 					resources.push_back("gl_VertexID"); // only read from when there are no other inputs
   1058 				else if (shaderType == glu::SHADERTYPE_FRAGMENT && resources.empty())
   1059 					resources.push_back("gl_FragCoord"); // only read from when there are no other inputs
   1060 				else if (shaderType == glu::SHADERTYPE_GEOMETRY && resources.empty())
   1061 					resources.push_back("gl_in[0].gl_Position");
   1062 				else if (shaderType == glu::SHADERTYPE_TESSELLATION_CONTROL)
   1063 				{
   1064 					const bool noInputs = resources.empty();
   1065 					resources.push_back("gl_InvocationID");
   1066 
   1067 					if (noInputs)
   1068 						resources.push_back("gl_in[0].gl_Position"); // only read from when there are no other inputs
   1069 				}
   1070 				else if (shaderType == glu::SHADERTYPE_TESSELLATION_EVALUATION && resources.empty())
   1071 					resources.push_back("gl_in[0].gl_Position"); // only read from when there are no other inputs
   1072 				else if (shaderType == glu::SHADERTYPE_COMPUTE && resources.empty())
   1073 					resources.push_back("gl_NumWorkGroups"); // only read from when there are no other inputs
   1074 			}
   1075 			else if (interface == PROGRAMINTERFACE_PROGRAM_OUTPUT)
   1076 			{
   1077 				if (shaderType == glu::SHADERTYPE_VERTEX)
   1078 					resources.push_back("gl_Position");
   1079 				else if (shaderType == glu::SHADERTYPE_FRAGMENT && resources.empty())
   1080 					resources.push_back("gl_FragDepth"); // only written to when there are no other outputs
   1081 				else if (shaderType == glu::SHADERTYPE_GEOMETRY)
   1082 					resources.push_back("gl_Position");
   1083 				else if (shaderType == glu::SHADERTYPE_TESSELLATION_CONTROL)
   1084 					resources.push_back("gl_out[0].gl_Position");
   1085 				else if (shaderType == glu::SHADERTYPE_TESSELLATION_EVALUATION)
   1086 					resources.push_back("gl_Position");
   1087 			}
   1088 
   1089 			break;
   1090 		}
   1091 
   1092 		case PROGRAMINTERFACE_TRANSFORM_FEEDBACK_VARYING:
   1093 		{
   1094 			for (int varyingNdx = 0; varyingNdx < (int)program->getTransformFeedbackVaryings().size(); ++varyingNdx)
   1095 			{
   1096 				const std::string& varyingName = program->getTransformFeedbackVaryings()[varyingNdx];
   1097 
   1098 				if (deStringBeginsWith(varyingName.c_str(), "gl_"))
   1099 					resources.push_back(varyingName); // builtin
   1100 				else
   1101 				{
   1102 					std::vector<VariablePathComponent> path;
   1103 
   1104 					if (!traverseProgramVariablePath(path, program, varyingName, VariableSearchFilter(glu::SHADERTYPE_VERTEX, glu::STORAGE_OUT)))
   1105 						DE_ASSERT(false); // Program failed validate, invalid operation
   1106 
   1107 					generateVariableTypeResourceNames(resources,
   1108 													  varyingName,
   1109 													  *path.back().getVariableType(),
   1110 													  RESOURCE_NAME_GENERATION_FLAG_TRANSFORM_FEEDBACK_VARIABLE);
   1111 				}
   1112 			}
   1113 
   1114 			break;
   1115 		}
   1116 
   1117 		default:
   1118 			DE_ASSERT(false);
   1119 	}
   1120 
   1121 	if (removeDuplicated)
   1122 	{
   1123 		std::set<std::string>		addedVariables;
   1124 		std::vector<std::string>	uniqueResouces;
   1125 
   1126 		for (int ndx = 0; ndx < (int)resources.size(); ++ndx)
   1127 		{
   1128 			if (addedVariables.find(resources[ndx]) == addedVariables.end())
   1129 			{
   1130 				addedVariables.insert(resources[ndx]);
   1131 				uniqueResouces.push_back(resources[ndx]);
   1132 			}
   1133 		}
   1134 
   1135 		uniqueResouces.swap(resources);
   1136 	}
   1137 
   1138 	return resources;
   1139 }
   1140 
   1141 glu::ProgramSources generateProgramInterfaceProgramSources (const ProgramInterfaceDefinition::Program* program)
   1142 {
   1143 	glu::ProgramSources sources;
   1144 
   1145 	DE_ASSERT(program->isValid());
   1146 
   1147 	for (int shaderNdx = 0; shaderNdx < (int)program->getShaders().size(); ++shaderNdx)
   1148 	{
   1149 		const ProgramInterfaceDefinition::Shader*	shader						= program->getShaders()[shaderNdx];
   1150 		bool										containsUserDefinedOutputs	= false;
   1151 		bool										containsUserDefinedInputs	= false;
   1152 		std::ostringstream							sourceBuf;
   1153 		std::ostringstream							usageBuf;
   1154 
   1155 		sourceBuf	<< glu::getGLSLVersionDeclaration(shader->getVersion()) << "\n"
   1156 					<< getShaderTypeDeclarations(shader->getType())
   1157 					<< "\n";
   1158 
   1159 		// Struct definitions
   1160 
   1161 		writeStructureDefinitions(sourceBuf, shader->getDefaultBlock());
   1162 
   1163 		// variables in the default scope
   1164 
   1165 		for (int ndx = 0; ndx < (int)shader->getDefaultBlock().variables.size(); ++ndx)
   1166 			sourceBuf << shader->getDefaultBlock().variables[ndx] << ";\n";
   1167 
   1168 		if (!shader->getDefaultBlock().variables.empty())
   1169 			sourceBuf << "\n";
   1170 
   1171 		// Interface blocks
   1172 
   1173 		for (int ndx = 0; ndx < (int)shader->getDefaultBlock().interfaceBlocks.size(); ++ndx)
   1174 			writeInterfaceBlock(sourceBuf, shader->getDefaultBlock().interfaceBlocks[ndx]);
   1175 
   1176 		// Use inputs and outputs so that they won't be removed by the optimizer
   1177 
   1178 		usageBuf <<	"highp vec4 readInputs()\n"
   1179 					"{\n"
   1180 					"	highp vec4 retValue = vec4(0.0);\n";
   1181 
   1182 		// User-defined inputs
   1183 
   1184 		for (int ndx = 0; ndx < (int)shader->getDefaultBlock().variables.size(); ++ndx)
   1185 		{
   1186 			if (shader->getDefaultBlock().variables[ndx].storage == glu::STORAGE_IN ||
   1187 				shader->getDefaultBlock().variables[ndx].storage == glu::STORAGE_UNIFORM)
   1188 			{
   1189 				writeVariableReadAccumulateExpression(usageBuf, "retValue", shader->getDefaultBlock().variables[ndx].name, shader->getDefaultBlock().variables[ndx].varType);
   1190 				containsUserDefinedInputs = true;
   1191 			}
   1192 		}
   1193 
   1194 		for (int interfaceNdx = 0; interfaceNdx < (int)shader->getDefaultBlock().interfaceBlocks.size(); ++interfaceNdx)
   1195 		{
   1196 			const glu::InterfaceBlock& interface = shader->getDefaultBlock().interfaceBlocks[interfaceNdx];
   1197 			if (interface.storage == glu::STORAGE_UNIFORM ||
   1198 				(interface.storage == glu::STORAGE_BUFFER && (interface.memoryAccessQualifierFlags & glu::MEMORYACCESSQUALIFIER_WRITEONLY_BIT) == 0))
   1199 			{
   1200 				writeInterfaceReadAccumulateExpression(usageBuf, "retValue", interface);
   1201 				containsUserDefinedInputs = true;
   1202 			}
   1203 		}
   1204 
   1205 		// Built-in-inputs
   1206 
   1207 		if (!containsUserDefinedInputs)
   1208 		{
   1209 			if (shader->getType() == glu::SHADERTYPE_VERTEX)
   1210 				usageBuf << "	retValue += vec4(float(gl_VertexID));\n";
   1211 			else if (shader->getType() == glu::SHADERTYPE_FRAGMENT)
   1212 				usageBuf << "	retValue += gl_FragCoord;\n";
   1213 			else if (shader->getType() == glu::SHADERTYPE_GEOMETRY)
   1214 				usageBuf << "	retValue += gl_in[0].gl_Position;\n";
   1215 			else if (shader->getType() == glu::SHADERTYPE_TESSELLATION_CONTROL)
   1216 				usageBuf << "	retValue += gl_in[0].gl_Position;\n";
   1217 			else if (shader->getType() == glu::SHADERTYPE_TESSELLATION_EVALUATION)
   1218 				usageBuf << "	retValue += gl_in[0].gl_Position;\n";
   1219 			else if (shader->getType() == glu::SHADERTYPE_COMPUTE)
   1220 				usageBuf << "	retValue += vec4(float(gl_NumWorkGroups.x));\n";
   1221 		}
   1222 
   1223 		usageBuf <<	"	return retValue;\n"
   1224 					"}\n\n";
   1225 
   1226 		usageBuf <<	"void writeOutputs(in highp vec4 dummyValue)\n"
   1227 					"{\n";
   1228 
   1229 		// User-defined outputs
   1230 
   1231 		for (int ndx = 0; ndx < (int)shader->getDefaultBlock().variables.size(); ++ndx)
   1232 		{
   1233 			if (shader->getDefaultBlock().variables[ndx].storage == glu::STORAGE_OUT)
   1234 			{
   1235 				writeVariableWriteExpression(usageBuf, "dummyValue", shader->getDefaultBlock().variables[ndx].name, shader->getDefaultBlock().variables[ndx].varType);
   1236 				containsUserDefinedOutputs = true;
   1237 			}
   1238 		}
   1239 
   1240 		for (int interfaceNdx = 0; interfaceNdx < (int)shader->getDefaultBlock().interfaceBlocks.size(); ++interfaceNdx)
   1241 		{
   1242 			const glu::InterfaceBlock& interface = shader->getDefaultBlock().interfaceBlocks[interfaceNdx];
   1243 			if (interface.storage == glu::STORAGE_BUFFER && (interface.memoryAccessQualifierFlags & glu::MEMORYACCESSQUALIFIER_READONLY_BIT) == 0)
   1244 			{
   1245 				writeInterfaceWriteExpression(usageBuf, "dummyValue", interface);
   1246 				containsUserDefinedOutputs = true;
   1247 			}
   1248 		}
   1249 
   1250 		// Builtin-outputs that must be written to
   1251 
   1252 		if (shader->getType() == glu::SHADERTYPE_VERTEX)
   1253 			usageBuf << "	gl_Position = dummyValue;\n";
   1254 		else if (shader->getType() == glu::SHADERTYPE_GEOMETRY)
   1255 			usageBuf << "	gl_Position = dummyValue;\n"
   1256 						 "	EmitVertex();\n";
   1257 		else if (shader->getType() == glu::SHADERTYPE_TESSELLATION_CONTROL)
   1258 			usageBuf << "	gl_out[gl_InvocationID].gl_Position = dummyValue;\n";
   1259 		else if (shader->getType() == glu::SHADERTYPE_TESSELLATION_EVALUATION)
   1260 			usageBuf << "	gl_Position = dummyValue;\n";
   1261 
   1262 		// Output to sink input data to
   1263 
   1264 		if (!containsUserDefinedOutputs)
   1265 		{
   1266 			if (shader->getType() == glu::SHADERTYPE_FRAGMENT)
   1267 				usageBuf << "	gl_FragDepth = dot(dummyValue.xy, dummyValue.xw);\n";
   1268 			else if (shader->getType() == glu::SHADERTYPE_COMPUTE)
   1269 				usageBuf << "	dummyOutputBlock.dummyValue = dummyValue;\n";
   1270 		}
   1271 
   1272 		usageBuf <<	"}\n\n"
   1273 					"void main()\n"
   1274 					"{\n"
   1275 					"	writeOutputs(readInputs());\n"
   1276 					"}\n";
   1277 
   1278 		// Interface for dummy output
   1279 
   1280 		if (shader->getType() == glu::SHADERTYPE_COMPUTE && !containsUserDefinedOutputs)
   1281 		{
   1282 			sourceBuf	<< "writeonly buffer DummyOutputInterface\n"
   1283 						<< "{\n"
   1284 						<< "	highp vec4 dummyValue;\n"
   1285 						<< "} dummyOutputBlock;\n\n";
   1286 		}
   1287 
   1288 		sources << glu::ShaderSource(shader->getType(), sourceBuf.str() + usageBuf.str());
   1289 	}
   1290 
   1291 	if (program->isSeparable())
   1292 		sources << glu::ProgramSeparable(true);
   1293 
   1294 	for (int ndx = 0; ndx < (int)program->getTransformFeedbackVaryings().size(); ++ndx)
   1295 		sources << glu::TransformFeedbackVarying(program->getTransformFeedbackVaryings()[ndx]);
   1296 
   1297 	if (program->getTransformFeedbackMode())
   1298 		sources << glu::TransformFeedbackMode(program->getTransformFeedbackMode());
   1299 
   1300 	return sources;
   1301 }
   1302 
   1303 bool findProgramVariablePathByPathName (std::vector<VariablePathComponent>& typePath, const ProgramInterfaceDefinition::Program* program, const std::string& pathName, const VariableSearchFilter& filter)
   1304 {
   1305 	std::vector<VariablePathComponent> modifiedPath;
   1306 
   1307 	if (!traverseProgramVariablePath(modifiedPath, program, pathName, filter))
   1308 		return false;
   1309 
   1310 	// modify param only on success
   1311 	typePath.swap(modifiedPath);
   1312 	return true;
   1313 }
   1314 
   1315 ProgramInterfaceDefinition::ShaderResourceUsage getShaderResourceUsage (const ProgramInterfaceDefinition::Shader* shader)
   1316 {
   1317 	ProgramInterfaceDefinition::ShaderResourceUsage retVal;
   1318 
   1319 	retVal.numInputs						= getNumTypeInstances(shader, glu::STORAGE_IN, dummyConstantTypeFilter<true>);
   1320 	retVal.numInputVectors					= getNumVectors(shader, glu::STORAGE_IN);
   1321 	retVal.numInputComponents				= getNumComponents(shader, glu::STORAGE_IN);
   1322 
   1323 	retVal.numOutputs						= getNumTypeInstances(shader, glu::STORAGE_OUT, dummyConstantTypeFilter<true>);
   1324 	retVal.numOutputVectors					= getNumVectors(shader, glu::STORAGE_OUT);
   1325 	retVal.numOutputComponents				= getNumComponents(shader, glu::STORAGE_OUT);
   1326 
   1327 	retVal.numDefaultBlockUniformComponents	= getNumDefaultBlockComponents(shader, glu::STORAGE_UNIFORM);
   1328 	retVal.numCombinedUniformComponents		= getNumComponents(shader, glu::STORAGE_UNIFORM);
   1329 	retVal.numUniformVectors				= getNumVectors(shader, glu::STORAGE_UNIFORM);
   1330 
   1331 	retVal.numSamplers						= getNumTypeInstances(shader, glu::STORAGE_UNIFORM, glu::isDataTypeSampler);
   1332 	retVal.numImages						= getNumTypeInstances(shader, glu::STORAGE_UNIFORM, glu::isDataTypeImage);
   1333 
   1334 	retVal.numAtomicCounterBuffers			= getNumAtomicCounterBuffers(shader);
   1335 	retVal.numAtomicCounters				= getNumTypeInstances(shader, glu::STORAGE_UNIFORM, glu::isDataTypeAtomicCounter);
   1336 
   1337 	retVal.numUniformBlocks					= getNumShaderBlocks(shader, glu::STORAGE_UNIFORM);
   1338 	retVal.numShaderStorageBlocks			= getNumShaderBlocks(shader, glu::STORAGE_BUFFER);
   1339 
   1340 	return retVal;
   1341 }
   1342 
   1343 ProgramInterfaceDefinition::ProgramResourceUsage getCombinedProgramResourceUsage (const ProgramInterfaceDefinition::Program* program)
   1344 {
   1345 	ProgramInterfaceDefinition::ProgramResourceUsage retVal;
   1346 
   1347 	retVal.uniformBufferMaxBinding				= -1; // max binding is inclusive upper bound. Allow 0 bindings by using negative value
   1348 	retVal.uniformBufferMaxSize					= 0;
   1349 	retVal.numUniformBlocks						= 0;
   1350 	retVal.numCombinedVertexUniformComponents	= 0;
   1351 	retVal.numCombinedFragmentUniformComponents	= 0;
   1352 	retVal.shaderStorageBufferMaxBinding		= -1; // see above
   1353 	retVal.shaderStorageBufferMaxSize			= 0;
   1354 	retVal.numShaderStorageBlocks				= 0;
   1355 	retVal.numVaryingComponents					= 0;
   1356 	retVal.numVaryingVectors					= 0;
   1357 	retVal.numCombinedSamplers					= 0;
   1358 	retVal.atomicCounterBufferMaxBinding		= -1; // see above
   1359 	retVal.atomicCounterBufferMaxSize			= 0;
   1360 	retVal.numAtomicCounterBuffers				= 0;
   1361 	retVal.numAtomicCounters					= 0;
   1362 	retVal.maxImageBinding						= -1; // see above
   1363 	retVal.numCombinedImages					= 0;
   1364 	retVal.numCombinedOutputResources			= 0;
   1365 	retVal.numXFBInterleavedComponents			= 0;
   1366 	retVal.numXFBSeparateAttribs				= 0;
   1367 	retVal.numXFBSeparateComponents				= 0;
   1368 	retVal.fragmentOutputMaxBinding				= -1; // see above
   1369 
   1370 	for (int shaderNdx = 0; shaderNdx < (int)program->getShaders().size(); ++shaderNdx)
   1371 	{
   1372 		const ProgramInterfaceDefinition::Shader* const shader = program->getShaders()[shaderNdx];
   1373 
   1374 		retVal.uniformBufferMaxBinding		= de::max(retVal.uniformBufferMaxBinding, getMaxBufferBinding(shader, glu::STORAGE_UNIFORM));
   1375 		retVal.uniformBufferMaxSize			= de::max(retVal.uniformBufferMaxSize, getBufferMaxSize(shader, glu::STORAGE_UNIFORM));
   1376 		retVal.numUniformBlocks				+= getNumShaderBlocks(shader, glu::STORAGE_UNIFORM);
   1377 
   1378 		if (shader->getType() == glu::SHADERTYPE_VERTEX)
   1379 			retVal.numCombinedVertexUniformComponents += getNumComponents(shader, glu::STORAGE_UNIFORM);
   1380 
   1381 		if (shader->getType() == glu::SHADERTYPE_FRAGMENT)
   1382 			retVal.numCombinedFragmentUniformComponents += getNumComponents(shader, glu::STORAGE_UNIFORM);
   1383 
   1384 		retVal.shaderStorageBufferMaxBinding	= de::max(retVal.shaderStorageBufferMaxBinding, getMaxBufferBinding(shader, glu::STORAGE_BUFFER));
   1385 		retVal.shaderStorageBufferMaxSize		= de::max(retVal.shaderStorageBufferMaxSize, getBufferMaxSize(shader, glu::STORAGE_BUFFER));
   1386 		retVal.numShaderStorageBlocks			+= getNumShaderBlocks(shader, glu::STORAGE_BUFFER);
   1387 
   1388 		if (shader->getType() == glu::SHADERTYPE_VERTEX)
   1389 		{
   1390 			retVal.numVaryingComponents += getNumComponents(shader, glu::STORAGE_OUT);
   1391 			retVal.numVaryingVectors	+= getNumVectors(shader, glu::STORAGE_OUT);
   1392 		}
   1393 
   1394 		retVal.numCombinedSamplers	+= getNumTypeInstances(shader, glu::STORAGE_UNIFORM, glu::isDataTypeSampler);
   1395 
   1396 		retVal.atomicCounterBufferMaxBinding	= de::max(retVal.atomicCounterBufferMaxBinding, getAtomicCounterMaxBinding(shader));
   1397 		retVal.atomicCounterBufferMaxSize		= de::max(retVal.atomicCounterBufferMaxSize, getAtomicCounterMaxBufferSize(shader));
   1398 		retVal.numAtomicCounterBuffers			+= getNumAtomicCounterBuffers(shader);
   1399 		retVal.numAtomicCounters				+= getNumTypeInstances(shader, glu::STORAGE_UNIFORM, glu::isDataTypeAtomicCounter);
   1400 		retVal.maxImageBinding					= de::max(retVal.maxImageBinding, getUniformMaxBinding(shader, glu::isDataTypeImage));
   1401 		retVal.numCombinedImages				+= getNumTypeInstances(shader, glu::STORAGE_UNIFORM, glu::isDataTypeImage);
   1402 
   1403 		retVal.numCombinedOutputResources		+= getNumTypeInstances(shader, glu::STORAGE_UNIFORM, glu::isDataTypeImage);
   1404 		retVal.numCombinedOutputResources		+= getNumShaderBlocks(shader, glu::STORAGE_BUFFER);
   1405 
   1406 		if (shader->getType() == glu::SHADERTYPE_FRAGMENT)
   1407 		{
   1408 			retVal.numCombinedOutputResources += getNumVectors(shader, glu::STORAGE_OUT);
   1409 			retVal.fragmentOutputMaxBinding = de::max(retVal.fragmentOutputMaxBinding, getFragmentOutputMaxLocation(shader));
   1410 		}
   1411 	}
   1412 
   1413 	if (program->getTransformFeedbackMode() == GL_INTERLEAVED_ATTRIBS)
   1414 		retVal.numXFBInterleavedComponents = getNumXFBComponents(program);
   1415 	else if (program->getTransformFeedbackMode() == GL_SEPARATE_ATTRIBS)
   1416 	{
   1417 		retVal.numXFBSeparateAttribs	= (int)program->getTransformFeedbackVaryings().size();
   1418 		retVal.numXFBSeparateComponents	= getNumMaxXFBOutputComponents(program);
   1419 	}
   1420 
   1421 	return retVal;
   1422 }
   1423 
   1424 } // Functional
   1425 } // gles31
   1426 } // deqp
   1427