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