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
containsMatchingSubtype(const glu::VarType & varType,bool (* predicate)(glu::DataType))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
containsMatchingSubtype(const std::vector<glu::VariableDeclaration> & decls,bool (* predicate)(glu::DataType))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
isOpaqueType(glu::DataType type)83 static bool isOpaqueType (glu::DataType type)
84 {
85 return glu::isDataTypeAtomicCounter(type) ||
86 glu::isDataTypeImage(type) ||
87 glu::isDataTypeSampler(type);
88 }
89
getShaderStageIndex(glu::ShaderType stage)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
Shader(glu::ShaderType type,glu::GLSLVersion version)105 Shader::Shader (glu::ShaderType type, glu::GLSLVersion version)
106 : m_shaderType (type)
107 , m_version (version)
108 {
109 }
110
~Shader(void)111 Shader::~Shader (void)
112 {
113 }
114
isIllegalVertexInput(const glu::VarType & varType)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
isIllegalVertexOutput(const glu::VarType & varType,bool insideAStruct=false,bool insideAnArray=false)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
isIllegalFragmentInput(const glu::VarType & varType)166 static bool isIllegalFragmentInput (const glu::VarType& varType)
167 {
168 return isIllegalVertexOutput(varType);
169 }
170
isIllegalFragmentOutput(const glu::VarType & varType,bool insideAnArray=false)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
isTypeIntegerOrContainsIntegers(const glu::VarType & varType)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
isValid(void) const218 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
Program(void)409 Program::Program (void)
410 : m_separable (false)
411 , m_xfbMode (0)
412 , m_geoNumOutputVertices (0)
413 , m_tessNumOutputVertices (0)
414 {
415 }
416
collectStructPtrs(std::set<const glu::StructType * > & dst,const glu::VarType & type)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
~Program(void)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
addShader(glu::ShaderType type,glu::GLSLVersion version)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
setSeparable(bool separable)470 void Program::setSeparable (bool separable)
471 {
472 m_separable = separable;
473 }
474
isSeparable(void) const475 bool Program::isSeparable (void) const
476 {
477 return m_separable;
478 }
479
getShaders(void) const480 const std::vector<Shader*>& Program::getShaders (void) const
481 {
482 return m_shaders;
483 }
484
getFirstStage(void) const485 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
getLastStage(void) const503 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
hasStage(glu::ShaderType stage) const521 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
addTransformFeedbackVarying(const std::string & varName)531 void Program::addTransformFeedbackVarying (const std::string& varName)
532 {
533 m_xfbVaryings.push_back(varName);
534 }
535
getTransformFeedbackVaryings(void) const536 const std::vector<std::string>& Program::getTransformFeedbackVaryings (void) const
537 {
538 return m_xfbVaryings;
539 }
540
setTransformFeedbackMode(deUint32 mode)541 void Program::setTransformFeedbackMode (deUint32 mode)
542 {
543 m_xfbMode = mode;
544 }
545
getTransformFeedbackMode(void) const546 deUint32 Program::getTransformFeedbackMode (void) const
547 {
548 return m_xfbMode;
549 }
550
getGeometryNumOutputVertices(void) const551 deUint32 Program::getGeometryNumOutputVertices (void) const
552 {
553 return m_geoNumOutputVertices;
554 }
555
setGeometryNumOutputVertices(deUint32 vertices)556 void Program::setGeometryNumOutputVertices (deUint32 vertices)
557 {
558 m_geoNumOutputVertices = vertices;
559 }
560
getTessellationNumOutputPatchVertices(void) const561 deUint32 Program::getTessellationNumOutputPatchVertices (void) const
562 {
563 return m_tessNumOutputVertices;
564 }
565
setTessellationNumOutputPatchVertices(deUint32 vertices)566 void Program::setTessellationNumOutputPatchVertices (deUint32 vertices)
567 {
568 m_tessNumOutputVertices = vertices;
569 }
570
isValid(void) const571 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
659