Fix PIPELINE_STAGE_TOP_OF_PIPE_BIT usage in api tests
[platform/upstream/VK-GL-CTS.git] / modules / gles31 / functional / es31fProgramInterfaceDefinition.cpp
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
34 namespace deqp
35 {
36 namespace gles31
37 {
38 namespace Functional
39 {
40 namespace ProgramInterfaceDefinition
41 {
42 namespace
43 {
44
45 static 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
57 DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(s_shaderStageOrder) == glu::SHADERTYPE_LAST);
58
59 static 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
75 static 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
83 static bool isOpaqueType (glu::DataType type)
84 {
85         return  glu::isDataTypeAtomicCounter(type)      ||
86                         glu::isDataTypeImage(type)                      ||
87                         glu::isDataTypeSampler(type);
88 }
89
90 static 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
105 Shader::Shader (glu::ShaderType type, glu::GLSLVersion version)
106         : m_shaderType  (type)
107         , m_version             (version)
108 {
109 }
110
111 Shader::~Shader (void)
112 {
113 }
114
115 static 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
125 static 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
166 static bool isIllegalFragmentInput (const glu::VarType& varType)
167 {
168         return isIllegalVertexOutput(varType);
169 }
170
171 static 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
198 static 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
218 bool 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
409 Program::Program (void)
410         : m_separable                           (false)
411         , m_xfbMode                                     (0)
412         , m_geoNumOutputVertices        (0)
413         , m_tessNumOutputVertices       (0)
414 {
415 }
416
417 static 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
430 Program::~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
455 Shader* 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
470 void Program::setSeparable (bool separable)
471 {
472         m_separable = separable;
473 }
474
475 bool Program::isSeparable (void) const
476 {
477         return m_separable;
478 }
479
480 const std::vector<Shader*>& Program::getShaders (void) const
481 {
482         return m_shaders;
483 }
484
485 glu::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
503 glu::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
521 bool 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
531 void Program::addTransformFeedbackVarying (const std::string& varName)
532 {
533         m_xfbVaryings.push_back(varName);
534 }
535
536 const std::vector<std::string>& Program::getTransformFeedbackVaryings (void) const
537 {
538         return m_xfbVaryings;
539 }
540
541 void Program::setTransformFeedbackMode (deUint32 mode)
542 {
543         m_xfbMode = mode;
544 }
545
546 deUint32 Program::getTransformFeedbackMode (void) const
547 {
548         return m_xfbMode;
549 }
550
551 deUint32 Program::getGeometryNumOutputVertices (void) const
552 {
553         return m_geoNumOutputVertices;
554 }
555
556 void Program::setGeometryNumOutputVertices (deUint32 vertices)
557 {
558         m_geoNumOutputVertices = vertices;
559 }
560
561 deUint32 Program::getTessellationNumOutputPatchVertices (void) const
562 {
563         return m_tessNumOutputVertices;
564 }
565
566 void Program::setTessellationNumOutputPatchVertices (deUint32 vertices)
567 {
568         m_tessNumOutputVertices = vertices;
569 }
570
571 bool 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