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 utilities 22 *//*--------------------------------------------------------------------*/ 23 24 #include "es31fProgramInterfaceDefinitionUtil.hpp" 25 #include "es31fProgramInterfaceDefinition.hpp" 26 #include "gluVarType.hpp" 27 #include "gluVarTypeUtil.hpp" 28 #include "gluShaderUtil.hpp" 29 #include "deString.h" 30 #include "deStringUtil.hpp" 31 #include "glwEnums.hpp" 32 33 #include <set> 34 #include <map> 35 #include <sstream> 36 #include <vector> 37 #include <algorithm> 38 39 namespace deqp 40 { 41 namespace gles31 42 { 43 namespace Functional 44 { 45 namespace ProgramInterfaceDefinition 46 { 47 48 VariableSearchFilter VariableSearchFilter::intersection (const VariableSearchFilter& a, const VariableSearchFilter& b) 49 { 50 const bool storageNonEmpty = (a.m_storage == b.m_storage) || (a.m_storage == glu::STORAGE_LAST) || (b.m_storage == glu::STORAGE_LAST); 51 const bool shaderTypeNonEmpty = (a.m_shaderType == b.m_shaderType) || (a.m_shaderType == glu::SHADERTYPE_LAST) || (b.m_shaderType == glu::SHADERTYPE_LAST); 52 53 return VariableSearchFilter((a.m_shaderType == glu::SHADERTYPE_LAST) ? (b.m_shaderType) : (a.m_shaderType), 54 (a.m_storage == glu::STORAGE_LAST) ? (b.m_storage) : (a.m_storage), 55 !storageNonEmpty || !shaderTypeNonEmpty || a.m_null || b.m_null); 56 } 57 58 } // ProgramInterfaceDefinition 59 60 static bool incrementMultiDimensionIndex (std::vector<int>& index, const std::vector<int>& dimensions) 61 { 62 int incrementDimensionNdx = (int)(index.size() - 1); 63 64 while (incrementDimensionNdx >= 0) 65 { 66 if (++index[incrementDimensionNdx] == dimensions[incrementDimensionNdx]) 67 index[incrementDimensionNdx--] = 0; 68 else 69 break; 70 } 71 72 return (incrementDimensionNdx != -1); 73 } 74 75 void generateVariableTypeResourceNames (std::vector<std::string>& resources, const std::string& name, const glu::VarType& type, deUint32 resourceNameGenerationFlags) 76 { 77 DE_ASSERT((resourceNameGenerationFlags & (~RESOURCE_NAME_GENERATION_FLAG_MASK)) == 0); 78 79 // remove top-level flag from children 80 const deUint32 childFlags = resourceNameGenerationFlags & ~((deUint32)RESOURCE_NAME_GENERATION_FLAG_TOP_LEVEL_BUFFER_VARIABLE); 81 82 if (type.isBasicType()) 83 resources.push_back(name); 84 else if (type.isStructType()) 85 { 86 const glu::StructType* structType = type.getStructPtr(); 87 for (int ndx = 0; ndx < structType->getNumMembers(); ++ndx) 88 generateVariableTypeResourceNames(resources, name + "." + structType->getMember(ndx).getName(), structType->getMember(ndx).getType(), childFlags); 89 } 90 else if (type.isArrayType()) 91 { 92 // Bottom-level arrays of basic types of a transform feedback variable will produce only the first 93 // element but without the trailing "[0]" 94 if (type.getElementType().isBasicType() && 95 (resourceNameGenerationFlags & RESOURCE_NAME_GENERATION_FLAG_TRANSFORM_FEEDBACK_VARIABLE) != 0) 96 { 97 resources.push_back(name); 98 } 99 // Bottom-level arrays of basic types and SSBO top-level arrays of any type procude only first element 100 else if (type.getElementType().isBasicType() || 101 (resourceNameGenerationFlags & RESOURCE_NAME_GENERATION_FLAG_TOP_LEVEL_BUFFER_VARIABLE) != 0) 102 { 103 generateVariableTypeResourceNames(resources, name + "[0]", type.getElementType(), childFlags); 104 } 105 // Other arrays of aggregate types are expanded 106 else 107 { 108 for (int ndx = 0; ndx < type.getArraySize(); ++ndx) 109 generateVariableTypeResourceNames(resources, name + "[" + de::toString(ndx) + "]", type.getElementType(), childFlags); 110 } 111 } 112 else 113 DE_ASSERT(false); 114 } 115 116 // Program source generation 117 118 namespace 119 { 120 121 using ProgramInterfaceDefinition::VariablePathComponent; 122 using ProgramInterfaceDefinition::VariableSearchFilter; 123 124 static const char* getShaderTypeDeclarations (glu::ShaderType type) 125 { 126 switch (type) 127 { 128 case glu::SHADERTYPE_VERTEX: 129 return ""; 130 131 case glu::SHADERTYPE_FRAGMENT: 132 return ""; 133 134 case glu::SHADERTYPE_GEOMETRY: 135 return "layout(points) in;\n" 136 "layout(points, max_vertices=3) out;\n"; 137 138 case glu::SHADERTYPE_TESSELLATION_CONTROL: 139 return "layout(vertices=1) out;\n"; 140 141 case glu::SHADERTYPE_TESSELLATION_EVALUATION: 142 return "layout(triangle, point_mode) in;\n"; 143 144 case glu::SHADERTYPE_COMPUTE: 145 return "layout(local_size_x=1) in;\n"; 146 147 default: 148 DE_ASSERT(false); 149 return DE_NULL; 150 } 151 } 152 153 class StructNameEqualPredicate 154 { 155 public: 156 StructNameEqualPredicate (const char* name) : m_name(name) { } 157 bool operator() (const glu::StructType* type) { return type->hasTypeName() && (deStringEqual(m_name, type->getTypeName()) == DE_TRUE); } 158 private: 159 const char* m_name; 160 }; 161 162 static void collectNamedStructureDefinitions (std::vector<const glu::StructType*>& dst, const glu::VarType& type) 163 { 164 if (type.isBasicType()) 165 return; 166 else if (type.isArrayType()) 167 return collectNamedStructureDefinitions(dst, type.getElementType()); 168 else if (type.isStructType()) 169 { 170 if (type.getStructPtr()->hasTypeName()) 171 { 172 // must be unique (may share the the same struct) 173 std::vector<const glu::StructType*>::iterator where = std::find_if(dst.begin(), dst.end(), StructNameEqualPredicate(type.getStructPtr()->getTypeName())); 174 if (where != dst.end()) 175 { 176 DE_ASSERT(**where == *type.getStructPtr()); 177 178 // identical type has been added already, types of members must be added too 179 return; 180 } 181 } 182 183 // Add types of members first 184 for (int ndx = 0; ndx < type.getStructPtr()->getNumMembers(); ++ndx) 185 collectNamedStructureDefinitions(dst, type.getStructPtr()->getMember(ndx).getType()); 186 187 dst.push_back(type.getStructPtr()); 188 } 189 else 190 DE_ASSERT(false); 191 } 192 193 static void writeStructureDefinitions (std::ostringstream& buf, const ProgramInterfaceDefinition::DefaultBlock& defaultBlock) 194 { 195 std::vector<const glu::StructType*> namedStructs; 196 197 // Collect all structs in post order 198 199 for (int ndx = 0; ndx < (int)defaultBlock.variables.size(); ++ndx) 200 collectNamedStructureDefinitions(namedStructs, defaultBlock.variables[ndx].varType); 201 202 for (int blockNdx = 0; blockNdx < (int)defaultBlock.interfaceBlocks.size(); ++blockNdx) 203 for (int ndx = 0; ndx < (int)defaultBlock.interfaceBlocks[blockNdx].variables.size(); ++ndx) 204 collectNamedStructureDefinitions(namedStructs, defaultBlock.interfaceBlocks[blockNdx].variables[ndx].varType); 205 206 // Write 207 208 for (int structNdx = 0; structNdx < (int)namedStructs.size(); ++structNdx) 209 { 210 buf << "struct " << namedStructs[structNdx]->getTypeName() << "\n" 211 "{\n"; 212 213 for (int memberNdx = 0; memberNdx < namedStructs[structNdx]->getNumMembers(); ++memberNdx) 214 buf << glu::indent(1) << glu::declare(namedStructs[structNdx]->getMember(memberNdx).getType(), namedStructs[structNdx]->getMember(memberNdx).getName(), 1) << ";\n"; 215 216 buf << "};\n"; 217 } 218 219 if (!namedStructs.empty()) 220 buf << "\n"; 221 } 222 223 static void writeInterfaceBlock (std::ostringstream& buf, const glu::InterfaceBlock& interfaceBlock) 224 { 225 buf << interfaceBlock.layout; 226 227 if (interfaceBlock.layout != glu::Layout()) 228 buf << " "; 229 230 buf << glu::getStorageName(interfaceBlock.storage) << " " << interfaceBlock.interfaceName << "\n" 231 << "{\n"; 232 233 for (int ndx = 0; ndx < (int)interfaceBlock.variables.size(); ++ndx) 234 buf << glu::indent(1) << interfaceBlock.variables[ndx] << ";\n"; 235 236 buf << "}"; 237 238 if (!interfaceBlock.instanceName.empty()) 239 buf << " " << interfaceBlock.instanceName; 240 241 for (int dimensionNdx = 0; dimensionNdx < (int)interfaceBlock.dimensions.size(); ++dimensionNdx) 242 buf << "[" << interfaceBlock.dimensions[dimensionNdx] << "]"; 243 244 buf << ";\n\n"; 245 } 246 247 static void writeVariableReadAccumulateExpression (std::ostringstream& buf, const std::string& accumulatorName, const std::string& name, const glu::VarType& varType) 248 { 249 if (varType.isBasicType()) 250 { 251 buf << "\t" << accumulatorName << " += "; 252 253 if (glu::isDataTypeScalar(varType.getBasicType())) 254 buf << "vec4(float(" << name << "))"; 255 else if (glu::isDataTypeVector(varType.getBasicType())) 256 buf << "vec4(" << name << ".xyxy)"; 257 else if (glu::isDataTypeMatrix(varType.getBasicType())) 258 buf << "vec4(float(" << name << "[0][0]))"; 259 else if (glu::isDataTypeSamplerMultisample(varType.getBasicType())) 260 buf << "vec4(float(textureSize(" << name << ").x))"; 261 else if (glu::isDataTypeSampler(varType.getBasicType())) 262 buf << "vec4(float(textureSize(" << name << ", 0).x))"; 263 else if (glu::isDataTypeImage(varType.getBasicType())) 264 buf << "vec4(float(imageSize(" << name << ").x))"; 265 else if (varType.getBasicType() == glu::TYPE_UINT_ATOMIC_COUNTER) 266 buf << "vec4(float(atomicCounterIncrement(" << name << ")))"; 267 else 268 DE_ASSERT(false); 269 270 buf << ";\n"; 271 } 272 else if (varType.isStructType()) 273 { 274 for (int ndx = 0; ndx < varType.getStructPtr()->getNumMembers(); ++ndx) 275 writeVariableReadAccumulateExpression(buf, accumulatorName, name + "." + varType.getStructPtr()->getMember(ndx).getName(), varType.getStructPtr()->getMember(ndx).getType()); 276 } 277 else if (varType.isArrayType()) 278 { 279 if (varType.getArraySize() != glu::VarType::UNSIZED_ARRAY) 280 for (int ndx = 0; ndx < varType.getArraySize(); ++ndx) 281 writeVariableReadAccumulateExpression(buf, accumulatorName, name + "[" + de::toString(ndx) + "]", varType.getElementType()); 282 else 283 writeVariableReadAccumulateExpression(buf, accumulatorName, name + "[8]", varType.getElementType()); 284 } 285 else 286 DE_ASSERT(false); 287 } 288 289 static void writeInterfaceReadAccumulateExpression (std::ostringstream& buf, const std::string& accumulatorName, const glu::InterfaceBlock& block) 290 { 291 if (block.dimensions.empty()) 292 { 293 const std::string prefix = (block.instanceName.empty()) ? ("") : (block.instanceName + "."); 294 295 for (int ndx = 0; ndx < (int)block.variables.size(); ++ndx) 296 writeVariableReadAccumulateExpression(buf, accumulatorName, prefix + block.variables[ndx].name, block.variables[ndx].varType); 297 } 298 else 299 { 300 std::vector<int> index(block.dimensions.size(), 0); 301 302 for (;;) 303 { 304 // access element 305 { 306 std::ostringstream name; 307 name << block.instanceName; 308 309 for (int dimensionNdx = 0; dimensionNdx < (int)block.dimensions.size(); ++dimensionNdx) 310 name << "[" << index[dimensionNdx] << "]"; 311 312 for (int ndx = 0; ndx < (int)block.variables.size(); ++ndx) 313 writeVariableReadAccumulateExpression(buf, accumulatorName, name.str() + "." + block.variables[ndx].name, block.variables[ndx].varType); 314 } 315 316 // increment index 317 if (!incrementMultiDimensionIndex(index, block.dimensions)) 318 break; 319 } 320 } 321 } 322 323 static void writeVariableWriteExpression (std::ostringstream& buf, const std::string& sourceVec4Name, const std::string& name, const glu::VarType& varType) 324 { 325 if (varType.isBasicType()) 326 { 327 buf << "\t" << name << " = "; 328 329 if (glu::isDataTypeScalar(varType.getBasicType())) 330 buf << glu::getDataTypeName(varType.getBasicType()) << "(" << sourceVec4Name << ".y)"; 331 else if (glu::isDataTypeVector(varType.getBasicType()) || glu::isDataTypeMatrix(varType.getBasicType())) 332 buf << glu::getDataTypeName(varType.getBasicType()) << "(" << glu::getDataTypeName(glu::getDataTypeScalarType(varType.getBasicType())) << "(" << sourceVec4Name << ".y))"; 333 else 334 DE_ASSERT(false); 335 336 buf << ";\n"; 337 } 338 else if (varType.isStructType()) 339 { 340 for (int ndx = 0; ndx < varType.getStructPtr()->getNumMembers(); ++ndx) 341 writeVariableWriteExpression(buf, sourceVec4Name, name + "." + varType.getStructPtr()->getMember(ndx).getName(), varType.getStructPtr()->getMember(ndx).getType()); 342 } 343 else if (varType.isArrayType()) 344 { 345 if (varType.getArraySize() != glu::VarType::UNSIZED_ARRAY) 346 for (int ndx = 0; ndx < varType.getArraySize(); ++ndx) 347 writeVariableWriteExpression(buf, sourceVec4Name, name + "[" + de::toString(ndx) + "]", varType.getElementType()); 348 else 349 writeVariableWriteExpression(buf, sourceVec4Name, name + "[9]", varType.getElementType()); 350 } 351 else 352 DE_ASSERT(false); 353 } 354 355 static void writeInterfaceWriteExpression (std::ostringstream& buf, const std::string& sourceVec4Name, const glu::InterfaceBlock& block) 356 { 357 if (block.dimensions.empty()) 358 { 359 const std::string prefix = (block.instanceName.empty()) ? ("") : (block.instanceName + "."); 360 361 for (int ndx = 0; ndx < (int)block.variables.size(); ++ndx) 362 writeVariableWriteExpression(buf, sourceVec4Name, prefix + block.variables[ndx].name, block.variables[ndx].varType); 363 } 364 else 365 { 366 std::vector<int> index(block.dimensions.size(), 0); 367 368 for (;;) 369 { 370 // access element 371 { 372 std::ostringstream name; 373 name << block.instanceName; 374 375 for (int dimensionNdx = 0; dimensionNdx < (int)block.dimensions.size(); ++dimensionNdx) 376 name << "[" << index[dimensionNdx] << "]"; 377 378 for (int ndx = 0; ndx < (int)block.variables.size(); ++ndx) 379 writeVariableWriteExpression(buf, sourceVec4Name, name.str() + "." + block.variables[ndx].name, block.variables[ndx].varType); 380 } 381 382 // increment index 383 if (!incrementMultiDimensionIndex(index, block.dimensions)) 384 break; 385 } 386 } 387 } 388 389 static bool traverseVariablePath (std::vector<VariablePathComponent>& typePath, const char* subPath, const glu::VarType& type) 390 { 391 glu::VarTokenizer tokenizer(subPath); 392 393 typePath.push_back(VariablePathComponent(&type)); 394 395 if (tokenizer.getToken() == glu::VarTokenizer::TOKEN_END) 396 return true; 397 398 if (type.isStructType() && tokenizer.getToken() == glu::VarTokenizer::TOKEN_PERIOD) 399 { 400 tokenizer.advance(); 401 402 // malformed path 403 if (tokenizer.getToken() != glu::VarTokenizer::TOKEN_IDENTIFIER) 404 return false; 405 406 for (int memberNdx = 0; memberNdx < type.getStructPtr()->getNumMembers(); ++memberNdx) 407 if (type.getStructPtr()->getMember(memberNdx).getName() == tokenizer.getIdentifier()) 408 return traverseVariablePath(typePath, subPath + tokenizer.getCurrentTokenEndLocation(), type.getStructPtr()->getMember(memberNdx).getType()); 409 410 // malformed path, no such member 411 return false; 412 } 413 else if (type.isArrayType() && tokenizer.getToken() == glu::VarTokenizer::TOKEN_LEFT_BRACKET) 414 { 415 tokenizer.advance(); 416 417 // malformed path 418 if (tokenizer.getToken() != glu::VarTokenizer::TOKEN_NUMBER) 419 return false; 420 421 tokenizer.advance(); 422 if (tokenizer.getToken() != glu::VarTokenizer::TOKEN_RIGHT_BRACKET) 423 return false; 424 425 return traverseVariablePath(typePath, subPath + tokenizer.getCurrentTokenEndLocation(), type.getElementType()); 426 } 427 428 return false; 429 } 430 431 static bool traverseVariablePath (std::vector<VariablePathComponent>& typePath, const std::string& path, const glu::VariableDeclaration& var) 432 { 433 if (glu::parseVariableName(path.c_str()) != var.name) 434 return false; 435 436 typePath.push_back(VariablePathComponent(&var)); 437 return traverseVariablePath(typePath, path.c_str() + var.name.length(), var.varType); 438 } 439 440 static bool traverseShaderVariablePath (std::vector<VariablePathComponent>& typePath, const ProgramInterfaceDefinition::Shader* shader, const std::string& path, const VariableSearchFilter& filter) 441 { 442 // Default block variable? 443 for (int varNdx = 0; varNdx < (int)shader->getDefaultBlock().variables.size(); ++varNdx) 444 if (filter.matchesFilter(shader->getDefaultBlock().variables[varNdx])) 445 if (traverseVariablePath(typePath, path, shader->getDefaultBlock().variables[varNdx])) 446 return true; 447 448 // is variable an interface block variable? 449 { 450 const std::string blockName = glu::parseVariableName(path.c_str()); 451 452 for (int interfaceNdx = 0; interfaceNdx < (int)shader->getDefaultBlock().interfaceBlocks.size(); ++interfaceNdx) 453 { 454 if (!filter.matchesFilter(shader->getDefaultBlock().interfaceBlocks[interfaceNdx])) 455 continue; 456 457 if (shader->getDefaultBlock().interfaceBlocks[interfaceNdx].interfaceName == blockName) 458 { 459 // resource is a member of a named interface block 460 // \note there is no array index specifier even if the interface is declared as an array of instances 461 const std::string blockMemberPath = path.substr(blockName.size() + 1); 462 const std::string blockMemeberName = glu::parseVariableName(blockMemberPath.c_str()); 463 464 for (int varNdx = 0; varNdx < (int)shader->getDefaultBlock().interfaceBlocks[interfaceNdx].variables.size(); ++varNdx) 465 { 466 if (shader->getDefaultBlock().interfaceBlocks[interfaceNdx].variables[varNdx].name == blockMemeberName) 467 { 468 typePath.push_back(VariablePathComponent(&shader->getDefaultBlock().interfaceBlocks[interfaceNdx])); 469 return traverseVariablePath(typePath, blockMemberPath, shader->getDefaultBlock().interfaceBlocks[interfaceNdx].variables[varNdx]); 470 } 471 } 472 473 // terminate search 474 return false; 475 } 476 else if (shader->getDefaultBlock().interfaceBlocks[interfaceNdx].instanceName.empty()) 477 { 478 const std::string blockMemeberName = glu::parseVariableName(path.c_str()); 479 480 // unnamed block contains such variable? 481 for (int varNdx = 0; varNdx < (int)shader->getDefaultBlock().interfaceBlocks[interfaceNdx].variables.size(); ++varNdx) 482 { 483 if (shader->getDefaultBlock().interfaceBlocks[interfaceNdx].variables[varNdx].name == blockMemeberName) 484 { 485 typePath.push_back(VariablePathComponent(&shader->getDefaultBlock().interfaceBlocks[interfaceNdx])); 486 return traverseVariablePath(typePath, path, shader->getDefaultBlock().interfaceBlocks[interfaceNdx].variables[varNdx]); 487 } 488 } 489 490 // continue search 491 } 492 } 493 } 494 495 return false; 496 } 497 498 static bool traverseProgramVariablePath (std::vector<VariablePathComponent>& typePath, const ProgramInterfaceDefinition::Program* program, const std::string& path, const VariableSearchFilter& filter) 499 { 500 for (int shaderNdx = 0; shaderNdx < (int)program->getShaders().size(); ++shaderNdx) 501 { 502 const ProgramInterfaceDefinition::Shader* shader = program->getShaders()[shaderNdx]; 503 504 if (filter.matchesFilter(shader)) 505 { 506 // \note modifying output variable even when returning false 507 typePath.clear(); 508 if (traverseShaderVariablePath(typePath, shader, path, filter)) 509 return true; 510 } 511 } 512 513 return false; 514 } 515 516 static bool containsSubType (const glu::VarType& complexType, glu::DataType basicType) 517 { 518 if (complexType.isBasicType()) 519 { 520 return complexType.getBasicType() == basicType; 521 } 522 else if (complexType.isArrayType()) 523 { 524 return containsSubType(complexType.getElementType(), basicType); 525 } 526 else if (complexType.isStructType()) 527 { 528 for (int ndx = 0; ndx < complexType.getStructPtr()->getNumMembers(); ++ndx) 529 if (containsSubType(complexType.getStructPtr()->getMember(ndx).getType(), basicType)) 530 return true; 531 return false; 532 } 533 else 534 { 535 DE_ASSERT(false); 536 return false; 537 } 538 } 539 540 static int getNumShaderBlocks (const ProgramInterfaceDefinition::Shader* shader, glu::Storage storage) 541 { 542 int retVal = 0; 543 544 for (int ndx = 0; ndx < (int)shader->getDefaultBlock().interfaceBlocks.size(); ++ndx) 545 { 546 if (shader->getDefaultBlock().interfaceBlocks[ndx].storage == storage) 547 { 548 int numInstances = 1; 549 550 for (int dimensionNdx = 0; dimensionNdx < (int)shader->getDefaultBlock().interfaceBlocks[ndx].dimensions.size(); ++dimensionNdx) 551 numInstances *= shader->getDefaultBlock().interfaceBlocks[ndx].dimensions[dimensionNdx]; 552 553 retVal += numInstances; 554 } 555 } 556 557 return retVal; 558 } 559 560 static int getNumAtomicCounterBuffers (const ProgramInterfaceDefinition::Shader* shader) 561 { 562 std::set<int> buffers; 563 564 for (int ndx = 0; ndx < (int)shader->getDefaultBlock().variables.size(); ++ndx) 565 { 566 if (containsSubType(shader->getDefaultBlock().variables[ndx].varType, glu::TYPE_UINT_ATOMIC_COUNTER)) 567 { 568 DE_ASSERT(shader->getDefaultBlock().variables[ndx].layout.binding != -1); 569 buffers.insert(shader->getDefaultBlock().variables[ndx].layout.binding); 570 } 571 } 572 573 return (int)buffers.size(); 574 } 575 576 template <bool B> 577 static bool dummyConstantTypeFilter (glu::DataType d) 578 { 579 DE_UNREF(d); 580 return B; 581 } 582 583 static int getNumTypeInstances (const glu::VarType& complexType, bool (*predicate)(glu::DataType)) 584 { 585 if (complexType.isBasicType()) 586 { 587 if (predicate(complexType.getBasicType())) 588 return 1; 589 else 590 return 0; 591 } 592 else if (complexType.isArrayType()) 593 { 594 const int arraySize = (complexType.getArraySize() == glu::VarType::UNSIZED_ARRAY) ? (1) : (complexType.getArraySize()); 595 return arraySize * getNumTypeInstances(complexType.getElementType(), predicate); 596 } 597 else if (complexType.isStructType()) 598 { 599 int sum = 0; 600 for (int ndx = 0; ndx < complexType.getStructPtr()->getNumMembers(); ++ndx) 601 sum += getNumTypeInstances(complexType.getStructPtr()->getMember(ndx).getType(), predicate); 602 return sum; 603 } 604 else 605 { 606 DE_ASSERT(false); 607 return false; 608 } 609 } 610 611 static int getMappedBasicTypeSum (const glu::VarType& complexType, int (*typeMap)(glu::DataType)) 612 { 613 if (complexType.isBasicType()) 614 return typeMap(complexType.getBasicType()); 615 else if (complexType.isArrayType()) 616 { 617 const int arraySize = (complexType.getArraySize() == glu::VarType::UNSIZED_ARRAY) ? (1) : (complexType.getArraySize()); 618 return arraySize * getMappedBasicTypeSum(complexType.getElementType(), typeMap); 619 } 620 else if (complexType.isStructType()) 621 { 622 int sum = 0; 623 for (int ndx = 0; ndx < complexType.getStructPtr()->getNumMembers(); ++ndx) 624 sum += getMappedBasicTypeSum(complexType.getStructPtr()->getMember(ndx).getType(), typeMap); 625 return sum; 626 } 627 else 628 { 629 DE_ASSERT(false); 630 return false; 631 } 632 } 633 634 static int getNumTypeInstances (const ProgramInterfaceDefinition::Shader* shader, glu::Storage storage, bool (*predicate)(glu::DataType)) 635 { 636 int retVal = 0; 637 638 for (int ndx = 0; ndx < (int)shader->getDefaultBlock().interfaceBlocks.size(); ++ndx) 639 { 640 if (shader->getDefaultBlock().interfaceBlocks[ndx].storage == storage) 641 { 642 int numInstances = 1; 643 644 for (int dimensionNdx = 0; dimensionNdx < (int)shader->getDefaultBlock().interfaceBlocks[ndx].dimensions.size(); ++dimensionNdx) 645 numInstances *= shader->getDefaultBlock().interfaceBlocks[ndx].dimensions[dimensionNdx]; 646 647 for (int varNdx = 0; varNdx < (int)shader->getDefaultBlock().interfaceBlocks[ndx].variables.size(); ++varNdx) 648 retVal += numInstances * getNumTypeInstances(shader->getDefaultBlock().interfaceBlocks[ndx].variables[varNdx].varType, predicate); 649 } 650 } 651 652 for (int varNdx = 0; varNdx < (int)shader->getDefaultBlock().variables.size(); ++varNdx) 653 if (shader->getDefaultBlock().variables[varNdx].storage == storage) 654 retVal += getNumTypeInstances(shader->getDefaultBlock().variables[varNdx].varType, predicate); 655 656 return retVal; 657 } 658 659 static int getMappedBasicTypeSum (const ProgramInterfaceDefinition::Shader* shader, glu::Storage storage, int (*typeMap)(glu::DataType)) 660 { 661 int retVal = 0; 662 663 for (int ndx = 0; ndx < (int)shader->getDefaultBlock().interfaceBlocks.size(); ++ndx) 664 { 665 if (shader->getDefaultBlock().interfaceBlocks[ndx].storage == storage) 666 { 667 int numInstances = 1; 668 669 for (int dimensionNdx = 0; dimensionNdx < (int)shader->getDefaultBlock().interfaceBlocks[ndx].dimensions.size(); ++dimensionNdx) 670 numInstances *= shader->getDefaultBlock().interfaceBlocks[ndx].dimensions[dimensionNdx]; 671 672 for (int varNdx = 0; varNdx < (int)shader->getDefaultBlock().interfaceBlocks[ndx].variables.size(); ++varNdx) 673 retVal += numInstances * getMappedBasicTypeSum(shader->getDefaultBlock().interfaceBlocks[ndx].variables[varNdx].varType, typeMap); 674 } 675 } 676 677 for (int varNdx = 0; varNdx < (int)shader->getDefaultBlock().variables.size(); ++varNdx) 678 if (shader->getDefaultBlock().variables[varNdx].storage == storage) 679 retVal += getMappedBasicTypeSum(shader->getDefaultBlock().variables[varNdx].varType, typeMap); 680 681 return retVal; 682 } 683 684 static int getNumDataTypeComponents (glu::DataType type) 685 { 686 if (glu::isDataTypeScalarOrVector(type) || glu::isDataTypeMatrix(type)) 687 return glu::getDataTypeScalarSize(type); 688 else 689 return 0; 690 } 691 692 static int getNumDataTypeVectors (glu::DataType type) 693 { 694 if (glu::isDataTypeScalar(type)) 695 return 1; 696 else if (glu::isDataTypeVector(type)) 697 return 1; 698 else if (glu::isDataTypeMatrix(type)) 699 return glu::getDataTypeMatrixNumColumns(type); 700 else 701 return 0; 702 } 703 704 static int getNumComponents (const ProgramInterfaceDefinition::Shader* shader, glu::Storage storage) 705 { 706 return getMappedBasicTypeSum(shader, storage, getNumDataTypeComponents); 707 } 708 709 static int getNumVectors (const ProgramInterfaceDefinition::Shader* shader, glu::Storage storage) 710 { 711 return getMappedBasicTypeSum(shader, storage, getNumDataTypeVectors); 712 } 713 714 static int getNumDefaultBlockComponents (const ProgramInterfaceDefinition::Shader* shader, glu::Storage storage) 715 { 716 int retVal = 0; 717 718 for (int varNdx = 0; varNdx < (int)shader->getDefaultBlock().variables.size(); ++varNdx) 719 if (shader->getDefaultBlock().variables[varNdx].storage == storage) 720 retVal += getMappedBasicTypeSum(shader->getDefaultBlock().variables[varNdx].varType, getNumDataTypeComponents); 721 722 return retVal; 723 } 724 725 static int getMaxBufferBinding (const ProgramInterfaceDefinition::Shader* shader, glu::Storage storage) 726 { 727 int maxBinding = -1; 728 729 for (int ndx = 0; ndx < (int)shader->getDefaultBlock().interfaceBlocks.size(); ++ndx) 730 { 731 if (shader->getDefaultBlock().interfaceBlocks[ndx].storage == storage) 732 { 733 const int binding = (shader->getDefaultBlock().interfaceBlocks[ndx].layout.binding == -1) ? (0) : (shader->getDefaultBlock().interfaceBlocks[ndx].layout.binding); 734 int numInstances = 1; 735 736 for (int dimensionNdx = 0; dimensionNdx < (int)shader->getDefaultBlock().interfaceBlocks[ndx].dimensions.size(); ++dimensionNdx) 737 numInstances *= shader->getDefaultBlock().interfaceBlocks[ndx].dimensions[dimensionNdx]; 738 739 maxBinding = de::max(maxBinding, binding + numInstances - 1); 740 } 741 } 742 743 return (int)maxBinding; 744 } 745 746 static int getBufferTypeSize (glu::DataType type, glu::MatrixOrder order) 747 { 748 // assume vec4 alignments, should produce values greater than or equal to the actual resource usage 749 int numVectors = 0; 750 751 if (glu::isDataTypeScalarOrVector(type)) 752 numVectors = 1; 753 else if (glu::isDataTypeMatrix(type) && order == glu::MATRIXORDER_ROW_MAJOR) 754 numVectors = glu::getDataTypeMatrixNumRows(type); 755 else if (glu::isDataTypeMatrix(type) && order != glu::MATRIXORDER_ROW_MAJOR) 756 numVectors = glu::getDataTypeMatrixNumColumns(type); 757 else 758 DE_ASSERT(false); 759 760 return 4 * numVectors; 761 } 762 763 static int getBufferVariableSize (const glu::VarType& type, glu::MatrixOrder order) 764 { 765 if (type.isBasicType()) 766 return getBufferTypeSize(type.getBasicType(), order); 767 else if (type.isArrayType()) 768 { 769 const int arraySize = (type.getArraySize() == glu::VarType::UNSIZED_ARRAY) ? (1) : (type.getArraySize()); 770 return arraySize * getBufferVariableSize(type.getElementType(), order); 771 } 772 else if (type.isStructType()) 773 { 774 int sum = 0; 775 for (int ndx = 0; ndx < type.getStructPtr()->getNumMembers(); ++ndx) 776 sum += getBufferVariableSize(type.getStructPtr()->getMember(ndx).getType(), order); 777 return sum; 778 } 779 else 780 { 781 DE_ASSERT(false); 782 return false; 783 } 784 } 785 786 static int getBufferSize (const glu::InterfaceBlock& block, glu::MatrixOrder blockOrder) 787 { 788 int size = 0; 789 790 for (int ndx = 0; ndx < (int)block.variables.size(); ++ndx) 791 size += getBufferVariableSize(block.variables[ndx].varType, (block.variables[ndx].layout.matrixOrder == glu::MATRIXORDER_LAST) ? (blockOrder) : (block.variables[ndx].layout.matrixOrder)); 792 793 return size; 794 } 795 796 static int getBufferMaxSize (const ProgramInterfaceDefinition::Shader* shader, glu::Storage storage) 797 { 798 int maxSize = 0; 799 800 for (int ndx = 0; ndx < (int)shader->getDefaultBlock().interfaceBlocks.size(); ++ndx) 801 if (shader->getDefaultBlock().interfaceBlocks[ndx].storage == storage) 802 maxSize = de::max(maxSize, getBufferSize(shader->getDefaultBlock().interfaceBlocks[ndx], shader->getDefaultBlock().interfaceBlocks[ndx].layout.matrixOrder)); 803 804 return (int)maxSize; 805 } 806 807 static int getAtomicCounterMaxBinding (const ProgramInterfaceDefinition::Shader* shader) 808 { 809 int maxBinding = -1; 810 811 for (int ndx = 0; ndx < (int)shader->getDefaultBlock().variables.size(); ++ndx) 812 { 813 if (containsSubType(shader->getDefaultBlock().variables[ndx].varType, glu::TYPE_UINT_ATOMIC_COUNTER)) 814 { 815 DE_ASSERT(shader->getDefaultBlock().variables[ndx].layout.binding != -1); 816 maxBinding = de::max(maxBinding, shader->getDefaultBlock().variables[ndx].layout.binding); 817 } 818 } 819 820 return (int)maxBinding; 821 } 822 823 static int getUniformMaxBinding (const ProgramInterfaceDefinition::Shader* shader, bool (*predicate)(glu::DataType)) 824 { 825 int maxBinding = -1; 826 827 for (int ndx = 0; ndx < (int)shader->getDefaultBlock().variables.size(); ++ndx) 828 maxBinding = de::max(maxBinding, shader->getDefaultBlock().variables[ndx].layout.binding + getNumTypeInstances(shader->getDefaultBlock().variables[ndx].varType, predicate)); 829 830 return (int)maxBinding; 831 } 832 833 static int getAtomicCounterMaxBufferSize (const ProgramInterfaceDefinition::Shader* shader) 834 { 835 std::map<int, int> bufferSizes; 836 int maxSize = 0; 837 838 for (int ndx = 0; ndx < (int)shader->getDefaultBlock().variables.size(); ++ndx) 839 { 840 if (containsSubType(shader->getDefaultBlock().variables[ndx].varType, glu::TYPE_UINT_ATOMIC_COUNTER)) 841 { 842 const int bufferBinding = shader->getDefaultBlock().variables[ndx].layout.binding; 843 const int offset = (shader->getDefaultBlock().variables[ndx].layout.offset == -1) ? (0) : (shader->getDefaultBlock().variables[ndx].layout.offset); 844 const int size = offset + 4 * getNumTypeInstances(shader->getDefaultBlock().variables[ndx].varType, glu::isDataTypeAtomicCounter); 845 846 DE_ASSERT(shader->getDefaultBlock().variables[ndx].layout.binding != -1); 847 848 if (bufferSizes.find(bufferBinding) == bufferSizes.end()) 849 bufferSizes[bufferBinding] = size; 850 else 851 bufferSizes[bufferBinding] = de::max<int>(bufferSizes[bufferBinding], size); 852 } 853 } 854 855 for (std::map<int, int>::iterator it = bufferSizes.begin(); it != bufferSizes.end(); ++it) 856 maxSize = de::max<int>(maxSize, it->second); 857 858 return maxSize; 859 } 860 861 static int getNumFeedbackVaryingComponents (const ProgramInterfaceDefinition::Program* program, const std::string& name) 862 { 863 std::vector<VariablePathComponent> path; 864 865 if (name == "gl_Position") 866 return 4; 867 868 DE_ASSERT(deStringBeginsWith(name.c_str(), "gl_") == DE_FALSE); 869 870 if (!traverseProgramVariablePath(path, program, name, VariableSearchFilter(glu::SHADERTYPE_VERTEX, glu::STORAGE_OUT))) 871 DE_ASSERT(false); // Program failed validate, invalid operation 872 873 return getMappedBasicTypeSum(*path.back().getVariableType(), getNumDataTypeComponents); 874 } 875 876 static int getNumXFBComponents (const ProgramInterfaceDefinition::Program* program) 877 { 878 int numComponents = 0; 879 880 for (int ndx = 0; ndx < (int)program->getTransformFeedbackVaryings().size(); ++ndx) 881 numComponents += getNumFeedbackVaryingComponents(program, program->getTransformFeedbackVaryings()[ndx]); 882 883 return numComponents; 884 } 885 886 static int getNumMaxXFBOutputComponents (const ProgramInterfaceDefinition::Program* program) 887 { 888 int numComponents = 0; 889 890 for (int ndx = 0; ndx < (int)program->getTransformFeedbackVaryings().size(); ++ndx) 891 numComponents = de::max(numComponents, getNumFeedbackVaryingComponents(program, program->getTransformFeedbackVaryings()[ndx])); 892 893 return numComponents; 894 } 895 896 static int getFragmentOutputMaxLocation (const ProgramInterfaceDefinition::Shader* shader) 897 { 898 DE_ASSERT(shader->getType() == glu::SHADERTYPE_FRAGMENT); 899 900 int maxOutputLocation = -1; 901 902 for (int ndx = 0; ndx < (int)shader->getDefaultBlock().variables.size(); ++ndx) 903 { 904 if (shader->getDefaultBlock().variables[ndx].storage == glu::STORAGE_OUT) 905 { 906 // missing location qualifier means location == 0 907 const int outputLocation = (shader->getDefaultBlock().variables[ndx].layout.location == -1) 908 ? (0) 909 : (shader->getDefaultBlock().variables[ndx].layout.location); 910 911 // only basic types or arrays of basic types possible 912 DE_ASSERT(!shader->getDefaultBlock().variables[ndx].varType.isStructType()); 913 914 const int locationSlotsTaken = (shader->getDefaultBlock().variables[ndx].varType.isArrayType()) 915 ? (shader->getDefaultBlock().variables[ndx].varType.getArraySize()) 916 : (1); 917 918 maxOutputLocation = de::max(maxOutputLocation, outputLocation + locationSlotsTaken - 1); 919 } 920 } 921 922 return maxOutputLocation; 923 } 924 925 } // anonymous 926 927 std::vector<std::string> getProgramInterfaceBlockMemberResourceList (const glu::InterfaceBlock& interfaceBlock) 928 { 929 const std::string namePrefix = (!interfaceBlock.instanceName.empty()) ? (interfaceBlock.interfaceName + ".") : (""); 930 const bool isTopLevelBufferVariable = (interfaceBlock.storage == glu::STORAGE_BUFFER); 931 std::vector<std::string> resources; 932 933 for (int variableNdx = 0; variableNdx < (int)interfaceBlock.variables.size(); ++variableNdx) 934 generateVariableTypeResourceNames(resources, 935 namePrefix + interfaceBlock.variables[variableNdx].name, 936 interfaceBlock.variables[variableNdx].varType, 937 (isTopLevelBufferVariable) ? 938 (RESOURCE_NAME_GENERATION_FLAG_TOP_LEVEL_BUFFER_VARIABLE) : 939 (RESOURCE_NAME_GENERATION_FLAG_DEFAULT)); 940 941 return resources; 942 } 943 944 std::vector<std::string> getProgramInterfaceResourceList (const ProgramInterfaceDefinition::Program* program, ProgramInterface interface) 945 { 946 // The same {uniform (block), buffer (variable)} can exist in multiple shaders, remove duplicates but keep order 947 const bool removeDuplicated = (interface == PROGRAMINTERFACE_UNIFORM) || 948 (interface == PROGRAMINTERFACE_UNIFORM_BLOCK) || 949 (interface == PROGRAMINTERFACE_BUFFER_VARIABLE) || 950 (interface == PROGRAMINTERFACE_SHADER_STORAGE_BLOCK); 951 std::vector<std::string> resources; 952 953 switch (interface) 954 { 955 case PROGRAMINTERFACE_UNIFORM: 956 case PROGRAMINTERFACE_BUFFER_VARIABLE: 957 { 958 const glu::Storage storage = (interface == PROGRAMINTERFACE_UNIFORM) ? (glu::STORAGE_UNIFORM) : (glu::STORAGE_BUFFER); 959 960 for (int shaderNdx = 0; shaderNdx < (int)program->getShaders().size(); ++shaderNdx) 961 { 962 const ProgramInterfaceDefinition::Shader* shader = program->getShaders()[shaderNdx]; 963 964 for (int variableNdx = 0; variableNdx < (int)shader->getDefaultBlock().variables.size(); ++variableNdx) 965 if (shader->getDefaultBlock().variables[variableNdx].storage == storage) 966 generateVariableTypeResourceNames(resources, 967 shader->getDefaultBlock().variables[variableNdx].name, 968 shader->getDefaultBlock().variables[variableNdx].varType, 969 RESOURCE_NAME_GENERATION_FLAG_DEFAULT); 970 971 for (int interfaceNdx = 0; interfaceNdx < (int)shader->getDefaultBlock().interfaceBlocks.size(); ++interfaceNdx) 972 { 973 const glu::InterfaceBlock& interfaceBlock = shader->getDefaultBlock().interfaceBlocks[interfaceNdx]; 974 if (interfaceBlock.storage == storage) 975 { 976 const std::vector<std::string> blockResources = getProgramInterfaceBlockMemberResourceList(interfaceBlock); 977 resources.insert(resources.end(), blockResources.begin(), blockResources.end()); 978 } 979 } 980 } 981 break; 982 } 983 984 case PROGRAMINTERFACE_UNIFORM_BLOCK: 985 case PROGRAMINTERFACE_SHADER_STORAGE_BLOCK: 986 { 987 const glu::Storage storage = (interface == PROGRAMINTERFACE_UNIFORM_BLOCK) ? (glu::STORAGE_UNIFORM) : (glu::STORAGE_BUFFER); 988 989 for (int shaderNdx = 0; shaderNdx < (int)program->getShaders().size(); ++shaderNdx) 990 { 991 const ProgramInterfaceDefinition::Shader* shader = program->getShaders()[shaderNdx]; 992 for (int interfaceNdx = 0; interfaceNdx < (int)shader->getDefaultBlock().interfaceBlocks.size(); ++interfaceNdx) 993 { 994 const glu::InterfaceBlock& interfaceBlock = shader->getDefaultBlock().interfaceBlocks[interfaceNdx]; 995 if (interfaceBlock.storage == storage) 996 { 997 std::vector<int> index(interfaceBlock.dimensions.size(), 0); 998 999 for (;;) 1000 { 1001 // add resource string for each element 1002 { 1003 std::ostringstream name; 1004 name << interfaceBlock.interfaceName; 1005 1006 for (int dimensionNdx = 0; dimensionNdx < (int)interfaceBlock.dimensions.size(); ++dimensionNdx) 1007 name << "[" << index[dimensionNdx] << "]"; 1008 1009 resources.push_back(name.str()); 1010 } 1011 1012 // increment index 1013 if (!incrementMultiDimensionIndex(index, interfaceBlock.dimensions)) 1014 break; 1015 } 1016 } 1017 } 1018 } 1019 break; 1020 } 1021 1022 case PROGRAMINTERFACE_PROGRAM_INPUT: 1023 case PROGRAMINTERFACE_PROGRAM_OUTPUT: 1024 { 1025 const glu::Storage storage = (interface == PROGRAMINTERFACE_PROGRAM_INPUT) ? (glu::STORAGE_IN) : (glu::STORAGE_OUT); 1026 const glu::ShaderType shaderType = (interface == PROGRAMINTERFACE_PROGRAM_INPUT) ? (program->getFirstStage()) : (program->getLastStage()); 1027 1028 for (int shaderNdx = 0; shaderNdx < (int)program->getShaders().size(); ++shaderNdx) 1029 { 1030 const ProgramInterfaceDefinition::Shader* shader = program->getShaders()[shaderNdx]; 1031 1032 if (shader->getType() != shaderType) 1033 continue; 1034 1035 for (int variableNdx = 0; variableNdx < (int)shader->getDefaultBlock().variables.size(); ++variableNdx) 1036 if (shader->getDefaultBlock().variables[variableNdx].storage == storage) 1037 generateVariableTypeResourceNames(resources, 1038 shader->getDefaultBlock().variables[variableNdx].name, 1039 shader->getDefaultBlock().variables[variableNdx].varType, 1040 RESOURCE_NAME_GENERATION_FLAG_DEFAULT); 1041 1042 for (int interfaceNdx = 0; interfaceNdx < (int)shader->getDefaultBlock().interfaceBlocks.size(); ++interfaceNdx) 1043 { 1044 const glu::InterfaceBlock& interfaceBlock = shader->getDefaultBlock().interfaceBlocks[interfaceNdx]; 1045 if (interfaceBlock.storage == storage) 1046 { 1047 const std::vector<std::string> blockResources = getProgramInterfaceBlockMemberResourceList(interfaceBlock); 1048 resources.insert(resources.end(), blockResources.begin(), blockResources.end()); 1049 } 1050 } 1051 } 1052 1053 // built-ins 1054 if (interface == PROGRAMINTERFACE_PROGRAM_INPUT) 1055 { 1056 if (shaderType == glu::SHADERTYPE_VERTEX && resources.empty()) 1057 resources.push_back("gl_VertexID"); // only read from when there are no other inputs 1058 else if (shaderType == glu::SHADERTYPE_FRAGMENT && resources.empty()) 1059 resources.push_back("gl_FragCoord"); // only read from when there are no other inputs 1060 else if (shaderType == glu::SHADERTYPE_GEOMETRY && resources.empty()) 1061 resources.push_back("gl_in[0].gl_Position"); 1062 else if (shaderType == glu::SHADERTYPE_TESSELLATION_CONTROL) 1063 { 1064 const bool noInputs = resources.empty(); 1065 resources.push_back("gl_InvocationID"); 1066 1067 if (noInputs) 1068 resources.push_back("gl_in[0].gl_Position"); // only read from when there are no other inputs 1069 } 1070 else if (shaderType == glu::SHADERTYPE_TESSELLATION_EVALUATION && resources.empty()) 1071 resources.push_back("gl_in[0].gl_Position"); // only read from when there are no other inputs 1072 else if (shaderType == glu::SHADERTYPE_COMPUTE && resources.empty()) 1073 resources.push_back("gl_NumWorkGroups"); // only read from when there are no other inputs 1074 } 1075 else if (interface == PROGRAMINTERFACE_PROGRAM_OUTPUT) 1076 { 1077 if (shaderType == glu::SHADERTYPE_VERTEX) 1078 resources.push_back("gl_Position"); 1079 else if (shaderType == glu::SHADERTYPE_FRAGMENT && resources.empty()) 1080 resources.push_back("gl_FragDepth"); // only written to when there are no other outputs 1081 else if (shaderType == glu::SHADERTYPE_GEOMETRY) 1082 resources.push_back("gl_Position"); 1083 else if (shaderType == glu::SHADERTYPE_TESSELLATION_CONTROL) 1084 resources.push_back("gl_out[0].gl_Position"); 1085 else if (shaderType == glu::SHADERTYPE_TESSELLATION_EVALUATION) 1086 resources.push_back("gl_Position"); 1087 } 1088 1089 break; 1090 } 1091 1092 case PROGRAMINTERFACE_TRANSFORM_FEEDBACK_VARYING: 1093 { 1094 for (int varyingNdx = 0; varyingNdx < (int)program->getTransformFeedbackVaryings().size(); ++varyingNdx) 1095 { 1096 const std::string& varyingName = program->getTransformFeedbackVaryings()[varyingNdx]; 1097 1098 if (deStringBeginsWith(varyingName.c_str(), "gl_")) 1099 resources.push_back(varyingName); // builtin 1100 else 1101 { 1102 std::vector<VariablePathComponent> path; 1103 1104 if (!traverseProgramVariablePath(path, program, varyingName, VariableSearchFilter(glu::SHADERTYPE_VERTEX, glu::STORAGE_OUT))) 1105 DE_ASSERT(false); // Program failed validate, invalid operation 1106 1107 generateVariableTypeResourceNames(resources, 1108 varyingName, 1109 *path.back().getVariableType(), 1110 RESOURCE_NAME_GENERATION_FLAG_TRANSFORM_FEEDBACK_VARIABLE); 1111 } 1112 } 1113 1114 break; 1115 } 1116 1117 default: 1118 DE_ASSERT(false); 1119 } 1120 1121 if (removeDuplicated) 1122 { 1123 std::set<std::string> addedVariables; 1124 std::vector<std::string> uniqueResouces; 1125 1126 for (int ndx = 0; ndx < (int)resources.size(); ++ndx) 1127 { 1128 if (addedVariables.find(resources[ndx]) == addedVariables.end()) 1129 { 1130 addedVariables.insert(resources[ndx]); 1131 uniqueResouces.push_back(resources[ndx]); 1132 } 1133 } 1134 1135 uniqueResouces.swap(resources); 1136 } 1137 1138 return resources; 1139 } 1140 1141 glu::ProgramSources generateProgramInterfaceProgramSources (const ProgramInterfaceDefinition::Program* program) 1142 { 1143 glu::ProgramSources sources; 1144 1145 DE_ASSERT(program->isValid()); 1146 1147 for (int shaderNdx = 0; shaderNdx < (int)program->getShaders().size(); ++shaderNdx) 1148 { 1149 const ProgramInterfaceDefinition::Shader* shader = program->getShaders()[shaderNdx]; 1150 bool containsUserDefinedOutputs = false; 1151 bool containsUserDefinedInputs = false; 1152 std::ostringstream sourceBuf; 1153 std::ostringstream usageBuf; 1154 1155 sourceBuf << glu::getGLSLVersionDeclaration(shader->getVersion()) << "\n" 1156 << getShaderTypeDeclarations(shader->getType()) 1157 << "\n"; 1158 1159 // Struct definitions 1160 1161 writeStructureDefinitions(sourceBuf, shader->getDefaultBlock()); 1162 1163 // variables in the default scope 1164 1165 for (int ndx = 0; ndx < (int)shader->getDefaultBlock().variables.size(); ++ndx) 1166 sourceBuf << shader->getDefaultBlock().variables[ndx] << ";\n"; 1167 1168 if (!shader->getDefaultBlock().variables.empty()) 1169 sourceBuf << "\n"; 1170 1171 // Interface blocks 1172 1173 for (int ndx = 0; ndx < (int)shader->getDefaultBlock().interfaceBlocks.size(); ++ndx) 1174 writeInterfaceBlock(sourceBuf, shader->getDefaultBlock().interfaceBlocks[ndx]); 1175 1176 // Use inputs and outputs so that they won't be removed by the optimizer 1177 1178 usageBuf << "highp vec4 readInputs()\n" 1179 "{\n" 1180 " highp vec4 retValue = vec4(0.0);\n"; 1181 1182 // User-defined inputs 1183 1184 for (int ndx = 0; ndx < (int)shader->getDefaultBlock().variables.size(); ++ndx) 1185 { 1186 if (shader->getDefaultBlock().variables[ndx].storage == glu::STORAGE_IN || 1187 shader->getDefaultBlock().variables[ndx].storage == glu::STORAGE_UNIFORM) 1188 { 1189 writeVariableReadAccumulateExpression(usageBuf, "retValue", shader->getDefaultBlock().variables[ndx].name, shader->getDefaultBlock().variables[ndx].varType); 1190 containsUserDefinedInputs = true; 1191 } 1192 } 1193 1194 for (int interfaceNdx = 0; interfaceNdx < (int)shader->getDefaultBlock().interfaceBlocks.size(); ++interfaceNdx) 1195 { 1196 const glu::InterfaceBlock& interface = shader->getDefaultBlock().interfaceBlocks[interfaceNdx]; 1197 if (interface.storage == glu::STORAGE_UNIFORM || 1198 (interface.storage == glu::STORAGE_BUFFER && (interface.memoryAccessQualifierFlags & glu::MEMORYACCESSQUALIFIER_WRITEONLY_BIT) == 0)) 1199 { 1200 writeInterfaceReadAccumulateExpression(usageBuf, "retValue", interface); 1201 containsUserDefinedInputs = true; 1202 } 1203 } 1204 1205 // Built-in-inputs 1206 1207 if (!containsUserDefinedInputs) 1208 { 1209 if (shader->getType() == glu::SHADERTYPE_VERTEX) 1210 usageBuf << " retValue += vec4(float(gl_VertexID));\n"; 1211 else if (shader->getType() == glu::SHADERTYPE_FRAGMENT) 1212 usageBuf << " retValue += gl_FragCoord;\n"; 1213 else if (shader->getType() == glu::SHADERTYPE_GEOMETRY) 1214 usageBuf << " retValue += gl_in[0].gl_Position;\n"; 1215 else if (shader->getType() == glu::SHADERTYPE_TESSELLATION_CONTROL) 1216 usageBuf << " retValue += gl_in[0].gl_Position;\n"; 1217 else if (shader->getType() == glu::SHADERTYPE_TESSELLATION_EVALUATION) 1218 usageBuf << " retValue += gl_in[0].gl_Position;\n"; 1219 else if (shader->getType() == glu::SHADERTYPE_COMPUTE) 1220 usageBuf << " retValue += vec4(float(gl_NumWorkGroups.x));\n"; 1221 } 1222 1223 usageBuf << " return retValue;\n" 1224 "}\n\n"; 1225 1226 usageBuf << "void writeOutputs(in highp vec4 dummyValue)\n" 1227 "{\n"; 1228 1229 // User-defined outputs 1230 1231 for (int ndx = 0; ndx < (int)shader->getDefaultBlock().variables.size(); ++ndx) 1232 { 1233 if (shader->getDefaultBlock().variables[ndx].storage == glu::STORAGE_OUT) 1234 { 1235 writeVariableWriteExpression(usageBuf, "dummyValue", shader->getDefaultBlock().variables[ndx].name, shader->getDefaultBlock().variables[ndx].varType); 1236 containsUserDefinedOutputs = true; 1237 } 1238 } 1239 1240 for (int interfaceNdx = 0; interfaceNdx < (int)shader->getDefaultBlock().interfaceBlocks.size(); ++interfaceNdx) 1241 { 1242 const glu::InterfaceBlock& interface = shader->getDefaultBlock().interfaceBlocks[interfaceNdx]; 1243 if (interface.storage == glu::STORAGE_BUFFER && (interface.memoryAccessQualifierFlags & glu::MEMORYACCESSQUALIFIER_READONLY_BIT) == 0) 1244 { 1245 writeInterfaceWriteExpression(usageBuf, "dummyValue", interface); 1246 containsUserDefinedOutputs = true; 1247 } 1248 } 1249 1250 // Builtin-outputs that must be written to 1251 1252 if (shader->getType() == glu::SHADERTYPE_VERTEX) 1253 usageBuf << " gl_Position = dummyValue;\n"; 1254 else if (shader->getType() == glu::SHADERTYPE_GEOMETRY) 1255 usageBuf << " gl_Position = dummyValue;\n" 1256 " EmitVertex();\n"; 1257 else if (shader->getType() == glu::SHADERTYPE_TESSELLATION_CONTROL) 1258 usageBuf << " gl_out[gl_InvocationID].gl_Position = dummyValue;\n"; 1259 else if (shader->getType() == glu::SHADERTYPE_TESSELLATION_EVALUATION) 1260 usageBuf << " gl_Position = dummyValue;\n"; 1261 1262 // Output to sink input data to 1263 1264 if (!containsUserDefinedOutputs) 1265 { 1266 if (shader->getType() == glu::SHADERTYPE_FRAGMENT) 1267 usageBuf << " gl_FragDepth = dot(dummyValue.xy, dummyValue.xw);\n"; 1268 else if (shader->getType() == glu::SHADERTYPE_COMPUTE) 1269 usageBuf << " dummyOutputBlock.dummyValue = dummyValue;\n"; 1270 } 1271 1272 usageBuf << "}\n\n" 1273 "void main()\n" 1274 "{\n" 1275 " writeOutputs(readInputs());\n" 1276 "}\n"; 1277 1278 // Interface for dummy output 1279 1280 if (shader->getType() == glu::SHADERTYPE_COMPUTE && !containsUserDefinedOutputs) 1281 { 1282 sourceBuf << "writeonly buffer DummyOutputInterface\n" 1283 << "{\n" 1284 << " highp vec4 dummyValue;\n" 1285 << "} dummyOutputBlock;\n\n"; 1286 } 1287 1288 sources << glu::ShaderSource(shader->getType(), sourceBuf.str() + usageBuf.str()); 1289 } 1290 1291 if (program->isSeparable()) 1292 sources << glu::ProgramSeparable(true); 1293 1294 for (int ndx = 0; ndx < (int)program->getTransformFeedbackVaryings().size(); ++ndx) 1295 sources << glu::TransformFeedbackVarying(program->getTransformFeedbackVaryings()[ndx]); 1296 1297 if (program->getTransformFeedbackMode()) 1298 sources << glu::TransformFeedbackMode(program->getTransformFeedbackMode()); 1299 1300 return sources; 1301 } 1302 1303 bool findProgramVariablePathByPathName (std::vector<VariablePathComponent>& typePath, const ProgramInterfaceDefinition::Program* program, const std::string& pathName, const VariableSearchFilter& filter) 1304 { 1305 std::vector<VariablePathComponent> modifiedPath; 1306 1307 if (!traverseProgramVariablePath(modifiedPath, program, pathName, filter)) 1308 return false; 1309 1310 // modify param only on success 1311 typePath.swap(modifiedPath); 1312 return true; 1313 } 1314 1315 ProgramInterfaceDefinition::ShaderResourceUsage getShaderResourceUsage (const ProgramInterfaceDefinition::Shader* shader) 1316 { 1317 ProgramInterfaceDefinition::ShaderResourceUsage retVal; 1318 1319 retVal.numInputs = getNumTypeInstances(shader, glu::STORAGE_IN, dummyConstantTypeFilter<true>); 1320 retVal.numInputVectors = getNumVectors(shader, glu::STORAGE_IN); 1321 retVal.numInputComponents = getNumComponents(shader, glu::STORAGE_IN); 1322 1323 retVal.numOutputs = getNumTypeInstances(shader, glu::STORAGE_OUT, dummyConstantTypeFilter<true>); 1324 retVal.numOutputVectors = getNumVectors(shader, glu::STORAGE_OUT); 1325 retVal.numOutputComponents = getNumComponents(shader, glu::STORAGE_OUT); 1326 1327 retVal.numDefaultBlockUniformComponents = getNumDefaultBlockComponents(shader, glu::STORAGE_UNIFORM); 1328 retVal.numCombinedUniformComponents = getNumComponents(shader, glu::STORAGE_UNIFORM); 1329 retVal.numUniformVectors = getNumVectors(shader, glu::STORAGE_UNIFORM); 1330 1331 retVal.numSamplers = getNumTypeInstances(shader, glu::STORAGE_UNIFORM, glu::isDataTypeSampler); 1332 retVal.numImages = getNumTypeInstances(shader, glu::STORAGE_UNIFORM, glu::isDataTypeImage); 1333 1334 retVal.numAtomicCounterBuffers = getNumAtomicCounterBuffers(shader); 1335 retVal.numAtomicCounters = getNumTypeInstances(shader, glu::STORAGE_UNIFORM, glu::isDataTypeAtomicCounter); 1336 1337 retVal.numUniformBlocks = getNumShaderBlocks(shader, glu::STORAGE_UNIFORM); 1338 retVal.numShaderStorageBlocks = getNumShaderBlocks(shader, glu::STORAGE_BUFFER); 1339 1340 return retVal; 1341 } 1342 1343 ProgramInterfaceDefinition::ProgramResourceUsage getCombinedProgramResourceUsage (const ProgramInterfaceDefinition::Program* program) 1344 { 1345 ProgramInterfaceDefinition::ProgramResourceUsage retVal; 1346 1347 retVal.uniformBufferMaxBinding = -1; // max binding is inclusive upper bound. Allow 0 bindings by using negative value 1348 retVal.uniformBufferMaxSize = 0; 1349 retVal.numUniformBlocks = 0; 1350 retVal.numCombinedVertexUniformComponents = 0; 1351 retVal.numCombinedFragmentUniformComponents = 0; 1352 retVal.shaderStorageBufferMaxBinding = -1; // see above 1353 retVal.shaderStorageBufferMaxSize = 0; 1354 retVal.numShaderStorageBlocks = 0; 1355 retVal.numVaryingComponents = 0; 1356 retVal.numVaryingVectors = 0; 1357 retVal.numCombinedSamplers = 0; 1358 retVal.atomicCounterBufferMaxBinding = -1; // see above 1359 retVal.atomicCounterBufferMaxSize = 0; 1360 retVal.numAtomicCounterBuffers = 0; 1361 retVal.numAtomicCounters = 0; 1362 retVal.maxImageBinding = -1; // see above 1363 retVal.numCombinedImages = 0; 1364 retVal.numCombinedOutputResources = 0; 1365 retVal.numXFBInterleavedComponents = 0; 1366 retVal.numXFBSeparateAttribs = 0; 1367 retVal.numXFBSeparateComponents = 0; 1368 retVal.fragmentOutputMaxBinding = -1; // see above 1369 1370 for (int shaderNdx = 0; shaderNdx < (int)program->getShaders().size(); ++shaderNdx) 1371 { 1372 const ProgramInterfaceDefinition::Shader* const shader = program->getShaders()[shaderNdx]; 1373 1374 retVal.uniformBufferMaxBinding = de::max(retVal.uniformBufferMaxBinding, getMaxBufferBinding(shader, glu::STORAGE_UNIFORM)); 1375 retVal.uniformBufferMaxSize = de::max(retVal.uniformBufferMaxSize, getBufferMaxSize(shader, glu::STORAGE_UNIFORM)); 1376 retVal.numUniformBlocks += getNumShaderBlocks(shader, glu::STORAGE_UNIFORM); 1377 1378 if (shader->getType() == glu::SHADERTYPE_VERTEX) 1379 retVal.numCombinedVertexUniformComponents += getNumComponents(shader, glu::STORAGE_UNIFORM); 1380 1381 if (shader->getType() == glu::SHADERTYPE_FRAGMENT) 1382 retVal.numCombinedFragmentUniformComponents += getNumComponents(shader, glu::STORAGE_UNIFORM); 1383 1384 retVal.shaderStorageBufferMaxBinding = de::max(retVal.shaderStorageBufferMaxBinding, getMaxBufferBinding(shader, glu::STORAGE_BUFFER)); 1385 retVal.shaderStorageBufferMaxSize = de::max(retVal.shaderStorageBufferMaxSize, getBufferMaxSize(shader, glu::STORAGE_BUFFER)); 1386 retVal.numShaderStorageBlocks += getNumShaderBlocks(shader, glu::STORAGE_BUFFER); 1387 1388 if (shader->getType() == glu::SHADERTYPE_VERTEX) 1389 { 1390 retVal.numVaryingComponents += getNumComponents(shader, glu::STORAGE_OUT); 1391 retVal.numVaryingVectors += getNumVectors(shader, glu::STORAGE_OUT); 1392 } 1393 1394 retVal.numCombinedSamplers += getNumTypeInstances(shader, glu::STORAGE_UNIFORM, glu::isDataTypeSampler); 1395 1396 retVal.atomicCounterBufferMaxBinding = de::max(retVal.atomicCounterBufferMaxBinding, getAtomicCounterMaxBinding(shader)); 1397 retVal.atomicCounterBufferMaxSize = de::max(retVal.atomicCounterBufferMaxSize, getAtomicCounterMaxBufferSize(shader)); 1398 retVal.numAtomicCounterBuffers += getNumAtomicCounterBuffers(shader); 1399 retVal.numAtomicCounters += getNumTypeInstances(shader, glu::STORAGE_UNIFORM, glu::isDataTypeAtomicCounter); 1400 retVal.maxImageBinding = de::max(retVal.maxImageBinding, getUniformMaxBinding(shader, glu::isDataTypeImage)); 1401 retVal.numCombinedImages += getNumTypeInstances(shader, glu::STORAGE_UNIFORM, glu::isDataTypeImage); 1402 1403 retVal.numCombinedOutputResources += getNumTypeInstances(shader, glu::STORAGE_UNIFORM, glu::isDataTypeImage); 1404 retVal.numCombinedOutputResources += getNumShaderBlocks(shader, glu::STORAGE_BUFFER); 1405 1406 if (shader->getType() == glu::SHADERTYPE_FRAGMENT) 1407 { 1408 retVal.numCombinedOutputResources += getNumVectors(shader, glu::STORAGE_OUT); 1409 retVal.fragmentOutputMaxBinding = de::max(retVal.fragmentOutputMaxBinding, getFragmentOutputMaxLocation(shader)); 1410 } 1411 } 1412 1413 if (program->getTransformFeedbackMode() == GL_INTERLEAVED_ATTRIBS) 1414 retVal.numXFBInterleavedComponents = getNumXFBComponents(program); 1415 else if (program->getTransformFeedbackMode() == GL_SEPARATE_ATTRIBS) 1416 { 1417 retVal.numXFBSeparateAttribs = (int)program->getTransformFeedbackVaryings().size(); 1418 retVal.numXFBSeparateComponents = getNumMaxXFBOutputComponents(program); 1419 } 1420 1421 return retVal; 1422 } 1423 1424 } // Functional 1425 } // gles31 1426 } // deqp 1427