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 (void)
49	: m_shaderTypeBits	(0xFFFFFFFFul)
50	, m_storageBits		(0xFFFFFFFFul)
51{
52}
53
54VariableSearchFilter VariableSearchFilter::createShaderTypeFilter (glu::ShaderType type)
55{
56	DE_ASSERT(type < glu::SHADERTYPE_LAST);
57
58	VariableSearchFilter filter;
59	filter.m_shaderTypeBits = (1u << type);
60	return filter;
61}
62
63VariableSearchFilter VariableSearchFilter::createStorageFilter (glu::Storage storage)
64{
65	DE_ASSERT(storage < glu::STORAGE_LAST);
66
67	VariableSearchFilter filter;
68	filter.m_storageBits = (1u << storage);
69	return filter;
70}
71
72VariableSearchFilter VariableSearchFilter::createShaderTypeStorageFilter (glu::ShaderType type, glu::Storage storage)
73{
74	return logicalAnd(createShaderTypeFilter(type), createStorageFilter(storage));
75}
76
77VariableSearchFilter VariableSearchFilter::logicalOr (const VariableSearchFilter& a, const VariableSearchFilter& b)
78{
79	VariableSearchFilter filter;
80	filter.m_shaderTypeBits	= a.m_shaderTypeBits | b.m_shaderTypeBits;
81	filter.m_storageBits	= a.m_storageBits | b.m_storageBits;
82	return filter;
83}
84
85VariableSearchFilter VariableSearchFilter::logicalAnd (const VariableSearchFilter& a, const VariableSearchFilter& b)
86{
87	VariableSearchFilter filter;
88	filter.m_shaderTypeBits	= a.m_shaderTypeBits & b.m_shaderTypeBits;
89	filter.m_storageBits	= a.m_storageBits & b.m_storageBits;
90	return filter;
91}
92
93bool VariableSearchFilter::matchesFilter (const ProgramInterfaceDefinition::Shader* shader) const
94{
95	DE_ASSERT(shader->getType() < glu::SHADERTYPE_LAST);
96	return (m_shaderTypeBits & (1u << shader->getType())) != 0;
97}
98
99bool VariableSearchFilter::matchesFilter (const glu::VariableDeclaration& variable) const
100{
101	DE_ASSERT(variable.storage < glu::STORAGE_LAST);
102	return (m_storageBits & (1u << variable.storage)) != 0;
103}
104
105bool VariableSearchFilter::matchesFilter (const glu::InterfaceBlock& block) const
106{
107	DE_ASSERT(block.storage < glu::STORAGE_LAST);
108	return (m_storageBits & (1u << block.storage)) != 0;
109}
110
111} // ProgramInterfaceDefinition
112
113static bool incrementMultiDimensionIndex (std::vector<int>& index, const std::vector<int>& dimensions)
114{
115	int incrementDimensionNdx = (int)(index.size() - 1);
116
117	while (incrementDimensionNdx >= 0)
118	{
119		if (++index[incrementDimensionNdx] == dimensions[incrementDimensionNdx])
120			index[incrementDimensionNdx--] = 0;
121		else
122			break;
123	}
124
125	return (incrementDimensionNdx != -1);
126}
127
128bool programContainsIOBlocks (const ProgramInterfaceDefinition::Program* program)
129{
130	for (int shaderNdx = 0; shaderNdx < (int)program->getShaders().size(); ++shaderNdx)
131	{
132		if (shaderContainsIOBlocks(program->getShaders()[shaderNdx]))
133			return true;
134	}
135
136	return false;
137}
138
139bool shaderContainsIOBlocks (const ProgramInterfaceDefinition::Shader* shader)
140{
141	for (int ndx = 0; ndx < (int)shader->getDefaultBlock().interfaceBlocks.size(); ++ndx)
142	{
143		const glu::Storage storage = shader->getDefaultBlock().interfaceBlocks[ndx].storage;
144		if (storage == glu::STORAGE_IN			||
145			storage == glu::STORAGE_OUT			||
146			storage == glu::STORAGE_PATCH_IN	||
147			storage == glu::STORAGE_PATCH_OUT)
148		{
149			return true;
150		}
151	}
152	return false;
153}
154
155glu::ShaderType getProgramTransformFeedbackStage (const ProgramInterfaceDefinition::Program* program)
156{
157	if (program->hasStage(glu::SHADERTYPE_GEOMETRY))
158		return glu::SHADERTYPE_GEOMETRY;
159
160	if (program->hasStage(glu::SHADERTYPE_TESSELLATION_EVALUATION))
161		return glu::SHADERTYPE_TESSELLATION_EVALUATION;
162
163	if (program->hasStage(glu::SHADERTYPE_VERTEX))
164		return glu::SHADERTYPE_VERTEX;
165
166	DE_ASSERT(false);
167	return glu::SHADERTYPE_LAST;
168}
169
170void generateVariableTypeResourceNames (std::vector<std::string>& resources, const std::string& name, const glu::VarType& type, deUint32 resourceNameGenerationFlags)
171{
172	DE_ASSERT((resourceNameGenerationFlags & (~RESOURCE_NAME_GENERATION_FLAG_MASK)) == 0);
173
174	// remove top-level flag from children
175	const deUint32 childFlags = resourceNameGenerationFlags & ~((deUint32)RESOURCE_NAME_GENERATION_FLAG_TOP_LEVEL_BUFFER_VARIABLE);
176
177	if (type.isBasicType())
178		resources.push_back(name);
179	else if (type.isStructType())
180	{
181		const glu::StructType* structType = type.getStructPtr();
182		for (int ndx = 0; ndx < structType->getNumMembers(); ++ndx)
183			generateVariableTypeResourceNames(resources, name + "." + structType->getMember(ndx).getName(), structType->getMember(ndx).getType(), childFlags);
184	}
185	else if (type.isArrayType())
186	{
187		// Bottom-level arrays of basic types of a transform feedback variable will produce only the first
188		// element but without the trailing "[0]"
189		if (type.getElementType().isBasicType() &&
190			(resourceNameGenerationFlags & RESOURCE_NAME_GENERATION_FLAG_TRANSFORM_FEEDBACK_VARIABLE) != 0)
191		{
192			resources.push_back(name);
193		}
194		// Bottom-level arrays of basic types and SSBO top-level arrays of any type procude only first element
195		else if (type.getElementType().isBasicType() ||
196				 (resourceNameGenerationFlags & RESOURCE_NAME_GENERATION_FLAG_TOP_LEVEL_BUFFER_VARIABLE) != 0)
197		{
198			generateVariableTypeResourceNames(resources, name + "[0]", type.getElementType(), childFlags);
199		}
200		// Other arrays of aggregate types are expanded
201		else
202		{
203			for (int ndx = 0; ndx < type.getArraySize(); ++ndx)
204				generateVariableTypeResourceNames(resources, name + "[" + de::toString(ndx) + "]", type.getElementType(), childFlags);
205		}
206	}
207	else
208		DE_ASSERT(false);
209}
210
211// Program source generation
212
213namespace
214{
215
216using ProgramInterfaceDefinition::VariablePathComponent;
217using ProgramInterfaceDefinition::VariableSearchFilter;
218
219static std::string getShaderExtensionDeclarations (const ProgramInterfaceDefinition::Shader* shader)
220{
221	if (shader->getVersion() > glu::GLSL_VERSION_440)
222		return "";
223
224	std::vector<std::string>	extensions;
225	std::ostringstream			buf;
226
227	if (shader->getType() == glu::SHADERTYPE_GEOMETRY)
228	{
229		extensions.push_back("GL_EXT_geometry_shader");
230	}
231	else if (shader->getType() == glu::SHADERTYPE_TESSELLATION_CONTROL ||
232			 shader->getType() == glu::SHADERTYPE_TESSELLATION_EVALUATION)
233	{
234		extensions.push_back("GL_EXT_tessellation_shader");
235	}
236
237	if (shaderContainsIOBlocks(shader))
238		extensions.push_back("GL_EXT_shader_io_blocks");
239
240	for (int ndx = 0; ndx < (int)extensions.size(); ++ndx)
241		buf << "#extension " << extensions[ndx] << " : require\n";
242	return buf.str();
243}
244
245static std::string getShaderTypeDeclarations (const ProgramInterfaceDefinition::Program* program, const ProgramInterfaceDefinition::Shader* shader)
246{
247	glu::ShaderType type = shader->getType();
248	auto isCoreGL = (shader->getVersion() > glu::GLSL_VERSION_440);
249
250	switch (type)
251	{
252		case glu::SHADERTYPE_VERTEX:
253			if (isCoreGL)
254				return "out gl_PerVertex { vec4 gl_Position; };\n";
255			return "";
256
257		case glu::SHADERTYPE_FRAGMENT:
258			return "";
259
260		case glu::SHADERTYPE_GEOMETRY:
261		{
262			std::ostringstream buf;
263			buf <<	"layout(points) in;\n"
264					"layout(points, max_vertices=" << program->getGeometryNumOutputVertices() << ") out;\n";
265			if (isCoreGL)
266			{
267				buf << "in gl_PerVertex { vec4 gl_Position; } gl_in[];\n"
268					   "out gl_PerVertex { vec4 gl_Position; };\n";
269			}
270			return buf.str();
271		}
272
273		case glu::SHADERTYPE_TESSELLATION_CONTROL:
274		{
275			std::ostringstream buf;
276			buf << "layout(vertices=" << program->getTessellationNumOutputPatchVertices() << ") out;\n";
277			if (isCoreGL)
278			{
279				buf << "in gl_PerVertex { vec4 gl_Position; } gl_in[];\n"
280					   "out gl_PerVertex { vec4 gl_Position; } gl_out[];\n";
281			}
282			return buf.str();
283		}
284
285		case glu::SHADERTYPE_TESSELLATION_EVALUATION:
286		{
287			std::ostringstream buf;
288			if (isCoreGL)
289			{
290				buf << "in gl_PerVertex { vec4 gl_Position; } gl_in[];\n"
291					   "out gl_PerVertex { vec4 gl_Position; };\n";
292			}
293			buf << "layout(triangles, point_mode) in;\n";
294			return buf.str();
295		}
296
297		case glu::SHADERTYPE_COMPUTE:
298			return "layout(local_size_x=1) in;\n";
299
300		default:
301			DE_ASSERT(false);
302			return "";
303	}
304}
305
306class StructNameEqualPredicate
307{
308public:
309				StructNameEqualPredicate	(const char* name) : m_name(name) { }
310	bool		operator()					(const glu::StructType* type) { return type->hasTypeName() && (deStringEqual(m_name, type->getTypeName()) == DE_TRUE); }
311private:
312	const char*	m_name;
313};
314
315static void collectNamedStructureDefinitions (std::vector<const glu::StructType*>& dst, const glu::VarType& type)
316{
317	if (type.isBasicType())
318		return;
319	else if (type.isArrayType())
320		return collectNamedStructureDefinitions(dst, type.getElementType());
321	else if (type.isStructType())
322	{
323		if (type.getStructPtr()->hasTypeName())
324		{
325			// must be unique (may share the the same struct)
326			std::vector<const glu::StructType*>::iterator where = std::find_if(dst.begin(), dst.end(), StructNameEqualPredicate(type.getStructPtr()->getTypeName()));
327			if (where != dst.end())
328			{
329				DE_ASSERT(**where == *type.getStructPtr());
330
331				// identical type has been added already, types of members must be added too
332				return;
333			}
334		}
335
336		// Add types of members first
337		for (int ndx = 0; ndx < type.getStructPtr()->getNumMembers(); ++ndx)
338			collectNamedStructureDefinitions(dst, type.getStructPtr()->getMember(ndx).getType());
339
340		dst.push_back(type.getStructPtr());
341	}
342	else
343		DE_ASSERT(false);
344}
345
346static void writeStructureDefinitions (std::ostringstream& buf, const ProgramInterfaceDefinition::DefaultBlock& defaultBlock)
347{
348	std::vector<const glu::StructType*> namedStructs;
349
350	// Collect all structs in post order
351
352	for (int ndx = 0; ndx < (int)defaultBlock.variables.size(); ++ndx)
353		collectNamedStructureDefinitions(namedStructs, defaultBlock.variables[ndx].varType);
354
355	for (int blockNdx = 0; blockNdx < (int)defaultBlock.interfaceBlocks.size(); ++blockNdx)
356		for (int ndx = 0; ndx < (int)defaultBlock.interfaceBlocks[blockNdx].variables.size(); ++ndx)
357			collectNamedStructureDefinitions(namedStructs, defaultBlock.interfaceBlocks[blockNdx].variables[ndx].varType);
358
359	// Write
360
361	for (int structNdx = 0; structNdx < (int)namedStructs.size(); ++structNdx)
362	{
363		buf <<	"struct " << namedStructs[structNdx]->getTypeName() << "\n"
364				"{\n";
365
366		for (int memberNdx = 0; memberNdx < namedStructs[structNdx]->getNumMembers(); ++memberNdx)
367			buf << glu::indent(1) << glu::declare(namedStructs[structNdx]->getMember(memberNdx).getType(), namedStructs[structNdx]->getMember(memberNdx).getName(), 1) << ";\n";
368
369		buf <<	"};\n";
370	}
371
372	if (!namedStructs.empty())
373		buf << "\n";
374}
375
376static void writeInterfaceBlock (std::ostringstream& buf, const glu::InterfaceBlock& interfaceBlock)
377{
378	buf << interfaceBlock.layout;
379
380	if (interfaceBlock.layout != glu::Layout())
381		buf << " ";
382
383	buf	<< glu::getStorageName(interfaceBlock.storage) << " " << interfaceBlock.interfaceName << "\n"
384		<< "{\n";
385
386	for (int ndx = 0; ndx < (int)interfaceBlock.variables.size(); ++ndx)
387		buf << glu::indent(1) << interfaceBlock.variables[ndx] << ";\n";
388
389	buf << "}";
390
391	if (!interfaceBlock.instanceName.empty())
392		buf << " " << interfaceBlock.instanceName;
393
394	for (int dimensionNdx = 0; dimensionNdx < (int)interfaceBlock.dimensions.size(); ++dimensionNdx)
395		buf << "[" << interfaceBlock.dimensions[dimensionNdx] << "]";
396
397	buf << ";\n\n";
398}
399
400static bool isReadableInterface (const glu::InterfaceBlock& interface)
401{
402	return	interface.storage == glu::STORAGE_UNIFORM	||
403			interface.storage == glu::STORAGE_IN		||
404			interface.storage == glu::STORAGE_PATCH_IN	||
405			(interface.storage == glu::STORAGE_BUFFER && (interface.memoryAccessQualifierFlags & glu::MEMORYACCESSQUALIFIER_WRITEONLY_BIT) == 0);
406}
407
408static bool isWritableInterface (const glu::InterfaceBlock& interface)
409{
410	return	interface.storage == glu::STORAGE_OUT		||
411			interface.storage == glu::STORAGE_PATCH_OUT	||
412			(interface.storage == glu::STORAGE_BUFFER && (interface.memoryAccessQualifierFlags & glu::MEMORYACCESSQUALIFIER_READONLY_BIT) == 0);
413}
414
415
416static void writeVariableReadAccumulateExpression (std::ostringstream&							buf,
417												   const std::string&							accumulatorName,
418												   const std::string&							name,
419												   glu::ShaderType								shaderType,
420												   glu::Storage									storage,
421												   const ProgramInterfaceDefinition::Program*	program,
422												   const glu::VarType&							varType)
423{
424	if (varType.isBasicType())
425	{
426		buf << "\t" << accumulatorName << " += ";
427
428		if (glu::isDataTypeScalar(varType.getBasicType()))
429			buf << "vec4(float(" << name << "))";
430		else if (glu::isDataTypeVector(varType.getBasicType()))
431			buf << "vec4(" << name << ".xyxy)";
432		else if (glu::isDataTypeMatrix(varType.getBasicType()))
433			buf << "vec4(float(" << name << "[0][0]))";
434		else if (glu::isDataTypeSamplerMultisample(varType.getBasicType()))
435			buf << "vec4(float(textureSize(" << name << ").x))";
436		else if (glu::isDataTypeSampler(varType.getBasicType()))
437			buf << "vec4(float(textureSize(" << name << ", 0).x))";
438		else if (glu::isDataTypeImage(varType.getBasicType()))
439			buf << "vec4(float(imageSize(" << name << ").x))";
440		else if (varType.getBasicType() == glu::TYPE_UINT_ATOMIC_COUNTER)
441			buf << "vec4(float(atomicCounterIncrement(" << name << ")))";
442		else
443			DE_ASSERT(false);
444
445		buf << ";\n";
446	}
447	else if (varType.isStructType())
448	{
449		for (int ndx = 0; ndx < varType.getStructPtr()->getNumMembers(); ++ndx)
450			writeVariableReadAccumulateExpression(buf,
451												  accumulatorName,
452												  name + "." + varType.getStructPtr()->getMember(ndx).getName(),
453												  shaderType,
454												  storage,
455												  program,
456												  varType.getStructPtr()->getMember(ndx).getType());
457	}
458	else if (varType.isArrayType())
459	{
460		if (varType.getArraySize() != glu::VarType::UNSIZED_ARRAY)
461		{
462			for (int ndx = 0; ndx < varType.getArraySize(); ++ndx)
463				writeVariableReadAccumulateExpression(buf,
464													  accumulatorName,
465													  name + "[" + de::toString(ndx) + "]",
466													  shaderType,
467													  storage,
468													  program,
469													  varType.getElementType());
470		}
471		else if (storage == glu::STORAGE_BUFFER)
472		{
473			// run-time sized array, read arbitrary
474			writeVariableReadAccumulateExpression(buf,
475												  accumulatorName,
476												  name + "[8]",
477												  shaderType,
478												  storage,
479												  program,
480												  varType.getElementType());
481		}
482		else
483		{
484			DE_ASSERT(storage == glu::STORAGE_IN);
485
486			if (shaderType == glu::SHADERTYPE_GEOMETRY)
487			{
488				// implicit sized geometry input array, size = primitive size. Just reading first is enough
489				writeVariableReadAccumulateExpression(buf,
490													  accumulatorName,
491													  name + "[0]",
492													  shaderType,
493													  storage,
494													  program,
495													  varType.getElementType());
496			}
497			else if (shaderType == glu::SHADERTYPE_TESSELLATION_CONTROL)
498			{
499				// implicit sized tessellation input array, size = input patch max size. Just reading current is enough
500				writeVariableReadAccumulateExpression(buf,
501													  accumulatorName,
502													  name + "[gl_InvocationID]",
503													  shaderType,
504													  storage,
505													  program,
506													  varType.getElementType());
507			}
508			else if (shaderType == glu::SHADERTYPE_TESSELLATION_EVALUATION)
509			{
510				// implicit sized tessellation input array, size = output patch max size. Read all to prevent optimizations
511				DE_ASSERT(program->getTessellationNumOutputPatchVertices() > 0);
512				for (int ndx = 0; ndx < (int)program->getTessellationNumOutputPatchVertices(); ++ndx)
513				{
514					writeVariableReadAccumulateExpression(buf,
515														  accumulatorName,
516														  name + "[" + de::toString(ndx) + "]",
517														  shaderType,
518														  storage,
519														  program,
520														  varType.getElementType());
521				}
522			}
523			else
524				DE_ASSERT(false);
525		}
526	}
527	else
528		DE_ASSERT(false);
529}
530
531static void writeInterfaceReadAccumulateExpression (std::ostringstream&							buf,
532													const std::string&							accumulatorName,
533													const glu::InterfaceBlock&					block,
534													glu::ShaderType								shaderType,
535													const ProgramInterfaceDefinition::Program*	program)
536{
537	if (block.dimensions.empty())
538	{
539		const std::string prefix = (block.instanceName.empty()) ? ("") : (block.instanceName + ".");
540
541		for (int ndx = 0; ndx < (int)block.variables.size(); ++ndx)
542		{
543			writeVariableReadAccumulateExpression(buf,
544												  accumulatorName,
545												  prefix + block.variables[ndx].name,
546												  shaderType,
547												  block.storage,
548												  program,
549												  block.variables[ndx].varType);
550		}
551	}
552	else
553	{
554		std::vector<int> index(block.dimensions.size(), 0);
555
556		for (;;)
557		{
558			// access element
559			{
560				std::ostringstream name;
561				name << block.instanceName;
562
563				for (int dimensionNdx = 0; dimensionNdx < (int)block.dimensions.size(); ++dimensionNdx)
564					name << "[" << index[dimensionNdx] << "]";
565
566				for (int ndx = 0; ndx < (int)block.variables.size(); ++ndx)
567				{
568					writeVariableReadAccumulateExpression(buf,
569														  accumulatorName,
570														  name.str() + "." + block.variables[ndx].name,
571														  shaderType,
572														  block.storage,
573														  program,
574														  block.variables[ndx].varType);
575				}
576			}
577
578			// increment index
579			if (!incrementMultiDimensionIndex(index, block.dimensions))
580				break;
581		}
582	}
583}
584
585static void writeVariableWriteExpression (std::ostringstream&							buf,
586										  const std::string&							sourceVec4Name,
587										  const std::string&							name,
588										  glu::ShaderType								shaderType,
589										  glu::Storage									storage,
590										  const ProgramInterfaceDefinition::Program*	program,
591										  const glu::VarType&							varType)
592{
593	if (varType.isBasicType())
594	{
595		buf << "\t" << name << " = ";
596
597		if (glu::isDataTypeScalar(varType.getBasicType()))
598			buf << glu::getDataTypeName(varType.getBasicType()) << "(" << sourceVec4Name << ".y)";
599		else if (glu::isDataTypeVector(varType.getBasicType()) || glu::isDataTypeMatrix(varType.getBasicType()))
600			buf << glu::getDataTypeName(varType.getBasicType()) << "(" << glu::getDataTypeName(glu::getDataTypeScalarType(varType.getBasicType())) << "(" << sourceVec4Name << ".y))";
601		else
602			DE_ASSERT(false);
603
604		buf << ";\n";
605	}
606	else if (varType.isStructType())
607	{
608		for (int ndx = 0; ndx < varType.getStructPtr()->getNumMembers(); ++ndx)
609			writeVariableWriteExpression(buf,
610										 sourceVec4Name,
611										 name + "." + varType.getStructPtr()->getMember(ndx).getName(),
612										 shaderType,
613										 storage,
614										 program,
615										 varType.getStructPtr()->getMember(ndx).getType());
616	}
617	else if (varType.isArrayType())
618	{
619		if (varType.getArraySize() != glu::VarType::UNSIZED_ARRAY)
620		{
621			for (int ndx = 0; ndx < varType.getArraySize(); ++ndx)
622				writeVariableWriteExpression(buf,
623											 sourceVec4Name,
624											 name + "[" + de::toString(ndx) + "]",
625											 shaderType,
626											 storage,
627											 program,
628											 varType.getElementType());
629		}
630		else if (storage == glu::STORAGE_BUFFER)
631		{
632			// run-time sized array, write arbitrary
633			writeVariableWriteExpression(buf,
634										 sourceVec4Name,
635										 name + "[9]",
636										 shaderType,
637										 storage,
638										 program,
639										 varType.getElementType());
640		}
641		else
642		{
643			DE_ASSERT(storage == glu::STORAGE_OUT);
644
645			if (shaderType == glu::SHADERTYPE_TESSELLATION_CONTROL)
646			{
647				// implicit sized tessellation onput array, size = output patch max size. Can only write to gl_InvocationID
648				writeVariableWriteExpression(buf,
649											 sourceVec4Name,
650											 name + "[gl_InvocationID]",
651											 shaderType,
652											 storage,
653											 program,
654											 varType.getElementType());
655			}
656			else
657				DE_ASSERT(false);
658		}
659	}
660	else
661		DE_ASSERT(false);
662}
663
664static void writeInterfaceWriteExpression (std::ostringstream&							buf,
665										   const std::string&							sourceVec4Name,
666										   const glu::InterfaceBlock&					block,
667										   glu::ShaderType								shaderType,
668										   const ProgramInterfaceDefinition::Program*	program)
669{
670	if (block.dimensions.empty())
671	{
672		const std::string prefix = (block.instanceName.empty()) ? ("") : (block.instanceName + ".");
673
674		for (int ndx = 0; ndx < (int)block.variables.size(); ++ndx)
675		{
676			writeVariableWriteExpression(buf,
677										 sourceVec4Name,
678										 prefix + block.variables[ndx].name,
679										 shaderType,
680										 block.storage,
681										 program,
682										 block.variables[ndx].varType);
683		}
684	}
685	else
686	{
687		std::vector<int> index(block.dimensions.size(), 0);
688
689		for (;;)
690		{
691			// access element
692			{
693				std::ostringstream name;
694				name << block.instanceName;
695
696				for (int dimensionNdx = 0; dimensionNdx < (int)block.dimensions.size(); ++dimensionNdx)
697					name << "[" << index[dimensionNdx] << "]";
698
699				for (int ndx = 0; ndx < (int)block.variables.size(); ++ndx)
700				{
701					writeVariableWriteExpression(buf,
702												 sourceVec4Name,
703												 name.str() + "." + block.variables[ndx].name,
704												 shaderType,
705												 block.storage,
706												 program,
707												 block.variables[ndx].varType);
708				}
709			}
710
711			// increment index
712			if (!incrementMultiDimensionIndex(index, block.dimensions))
713				break;
714		}
715	}
716}
717
718static bool traverseVariablePath (std::vector<VariablePathComponent>& typePath, const char* subPath, const glu::VarType& type)
719{
720	glu::VarTokenizer tokenizer(subPath);
721
722	typePath.push_back(VariablePathComponent(&type));
723
724	if (tokenizer.getToken() == glu::VarTokenizer::TOKEN_END)
725		return true;
726
727	if (type.isStructType() && tokenizer.getToken() == glu::VarTokenizer::TOKEN_PERIOD)
728	{
729		tokenizer.advance();
730
731		// malformed path
732		if (tokenizer.getToken() != glu::VarTokenizer::TOKEN_IDENTIFIER)
733			return false;
734
735		for (int memberNdx = 0; memberNdx < type.getStructPtr()->getNumMembers(); ++memberNdx)
736			if (type.getStructPtr()->getMember(memberNdx).getName() == tokenizer.getIdentifier())
737				return traverseVariablePath(typePath, subPath + tokenizer.getCurrentTokenEndLocation(), type.getStructPtr()->getMember(memberNdx).getType());
738
739		// malformed path, no such member
740		return false;
741	}
742	else if (type.isArrayType() && tokenizer.getToken() == glu::VarTokenizer::TOKEN_LEFT_BRACKET)
743	{
744		tokenizer.advance();
745
746		// malformed path
747		if (tokenizer.getToken() != glu::VarTokenizer::TOKEN_NUMBER)
748			return false;
749
750		tokenizer.advance();
751		if (tokenizer.getToken() != glu::VarTokenizer::TOKEN_RIGHT_BRACKET)
752			return false;
753
754		return traverseVariablePath(typePath, subPath + tokenizer.getCurrentTokenEndLocation(), type.getElementType());
755	}
756
757	return false;
758}
759
760static bool traverseVariablePath (std::vector<VariablePathComponent>& typePath, const std::string& path, const glu::VariableDeclaration& var)
761{
762	if (glu::parseVariableName(path.c_str()) != var.name)
763		return false;
764
765	typePath.push_back(VariablePathComponent(&var));
766	return traverseVariablePath(typePath, path.c_str() + var.name.length(), var.varType);
767}
768
769static bool traverseShaderVariablePath (std::vector<VariablePathComponent>& typePath, const ProgramInterfaceDefinition::Shader* shader, const std::string& path, const VariableSearchFilter& filter)
770{
771	// Default block variable?
772	for (int varNdx = 0; varNdx < (int)shader->getDefaultBlock().variables.size(); ++varNdx)
773		if (filter.matchesFilter(shader->getDefaultBlock().variables[varNdx]))
774			if (traverseVariablePath(typePath, path, shader->getDefaultBlock().variables[varNdx]))
775				return true;
776
777	// is variable an interface block variable?
778	{
779		const std::string blockName = glu::parseVariableName(path.c_str());
780
781		for (int interfaceNdx = 0; interfaceNdx < (int)shader->getDefaultBlock().interfaceBlocks.size(); ++interfaceNdx)
782		{
783			if (!filter.matchesFilter(shader->getDefaultBlock().interfaceBlocks[interfaceNdx]))
784				continue;
785
786			if (shader->getDefaultBlock().interfaceBlocks[interfaceNdx].interfaceName == blockName)
787			{
788				// resource is a member of a named interface block
789				// \note there is no array index specifier even if the interface is declared as an array of instances
790				const std::string blockMemberPath = path.substr(blockName.size() + 1);
791				const std::string blockMemeberName = glu::parseVariableName(blockMemberPath.c_str());
792
793				for (int varNdx = 0; varNdx < (int)shader->getDefaultBlock().interfaceBlocks[interfaceNdx].variables.size(); ++varNdx)
794				{
795					if (shader->getDefaultBlock().interfaceBlocks[interfaceNdx].variables[varNdx].name == blockMemeberName)
796					{
797						typePath.push_back(VariablePathComponent(&shader->getDefaultBlock().interfaceBlocks[interfaceNdx]));
798						return traverseVariablePath(typePath, blockMemberPath, shader->getDefaultBlock().interfaceBlocks[interfaceNdx].variables[varNdx]);
799					}
800				}
801
802				// terminate search
803				return false;
804			}
805			else if (shader->getDefaultBlock().interfaceBlocks[interfaceNdx].instanceName.empty())
806			{
807				const std::string blockMemeberName = glu::parseVariableName(path.c_str());
808
809				// unnamed block contains such variable?
810				for (int varNdx = 0; varNdx < (int)shader->getDefaultBlock().interfaceBlocks[interfaceNdx].variables.size(); ++varNdx)
811				{
812					if (shader->getDefaultBlock().interfaceBlocks[interfaceNdx].variables[varNdx].name == blockMemeberName)
813					{
814						typePath.push_back(VariablePathComponent(&shader->getDefaultBlock().interfaceBlocks[interfaceNdx]));
815						return traverseVariablePath(typePath, path, shader->getDefaultBlock().interfaceBlocks[interfaceNdx].variables[varNdx]);
816					}
817				}
818
819				// continue search
820			}
821		}
822	}
823
824	return false;
825}
826
827static bool traverseProgramVariablePath (std::vector<VariablePathComponent>& typePath, const ProgramInterfaceDefinition::Program* program, const std::string& path, const VariableSearchFilter& filter)
828{
829	for (int shaderNdx = 0; shaderNdx < (int)program->getShaders().size(); ++shaderNdx)
830	{
831		const ProgramInterfaceDefinition::Shader* shader = program->getShaders()[shaderNdx];
832
833		if (filter.matchesFilter(shader))
834		{
835			// \note modifying output variable even when returning false
836			typePath.clear();
837			if (traverseShaderVariablePath(typePath, shader, path, filter))
838				return true;
839		}
840	}
841
842	return false;
843}
844
845static bool containsSubType (const glu::VarType& complexType, glu::DataType basicType)
846{
847	if (complexType.isBasicType())
848	{
849		return complexType.getBasicType() == basicType;
850	}
851	else if (complexType.isArrayType())
852	{
853		return containsSubType(complexType.getElementType(), basicType);
854	}
855	else if (complexType.isStructType())
856	{
857		for (int ndx = 0; ndx < complexType.getStructPtr()->getNumMembers(); ++ndx)
858			if (containsSubType(complexType.getStructPtr()->getMember(ndx).getType(), basicType))
859				return true;
860		return false;
861	}
862	else
863	{
864		DE_ASSERT(false);
865		return false;
866	}
867}
868
869static int getNumShaderBlocks (const ProgramInterfaceDefinition::Shader* shader, glu::Storage storage)
870{
871	int retVal = 0;
872
873	for (int ndx = 0; ndx < (int)shader->getDefaultBlock().interfaceBlocks.size(); ++ndx)
874	{
875		if (shader->getDefaultBlock().interfaceBlocks[ndx].storage == storage)
876		{
877			int numInstances = 1;
878
879			for (int dimensionNdx = 0; dimensionNdx < (int)shader->getDefaultBlock().interfaceBlocks[ndx].dimensions.size(); ++dimensionNdx)
880				numInstances *= shader->getDefaultBlock().interfaceBlocks[ndx].dimensions[dimensionNdx];
881
882			retVal += numInstances;
883		}
884	}
885
886	return retVal;
887}
888
889static int getNumAtomicCounterBuffers (const ProgramInterfaceDefinition::Shader* shader)
890{
891	std::set<int> buffers;
892
893	for (int ndx = 0; ndx < (int)shader->getDefaultBlock().variables.size(); ++ndx)
894	{
895		if (containsSubType(shader->getDefaultBlock().variables[ndx].varType, glu::TYPE_UINT_ATOMIC_COUNTER))
896		{
897			DE_ASSERT(shader->getDefaultBlock().variables[ndx].layout.binding != -1);
898			buffers.insert(shader->getDefaultBlock().variables[ndx].layout.binding);
899		}
900	}
901
902	return (int)buffers.size();
903}
904
905template <typename DataTypeMap>
906static int accumulateComplexType (const glu::VarType& complexType, const DataTypeMap& dTypeMap)
907{
908	if (complexType.isBasicType())
909		return dTypeMap(complexType.getBasicType());
910	else if (complexType.isArrayType())
911	{
912		const int arraySize = (complexType.getArraySize() == glu::VarType::UNSIZED_ARRAY) ? (1) : (complexType.getArraySize());
913		return arraySize * accumulateComplexType(complexType.getElementType(), dTypeMap);
914	}
915	else if (complexType.isStructType())
916	{
917		int sum = 0;
918		for (int ndx = 0; ndx < complexType.getStructPtr()->getNumMembers(); ++ndx)
919			sum += accumulateComplexType(complexType.getStructPtr()->getMember(ndx).getType(), dTypeMap);
920		return sum;
921	}
922	else
923	{
924		DE_ASSERT(false);
925		return false;
926	}
927}
928
929template <typename InterfaceBlockFilter, typename VarDeclFilter, typename DataTypeMap>
930static int accumulateShader (const ProgramInterfaceDefinition::Shader* shader,
931							 const InterfaceBlockFilter& ibFilter,
932							 const VarDeclFilter& vdFilter,
933							 const DataTypeMap& dMap)
934{
935	int retVal = 0;
936
937	for (int ndx = 0; ndx < (int)shader->getDefaultBlock().interfaceBlocks.size(); ++ndx)
938	{
939		if (ibFilter(shader->getDefaultBlock().interfaceBlocks[ndx]))
940		{
941			int numInstances = 1;
942
943			for (int dimensionNdx = 0; dimensionNdx < (int)shader->getDefaultBlock().interfaceBlocks[ndx].dimensions.size(); ++dimensionNdx)
944				numInstances *= shader->getDefaultBlock().interfaceBlocks[ndx].dimensions[dimensionNdx];
945
946			for (int varNdx = 0; varNdx < (int)shader->getDefaultBlock().interfaceBlocks[ndx].variables.size(); ++varNdx)
947				retVal += numInstances * accumulateComplexType(shader->getDefaultBlock().interfaceBlocks[ndx].variables[varNdx].varType, dMap);
948		}
949	}
950
951	for (int varNdx = 0; varNdx < (int)shader->getDefaultBlock().variables.size(); ++varNdx)
952		if (vdFilter(shader->getDefaultBlock().variables[varNdx]))
953			retVal += accumulateComplexType(shader->getDefaultBlock().variables[varNdx].varType, dMap);
954
955	return retVal;
956}
957
958static bool unusedTrueConstantTypeFilter (glu::DataType d)
959{
960	DE_UNREF(d);
961	return true;
962}
963
964class InstanceCounter
965{
966public:
967	InstanceCounter (bool (*predicate)(glu::DataType))
968		: m_predicate(predicate)
969	{
970	}
971
972	int operator() (glu::DataType t) const
973	{
974		return (m_predicate(t)) ? (1) : (0);
975	}
976
977private:
978	bool (*const m_predicate)(glu::DataType);
979};
980
981class InterfaceBlockStorageFilter
982{
983public:
984	InterfaceBlockStorageFilter (glu::Storage storage)
985		: m_storage(storage)
986	{
987	}
988
989	bool operator() (const glu::InterfaceBlock& b) const
990	{
991		return m_storage == b.storage;
992	}
993
994private:
995	const glu::Storage m_storage;
996};
997
998class VariableDeclarationStorageFilter
999{
1000public:
1001	VariableDeclarationStorageFilter (glu::Storage storage)
1002		: m_storage(storage)
1003	{
1004	}
1005
1006	bool operator() (const glu::VariableDeclaration& d) const
1007	{
1008		return m_storage == d.storage;
1009	}
1010
1011private:
1012	const glu::Storage m_storage;
1013};
1014
1015static int getNumTypeInstances (const glu::VarType& complexType, bool (*predicate)(glu::DataType))
1016{
1017	return accumulateComplexType(complexType, InstanceCounter(predicate));
1018}
1019
1020static int getNumTypeInstances (const ProgramInterfaceDefinition::Shader* shader, glu::Storage storage, bool (*predicate)(glu::DataType))
1021{
1022	return accumulateShader(shader, InterfaceBlockStorageFilter(storage), VariableDeclarationStorageFilter(storage), InstanceCounter(predicate));
1023}
1024
1025static int getNumTypeInstances (const ProgramInterfaceDefinition::Shader* shader, glu::Storage storage)
1026{
1027	return getNumTypeInstances(shader, storage, unusedTrueConstantTypeFilter);
1028}
1029
1030static int accumulateShaderStorage (const ProgramInterfaceDefinition::Shader* shader, glu::Storage storage, int (*typeMap)(glu::DataType))
1031{
1032	return accumulateShader(shader, InterfaceBlockStorageFilter(storage), VariableDeclarationStorageFilter(storage), typeMap);
1033}
1034
1035static int getNumDataTypeComponents (glu::DataType type)
1036{
1037	if (glu::isDataTypeScalarOrVector(type) || glu::isDataTypeMatrix(type))
1038		return glu::getDataTypeScalarSize(type);
1039	else
1040		return 0;
1041}
1042
1043static int getNumDataTypeVectors (glu::DataType type)
1044{
1045	if (glu::isDataTypeScalar(type))
1046		return 1;
1047	else if (glu::isDataTypeVector(type))
1048		return 1;
1049	else if (glu::isDataTypeMatrix(type))
1050		return glu::getDataTypeMatrixNumColumns(type);
1051	else
1052		return 0;
1053}
1054
1055static int getNumComponents (const ProgramInterfaceDefinition::Shader* shader, glu::Storage storage)
1056{
1057	return accumulateShaderStorage(shader, storage, getNumDataTypeComponents);
1058}
1059
1060static int getNumVectors (const ProgramInterfaceDefinition::Shader* shader, glu::Storage storage)
1061{
1062	return accumulateShaderStorage(shader, storage, getNumDataTypeVectors);
1063}
1064
1065static int getNumDefaultBlockComponents (const ProgramInterfaceDefinition::Shader* shader, glu::Storage storage)
1066{
1067	int retVal = 0;
1068
1069	for (int varNdx = 0; varNdx < (int)shader->getDefaultBlock().variables.size(); ++varNdx)
1070		if (shader->getDefaultBlock().variables[varNdx].storage == storage)
1071			retVal += accumulateComplexType(shader->getDefaultBlock().variables[varNdx].varType, getNumDataTypeComponents);
1072
1073	return retVal;
1074}
1075
1076static int getMaxBufferBinding (const ProgramInterfaceDefinition::Shader* shader, glu::Storage storage)
1077{
1078	int maxBinding = -1;
1079
1080	for (int ndx = 0; ndx < (int)shader->getDefaultBlock().interfaceBlocks.size(); ++ndx)
1081	{
1082		if (shader->getDefaultBlock().interfaceBlocks[ndx].storage == storage)
1083		{
1084			const int	binding			= (shader->getDefaultBlock().interfaceBlocks[ndx].layout.binding == -1) ? (0) : (shader->getDefaultBlock().interfaceBlocks[ndx].layout.binding);
1085			int			numInstances	= 1;
1086
1087			for (int dimensionNdx = 0; dimensionNdx < (int)shader->getDefaultBlock().interfaceBlocks[ndx].dimensions.size(); ++dimensionNdx)
1088				numInstances *= shader->getDefaultBlock().interfaceBlocks[ndx].dimensions[dimensionNdx];
1089
1090			maxBinding = de::max(maxBinding, binding + numInstances - 1);
1091		}
1092	}
1093
1094	return (int)maxBinding;
1095}
1096
1097static int getBufferTypeSize (glu::DataType type, glu::MatrixOrder order)
1098{
1099	// assume vec4 alignments, should produce values greater than or equal to the actual resource usage
1100	int numVectors = 0;
1101
1102	if (glu::isDataTypeScalarOrVector(type))
1103		numVectors = 1;
1104	else if (glu::isDataTypeMatrix(type) && order == glu::MATRIXORDER_ROW_MAJOR)
1105		numVectors = glu::getDataTypeMatrixNumRows(type);
1106	else if (glu::isDataTypeMatrix(type) && order != glu::MATRIXORDER_ROW_MAJOR)
1107		numVectors = glu::getDataTypeMatrixNumColumns(type);
1108	else
1109		DE_ASSERT(false);
1110
1111	return 4 * numVectors;
1112}
1113
1114static int getBufferVariableSize (const glu::VarType& type, glu::MatrixOrder order)
1115{
1116	if (type.isBasicType())
1117		return getBufferTypeSize(type.getBasicType(), order);
1118	else if (type.isArrayType())
1119	{
1120		const int arraySize = (type.getArraySize() == glu::VarType::UNSIZED_ARRAY) ? (1) : (type.getArraySize());
1121		return arraySize * getBufferVariableSize(type.getElementType(), order);
1122	}
1123	else if (type.isStructType())
1124	{
1125		int sum = 0;
1126		for (int ndx = 0; ndx < type.getStructPtr()->getNumMembers(); ++ndx)
1127			sum += getBufferVariableSize(type.getStructPtr()->getMember(ndx).getType(), order);
1128		return sum;
1129	}
1130	else
1131	{
1132		DE_ASSERT(false);
1133		return false;
1134	}
1135}
1136
1137static int getBufferSize (const glu::InterfaceBlock& block, glu::MatrixOrder blockOrder)
1138{
1139	int size = 0;
1140
1141	for (int ndx = 0; ndx < (int)block.variables.size(); ++ndx)
1142		size += getBufferVariableSize(block.variables[ndx].varType, (block.variables[ndx].layout.matrixOrder == glu::MATRIXORDER_LAST) ? (blockOrder) : (block.variables[ndx].layout.matrixOrder));
1143
1144	return size;
1145}
1146
1147static int getBufferMaxSize (const ProgramInterfaceDefinition::Shader* shader, glu::Storage storage)
1148{
1149	int maxSize = 0;
1150
1151	for (int ndx = 0; ndx < (int)shader->getDefaultBlock().interfaceBlocks.size(); ++ndx)
1152		if (shader->getDefaultBlock().interfaceBlocks[ndx].storage == storage)
1153			maxSize = de::max(maxSize, getBufferSize(shader->getDefaultBlock().interfaceBlocks[ndx], shader->getDefaultBlock().interfaceBlocks[ndx].layout.matrixOrder));
1154
1155	return (int)maxSize;
1156}
1157
1158static int getAtomicCounterMaxBinding (const ProgramInterfaceDefinition::Shader* shader)
1159{
1160	int maxBinding = -1;
1161
1162	for (int ndx = 0; ndx < (int)shader->getDefaultBlock().variables.size(); ++ndx)
1163	{
1164		if (containsSubType(shader->getDefaultBlock().variables[ndx].varType, glu::TYPE_UINT_ATOMIC_COUNTER))
1165		{
1166			DE_ASSERT(shader->getDefaultBlock().variables[ndx].layout.binding != -1);
1167			maxBinding = de::max(maxBinding, shader->getDefaultBlock().variables[ndx].layout.binding);
1168		}
1169	}
1170
1171	return (int)maxBinding;
1172}
1173
1174static int getUniformMaxBinding (const ProgramInterfaceDefinition::Shader* shader, bool (*predicate)(glu::DataType))
1175{
1176	int maxBinding = -1;
1177
1178	for (int ndx = 0; ndx < (int)shader->getDefaultBlock().variables.size(); ++ndx)
1179	{
1180		const int binding		= (shader->getDefaultBlock().variables[ndx].layout.binding == -1) ? (0) : (shader->getDefaultBlock().variables[ndx].layout.binding);
1181		const int numInstances	= getNumTypeInstances(shader->getDefaultBlock().variables[ndx].varType, predicate);
1182
1183		maxBinding = de::max(maxBinding, binding + numInstances - 1);
1184	}
1185
1186	return maxBinding;
1187}
1188
1189static int getAtomicCounterMaxBufferSize (const ProgramInterfaceDefinition::Shader* shader)
1190{
1191	std::map<int, int>	bufferSizes;
1192	int					maxSize			= 0;
1193
1194	for (int ndx = 0; ndx < (int)shader->getDefaultBlock().variables.size(); ++ndx)
1195	{
1196		if (containsSubType(shader->getDefaultBlock().variables[ndx].varType, glu::TYPE_UINT_ATOMIC_COUNTER))
1197		{
1198			const int bufferBinding	= shader->getDefaultBlock().variables[ndx].layout.binding;
1199			const int offset		= (shader->getDefaultBlock().variables[ndx].layout.offset == -1) ? (0) : (shader->getDefaultBlock().variables[ndx].layout.offset);
1200			const int size			= offset + 4 * getNumTypeInstances(shader->getDefaultBlock().variables[ndx].varType, glu::isDataTypeAtomicCounter);
1201
1202			DE_ASSERT(shader->getDefaultBlock().variables[ndx].layout.binding != -1);
1203
1204			if (bufferSizes.find(bufferBinding) == bufferSizes.end())
1205				bufferSizes[bufferBinding] = size;
1206			else
1207				bufferSizes[bufferBinding] = de::max<int>(bufferSizes[bufferBinding], size);
1208		}
1209	}
1210
1211	for (std::map<int, int>::iterator it = bufferSizes.begin(); it != bufferSizes.end(); ++it)
1212		maxSize = de::max<int>(maxSize, it->second);
1213
1214	return maxSize;
1215}
1216
1217static int getNumFeedbackVaryingComponents (const ProgramInterfaceDefinition::Program* program, const std::string& name)
1218{
1219	std::vector<VariablePathComponent> path;
1220
1221	if (name == "gl_Position")
1222		return 4;
1223
1224	DE_ASSERT(deStringBeginsWith(name.c_str(), "gl_") == DE_FALSE);
1225
1226	if (!traverseProgramVariablePath(path, program, name, VariableSearchFilter::createShaderTypeStorageFilter(getProgramTransformFeedbackStage(program), glu::STORAGE_OUT)))
1227		DE_ASSERT(false); // Program failed validate, invalid operation
1228
1229	return accumulateComplexType(*path.back().getVariableType(), getNumDataTypeComponents);
1230}
1231
1232static int getNumXFBComponents (const ProgramInterfaceDefinition::Program* program)
1233{
1234	int numComponents = 0;
1235
1236	for (int ndx = 0; ndx < (int)program->getTransformFeedbackVaryings().size(); ++ndx)
1237		numComponents += getNumFeedbackVaryingComponents(program, program->getTransformFeedbackVaryings()[ndx]);
1238
1239	return numComponents;
1240}
1241
1242static int getNumMaxXFBOutputComponents (const ProgramInterfaceDefinition::Program* program)
1243{
1244	int numComponents = 0;
1245
1246	for (int ndx = 0; ndx < (int)program->getTransformFeedbackVaryings().size(); ++ndx)
1247		numComponents = de::max(numComponents, getNumFeedbackVaryingComponents(program, program->getTransformFeedbackVaryings()[ndx]));
1248
1249	return numComponents;
1250}
1251
1252static int getFragmentOutputMaxLocation (const ProgramInterfaceDefinition::Shader* shader)
1253{
1254	DE_ASSERT(shader->getType() == glu::SHADERTYPE_FRAGMENT);
1255
1256	int maxOutputLocation = -1;
1257
1258	for (int ndx = 0; ndx < (int)shader->getDefaultBlock().variables.size(); ++ndx)
1259	{
1260		if (shader->getDefaultBlock().variables[ndx].storage == glu::STORAGE_OUT)
1261		{
1262			// missing location qualifier means location == 0
1263			const int outputLocation		= (shader->getDefaultBlock().variables[ndx].layout.location == -1)
1264												? (0)
1265												: (shader->getDefaultBlock().variables[ndx].layout.location);
1266
1267			// only basic types or arrays of basic types possible
1268			DE_ASSERT(!shader->getDefaultBlock().variables[ndx].varType.isStructType());
1269
1270			const int locationSlotsTaken	= (shader->getDefaultBlock().variables[ndx].varType.isArrayType())
1271												? (shader->getDefaultBlock().variables[ndx].varType.getArraySize())
1272												: (1);
1273
1274			maxOutputLocation = de::max(maxOutputLocation, outputLocation + locationSlotsTaken - 1);
1275		}
1276	}
1277
1278	return maxOutputLocation;
1279}
1280
1281} // anonymous
1282
1283std::vector<std::string> getProgramInterfaceBlockMemberResourceList (const glu::InterfaceBlock& interfaceBlock)
1284{
1285	const std::string			namePrefix					= (!interfaceBlock.instanceName.empty()) ? (interfaceBlock.interfaceName + ".") : ("");
1286	const bool					isTopLevelBufferVariable	= (interfaceBlock.storage == glu::STORAGE_BUFFER);
1287	std::vector<std::string>	resources;
1288
1289	// \note this is defined in the GLSL spec, not in the GL spec
1290	for (int variableNdx = 0; variableNdx < (int)interfaceBlock.variables.size(); ++variableNdx)
1291		generateVariableTypeResourceNames(resources,
1292										  namePrefix + interfaceBlock.variables[variableNdx].name,
1293										  interfaceBlock.variables[variableNdx].varType,
1294										  (isTopLevelBufferVariable) ?
1295											(RESOURCE_NAME_GENERATION_FLAG_TOP_LEVEL_BUFFER_VARIABLE) :
1296											(RESOURCE_NAME_GENERATION_FLAG_DEFAULT));
1297
1298	return resources;
1299}
1300
1301std::vector<std::string> getProgramInterfaceResourceList (const ProgramInterfaceDefinition::Program* program, ProgramInterface interface)
1302{
1303	// The same {uniform (block), buffer (variable)} can exist in multiple shaders, remove duplicates but keep order
1304	const bool					removeDuplicated	= (interface == PROGRAMINTERFACE_UNIFORM)			||
1305													  (interface == PROGRAMINTERFACE_UNIFORM_BLOCK)		||
1306													  (interface == PROGRAMINTERFACE_BUFFER_VARIABLE)	||
1307													  (interface == PROGRAMINTERFACE_SHADER_STORAGE_BLOCK);
1308	std::vector<std::string>	resources;
1309
1310	switch (interface)
1311	{
1312		case PROGRAMINTERFACE_UNIFORM:
1313		case PROGRAMINTERFACE_BUFFER_VARIABLE:
1314		{
1315			const glu::Storage storage = (interface == PROGRAMINTERFACE_UNIFORM) ? (glu::STORAGE_UNIFORM) : (glu::STORAGE_BUFFER);
1316
1317			for (int shaderNdx = 0; shaderNdx < (int)program->getShaders().size(); ++shaderNdx)
1318			{
1319				const ProgramInterfaceDefinition::Shader* shader = program->getShaders()[shaderNdx];
1320
1321				for (int variableNdx = 0; variableNdx < (int)shader->getDefaultBlock().variables.size(); ++variableNdx)
1322					if (shader->getDefaultBlock().variables[variableNdx].storage == storage)
1323						generateVariableTypeResourceNames(resources,
1324														  shader->getDefaultBlock().variables[variableNdx].name,
1325														  shader->getDefaultBlock().variables[variableNdx].varType,
1326														  RESOURCE_NAME_GENERATION_FLAG_DEFAULT);
1327
1328				for (int interfaceNdx = 0; interfaceNdx < (int)shader->getDefaultBlock().interfaceBlocks.size(); ++interfaceNdx)
1329				{
1330					const glu::InterfaceBlock& interfaceBlock = shader->getDefaultBlock().interfaceBlocks[interfaceNdx];
1331					if (interfaceBlock.storage == storage)
1332					{
1333						const std::vector<std::string> blockResources = getProgramInterfaceBlockMemberResourceList(interfaceBlock);
1334						resources.insert(resources.end(), blockResources.begin(), blockResources.end());
1335					}
1336				}
1337			}
1338			break;
1339		}
1340
1341		case PROGRAMINTERFACE_UNIFORM_BLOCK:
1342		case PROGRAMINTERFACE_SHADER_STORAGE_BLOCK:
1343		{
1344			const glu::Storage storage = (interface == PROGRAMINTERFACE_UNIFORM_BLOCK) ? (glu::STORAGE_UNIFORM) : (glu::STORAGE_BUFFER);
1345
1346			for (int shaderNdx = 0; shaderNdx < (int)program->getShaders().size(); ++shaderNdx)
1347			{
1348				const ProgramInterfaceDefinition::Shader* shader = program->getShaders()[shaderNdx];
1349				for (int interfaceNdx = 0; interfaceNdx < (int)shader->getDefaultBlock().interfaceBlocks.size(); ++interfaceNdx)
1350				{
1351					const glu::InterfaceBlock& interfaceBlock = shader->getDefaultBlock().interfaceBlocks[interfaceNdx];
1352					if (interfaceBlock.storage == storage)
1353					{
1354						std::vector<int> index(interfaceBlock.dimensions.size(), 0);
1355
1356						for (;;)
1357						{
1358							// add resource string for each element
1359							{
1360								std::ostringstream name;
1361								name << interfaceBlock.interfaceName;
1362
1363								for (int dimensionNdx = 0; dimensionNdx < (int)interfaceBlock.dimensions.size(); ++dimensionNdx)
1364									name << "[" << index[dimensionNdx] << "]";
1365
1366								resources.push_back(name.str());
1367							}
1368
1369							// increment index
1370							if (!incrementMultiDimensionIndex(index, interfaceBlock.dimensions))
1371								break;
1372						}
1373					}
1374				}
1375			}
1376			break;
1377		}
1378
1379		case PROGRAMINTERFACE_PROGRAM_INPUT:
1380		case PROGRAMINTERFACE_PROGRAM_OUTPUT:
1381		{
1382			const glu::Storage		queryStorage		= (interface == PROGRAMINTERFACE_PROGRAM_INPUT) ? (glu::STORAGE_IN) : (glu::STORAGE_OUT);
1383			const glu::Storage		queryPatchStorage	= (interface == PROGRAMINTERFACE_PROGRAM_INPUT) ? (glu::STORAGE_PATCH_IN) : (glu::STORAGE_PATCH_OUT);
1384			const glu::ShaderType	shaderType			= (interface == PROGRAMINTERFACE_PROGRAM_INPUT) ? (program->getFirstStage()) : (program->getLastStage());
1385
1386			for (int shaderNdx = 0; shaderNdx < (int)program->getShaders().size(); ++shaderNdx)
1387			{
1388				const ProgramInterfaceDefinition::Shader* shader = program->getShaders()[shaderNdx];
1389
1390				if (shader->getType() != shaderType)
1391					continue;
1392
1393				for (int variableNdx = 0; variableNdx < (int)shader->getDefaultBlock().variables.size(); ++variableNdx)
1394				{
1395					const glu::Storage variableStorage = shader->getDefaultBlock().variables[variableNdx].storage;
1396					if (variableStorage == queryStorage || variableStorage == queryPatchStorage)
1397						generateVariableTypeResourceNames(resources,
1398														  shader->getDefaultBlock().variables[variableNdx].name,
1399														  shader->getDefaultBlock().variables[variableNdx].varType,
1400														  RESOURCE_NAME_GENERATION_FLAG_DEFAULT);
1401				}
1402
1403				for (int interfaceNdx = 0; interfaceNdx < (int)shader->getDefaultBlock().interfaceBlocks.size(); ++interfaceNdx)
1404				{
1405					const glu::InterfaceBlock& interfaceBlock = shader->getDefaultBlock().interfaceBlocks[interfaceNdx];
1406					if (interfaceBlock.storage == queryStorage || interfaceBlock.storage == queryPatchStorage)
1407					{
1408						const std::vector<std::string> blockResources = getProgramInterfaceBlockMemberResourceList(interfaceBlock);
1409						resources.insert(resources.end(), blockResources.begin(), blockResources.end());
1410					}
1411				}
1412			}
1413
1414			// built-ins
1415			if (interface == PROGRAMINTERFACE_PROGRAM_INPUT)
1416			{
1417				if (shaderType == glu::SHADERTYPE_VERTEX && resources.empty())
1418					resources.push_back("gl_VertexID"); // only read from when there are no other inputs
1419				else if (shaderType == glu::SHADERTYPE_FRAGMENT && resources.empty())
1420					resources.push_back("gl_FragCoord"); // only read from when there are no other inputs
1421				else if (shaderType == glu::SHADERTYPE_GEOMETRY)
1422					resources.push_back("gl_PerVertex.gl_Position");
1423				else if (shaderType == glu::SHADERTYPE_TESSELLATION_CONTROL)
1424				{
1425					resources.push_back("gl_InvocationID");
1426					resources.push_back("gl_PerVertex.gl_Position");
1427				}
1428				else if (shaderType == glu::SHADERTYPE_TESSELLATION_EVALUATION)
1429					resources.push_back("gl_PerVertex.gl_Position");
1430				else if (shaderType == glu::SHADERTYPE_COMPUTE && resources.empty())
1431					resources.push_back("gl_NumWorkGroups"); // only read from when there are no other inputs
1432			}
1433			else if (interface == PROGRAMINTERFACE_PROGRAM_OUTPUT)
1434			{
1435				if (shaderType == glu::SHADERTYPE_VERTEX)
1436					resources.push_back("gl_Position");
1437				else if (shaderType == glu::SHADERTYPE_FRAGMENT && resources.empty())
1438					resources.push_back("gl_FragDepth"); // only written to when there are no other outputs
1439				else if (shaderType == glu::SHADERTYPE_GEOMETRY)
1440					resources.push_back("gl_Position");
1441				else if (shaderType == glu::SHADERTYPE_TESSELLATION_CONTROL)
1442				{
1443					resources.push_back("gl_PerVertex.gl_Position");
1444					resources.push_back("gl_TessLevelOuter[0]");
1445					resources.push_back("gl_TessLevelInner[0]");
1446				}
1447				else if (shaderType == glu::SHADERTYPE_TESSELLATION_EVALUATION)
1448					resources.push_back("gl_Position");
1449			}
1450
1451			break;
1452		}
1453
1454		case PROGRAMINTERFACE_TRANSFORM_FEEDBACK_VARYING:
1455		{
1456			const glu::ShaderType xfbStage = getProgramTransformFeedbackStage(program);
1457
1458			for (int varyingNdx = 0; varyingNdx < (int)program->getTransformFeedbackVaryings().size(); ++varyingNdx)
1459			{
1460				const std::string& varyingName = program->getTransformFeedbackVaryings()[varyingNdx];
1461
1462				if (deStringBeginsWith(varyingName.c_str(), "gl_"))
1463					resources.push_back(varyingName); // builtin
1464				else
1465				{
1466					std::vector<VariablePathComponent> path;
1467
1468					if (!traverseProgramVariablePath(path, program, varyingName, VariableSearchFilter::createShaderTypeStorageFilter(xfbStage, glu::STORAGE_OUT)))
1469						DE_ASSERT(false); // Program failed validate, invalid operation
1470
1471					generateVariableTypeResourceNames(resources,
1472													  varyingName,
1473													  *path.back().getVariableType(),
1474													  RESOURCE_NAME_GENERATION_FLAG_TRANSFORM_FEEDBACK_VARIABLE);
1475				}
1476			}
1477
1478			break;
1479		}
1480
1481		default:
1482			DE_ASSERT(false);
1483	}
1484
1485	if (removeDuplicated)
1486	{
1487		std::set<std::string>		addedVariables;
1488		std::vector<std::string>	uniqueResouces;
1489
1490		for (int ndx = 0; ndx < (int)resources.size(); ++ndx)
1491		{
1492			if (addedVariables.find(resources[ndx]) == addedVariables.end())
1493			{
1494				addedVariables.insert(resources[ndx]);
1495				uniqueResouces.push_back(resources[ndx]);
1496			}
1497		}
1498
1499		uniqueResouces.swap(resources);
1500	}
1501
1502	return resources;
1503}
1504
1505/**
1506 * Name of the unused uniform added by generateProgramInterfaceProgramSources
1507 *
1508 * A uniform named "unusedZero" is added by
1509 * generateProgramInterfaceProgramSources.  It is used in expressions to
1510 * prevent various program resources from being eliminated by the GLSL
1511 * compiler's optimizer.
1512 *
1513 * \sa deqp::gles31::Functional::ProgramInterfaceDefinition::generateProgramInterfaceProgramSources
1514 */
1515const char* getUnusedZeroUniformName()
1516{
1517	return "unusedZero";
1518}
1519
1520glu::ProgramSources generateProgramInterfaceProgramSources (const ProgramInterfaceDefinition::Program* program)
1521{
1522	glu::ProgramSources sources;
1523
1524	DE_ASSERT(program->isValid());
1525
1526	for (int shaderNdx = 0; shaderNdx < (int)program->getShaders().size(); ++shaderNdx)
1527	{
1528		const ProgramInterfaceDefinition::Shader*	shader						= program->getShaders()[shaderNdx];
1529		bool										containsUserDefinedOutputs	= false;
1530		bool										containsUserDefinedInputs	= false;
1531		std::ostringstream							sourceBuf;
1532		std::ostringstream							usageBuf;
1533
1534		sourceBuf	<< glu::getGLSLVersionDeclaration(shader->getVersion()) << "\n"
1535					<< getShaderExtensionDeclarations(shader)
1536					<< getShaderTypeDeclarations(program, shader)
1537					<< "\n";
1538
1539		// Struct definitions
1540
1541		writeStructureDefinitions(sourceBuf, shader->getDefaultBlock());
1542
1543		// variables in the default scope
1544
1545		for (int ndx = 0; ndx < (int)shader->getDefaultBlock().variables.size(); ++ndx)
1546			sourceBuf << shader->getDefaultBlock().variables[ndx] << ";\n";
1547
1548		if (!shader->getDefaultBlock().variables.empty())
1549			sourceBuf << "\n";
1550
1551		// Interface blocks
1552
1553		for (int ndx = 0; ndx < (int)shader->getDefaultBlock().interfaceBlocks.size(); ++ndx)
1554			writeInterfaceBlock(sourceBuf, shader->getDefaultBlock().interfaceBlocks[ndx]);
1555
1556		// Use inputs and outputs so that they won't be removed by the optimizer
1557
1558		usageBuf <<	"highp uniform vec4 " << getUnusedZeroUniformName() << "; // Default value is vec4(0.0).\n"
1559					"highp vec4 readInputs()\n"
1560					"{\n"
1561					"	highp vec4 retValue = " << getUnusedZeroUniformName() << ";\n";
1562
1563		// User-defined inputs
1564
1565		for (int ndx = 0; ndx < (int)shader->getDefaultBlock().variables.size(); ++ndx)
1566		{
1567			if (shader->getDefaultBlock().variables[ndx].storage == glu::STORAGE_IN			||
1568				shader->getDefaultBlock().variables[ndx].storage == glu::STORAGE_PATCH_IN	||
1569				shader->getDefaultBlock().variables[ndx].storage == glu::STORAGE_UNIFORM)
1570			{
1571				writeVariableReadAccumulateExpression(usageBuf,
1572													  "retValue",
1573													  shader->getDefaultBlock().variables[ndx].name,
1574													  shader->getType(),
1575													  shader->getDefaultBlock().variables[ndx].storage,
1576													  program,
1577													  shader->getDefaultBlock().variables[ndx].varType);
1578				containsUserDefinedInputs = true;
1579			}
1580		}
1581
1582		for (int interfaceNdx = 0; interfaceNdx < (int)shader->getDefaultBlock().interfaceBlocks.size(); ++interfaceNdx)
1583		{
1584			const glu::InterfaceBlock& interface = shader->getDefaultBlock().interfaceBlocks[interfaceNdx];
1585			if (isReadableInterface(interface))
1586			{
1587				writeInterfaceReadAccumulateExpression(usageBuf,
1588													   "retValue",
1589													   interface,
1590													   shader->getType(),
1591													   program);
1592				containsUserDefinedInputs = true;
1593			}
1594		}
1595
1596		// Built-in-inputs
1597
1598		switch (shader->getType())
1599		{
1600			case glu::SHADERTYPE_VERTEX:
1601				// make readInputs to never be compile time constant
1602				if (!containsUserDefinedInputs)
1603					usageBuf << "	retValue += vec4(float(gl_VertexID));\n";
1604				break;
1605
1606			case glu::SHADERTYPE_FRAGMENT:
1607				// make readInputs to never be compile time constant
1608				if (!containsUserDefinedInputs)
1609					usageBuf << "	retValue += gl_FragCoord;\n";
1610				break;
1611			case glu::SHADERTYPE_GEOMETRY:
1612				// always use previous stage's output values so that previous stage won't be optimized out
1613				usageBuf << "	retValue += gl_in[0].gl_Position;\n";
1614				break;
1615			case glu::SHADERTYPE_TESSELLATION_CONTROL:
1616				// always use previous stage's output values so that previous stage won't be optimized out
1617				usageBuf << "	retValue += gl_in[0].gl_Position;\n";
1618				break;
1619			case glu::SHADERTYPE_TESSELLATION_EVALUATION:
1620				// always use previous stage's output values so that previous stage won't be optimized out
1621				usageBuf << "	retValue += gl_in[0].gl_Position;\n";
1622				break;
1623
1624			case glu::SHADERTYPE_COMPUTE:
1625				// make readInputs to never be compile time constant
1626				if (!containsUserDefinedInputs)
1627					usageBuf << "	retValue += vec4(float(gl_NumWorkGroups.x));\n";
1628				break;
1629			default:
1630				DE_ASSERT(false);
1631		}
1632
1633		usageBuf <<	"	return retValue;\n"
1634					"}\n\n";
1635
1636		usageBuf <<	"void writeOutputs(in highp vec4 unusedValue)\n"
1637					"{\n";
1638
1639		// User-defined outputs
1640
1641		for (int ndx = 0; ndx < (int)shader->getDefaultBlock().variables.size(); ++ndx)
1642		{
1643			if (shader->getDefaultBlock().variables[ndx].storage == glu::STORAGE_OUT ||
1644				shader->getDefaultBlock().variables[ndx].storage == glu::STORAGE_PATCH_OUT)
1645			{
1646				writeVariableWriteExpression(usageBuf,
1647											 "unusedValue",
1648											 shader->getDefaultBlock().variables[ndx].name,
1649											 shader->getType(),
1650											 shader->getDefaultBlock().variables[ndx].storage,
1651											 program,
1652											 shader->getDefaultBlock().variables[ndx].varType);
1653				containsUserDefinedOutputs = true;
1654			}
1655		}
1656
1657		for (int interfaceNdx = 0; interfaceNdx < (int)shader->getDefaultBlock().interfaceBlocks.size(); ++interfaceNdx)
1658		{
1659			const glu::InterfaceBlock& interface = shader->getDefaultBlock().interfaceBlocks[interfaceNdx];
1660			if (isWritableInterface(interface))
1661			{
1662				writeInterfaceWriteExpression(usageBuf, "unusedValue", interface, shader->getType(), program);
1663				containsUserDefinedOutputs = true;
1664			}
1665		}
1666
1667		// Builtin-outputs that must be written to
1668
1669		if (shader->getType() == glu::SHADERTYPE_VERTEX)
1670			usageBuf << "	gl_Position = unusedValue;\n";
1671		else if (shader->getType() == glu::SHADERTYPE_GEOMETRY)
1672			usageBuf << "	gl_Position = unusedValue;\n"
1673						 "	EmitVertex();\n";
1674		else if (shader->getType() == glu::SHADERTYPE_TESSELLATION_CONTROL)
1675			usageBuf << "	gl_out[gl_InvocationID].gl_Position = unusedValue;\n"
1676						"	gl_TessLevelOuter[0] = 2.8;\n"
1677						"	gl_TessLevelOuter[1] = 2.8;\n"
1678						"	gl_TessLevelOuter[2] = 2.8;\n"
1679						"	gl_TessLevelOuter[3] = 2.8;\n"
1680						"	gl_TessLevelInner[0] = 2.8;\n"
1681						"	gl_TessLevelInner[1] = 2.8;\n";
1682		else if (shader->getType() == glu::SHADERTYPE_TESSELLATION_EVALUATION)
1683			usageBuf << "	gl_Position = unusedValue;\n";
1684
1685		// Output to sink input data to
1686
1687		if (!containsUserDefinedOutputs)
1688		{
1689			if (shader->getType() == glu::SHADERTYPE_FRAGMENT)
1690				usageBuf << "	gl_FragDepth = dot(unusedValue.xy, unusedValue.xw);\n";
1691			else if (shader->getType() == glu::SHADERTYPE_COMPUTE)
1692				usageBuf << "	unusedOutputBlock.unusedValue = unusedValue;\n";
1693		}
1694
1695		usageBuf <<	"}\n\n"
1696					"void main()\n"
1697					"{\n"
1698					"	writeOutputs(readInputs());\n"
1699					"}\n";
1700
1701		// Interface for unused output
1702
1703		if (shader->getType() == glu::SHADERTYPE_COMPUTE && !containsUserDefinedOutputs)
1704		{
1705			sourceBuf	<< "writeonly buffer UnusedOutputInterface\n"
1706						<< "{\n"
1707						<< "	highp vec4 unusedValue;\n"
1708						<< "} unusedOutputBlock;\n\n";
1709		}
1710
1711		sources << glu::ShaderSource(shader->getType(), sourceBuf.str() + usageBuf.str());
1712	}
1713
1714	if (program->isSeparable())
1715		sources << glu::ProgramSeparable(true);
1716
1717	for (int ndx = 0; ndx < (int)program->getTransformFeedbackVaryings().size(); ++ndx)
1718		sources << glu::TransformFeedbackVarying(program->getTransformFeedbackVaryings()[ndx]);
1719
1720	if (program->getTransformFeedbackMode())
1721		sources << glu::TransformFeedbackMode(program->getTransformFeedbackMode());
1722
1723	return sources;
1724}
1725
1726bool findProgramVariablePathByPathName (std::vector<VariablePathComponent>& typePath, const ProgramInterfaceDefinition::Program* program, const std::string& pathName, const VariableSearchFilter& filter)
1727{
1728	std::vector<VariablePathComponent> modifiedPath;
1729
1730	if (!traverseProgramVariablePath(modifiedPath, program, pathName, filter))
1731		return false;
1732
1733	// modify param only on success
1734	typePath.swap(modifiedPath);
1735	return true;
1736}
1737
1738ProgramInterfaceDefinition::ShaderResourceUsage getShaderResourceUsage (const ProgramInterfaceDefinition::Program* program, const ProgramInterfaceDefinition::Shader* shader)
1739{
1740	ProgramInterfaceDefinition::ShaderResourceUsage retVal;
1741
1742	retVal.numInputs						= getNumTypeInstances(shader, glu::STORAGE_IN);
1743	retVal.numInputVectors					= getNumVectors(shader, glu::STORAGE_IN);
1744	retVal.numInputComponents				= getNumComponents(shader, glu::STORAGE_IN);
1745
1746	retVal.numOutputs						= getNumTypeInstances(shader, glu::STORAGE_OUT);
1747	retVal.numOutputVectors					= getNumVectors(shader, glu::STORAGE_OUT);
1748	retVal.numOutputComponents				= getNumComponents(shader, glu::STORAGE_OUT);
1749
1750	retVal.numPatchInputComponents			= getNumComponents(shader, glu::STORAGE_PATCH_IN);
1751	retVal.numPatchOutputComponents			= getNumComponents(shader, glu::STORAGE_PATCH_OUT);
1752
1753	retVal.numDefaultBlockUniformComponents	= getNumDefaultBlockComponents(shader, glu::STORAGE_UNIFORM);
1754	retVal.numCombinedUniformComponents		= getNumComponents(shader, glu::STORAGE_UNIFORM);
1755	retVal.numUniformVectors				= getNumVectors(shader, glu::STORAGE_UNIFORM);
1756
1757	retVal.numSamplers						= getNumTypeInstances(shader, glu::STORAGE_UNIFORM, glu::isDataTypeSampler);
1758	retVal.numImages						= getNumTypeInstances(shader, glu::STORAGE_UNIFORM, glu::isDataTypeImage);
1759
1760	retVal.numAtomicCounterBuffers			= getNumAtomicCounterBuffers(shader);
1761	retVal.numAtomicCounters				= getNumTypeInstances(shader, glu::STORAGE_UNIFORM, glu::isDataTypeAtomicCounter);
1762
1763	retVal.numUniformBlocks					= getNumShaderBlocks(shader, glu::STORAGE_UNIFORM);
1764	retVal.numShaderStorageBlocks			= getNumShaderBlocks(shader, glu::STORAGE_BUFFER);
1765
1766	// add builtins
1767	switch (shader->getType())
1768	{
1769		case glu::SHADERTYPE_VERTEX:
1770			// gl_Position is not counted
1771			break;
1772
1773		case glu::SHADERTYPE_FRAGMENT:
1774			// nada
1775			break;
1776
1777		case glu::SHADERTYPE_GEOMETRY:
1778			// gl_Position in (point mode => size 1)
1779			retVal.numInputs			+= 1;
1780			retVal.numInputVectors		+= 1;
1781			retVal.numInputComponents	+= 4;
1782
1783			// gl_Position out
1784			retVal.numOutputs			+= 1;
1785			retVal.numOutputVectors		+= 1;
1786			retVal.numOutputComponents	+= 4;
1787			break;
1788
1789		case glu::SHADERTYPE_TESSELLATION_CONTROL:
1790			// gl_Position in is read up to gl_InstanceID
1791			retVal.numInputs			+= 1 * program->getTessellationNumOutputPatchVertices();
1792			retVal.numInputVectors		+= 1 * program->getTessellationNumOutputPatchVertices();
1793			retVal.numInputComponents	+= 4 * program->getTessellationNumOutputPatchVertices();
1794
1795			// gl_Position out, size = num patch out vertices
1796			retVal.numOutputs			+= 1 * program->getTessellationNumOutputPatchVertices();
1797			retVal.numOutputVectors		+= 1 * program->getTessellationNumOutputPatchVertices();
1798			retVal.numOutputComponents	+= 4 * program->getTessellationNumOutputPatchVertices();
1799			break;
1800
1801		case glu::SHADERTYPE_TESSELLATION_EVALUATION:
1802			// gl_Position in is read up to gl_InstanceID
1803			retVal.numInputs			+= 1 * program->getTessellationNumOutputPatchVertices();
1804			retVal.numInputVectors		+= 1 * program->getTessellationNumOutputPatchVertices();
1805			retVal.numInputComponents	+= 4 * program->getTessellationNumOutputPatchVertices();
1806
1807			// gl_Position out
1808			retVal.numOutputs			+= 1;
1809			retVal.numOutputVectors		+= 1;
1810			retVal.numOutputComponents	+= 4;
1811			break;
1812
1813		case glu::SHADERTYPE_COMPUTE:
1814			// nada
1815			break;
1816
1817		default:
1818			DE_ASSERT(false);
1819			break;
1820	}
1821	return retVal;
1822}
1823
1824ProgramInterfaceDefinition::ProgramResourceUsage getCombinedProgramResourceUsage (const ProgramInterfaceDefinition::Program* program)
1825{
1826	ProgramInterfaceDefinition::ProgramResourceUsage	retVal;
1827	int													numVertexOutputComponents	= 0;
1828	int													numFragmentInputComponents	= 0;
1829	int													numVertexOutputVectors		= 0;
1830	int													numFragmentInputVectors		= 0;
1831
1832	retVal.uniformBufferMaxBinding					= -1; // max binding is inclusive upper bound. Allow 0 bindings by using negative value
1833	retVal.uniformBufferMaxSize						= 0;
1834	retVal.numUniformBlocks							= 0;
1835	retVal.numCombinedVertexUniformComponents		= 0;
1836	retVal.numCombinedFragmentUniformComponents		= 0;
1837	retVal.numCombinedGeometryUniformComponents		= 0;
1838	retVal.numCombinedTessControlUniformComponents	= 0;
1839	retVal.numCombinedTessEvalUniformComponents		= 0;
1840	retVal.shaderStorageBufferMaxBinding			= -1; // see above
1841	retVal.shaderStorageBufferMaxSize				= 0;
1842	retVal.numShaderStorageBlocks					= 0;
1843	retVal.numVaryingComponents						= 0;
1844	retVal.numVaryingVectors						= 0;
1845	retVal.numCombinedSamplers						= 0;
1846	retVal.atomicCounterBufferMaxBinding			= -1; // see above
1847	retVal.atomicCounterBufferMaxSize				= 0;
1848	retVal.numAtomicCounterBuffers					= 0;
1849	retVal.numAtomicCounters						= 0;
1850	retVal.maxImageBinding							= -1; // see above
1851	retVal.numCombinedImages						= 0;
1852	retVal.numCombinedOutputResources				= 0;
1853	retVal.numXFBInterleavedComponents				= 0;
1854	retVal.numXFBSeparateAttribs					= 0;
1855	retVal.numXFBSeparateComponents					= 0;
1856	retVal.fragmentOutputMaxBinding					= -1; // see above
1857
1858	for (int shaderNdx = 0; shaderNdx < (int)program->getShaders().size(); ++shaderNdx)
1859	{
1860		const ProgramInterfaceDefinition::Shader* const shader = program->getShaders()[shaderNdx];
1861
1862		retVal.uniformBufferMaxBinding		= de::max(retVal.uniformBufferMaxBinding, getMaxBufferBinding(shader, glu::STORAGE_UNIFORM));
1863		retVal.uniformBufferMaxSize			= de::max(retVal.uniformBufferMaxSize, getBufferMaxSize(shader, glu::STORAGE_UNIFORM));
1864		retVal.numUniformBlocks				+= getNumShaderBlocks(shader, glu::STORAGE_UNIFORM);
1865
1866		switch (shader->getType())
1867		{
1868			case glu::SHADERTYPE_VERTEX:					retVal.numCombinedVertexUniformComponents		+= getNumComponents(shader, glu::STORAGE_UNIFORM); break;
1869			case glu::SHADERTYPE_FRAGMENT:					retVal.numCombinedFragmentUniformComponents		+= getNumComponents(shader, glu::STORAGE_UNIFORM); break;
1870			case glu::SHADERTYPE_GEOMETRY:					retVal.numCombinedGeometryUniformComponents		+= getNumComponents(shader, glu::STORAGE_UNIFORM); break;
1871			case glu::SHADERTYPE_TESSELLATION_CONTROL:		retVal.numCombinedTessControlUniformComponents	+= getNumComponents(shader, glu::STORAGE_UNIFORM); break;
1872			case glu::SHADERTYPE_TESSELLATION_EVALUATION:	retVal.numCombinedTessEvalUniformComponents		+= getNumComponents(shader, glu::STORAGE_UNIFORM); break;
1873			default: break;
1874		}
1875
1876		retVal.shaderStorageBufferMaxBinding	= de::max(retVal.shaderStorageBufferMaxBinding, getMaxBufferBinding(shader, glu::STORAGE_BUFFER));
1877		retVal.shaderStorageBufferMaxSize		= de::max(retVal.shaderStorageBufferMaxSize, getBufferMaxSize(shader, glu::STORAGE_BUFFER));
1878		retVal.numShaderStorageBlocks			+= getNumShaderBlocks(shader, glu::STORAGE_BUFFER);
1879
1880		if (shader->getType() == glu::SHADERTYPE_VERTEX)
1881		{
1882			numVertexOutputComponents	+= getNumComponents(shader, glu::STORAGE_OUT);
1883			numVertexOutputVectors		+= getNumVectors(shader, glu::STORAGE_OUT);
1884		}
1885		else if (shader->getType() == glu::SHADERTYPE_FRAGMENT)
1886		{
1887			numFragmentInputComponents	+= getNumComponents(shader, glu::STORAGE_IN);
1888			numFragmentInputVectors		+= getNumVectors(shader, glu::STORAGE_IN);
1889		}
1890
1891		retVal.numCombinedSamplers	+= getNumTypeInstances(shader, glu::STORAGE_UNIFORM, glu::isDataTypeSampler);
1892
1893		retVal.atomicCounterBufferMaxBinding	= de::max(retVal.atomicCounterBufferMaxBinding, getAtomicCounterMaxBinding(shader));
1894		retVal.atomicCounterBufferMaxSize		= de::max(retVal.atomicCounterBufferMaxSize, getAtomicCounterMaxBufferSize(shader));
1895		retVal.numAtomicCounterBuffers			+= getNumAtomicCounterBuffers(shader);
1896		retVal.numAtomicCounters				+= getNumTypeInstances(shader, glu::STORAGE_UNIFORM, glu::isDataTypeAtomicCounter);
1897		retVal.maxImageBinding					= de::max(retVal.maxImageBinding, getUniformMaxBinding(shader, glu::isDataTypeImage));
1898		retVal.numCombinedImages				+= getNumTypeInstances(shader, glu::STORAGE_UNIFORM, glu::isDataTypeImage);
1899
1900		retVal.numCombinedOutputResources		+= getNumTypeInstances(shader, glu::STORAGE_UNIFORM, glu::isDataTypeImage);
1901		retVal.numCombinedOutputResources		+= getNumShaderBlocks(shader, glu::STORAGE_BUFFER);
1902
1903		if (shader->getType() == glu::SHADERTYPE_FRAGMENT)
1904		{
1905			retVal.numCombinedOutputResources += getNumVectors(shader, glu::STORAGE_OUT);
1906			retVal.fragmentOutputMaxBinding = de::max(retVal.fragmentOutputMaxBinding, getFragmentOutputMaxLocation(shader));
1907		}
1908	}
1909
1910	if (program->getTransformFeedbackMode() == GL_INTERLEAVED_ATTRIBS)
1911		retVal.numXFBInterleavedComponents = getNumXFBComponents(program);
1912	else if (program->getTransformFeedbackMode() == GL_SEPARATE_ATTRIBS)
1913	{
1914		retVal.numXFBSeparateAttribs	= (int)program->getTransformFeedbackVaryings().size();
1915		retVal.numXFBSeparateComponents	= getNumMaxXFBOutputComponents(program);
1916	}
1917
1918	// legacy limits
1919	retVal.numVaryingComponents	= de::max(numVertexOutputComponents, numFragmentInputComponents);
1920	retVal.numVaryingVectors	= de::max(numVertexOutputVectors, numFragmentInputVectors);
1921
1922	return retVal;
1923}
1924
1925} // Functional
1926} // gles31
1927} // deqp
1928