es31fProgramInterfaceDefinition.cpp revision c423ce6164cdd88c8c3e47bec4ec34476743042a
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 for (int interfaceNdx = 0; interfaceNdx < (int)m_defaultBlock.interfaceBlocks.size(); ++interfaceNdx) 279 { 280 if (m_defaultBlock.interfaceBlocks[interfaceNdx].storage == glu::STORAGE_IN || 281 m_defaultBlock.interfaceBlocks[interfaceNdx].storage == glu::STORAGE_PATCH_IN || 282 m_defaultBlock.interfaceBlocks[interfaceNdx].storage == glu::STORAGE_PATCH_OUT) 283 { 284 return false; 285 } 286 } 287 } 288 else if (m_shaderType == glu::SHADERTYPE_FRAGMENT) 289 { 290 for (int varNdx = 0; varNdx < (int)m_defaultBlock.variables.size(); ++varNdx) 291 { 292 if (m_defaultBlock.variables[varNdx].storage == glu::STORAGE_IN && isIllegalFragmentInput(m_defaultBlock.variables[varNdx].varType)) 293 return false; 294 if (m_defaultBlock.variables[varNdx].storage == glu::STORAGE_IN && m_defaultBlock.variables[varNdx].interpolation != glu::INTERPOLATION_FLAT && isTypeIntegerOrContainsIntegers(m_defaultBlock.variables[varNdx].varType)) 295 return false; 296 if (m_defaultBlock.variables[varNdx].storage == glu::STORAGE_OUT && isIllegalFragmentOutput(m_defaultBlock.variables[varNdx].varType)) 297 return false; 298 } 299 for (int interfaceNdx = 0; interfaceNdx < (int)m_defaultBlock.interfaceBlocks.size(); ++interfaceNdx) 300 { 301 if (m_defaultBlock.interfaceBlocks[interfaceNdx].storage == glu::STORAGE_PATCH_IN || 302 m_defaultBlock.interfaceBlocks[interfaceNdx].storage == glu::STORAGE_OUT || 303 m_defaultBlock.interfaceBlocks[interfaceNdx].storage == glu::STORAGE_PATCH_OUT) 304 { 305 return false; 306 } 307 } 308 } 309 else if (m_shaderType == glu::SHADERTYPE_COMPUTE) 310 { 311 for (int varNdx = 0; varNdx < (int)m_defaultBlock.variables.size(); ++varNdx) 312 { 313 if (m_defaultBlock.variables[varNdx].storage == glu::STORAGE_IN || 314 m_defaultBlock.variables[varNdx].storage == glu::STORAGE_PATCH_IN || 315 m_defaultBlock.variables[varNdx].storage == glu::STORAGE_OUT || 316 m_defaultBlock.variables[varNdx].storage == glu::STORAGE_PATCH_OUT) 317 { 318 return false; 319 } 320 } 321 for (int interfaceNdx = 0; interfaceNdx < (int)m_defaultBlock.interfaceBlocks.size(); ++interfaceNdx) 322 { 323 if (m_defaultBlock.interfaceBlocks[interfaceNdx].storage == glu::STORAGE_IN || 324 m_defaultBlock.interfaceBlocks[interfaceNdx].storage == glu::STORAGE_PATCH_IN || 325 m_defaultBlock.interfaceBlocks[interfaceNdx].storage == glu::STORAGE_OUT || 326 m_defaultBlock.interfaceBlocks[interfaceNdx].storage == glu::STORAGE_PATCH_OUT) 327 { 328 return false; 329 } 330 } 331 } 332 else if (m_shaderType == glu::SHADERTYPE_GEOMETRY) 333 { 334 for (int varNdx = 0; varNdx < (int)m_defaultBlock.variables.size(); ++varNdx) 335 { 336 if (m_defaultBlock.variables[varNdx].storage == glu::STORAGE_PATCH_IN || 337 m_defaultBlock.variables[varNdx].storage == glu::STORAGE_PATCH_OUT) 338 { 339 return false; 340 } 341 // arrayed input 342 if (m_defaultBlock.variables[varNdx].storage == glu::STORAGE_IN && !m_defaultBlock.variables[varNdx].varType.isArrayType()) 343 return false; 344 } 345 for (int interfaceNdx = 0; interfaceNdx < (int)m_defaultBlock.interfaceBlocks.size(); ++interfaceNdx) 346 { 347 if (m_defaultBlock.interfaceBlocks[interfaceNdx].storage == glu::STORAGE_PATCH_IN || 348 m_defaultBlock.interfaceBlocks[interfaceNdx].storage == glu::STORAGE_PATCH_OUT) 349 { 350 return false; 351 } 352 // arrayed input 353 if (m_defaultBlock.interfaceBlocks[interfaceNdx].storage == glu::STORAGE_IN && m_defaultBlock.interfaceBlocks[interfaceNdx].dimensions.empty()) 354 return false; 355 } 356 } 357 else if (m_shaderType == glu::SHADERTYPE_TESSELLATION_CONTROL) 358 { 359 for (int varNdx = 0; varNdx < (int)m_defaultBlock.variables.size(); ++varNdx) 360 { 361 if (m_defaultBlock.variables[varNdx].storage == glu::STORAGE_PATCH_IN) 362 return false; 363 // arrayed input 364 if (m_defaultBlock.variables[varNdx].storage == glu::STORAGE_IN && !m_defaultBlock.variables[varNdx].varType.isArrayType()) 365 return false; 366 // arrayed output 367 if (m_defaultBlock.variables[varNdx].storage == glu::STORAGE_OUT && !m_defaultBlock.variables[varNdx].varType.isArrayType()) 368 return false; 369 } 370 for (int interfaceNdx = 0; interfaceNdx < (int)m_defaultBlock.interfaceBlocks.size(); ++interfaceNdx) 371 { 372 if (m_defaultBlock.interfaceBlocks[interfaceNdx].storage == glu::STORAGE_PATCH_IN) 373 return false; 374 // arrayed input 375 if (m_defaultBlock.interfaceBlocks[interfaceNdx].storage == glu::STORAGE_IN && m_defaultBlock.interfaceBlocks[interfaceNdx].dimensions.empty()) 376 return false; 377 // arrayed output 378 if (m_defaultBlock.interfaceBlocks[interfaceNdx].storage == glu::STORAGE_OUT && m_defaultBlock.interfaceBlocks[interfaceNdx].dimensions.empty()) 379 return false; 380 } 381 } 382 else if (m_shaderType == glu::SHADERTYPE_TESSELLATION_EVALUATION) 383 { 384 for (int varNdx = 0; varNdx < (int)m_defaultBlock.variables.size(); ++varNdx) 385 { 386 if (m_defaultBlock.variables[varNdx].storage == glu::STORAGE_PATCH_OUT) 387 return false; 388 // arrayed input 389 if (m_defaultBlock.variables[varNdx].storage == glu::STORAGE_IN && !m_defaultBlock.variables[varNdx].varType.isArrayType()) 390 return false; 391 } 392 for (int interfaceNdx = 0; interfaceNdx < (int)m_defaultBlock.interfaceBlocks.size(); ++interfaceNdx) 393 { 394 if (m_defaultBlock.interfaceBlocks[interfaceNdx].storage == glu::STORAGE_PATCH_OUT) 395 return false; 396 // arrayed input 397 if (m_defaultBlock.interfaceBlocks[interfaceNdx].storage == glu::STORAGE_IN && m_defaultBlock.interfaceBlocks[interfaceNdx].dimensions.empty()) 398 return false; 399 } 400 } 401 else 402 DE_ASSERT(false); 403 404 return true; 405} 406 407Program::Program (void) 408 : m_separable (false) 409 , m_xfbMode (0) 410 , m_geoNumOutputVertices (0) 411 , m_tessNumOutputVertices (0) 412{ 413} 414 415static void collectStructPtrs (std::set<const glu::StructType*>& dst, const glu::VarType& type) 416{ 417 if (type.isArrayType()) 418 collectStructPtrs(dst, type.getElementType()); 419 else if (type.isStructType()) 420 { 421 dst.insert(type.getStructPtr()); 422 423 for (int memberNdx = 0; memberNdx < type.getStructPtr()->getNumMembers(); ++memberNdx) 424 collectStructPtrs(dst, type.getStructPtr()->getMember(memberNdx).getType()); 425 } 426} 427 428Program::~Program (void) 429{ 430 // delete shader struct types, need to be done by the program since shaders might share struct types 431 { 432 std::set<const glu::StructType*> structTypes; 433 434 for (int shaderNdx = 0; shaderNdx < (int)m_shaders.size(); ++shaderNdx) 435 { 436 for (int varNdx = 0; varNdx < (int)m_shaders[shaderNdx]->m_defaultBlock.variables.size(); ++varNdx) 437 collectStructPtrs(structTypes, m_shaders[shaderNdx]->m_defaultBlock.variables[varNdx].varType); 438 439 for (int interfaceNdx = 0; interfaceNdx < (int)m_shaders[shaderNdx]->m_defaultBlock.interfaceBlocks.size(); ++interfaceNdx) 440 for (int varNdx = 0; varNdx < (int)m_shaders[shaderNdx]->m_defaultBlock.interfaceBlocks[interfaceNdx].variables.size(); ++varNdx) 441 collectStructPtrs(structTypes, m_shaders[shaderNdx]->m_defaultBlock.interfaceBlocks[interfaceNdx].variables[varNdx].varType); 442 } 443 444 for (std::set<const glu::StructType*>::iterator it = structTypes.begin(); it != structTypes.end(); ++it) 445 delete *it; 446 } 447 448 for (int shaderNdx = 0; shaderNdx < (int)m_shaders.size(); ++shaderNdx) 449 delete m_shaders[shaderNdx]; 450 m_shaders.clear(); 451} 452 453Shader* Program::addShader (glu::ShaderType type, glu::GLSLVersion version) 454{ 455 DE_ASSERT(type < glu::SHADERTYPE_LAST); 456 457 Shader* shader; 458 459 // make sure push_back() cannot throw 460 m_shaders.reserve(m_shaders.size() + 1); 461 462 shader = new Shader(type, version); 463 m_shaders.push_back(shader); 464 465 return shader; 466} 467 468void Program::setSeparable (bool separable) 469{ 470 m_separable = separable; 471} 472 473bool Program::isSeparable (void) const 474{ 475 return m_separable; 476} 477 478const std::vector<Shader*>& Program::getShaders (void) const 479{ 480 return m_shaders; 481} 482 483glu::ShaderType Program::getFirstStage (void) const 484{ 485 const int nullValue = DE_LENGTH_OF_ARRAY(s_shaderStageOrder); 486 int firstStage = nullValue; 487 488 for (int shaderNdx = 0; shaderNdx < (int)m_shaders.size(); ++shaderNdx) 489 { 490 const int index = getShaderStageIndex(m_shaders[shaderNdx]->getType()); 491 if (index != -1) 492 firstStage = de::min(firstStage, index); 493 } 494 495 if (firstStage == nullValue) 496 return glu::SHADERTYPE_LAST; 497 else 498 return s_shaderStageOrder[firstStage]; 499} 500 501glu::ShaderType Program::getLastStage (void) const 502{ 503 const int nullValue = -1; 504 int lastStage = nullValue; 505 506 for (int shaderNdx = 0; shaderNdx < (int)m_shaders.size(); ++shaderNdx) 507 { 508 const int index = getShaderStageIndex(m_shaders[shaderNdx]->getType()); 509 if (index != -1) 510 lastStage = de::max(lastStage, index); 511 } 512 513 if (lastStage == nullValue) 514 return glu::SHADERTYPE_LAST; 515 else 516 return s_shaderStageOrder[lastStage]; 517} 518 519bool Program::hasStage (glu::ShaderType stage) const 520{ 521 for (int shaderNdx = 0; shaderNdx < (int)m_shaders.size(); ++shaderNdx) 522 { 523 if (m_shaders[shaderNdx]->getType() == stage) 524 return true; 525 } 526 return false; 527} 528 529void Program::addTransformFeedbackVarying (const std::string& varName) 530{ 531 m_xfbVaryings.push_back(varName); 532} 533 534const std::vector<std::string>& Program::getTransformFeedbackVaryings (void) const 535{ 536 return m_xfbVaryings; 537} 538 539void Program::setTransformFeedbackMode (deUint32 mode) 540{ 541 m_xfbMode = mode; 542} 543 544deUint32 Program::getTransformFeedbackMode (void) const 545{ 546 return m_xfbMode; 547} 548 549deUint32 Program::getGeometryNumOutputVertices (void) const 550{ 551 return m_geoNumOutputVertices; 552} 553 554void Program::setGeometryNumOutputVertices (deUint32 vertices) 555{ 556 m_geoNumOutputVertices = vertices; 557} 558 559deUint32 Program::getTessellationNumOutputPatchVertices (void) const 560{ 561 return m_tessNumOutputVertices; 562} 563 564void Program::setTessellationNumOutputPatchVertices (deUint32 vertices) 565{ 566 m_tessNumOutputVertices = vertices; 567} 568 569bool Program::isValid (void) const 570{ 571 bool computePresent = false; 572 bool vertexPresent = false; 573 bool fragmentPresent = false; 574 bool tessControlPresent = false; 575 bool tessEvalPresent = false; 576 bool geometryPresent = false; 577 578 if (m_shaders.empty()) 579 return false; 580 581 for (int ndx = 0; ndx < (int)m_shaders.size(); ++ndx) 582 if (!m_shaders[ndx]->isValid()) 583 return false; 584 585 // same version 586 for (int ndx = 1; ndx < (int)m_shaders.size(); ++ndx) 587 if (m_shaders[0]->getVersion() != m_shaders[ndx]->getVersion()) 588 return false; 589 590 for (int ndx = 0; ndx < (int)m_shaders.size(); ++ndx) 591 { 592 switch (m_shaders[ndx]->getType()) 593 { 594 case glu::SHADERTYPE_COMPUTE: computePresent = true; break; 595 case glu::SHADERTYPE_VERTEX: vertexPresent = true; break; 596 case glu::SHADERTYPE_FRAGMENT: fragmentPresent = true; break; 597 case glu::SHADERTYPE_TESSELLATION_CONTROL: tessControlPresent = true; break; 598 case glu::SHADERTYPE_TESSELLATION_EVALUATION: tessEvalPresent = true; break; 599 case glu::SHADERTYPE_GEOMETRY: geometryPresent = true; break; 600 default: 601 DE_ASSERT(false); 602 break; 603 } 604 } 605 // compute present -> no other stages present 606 { 607 const bool nonComputePresent = vertexPresent || fragmentPresent || tessControlPresent || tessEvalPresent || geometryPresent; 608 if (computePresent && nonComputePresent) 609 return false; 610 } 611 612 // must contain both vertex and fragment shaders 613 if (!computePresent && !m_separable) 614 { 615 if (!vertexPresent || !fragmentPresent) 616 return false; 617 } 618 619 // tess.Eval present <=> tess.Control present 620 if (!m_separable) 621 { 622 if (tessEvalPresent != tessControlPresent) 623 return false; 624 } 625 626 if ((m_tessNumOutputVertices != 0) != (tessControlPresent || tessEvalPresent)) 627 return false; 628 629 if ((m_geoNumOutputVertices != 0) != geometryPresent) 630 return false; 631 632 return true; 633} 634 635} // ProgramInterfaceDefinition 636} // Functional 637} // gles31 638} // deqp 639