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
32namespace deqp
33{
34namespace gles31
35{
36namespace Functional
37{
38namespace ProgramInterfaceDefinition
39{
40namespace
41{
42
43static 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
55DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(s_shaderStageOrder) == glu::SHADERTYPE_LAST);
56
57static 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
73static 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
81static bool isOpaqueType (glu::DataType type)
82{
83	return	glu::isDataTypeAtomicCounter(type)	||
84			glu::isDataTypeImage(type)			||
85			glu::isDataTypeSampler(type);
86}
87
88static 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
103Shader::Shader (glu::ShaderType type, glu::GLSLVersion version)
104	: m_shaderType	(type)
105	, m_version		(version)
106{
107}
108
109Shader::~Shader (void)
110{
111}
112
113static 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
123static 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
164static bool isIllegalFragmentInput (const glu::VarType& varType)
165{
166	return isIllegalVertexOutput(varType);
167}
168
169static 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
196static 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
216bool 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
295Program::Program (void)
296	: m_separable	(false)
297	, m_xfbMode		(0)
298{
299}
300
301static 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
314Program::~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
339Shader* 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
352void Program::setSeparable (bool separable)
353{
354	m_separable = separable;
355}
356
357bool Program::isSeparable (void) const
358{
359	return m_separable;
360}
361
362const std::vector<Shader*>& Program::getShaders (void) const
363{
364	return m_shaders;
365}
366
367glu::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
385glu::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
403void Program::addTransformFeedbackVarying (const std::string& varName)
404{
405	m_xfbVaryings.push_back(varName);
406}
407
408const std::vector<std::string>& Program::getTransformFeedbackVaryings (void) const
409{
410	return m_xfbVaryings;
411}
412
413void Program::setTransformFeedbackMode (deUint32 mode)
414{
415	m_xfbMode = mode;
416}
417
418deUint32 Program::getTransformFeedbackMode (void) const
419{
420	return m_xfbMode;
421}
422
423bool 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