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