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
39namespace deqp
40{
41namespace gles31
42{
43namespace Functional
44{
45namespace ProgramInterfaceDefinition
46{
47
48VariableSearchFilter 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
60static 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
75void 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
118namespace
119{
120
121using ProgramInterfaceDefinition::VariablePathComponent;
122using ProgramInterfaceDefinition::VariableSearchFilter;
123
124static 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
153class StructNameEqualPredicate
154{
155public:
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); }
158private:
159	const char*	m_name;
160};
161
162static 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
193static 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
223static 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
247static 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
289static 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
323static 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
355static 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
389static 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
431static 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
440static 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
498static 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
516static 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
540static 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
560static 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
576template <bool B>
577static bool dummyConstantTypeFilter (glu::DataType d)
578{
579	DE_UNREF(d);
580	return B;
581}
582
583static 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
611static 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
634static 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
659static 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
684static 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
692static 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
704static int getNumComponents (const ProgramInterfaceDefinition::Shader* shader, glu::Storage storage)
705{
706	return getMappedBasicTypeSum(shader, storage, getNumDataTypeComponents);
707}
708
709static int getNumVectors (const ProgramInterfaceDefinition::Shader* shader, glu::Storage storage)
710{
711	return getMappedBasicTypeSum(shader, storage, getNumDataTypeVectors);
712}
713
714static 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
725static 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
746static 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
763static 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
786static 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
796static 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
807static 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
823static 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
833static 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
861static 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
876static 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
886static 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
896static 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
927std::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
944std::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
1141glu::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
1303bool 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
1315ProgramInterfaceDefinition::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
1343ProgramInterfaceDefinition::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