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