• 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 "gluVarType.hpp"
26 #include "gluShaderProgram.hpp"
27 #include "deSTLUtil.hpp"
28 #include "glwEnums.hpp"
29 
30 #include <set>
31 
32 namespace deqp
33 {
34 namespace gles31
35 {
36 namespace Functional
37 {
38 namespace ProgramInterfaceDefinition
39 {
40 namespace
41 {
42 
43 static const glu::ShaderType s_shaderStageOrder[] =
44 {
45 	glu::SHADERTYPE_COMPUTE,
46 
47 	glu::SHADERTYPE_VERTEX,
48 	glu::SHADERTYPE_TESSELLATION_CONTROL,
49 	glu::SHADERTYPE_TESSELLATION_EVALUATION,
50 	glu::SHADERTYPE_GEOMETRY,
51 	glu::SHADERTYPE_FRAGMENT
52 };
53 
54 // s_shaderStageOrder does not contain ShaderType_LAST
55 DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(s_shaderStageOrder) == glu::SHADERTYPE_LAST);
56 
containsMatchingSubtype(const glu::VarType & varType,bool (* predicate)(glu::DataType))57 static bool containsMatchingSubtype (const glu::VarType& varType, bool (*predicate)(glu::DataType))
58 {
59 	if (varType.isBasicType() && predicate(varType.getBasicType()))
60 		return true;
61 
62 	if (varType.isArrayType())
63 		return containsMatchingSubtype(varType.getElementType(), predicate);
64 
65 	if (varType.isStructType())
66 		for (int memberNdx = 0; memberNdx < varType.getStructPtr()->getNumMembers(); ++memberNdx)
67 			if (containsMatchingSubtype(varType.getStructPtr()->getMember(memberNdx).getType(), predicate))
68 				return true;
69 
70 	return false;
71 }
72 
containsMatchingSubtype(const std::vector<glu::VariableDeclaration> & decls,bool (* predicate)(glu::DataType))73 static bool containsMatchingSubtype (const std::vector<glu::VariableDeclaration>& decls, bool (*predicate)(glu::DataType))
74 {
75 	for (int varNdx = 0; varNdx < (int)decls.size(); ++varNdx)
76 		if (containsMatchingSubtype(decls[varNdx].varType, predicate))
77 			return true;
78 	return false;
79 }
80 
isOpaqueType(glu::DataType type)81 static bool isOpaqueType (glu::DataType type)
82 {
83 	return	glu::isDataTypeAtomicCounter(type)	||
84 			glu::isDataTypeImage(type)			||
85 			glu::isDataTypeSampler(type);
86 }
87 
getShaderStageIndex(glu::ShaderType stage)88 static int getShaderStageIndex (glu::ShaderType stage)
89 {
90 	const glu::ShaderType* const it = std::find(DE_ARRAY_BEGIN(s_shaderStageOrder), DE_ARRAY_END(s_shaderStageOrder), stage);
91 
92 	if (it == DE_ARRAY_END(s_shaderStageOrder))
93 		return -1;
94 	else
95 	{
96 		const int index = (int)(it - DE_ARRAY_BEGIN(s_shaderStageOrder));
97 		return index;
98 	}
99 }
100 
101 } // anonymous
102 
Shader(glu::ShaderType type,glu::GLSLVersion version)103 Shader::Shader (glu::ShaderType type, glu::GLSLVersion version)
104 	: m_shaderType	(type)
105 	, m_version		(version)
106 {
107 }
108 
~Shader(void)109 Shader::~Shader (void)
110 {
111 }
112 
isIllegalVertexInput(const glu::VarType & varType)113 static bool isIllegalVertexInput (const glu::VarType& varType)
114 {
115 	// booleans, opaque types, arrays, structs are not allowed as inputs
116 	if (!varType.isBasicType())
117 		return true;
118 	if (glu::isDataTypeBoolOrBVec(varType.getBasicType()))
119 		return true;
120 	return false;
121 }
122 
isIllegalVertexOutput(const glu::VarType & varType,bool insideAStruct=false,bool insideAnArray=false)123 static bool isIllegalVertexOutput (const glu::VarType& varType, bool insideAStruct = false, bool insideAnArray = false)
124 {
125 	// booleans, opaque types, arrays of arrays, arrays of structs, array in struct, struct struct are not allowed as vertex outputs
126 
127 	if (varType.isBasicType())
128 	{
129 		const bool isOpaqueType = !glu::isDataTypeScalar(varType.getBasicType()) && !glu::isDataTypeVector(varType.getBasicType()) && !glu::isDataTypeMatrix(varType.getBasicType());
130 
131 		if (glu::isDataTypeBoolOrBVec(varType.getBasicType()))
132 			return true;
133 
134 		if (isOpaqueType)
135 			return true;
136 
137 		return false;
138 	}
139 	else if (varType.isArrayType())
140 	{
141 		if (insideAnArray || insideAStruct)
142 			return true;
143 
144 		return isIllegalVertexOutput(varType.getElementType(), insideAStruct, true);
145 	}
146 	else if (varType.isStructType())
147 	{
148 		if (insideAnArray || insideAStruct)
149 			return true;
150 
151 		for (int ndx = 0; ndx < varType.getStructPtr()->getNumMembers(); ++ndx)
152 			if (isIllegalVertexOutput(varType.getStructPtr()->getMember(ndx).getType(), true, insideAnArray))
153 				return true;
154 
155 		return false;
156 	}
157 	else
158 	{
159 		DE_ASSERT(false);
160 		return true;
161 	}
162 }
163 
isIllegalFragmentInput(const glu::VarType & varType)164 static bool isIllegalFragmentInput (const glu::VarType& varType)
165 {
166 	return isIllegalVertexOutput(varType);
167 }
168 
isIllegalFragmentOutput(const glu::VarType & varType,bool insideAnArray=false)169 static bool isIllegalFragmentOutput (const glu::VarType& varType, bool insideAnArray = false)
170 {
171 	// booleans, opaque types, matrices, structs, arrays of arrays are not allowed as outputs
172 
173 	if (varType.isBasicType())
174 	{
175 		const bool isOpaqueType = !glu::isDataTypeScalar(varType.getBasicType()) && !glu::isDataTypeVector(varType.getBasicType()) && !glu::isDataTypeMatrix(varType.getBasicType());
176 
177 		if (glu::isDataTypeBoolOrBVec(varType.getBasicType()) || isOpaqueType || glu::isDataTypeMatrix(varType.getBasicType()))
178 			return true;
179 		return false;
180 	}
181 	else if (varType.isArrayType())
182 	{
183 		if (insideAnArray)
184 			return true;
185 		return isIllegalFragmentOutput(varType.getElementType(), true);
186 	}
187 	else if (varType.isStructType())
188 		return true;
189 	else
190 	{
191 		DE_ASSERT(false);
192 		return true;
193 	}
194 }
195 
isTypeIntegerOrContainsIntegers(const glu::VarType & varType)196 static bool isTypeIntegerOrContainsIntegers (const glu::VarType& varType)
197 {
198 	if (varType.isBasicType())
199 		return glu::isDataTypeIntOrIVec(varType.getBasicType()) || glu::isDataTypeUintOrUVec(varType.getBasicType());
200 	else if (varType.isArrayType())
201 		return isTypeIntegerOrContainsIntegers(varType.getElementType());
202 	else if (varType.isStructType())
203 	{
204 		for (int ndx = 0; ndx < varType.getStructPtr()->getNumMembers(); ++ndx)
205 			if (isTypeIntegerOrContainsIntegers(varType.getStructPtr()->getMember(ndx).getType()))
206 				return true;
207 		return false;
208 	}
209 	else
210 	{
211 		DE_ASSERT(false);
212 		return true;
213 	}
214 }
215 
isValid(void) const216 bool Shader::isValid (void) const
217 {
218 	// Default block variables
219 	{
220 		for (int varNdx = 0; varNdx < (int)m_defaultBlock.variables.size(); ++varNdx)
221 		{
222 			// atomic declaration in the default block without binding
223 			if (m_defaultBlock.variables[varNdx].layout.binding == -1 &&
224 				containsMatchingSubtype(m_defaultBlock.variables[varNdx].varType, glu::isDataTypeAtomicCounter))
225 				return false;
226 
227 			// atomic declaration in a struct
228 			if (m_defaultBlock.variables[varNdx].varType.isStructType() &&
229 				containsMatchingSubtype(m_defaultBlock.variables[varNdx].varType, glu::isDataTypeAtomicCounter))
230 				return false;
231 
232 			// Unsupported layout qualifiers
233 
234 			if (m_defaultBlock.variables[varNdx].layout.matrixOrder != glu::MATRIXORDER_LAST)
235 				return false;
236 
237 			if (containsMatchingSubtype(m_defaultBlock.variables[varNdx].varType, glu::isDataTypeSampler))
238 			{
239 				const glu::Layout layoutWithLocationAndBinding(m_defaultBlock.variables[varNdx].layout.location, m_defaultBlock.variables[varNdx].layout.binding);
240 
241 				if (m_defaultBlock.variables[varNdx].layout != layoutWithLocationAndBinding)
242 					return false;
243 			}
244 		}
245 	}
246 
247 	// Interface blocks
248 	{
249 		for (int interfaceNdx = 0; interfaceNdx < (int)m_defaultBlock.interfaceBlocks.size(); ++interfaceNdx)
250 		{
251 			// ES31 disallows interface block array arrays
252 			if (m_defaultBlock.interfaceBlocks[interfaceNdx].dimensions.size() > 1)
253 				return false;
254 
255 			// Interface block arrays must have instance name
256 			if (!m_defaultBlock.interfaceBlocks[interfaceNdx].dimensions.empty() && m_defaultBlock.interfaceBlocks[interfaceNdx].instanceName.empty())
257 				return false;
258 
259 			// Opaque types in interface block
260 			if (containsMatchingSubtype(m_defaultBlock.interfaceBlocks[interfaceNdx].variables, isOpaqueType))
261 				return false;
262 		}
263 	}
264 
265 	// Shader type specific
266 
267 	if (m_shaderType == glu::SHADERTYPE_VERTEX)
268 	{
269 		for (int varNdx = 0; varNdx < (int)m_defaultBlock.variables.size(); ++varNdx)
270 		{
271 			if (m_defaultBlock.variables[varNdx].storage == glu::STORAGE_IN && isIllegalVertexInput(m_defaultBlock.variables[varNdx].varType))
272 				return false;
273 			if (m_defaultBlock.variables[varNdx].storage == glu::STORAGE_OUT && isIllegalVertexOutput(m_defaultBlock.variables[varNdx].varType))
274 				return false;
275 			if (m_defaultBlock.variables[varNdx].storage == glu::STORAGE_OUT && m_defaultBlock.variables[varNdx].interpolation != glu::INTERPOLATION_FLAT && isTypeIntegerOrContainsIntegers(m_defaultBlock.variables[varNdx].varType))
276 				return false;
277 		}
278 	}
279 	else if (m_shaderType == glu::SHADERTYPE_FRAGMENT)
280 	{
281 		for (int varNdx = 0; varNdx < (int)m_defaultBlock.variables.size(); ++varNdx)
282 		{
283 			if (m_defaultBlock.variables[varNdx].storage == glu::STORAGE_IN && isIllegalFragmentInput(m_defaultBlock.variables[varNdx].varType))
284 				return false;
285 			if (m_defaultBlock.variables[varNdx].storage == glu::STORAGE_IN && m_defaultBlock.variables[varNdx].interpolation != glu::INTERPOLATION_FLAT && isTypeIntegerOrContainsIntegers(m_defaultBlock.variables[varNdx].varType))
286 				return false;
287 			if (m_defaultBlock.variables[varNdx].storage == glu::STORAGE_OUT && isIllegalFragmentOutput(m_defaultBlock.variables[varNdx].varType))
288 				return false;
289 		}
290 	}
291 
292 	return true;
293 }
294 
Program(void)295 Program::Program (void)
296 	: m_separable	(false)
297 	, m_xfbMode		(0)
298 {
299 }
300 
collectStructPtrs(std::set<const glu::StructType * > & dst,const glu::VarType & type)301 static void collectStructPtrs (std::set<const glu::StructType*>& dst, const glu::VarType& type)
302 {
303 	if (type.isArrayType())
304 		collectStructPtrs(dst, type.getElementType());
305 	else if (type.isStructType())
306 	{
307 		dst.insert(type.getStructPtr());
308 
309 		for (int memberNdx = 0; memberNdx < type.getStructPtr()->getNumMembers(); ++memberNdx)
310 			collectStructPtrs(dst, type.getStructPtr()->getMember(memberNdx).getType());
311 	}
312 }
313 
~Program(void)314 Program::~Program (void)
315 {
316 	// delete shader struct types, need to be done by the program since shaders might share struct types
317 	{
318 		std::set<const glu::StructType*> structTypes;
319 
320 		for (int shaderNdx = 0; shaderNdx < (int)m_shaders.size(); ++shaderNdx)
321 		{
322 			for (int varNdx = 0; varNdx < (int)m_shaders[shaderNdx]->m_defaultBlock.variables.size(); ++varNdx)
323 				collectStructPtrs(structTypes, m_shaders[shaderNdx]->m_defaultBlock.variables[varNdx].varType);
324 
325 			for (int interfaceNdx = 0; interfaceNdx < (int)m_shaders[shaderNdx]->m_defaultBlock.interfaceBlocks.size(); ++interfaceNdx)
326 				for (int varNdx = 0; varNdx < (int)m_shaders[shaderNdx]->m_defaultBlock.interfaceBlocks[interfaceNdx].variables.size(); ++varNdx)
327 					collectStructPtrs(structTypes, m_shaders[shaderNdx]->m_defaultBlock.interfaceBlocks[interfaceNdx].variables[varNdx].varType);
328 		}
329 
330 		for (std::set<const glu::StructType*>::iterator it = structTypes.begin(); it != structTypes.end(); ++it)
331 			delete *it;
332 	}
333 
334 	for (int shaderNdx = 0; shaderNdx < (int)m_shaders.size(); ++shaderNdx)
335 		delete m_shaders[shaderNdx];
336 	m_shaders.clear();
337 }
338 
addShader(glu::ShaderType type,glu::GLSLVersion version)339 Shader* Program::addShader (glu::ShaderType type, glu::GLSLVersion version)
340 {
341 	Shader* shader;
342 
343 	// make sure push_back() cannot throw
344 	m_shaders.reserve(m_shaders.size() + 1);
345 
346 	shader = new Shader(type, version);
347 	m_shaders.push_back(shader);
348 
349 	return shader;
350 }
351 
setSeparable(bool separable)352 void Program::setSeparable (bool separable)
353 {
354 	m_separable = separable;
355 }
356 
isSeparable(void) const357 bool Program::isSeparable (void) const
358 {
359 	return m_separable;
360 }
361 
getShaders(void) const362 const std::vector<Shader*>& Program::getShaders (void) const
363 {
364 	return m_shaders;
365 }
366 
getFirstStage(void) const367 glu::ShaderType Program::getFirstStage (void) const
368 {
369 	const int	nullValue	= DE_LENGTH_OF_ARRAY(s_shaderStageOrder);
370 	int			firstStage	= nullValue;
371 
372 	for (int shaderNdx = 0; shaderNdx < (int)m_shaders.size(); ++shaderNdx)
373 	{
374 		const int index = getShaderStageIndex(m_shaders[shaderNdx]->getType());
375 		if (index != -1)
376 			firstStage = de::min(firstStage, index);
377 	}
378 
379 	if (firstStage == nullValue)
380 		return glu::SHADERTYPE_LAST;
381 	else
382 		return s_shaderStageOrder[firstStage];
383 }
384 
getLastStage(void) const385 glu::ShaderType Program::getLastStage (void) const
386 {
387 	const int	nullValue	= -1;
388 	int			lastStage	= nullValue;
389 
390 	for (int shaderNdx = 0; shaderNdx < (int)m_shaders.size(); ++shaderNdx)
391 	{
392 		const int index = getShaderStageIndex(m_shaders[shaderNdx]->getType());
393 		if (index != -1)
394 			lastStage = de::max(lastStage, index);
395 	}
396 
397 	if (lastStage == nullValue)
398 		return glu::SHADERTYPE_LAST;
399 	else
400 		return s_shaderStageOrder[lastStage];
401 }
402 
addTransformFeedbackVarying(const std::string & varName)403 void Program::addTransformFeedbackVarying (const std::string& varName)
404 {
405 	m_xfbVaryings.push_back(varName);
406 }
407 
getTransformFeedbackVaryings(void) const408 const std::vector<std::string>& Program::getTransformFeedbackVaryings (void) const
409 {
410 	return m_xfbVaryings;
411 }
412 
setTransformFeedbackMode(deUint32 mode)413 void Program::setTransformFeedbackMode (deUint32 mode)
414 {
415 	m_xfbMode = mode;
416 }
417 
getTransformFeedbackMode(void) const418 deUint32 Program::getTransformFeedbackMode (void) const
419 {
420 	return m_xfbMode;
421 }
422 
isValid(void) const423 bool Program::isValid (void) const
424 {
425 	bool computePresent = false;
426 
427 	if (m_shaders.empty())
428 		return false;
429 
430 	for (int ndx = 0; ndx < (int)m_shaders.size(); ++ndx)
431 		if (!m_shaders[ndx]->isValid())
432 			return false;
433 
434 	// same version
435 	for (int ndx = 1; ndx < (int)m_shaders.size(); ++ndx)
436 		if (m_shaders[0]->getVersion() != m_shaders[ndx]->getVersion())
437 			return false;
438 
439 	// compute present -> no other stages present
440 	{
441 		bool nonComputePresent = false;
442 
443 		for (int ndx = 0; ndx < (int)m_shaders.size(); ++ndx)
444 		{
445 			if (m_shaders[ndx]->getType() == glu::SHADERTYPE_COMPUTE)
446 				computePresent = true;
447 			else
448 				nonComputePresent = true;
449 		}
450 
451 		if (computePresent && nonComputePresent)
452 			return false;
453 	}
454 
455 	// must contain both vertex and fragment shaders
456 	if (!computePresent && !m_separable)
457 	{
458 		bool vertexPresent = false;
459 		bool fragmentPresent = false;
460 
461 		for (int ndx = 0; ndx < (int)m_shaders.size(); ++ndx)
462 		{
463 			if (m_shaders[ndx]->getType() == glu::SHADERTYPE_VERTEX)
464 				vertexPresent = true;
465 			else if (m_shaders[ndx]->getType() == glu::SHADERTYPE_FRAGMENT)
466 				fragmentPresent = true;
467 		}
468 
469 		if (!vertexPresent || !fragmentPresent)
470 			return false;
471 	}
472 
473 	// tess.Eval present <=> tess.Control present
474 	{
475 		bool tessEvalPresent = false;
476 		bool tessControlPresent = false;
477 
478 		for (int ndx = 0; ndx < (int)m_shaders.size(); ++ndx)
479 		{
480 			if (m_shaders[ndx]->getType() == glu::SHADERTYPE_TESSELLATION_EVALUATION)
481 				tessEvalPresent = true;
482 			else if (m_shaders[ndx]->getType() == glu::SHADERTYPE_TESSELLATION_CONTROL)
483 				tessControlPresent = true;
484 		}
485 
486 		if (tessEvalPresent != tessControlPresent)
487 			return false;
488 	}
489 
490 	return true;
491 }
492 
493 } // ProgramInterfaceDefinition
494 } // Functional
495 } // gles31
496 } // deqp
497