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