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