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
22 *//*--------------------------------------------------------------------*/
23
24#include "es31fProgramInterfaceDefinition.hpp"
25#include "es31fProgramInterfaceDefinitionUtil.hpp"
26#include "gluVarType.hpp"
27#include "gluShaderProgram.hpp"
28#include "deSTLUtil.hpp"
29#include "deStringUtil.hpp"
30#include "glwEnums.hpp"
31
32#include <set>
33
34namespace deqp
35{
36namespace gles31
37{
38namespace Functional
39{
40namespace ProgramInterfaceDefinition
41{
42namespace
43{
44
45static const glu::ShaderType s_shaderStageOrder[] =
46{
47	glu::SHADERTYPE_COMPUTE,
48
49	glu::SHADERTYPE_VERTEX,
50	glu::SHADERTYPE_TESSELLATION_CONTROL,
51	glu::SHADERTYPE_TESSELLATION_EVALUATION,
52	glu::SHADERTYPE_GEOMETRY,
53	glu::SHADERTYPE_FRAGMENT
54};
55
56// s_shaderStageOrder does not contain ShaderType_LAST
57DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(s_shaderStageOrder) == glu::SHADERTYPE_LAST);
58
59static bool containsMatchingSubtype (const glu::VarType& varType, bool (*predicate)(glu::DataType))
60{
61	if (varType.isBasicType() && predicate(varType.getBasicType()))
62		return true;
63
64	if (varType.isArrayType())
65		return containsMatchingSubtype(varType.getElementType(), predicate);
66
67	if (varType.isStructType())
68		for (int memberNdx = 0; memberNdx < varType.getStructPtr()->getNumMembers(); ++memberNdx)
69			if (containsMatchingSubtype(varType.getStructPtr()->getMember(memberNdx).getType(), predicate))
70				return true;
71
72	return false;
73}
74
75static bool containsMatchingSubtype (const std::vector<glu::VariableDeclaration>& decls, bool (*predicate)(glu::DataType))
76{
77	for (int varNdx = 0; varNdx < (int)decls.size(); ++varNdx)
78		if (containsMatchingSubtype(decls[varNdx].varType, predicate))
79			return true;
80	return false;
81}
82
83static bool isOpaqueType (glu::DataType type)
84{
85	return	glu::isDataTypeAtomicCounter(type)	||
86			glu::isDataTypeImage(type)			||
87			glu::isDataTypeSampler(type);
88}
89
90static int getShaderStageIndex (glu::ShaderType stage)
91{
92	const glu::ShaderType* const it = std::find(DE_ARRAY_BEGIN(s_shaderStageOrder), DE_ARRAY_END(s_shaderStageOrder), stage);
93
94	if (it == DE_ARRAY_END(s_shaderStageOrder))
95		return -1;
96	else
97	{
98		const int index = (int)(it - DE_ARRAY_BEGIN(s_shaderStageOrder));
99		return index;
100	}
101}
102
103} // anonymous
104
105Shader::Shader (glu::ShaderType type, glu::GLSLVersion version)
106	: m_shaderType	(type)
107	, m_version		(version)
108{
109}
110
111Shader::~Shader (void)
112{
113}
114
115static bool isIllegalVertexInput (const glu::VarType& varType)
116{
117	// booleans, opaque types, arrays, structs are not allowed as inputs
118	if (!varType.isBasicType())
119		return true;
120	if (glu::isDataTypeBoolOrBVec(varType.getBasicType()))
121		return true;
122	return false;
123}
124
125static bool isIllegalVertexOutput (const glu::VarType& varType, bool insideAStruct = false, bool insideAnArray = false)
126{
127	// booleans, opaque types, arrays of arrays, arrays of structs, array in struct, struct struct are not allowed as vertex outputs
128
129	if (varType.isBasicType())
130	{
131		const bool isOpaqueType = !glu::isDataTypeScalar(varType.getBasicType()) && !glu::isDataTypeVector(varType.getBasicType()) && !glu::isDataTypeMatrix(varType.getBasicType());
132
133		if (glu::isDataTypeBoolOrBVec(varType.getBasicType()))
134			return true;
135
136		if (isOpaqueType)
137			return true;
138
139		return false;
140	}
141	else if (varType.isArrayType())
142	{
143		if (insideAnArray || insideAStruct)
144			return true;
145
146		return isIllegalVertexOutput(varType.getElementType(), insideAStruct, true);
147	}
148	else if (varType.isStructType())
149	{
150		if (insideAnArray || insideAStruct)
151			return true;
152
153		for (int ndx = 0; ndx < varType.getStructPtr()->getNumMembers(); ++ndx)
154			if (isIllegalVertexOutput(varType.getStructPtr()->getMember(ndx).getType(), true, insideAnArray))
155				return true;
156
157		return false;
158	}
159	else
160	{
161		DE_ASSERT(false);
162		return true;
163	}
164}
165
166static bool isIllegalFragmentInput (const glu::VarType& varType)
167{
168	return isIllegalVertexOutput(varType);
169}
170
171static bool isIllegalFragmentOutput (const glu::VarType& varType, bool insideAnArray = false)
172{
173	// booleans, opaque types, matrices, structs, arrays of arrays are not allowed as outputs
174
175	if (varType.isBasicType())
176	{
177		const bool isOpaqueType = !glu::isDataTypeScalar(varType.getBasicType()) && !glu::isDataTypeVector(varType.getBasicType()) && !glu::isDataTypeMatrix(varType.getBasicType());
178
179		if (glu::isDataTypeBoolOrBVec(varType.getBasicType()) || isOpaqueType || glu::isDataTypeMatrix(varType.getBasicType()))
180			return true;
181		return false;
182	}
183	else if (varType.isArrayType())
184	{
185		if (insideAnArray)
186			return true;
187		return isIllegalFragmentOutput(varType.getElementType(), true);
188	}
189	else if (varType.isStructType())
190		return true;
191	else
192	{
193		DE_ASSERT(false);
194		return true;
195	}
196}
197
198static bool isTypeIntegerOrContainsIntegers (const glu::VarType& varType)
199{
200	if (varType.isBasicType())
201		return glu::isDataTypeIntOrIVec(varType.getBasicType()) || glu::isDataTypeUintOrUVec(varType.getBasicType());
202	else if (varType.isArrayType())
203		return isTypeIntegerOrContainsIntegers(varType.getElementType());
204	else if (varType.isStructType())
205	{
206		for (int ndx = 0; ndx < varType.getStructPtr()->getNumMembers(); ++ndx)
207			if (isTypeIntegerOrContainsIntegers(varType.getStructPtr()->getMember(ndx).getType()))
208				return true;
209		return false;
210	}
211	else
212	{
213		DE_ASSERT(false);
214		return true;
215	}
216}
217
218bool Shader::isValid (void) const
219{
220	// Default block variables
221	{
222		for (int varNdx = 0; varNdx < (int)m_defaultBlock.variables.size(); ++varNdx)
223		{
224			// atomic declaration in the default block without binding
225			if (m_defaultBlock.variables[varNdx].layout.binding == -1 &&
226				containsMatchingSubtype(m_defaultBlock.variables[varNdx].varType, glu::isDataTypeAtomicCounter))
227				return false;
228
229			// atomic declaration in a struct
230			if (m_defaultBlock.variables[varNdx].varType.isStructType() &&
231				containsMatchingSubtype(m_defaultBlock.variables[varNdx].varType, glu::isDataTypeAtomicCounter))
232				return false;
233
234			// Unsupported layout qualifiers
235
236			if (m_defaultBlock.variables[varNdx].layout.matrixOrder != glu::MATRIXORDER_LAST)
237				return false;
238
239			if (containsMatchingSubtype(m_defaultBlock.variables[varNdx].varType, glu::isDataTypeSampler))
240			{
241				const glu::Layout layoutWithLocationAndBinding(m_defaultBlock.variables[varNdx].layout.location, m_defaultBlock.variables[varNdx].layout.binding);
242
243				if (m_defaultBlock.variables[varNdx].layout != layoutWithLocationAndBinding)
244					return false;
245			}
246		}
247	}
248
249	// Interface blocks
250	{
251		for (int interfaceNdx = 0; interfaceNdx < (int)m_defaultBlock.interfaceBlocks.size(); ++interfaceNdx)
252		{
253			// ES31 disallows interface block array arrays
254			if (m_defaultBlock.interfaceBlocks[interfaceNdx].dimensions.size() > 1)
255				return false;
256
257			// Interface block arrays must have instance name
258			if (!m_defaultBlock.interfaceBlocks[interfaceNdx].dimensions.empty() && m_defaultBlock.interfaceBlocks[interfaceNdx].instanceName.empty())
259				return false;
260
261			// Opaque types in interface block
262			if (containsMatchingSubtype(m_defaultBlock.interfaceBlocks[interfaceNdx].variables, isOpaqueType))
263				return false;
264		}
265	}
266
267	// Shader type specific
268
269	if (m_shaderType == glu::SHADERTYPE_VERTEX)
270	{
271		for (int varNdx = 0; varNdx < (int)m_defaultBlock.variables.size(); ++varNdx)
272		{
273			if (m_defaultBlock.variables[varNdx].storage == glu::STORAGE_IN && isIllegalVertexInput(m_defaultBlock.variables[varNdx].varType))
274				return false;
275			if (m_defaultBlock.variables[varNdx].storage == glu::STORAGE_OUT && isIllegalVertexOutput(m_defaultBlock.variables[varNdx].varType))
276				return false;
277			if (m_defaultBlock.variables[varNdx].storage == glu::STORAGE_OUT && m_defaultBlock.variables[varNdx].interpolation != glu::INTERPOLATION_FLAT && isTypeIntegerOrContainsIntegers(m_defaultBlock.variables[varNdx].varType))
278				return false;
279		}
280		for (int interfaceNdx = 0; interfaceNdx < (int)m_defaultBlock.interfaceBlocks.size(); ++interfaceNdx)
281		{
282			if (m_defaultBlock.interfaceBlocks[interfaceNdx].storage == glu::STORAGE_IN			||
283				m_defaultBlock.interfaceBlocks[interfaceNdx].storage == glu::STORAGE_PATCH_IN	||
284				m_defaultBlock.interfaceBlocks[interfaceNdx].storage == glu::STORAGE_PATCH_OUT)
285			{
286				return false;
287			}
288		}
289	}
290	else if (m_shaderType == glu::SHADERTYPE_FRAGMENT)
291	{
292		for (int varNdx = 0; varNdx < (int)m_defaultBlock.variables.size(); ++varNdx)
293		{
294			if (m_defaultBlock.variables[varNdx].storage == glu::STORAGE_IN && isIllegalFragmentInput(m_defaultBlock.variables[varNdx].varType))
295				return false;
296			if (m_defaultBlock.variables[varNdx].storage == glu::STORAGE_IN && m_defaultBlock.variables[varNdx].interpolation != glu::INTERPOLATION_FLAT && isTypeIntegerOrContainsIntegers(m_defaultBlock.variables[varNdx].varType))
297				return false;
298			if (m_defaultBlock.variables[varNdx].storage == glu::STORAGE_OUT && isIllegalFragmentOutput(m_defaultBlock.variables[varNdx].varType))
299				return false;
300		}
301		for (int interfaceNdx = 0; interfaceNdx < (int)m_defaultBlock.interfaceBlocks.size(); ++interfaceNdx)
302		{
303			if (m_defaultBlock.interfaceBlocks[interfaceNdx].storage == glu::STORAGE_PATCH_IN	||
304				m_defaultBlock.interfaceBlocks[interfaceNdx].storage == glu::STORAGE_OUT		||
305				m_defaultBlock.interfaceBlocks[interfaceNdx].storage == glu::STORAGE_PATCH_OUT)
306			{
307				return false;
308			}
309		}
310	}
311	else if (m_shaderType == glu::SHADERTYPE_COMPUTE)
312	{
313		for (int varNdx = 0; varNdx < (int)m_defaultBlock.variables.size(); ++varNdx)
314		{
315			if (m_defaultBlock.variables[varNdx].storage == glu::STORAGE_IN			||
316				m_defaultBlock.variables[varNdx].storage == glu::STORAGE_PATCH_IN	||
317				m_defaultBlock.variables[varNdx].storage == glu::STORAGE_OUT		||
318				m_defaultBlock.variables[varNdx].storage == glu::STORAGE_PATCH_OUT)
319			{
320				return false;
321			}
322		}
323		for (int interfaceNdx = 0; interfaceNdx < (int)m_defaultBlock.interfaceBlocks.size(); ++interfaceNdx)
324		{
325			if (m_defaultBlock.interfaceBlocks[interfaceNdx].storage == glu::STORAGE_IN			||
326				m_defaultBlock.interfaceBlocks[interfaceNdx].storage == glu::STORAGE_PATCH_IN	||
327				m_defaultBlock.interfaceBlocks[interfaceNdx].storage == glu::STORAGE_OUT		||
328				m_defaultBlock.interfaceBlocks[interfaceNdx].storage == glu::STORAGE_PATCH_OUT)
329			{
330				return false;
331			}
332		}
333	}
334	else if (m_shaderType == glu::SHADERTYPE_GEOMETRY)
335	{
336		for (int varNdx = 0; varNdx < (int)m_defaultBlock.variables.size(); ++varNdx)
337		{
338			if (m_defaultBlock.variables[varNdx].storage == glu::STORAGE_PATCH_IN	||
339				m_defaultBlock.variables[varNdx].storage == glu::STORAGE_PATCH_OUT)
340			{
341				return false;
342			}
343			// arrayed input
344			if (m_defaultBlock.variables[varNdx].storage == glu::STORAGE_IN && !m_defaultBlock.variables[varNdx].varType.isArrayType())
345				return false;
346		}
347		for (int interfaceNdx = 0; interfaceNdx < (int)m_defaultBlock.interfaceBlocks.size(); ++interfaceNdx)
348		{
349			if (m_defaultBlock.interfaceBlocks[interfaceNdx].storage == glu::STORAGE_PATCH_IN	||
350				m_defaultBlock.interfaceBlocks[interfaceNdx].storage == glu::STORAGE_PATCH_OUT)
351			{
352				return false;
353			}
354			// arrayed input
355			if (m_defaultBlock.interfaceBlocks[interfaceNdx].storage == glu::STORAGE_IN && m_defaultBlock.interfaceBlocks[interfaceNdx].dimensions.empty())
356				return false;
357		}
358	}
359	else if (m_shaderType == glu::SHADERTYPE_TESSELLATION_CONTROL)
360	{
361		for (int varNdx = 0; varNdx < (int)m_defaultBlock.variables.size(); ++varNdx)
362		{
363			if (m_defaultBlock.variables[varNdx].storage == glu::STORAGE_PATCH_IN)
364				return false;
365			// arrayed input
366			if (m_defaultBlock.variables[varNdx].storage == glu::STORAGE_IN && !m_defaultBlock.variables[varNdx].varType.isArrayType())
367				return false;
368			// arrayed output
369			if (m_defaultBlock.variables[varNdx].storage == glu::STORAGE_OUT && !m_defaultBlock.variables[varNdx].varType.isArrayType())
370				return false;
371		}
372		for (int interfaceNdx = 0; interfaceNdx < (int)m_defaultBlock.interfaceBlocks.size(); ++interfaceNdx)
373		{
374			if (m_defaultBlock.interfaceBlocks[interfaceNdx].storage == glu::STORAGE_PATCH_IN)
375				return false;
376			// arrayed input
377			if (m_defaultBlock.interfaceBlocks[interfaceNdx].storage == glu::STORAGE_IN && m_defaultBlock.interfaceBlocks[interfaceNdx].dimensions.empty())
378				return false;
379			// arrayed output
380			if (m_defaultBlock.interfaceBlocks[interfaceNdx].storage == glu::STORAGE_OUT && m_defaultBlock.interfaceBlocks[interfaceNdx].dimensions.empty())
381				return false;
382		}
383	}
384	else if (m_shaderType == glu::SHADERTYPE_TESSELLATION_EVALUATION)
385	{
386		for (int varNdx = 0; varNdx < (int)m_defaultBlock.variables.size(); ++varNdx)
387		{
388			if (m_defaultBlock.variables[varNdx].storage == glu::STORAGE_PATCH_OUT)
389				return false;
390			// arrayed input
391			if (m_defaultBlock.variables[varNdx].storage == glu::STORAGE_IN && !m_defaultBlock.variables[varNdx].varType.isArrayType())
392				return false;
393		}
394		for (int interfaceNdx = 0; interfaceNdx < (int)m_defaultBlock.interfaceBlocks.size(); ++interfaceNdx)
395		{
396			if (m_defaultBlock.interfaceBlocks[interfaceNdx].storage == glu::STORAGE_PATCH_OUT)
397				return false;
398			// arrayed input
399			if (m_defaultBlock.interfaceBlocks[interfaceNdx].storage == glu::STORAGE_IN && m_defaultBlock.interfaceBlocks[interfaceNdx].dimensions.empty())
400				return false;
401		}
402	}
403	else
404		DE_ASSERT(false);
405
406	return true;
407}
408
409Program::Program (void)
410	: m_separable				(false)
411	, m_xfbMode					(0)
412	, m_geoNumOutputVertices	(0)
413	, m_tessNumOutputVertices	(0)
414{
415}
416
417static void collectStructPtrs (std::set<const glu::StructType*>& dst, const glu::VarType& type)
418{
419	if (type.isArrayType())
420		collectStructPtrs(dst, type.getElementType());
421	else if (type.isStructType())
422	{
423		dst.insert(type.getStructPtr());
424
425		for (int memberNdx = 0; memberNdx < type.getStructPtr()->getNumMembers(); ++memberNdx)
426			collectStructPtrs(dst, type.getStructPtr()->getMember(memberNdx).getType());
427	}
428}
429
430Program::~Program (void)
431{
432	// delete shader struct types, need to be done by the program since shaders might share struct types
433	{
434		std::set<const glu::StructType*> structTypes;
435
436		for (int shaderNdx = 0; shaderNdx < (int)m_shaders.size(); ++shaderNdx)
437		{
438			for (int varNdx = 0; varNdx < (int)m_shaders[shaderNdx]->m_defaultBlock.variables.size(); ++varNdx)
439				collectStructPtrs(structTypes, m_shaders[shaderNdx]->m_defaultBlock.variables[varNdx].varType);
440
441			for (int interfaceNdx = 0; interfaceNdx < (int)m_shaders[shaderNdx]->m_defaultBlock.interfaceBlocks.size(); ++interfaceNdx)
442				for (int varNdx = 0; varNdx < (int)m_shaders[shaderNdx]->m_defaultBlock.interfaceBlocks[interfaceNdx].variables.size(); ++varNdx)
443					collectStructPtrs(structTypes, m_shaders[shaderNdx]->m_defaultBlock.interfaceBlocks[interfaceNdx].variables[varNdx].varType);
444		}
445
446		for (std::set<const glu::StructType*>::iterator it = structTypes.begin(); it != structTypes.end(); ++it)
447			delete *it;
448	}
449
450	for (int shaderNdx = 0; shaderNdx < (int)m_shaders.size(); ++shaderNdx)
451		delete m_shaders[shaderNdx];
452	m_shaders.clear();
453}
454
455Shader* Program::addShader (glu::ShaderType type, glu::GLSLVersion version)
456{
457	DE_ASSERT(type < glu::SHADERTYPE_LAST);
458
459	Shader* shader;
460
461	// make sure push_back() cannot throw
462	m_shaders.reserve(m_shaders.size() + 1);
463
464	shader = new Shader(type, version);
465	m_shaders.push_back(shader);
466
467	return shader;
468}
469
470void Program::setSeparable (bool separable)
471{
472	m_separable = separable;
473}
474
475bool Program::isSeparable (void) const
476{
477	return m_separable;
478}
479
480const std::vector<Shader*>& Program::getShaders (void) const
481{
482	return m_shaders;
483}
484
485glu::ShaderType Program::getFirstStage (void) const
486{
487	const int	nullValue	= DE_LENGTH_OF_ARRAY(s_shaderStageOrder);
488	int			firstStage	= nullValue;
489
490	for (int shaderNdx = 0; shaderNdx < (int)m_shaders.size(); ++shaderNdx)
491	{
492		const int index = getShaderStageIndex(m_shaders[shaderNdx]->getType());
493		if (index != -1)
494			firstStage = de::min(firstStage, index);
495	}
496
497	if (firstStage == nullValue)
498		return glu::SHADERTYPE_LAST;
499	else
500		return s_shaderStageOrder[firstStage];
501}
502
503glu::ShaderType Program::getLastStage (void) const
504{
505	const int	nullValue	= -1;
506	int			lastStage	= nullValue;
507
508	for (int shaderNdx = 0; shaderNdx < (int)m_shaders.size(); ++shaderNdx)
509	{
510		const int index = getShaderStageIndex(m_shaders[shaderNdx]->getType());
511		if (index != -1)
512			lastStage = de::max(lastStage, index);
513	}
514
515	if (lastStage == nullValue)
516		return glu::SHADERTYPE_LAST;
517	else
518		return s_shaderStageOrder[lastStage];
519}
520
521bool Program::hasStage (glu::ShaderType stage) const
522{
523	for (int shaderNdx = 0; shaderNdx < (int)m_shaders.size(); ++shaderNdx)
524	{
525		if (m_shaders[shaderNdx]->getType() == stage)
526			return true;
527	}
528	return false;
529}
530
531void Program::addTransformFeedbackVarying (const std::string& varName)
532{
533	m_xfbVaryings.push_back(varName);
534}
535
536const std::vector<std::string>& Program::getTransformFeedbackVaryings (void) const
537{
538	return m_xfbVaryings;
539}
540
541void Program::setTransformFeedbackMode (deUint32 mode)
542{
543	m_xfbMode = mode;
544}
545
546deUint32 Program::getTransformFeedbackMode (void) const
547{
548	return m_xfbMode;
549}
550
551deUint32 Program::getGeometryNumOutputVertices (void) const
552{
553	return m_geoNumOutputVertices;
554}
555
556void Program::setGeometryNumOutputVertices (deUint32 vertices)
557{
558	m_geoNumOutputVertices = vertices;
559}
560
561deUint32 Program::getTessellationNumOutputPatchVertices (void) const
562{
563	return m_tessNumOutputVertices;
564}
565
566void Program::setTessellationNumOutputPatchVertices (deUint32 vertices)
567{
568	m_tessNumOutputVertices = vertices;
569}
570
571bool Program::isValid (void) const
572{
573	const bool	isOpenGLES			= (m_shaders.empty()) ? (false) : (glu::glslVersionIsES(m_shaders[0]->getVersion()));
574	bool		computePresent		= false;
575	bool		vertexPresent		= false;
576	bool		fragmentPresent		= false;
577	bool		tessControlPresent	= false;
578	bool		tessEvalPresent		= false;
579	bool		geometryPresent		= false;
580
581	if (m_shaders.empty())
582		return false;
583
584	for (int ndx = 0; ndx < (int)m_shaders.size(); ++ndx)
585		if (!m_shaders[ndx]->isValid())
586			return false;
587
588	// same version
589	for (int ndx = 1; ndx < (int)m_shaders.size(); ++ndx)
590		if (m_shaders[0]->getVersion() != m_shaders[ndx]->getVersion())
591			return false;
592
593	for (int ndx = 0; ndx < (int)m_shaders.size(); ++ndx)
594	{
595		switch (m_shaders[ndx]->getType())
596		{
597			case glu::SHADERTYPE_COMPUTE:					computePresent = true;		break;
598			case glu::SHADERTYPE_VERTEX:					vertexPresent = true;		break;
599			case glu::SHADERTYPE_FRAGMENT:					fragmentPresent = true;		break;
600			case glu::SHADERTYPE_TESSELLATION_CONTROL:		tessControlPresent = true;	break;
601			case glu::SHADERTYPE_TESSELLATION_EVALUATION:	tessEvalPresent = true;		break;
602			case glu::SHADERTYPE_GEOMETRY:					geometryPresent = true;		break;
603			default:
604				DE_ASSERT(false);
605				break;
606		}
607	}
608	// compute present -> no other stages present
609	{
610		const bool nonComputePresent = vertexPresent || fragmentPresent || tessControlPresent || tessEvalPresent || geometryPresent;
611		if (computePresent && nonComputePresent)
612			return false;
613	}
614
615	// must contain both vertex and fragment shaders
616	if (!computePresent && !m_separable)
617	{
618		if (!vertexPresent || !fragmentPresent)
619			return false;
620	}
621
622	// tess.Eval present <=> tess.Control present
623	if (!m_separable)
624	{
625		if (tessEvalPresent != tessControlPresent)
626			return false;
627	}
628
629	if ((m_tessNumOutputVertices != 0) != (tessControlPresent || tessEvalPresent))
630		return false;
631
632	if ((m_geoNumOutputVertices != 0) != geometryPresent)
633		return false;
634
635	for (int ndx = 0; ndx < (int)m_xfbVaryings.size(); ++ndx)
636	{
637		// user-defined
638		if (!de::beginsWith(m_xfbVaryings[ndx], "gl_"))
639		{
640			std::vector<ProgramInterfaceDefinition::VariablePathComponent> path;
641			if (!findProgramVariablePathByPathName(path, this, m_xfbVaryings[ndx], VariableSearchFilter::createShaderTypeStorageFilter(getProgramTransformFeedbackStage(this), glu::STORAGE_OUT)))
642				return false;
643			if (!path.back().isVariableType())
644				return false;
645
646			// Khronos bug #12787 disallowed capturing whole structs in OpenGL ES.
647			if (path.back().getVariableType()->isStructType() && isOpenGLES)
648				return false;
649		}
650	}
651
652	return true;
653}
654
655} // ProgramInterfaceDefinition
656} // Functional
657} // gles31
658} // deqp
659