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