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