• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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