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 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 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 81 static bool isOpaqueType (glu::DataType type) 82 { 83 return glu::isDataTypeAtomicCounter(type) || 84 glu::isDataTypeImage(type) || 85 glu::isDataTypeSampler(type); 86 } 87 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 103 Shader::Shader (glu::ShaderType type, glu::GLSLVersion version) 104 : m_shaderType (type) 105 , m_version (version) 106 { 107 } 108 109 Shader::~Shader (void) 110 { 111 } 112 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 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 164 static bool isIllegalFragmentInput (const glu::VarType& varType) 165 { 166 return isIllegalVertexOutput(varType); 167 } 168 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 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 216 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 295 Program::Program (void) 296 : m_separable (false) 297 , m_xfbMode (0) 298 { 299 } 300 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 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 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 352 void Program::setSeparable (bool separable) 353 { 354 m_separable = separable; 355 } 356 357 bool Program::isSeparable (void) const 358 { 359 return m_separable; 360 } 361 362 const std::vector<Shader*>& Program::getShaders (void) const 363 { 364 return m_shaders; 365 } 366 367 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 385 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 403 void Program::addTransformFeedbackVarying (const std::string& varName) 404 { 405 m_xfbVaryings.push_back(varName); 406 } 407 408 const std::vector<std::string>& Program::getTransformFeedbackVaryings (void) const 409 { 410 return m_xfbVaryings; 411 } 412 413 void Program::setTransformFeedbackMode (deUint32 mode) 414 { 415 m_xfbMode = mode; 416 } 417 418 deUint32 Program::getTransformFeedbackMode (void) const 419 { 420 return m_xfbMode; 421 } 422 423 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