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