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 39namespace deqp 40{ 41namespace gles31 42{ 43namespace Functional 44{ 45namespace ProgramInterfaceDefinition 46{ 47 48VariableSearchFilter::VariableSearchFilter (void) 49 : m_shaderTypeBits (0xFFFFFFFFul) 50 , m_storageBits (0xFFFFFFFFul) 51{ 52} 53 54VariableSearchFilter VariableSearchFilter::createShaderTypeFilter (glu::ShaderType type) 55{ 56 DE_ASSERT(type < glu::SHADERTYPE_LAST); 57 58 VariableSearchFilter filter; 59 filter.m_shaderTypeBits = (1u << type); 60 return filter; 61} 62 63VariableSearchFilter VariableSearchFilter::createStorageFilter (glu::Storage storage) 64{ 65 DE_ASSERT(storage < glu::STORAGE_LAST); 66 67 VariableSearchFilter filter; 68 filter.m_storageBits = (1u << storage); 69 return filter; 70} 71 72VariableSearchFilter VariableSearchFilter::createShaderTypeStorageFilter (glu::ShaderType type, glu::Storage storage) 73{ 74 return logicalAnd(createShaderTypeFilter(type), createStorageFilter(storage)); 75} 76 77VariableSearchFilter VariableSearchFilter::logicalOr (const VariableSearchFilter& a, const VariableSearchFilter& b) 78{ 79 VariableSearchFilter filter; 80 filter.m_shaderTypeBits = a.m_shaderTypeBits | b.m_shaderTypeBits; 81 filter.m_storageBits = a.m_storageBits | b.m_storageBits; 82 return filter; 83} 84 85VariableSearchFilter VariableSearchFilter::logicalAnd (const VariableSearchFilter& a, const VariableSearchFilter& b) 86{ 87 VariableSearchFilter filter; 88 filter.m_shaderTypeBits = a.m_shaderTypeBits & b.m_shaderTypeBits; 89 filter.m_storageBits = a.m_storageBits & b.m_storageBits; 90 return filter; 91} 92 93bool VariableSearchFilter::matchesFilter (const ProgramInterfaceDefinition::Shader* shader) const 94{ 95 DE_ASSERT(shader->getType() < glu::SHADERTYPE_LAST); 96 return (m_shaderTypeBits & (1u << shader->getType())) != 0; 97} 98 99bool VariableSearchFilter::matchesFilter (const glu::VariableDeclaration& variable) const 100{ 101 DE_ASSERT(variable.storage < glu::STORAGE_LAST); 102 return (m_storageBits & (1u << variable.storage)) != 0; 103} 104 105bool VariableSearchFilter::matchesFilter (const glu::InterfaceBlock& block) const 106{ 107 DE_ASSERT(block.storage < glu::STORAGE_LAST); 108 return (m_storageBits & (1u << block.storage)) != 0; 109} 110 111} // ProgramInterfaceDefinition 112 113static bool incrementMultiDimensionIndex (std::vector<int>& index, const std::vector<int>& dimensions) 114{ 115 int incrementDimensionNdx = (int)(index.size() - 1); 116 117 while (incrementDimensionNdx >= 0) 118 { 119 if (++index[incrementDimensionNdx] == dimensions[incrementDimensionNdx]) 120 index[incrementDimensionNdx--] = 0; 121 else 122 break; 123 } 124 125 return (incrementDimensionNdx != -1); 126} 127 128bool programContainsIOBlocks (const ProgramInterfaceDefinition::Program* program) 129{ 130 for (int shaderNdx = 0; shaderNdx < (int)program->getShaders().size(); ++shaderNdx) 131 { 132 if (shaderContainsIOBlocks(program->getShaders()[shaderNdx])) 133 return true; 134 } 135 136 return false; 137} 138 139bool shaderContainsIOBlocks (const ProgramInterfaceDefinition::Shader* shader) 140{ 141 for (int ndx = 0; ndx < (int)shader->getDefaultBlock().interfaceBlocks.size(); ++ndx) 142 { 143 const glu::Storage storage = shader->getDefaultBlock().interfaceBlocks[ndx].storage; 144 if (storage == glu::STORAGE_IN || 145 storage == glu::STORAGE_OUT || 146 storage == glu::STORAGE_PATCH_IN || 147 storage == glu::STORAGE_PATCH_OUT) 148 { 149 return true; 150 } 151 } 152 return false; 153} 154 155glu::ShaderType getProgramTransformFeedbackStage (const ProgramInterfaceDefinition::Program* program) 156{ 157 if (program->hasStage(glu::SHADERTYPE_GEOMETRY)) 158 return glu::SHADERTYPE_GEOMETRY; 159 160 if (program->hasStage(glu::SHADERTYPE_TESSELLATION_EVALUATION)) 161 return glu::SHADERTYPE_TESSELLATION_EVALUATION; 162 163 if (program->hasStage(glu::SHADERTYPE_VERTEX)) 164 return glu::SHADERTYPE_VERTEX; 165 166 DE_ASSERT(false); 167 return glu::SHADERTYPE_LAST; 168} 169 170void generateVariableTypeResourceNames (std::vector<std::string>& resources, const std::string& name, const glu::VarType& type, deUint32 resourceNameGenerationFlags) 171{ 172 DE_ASSERT((resourceNameGenerationFlags & (~RESOURCE_NAME_GENERATION_FLAG_MASK)) == 0); 173 174 // remove top-level flag from children 175 const deUint32 childFlags = resourceNameGenerationFlags & ~((deUint32)RESOURCE_NAME_GENERATION_FLAG_TOP_LEVEL_BUFFER_VARIABLE); 176 177 if (type.isBasicType()) 178 resources.push_back(name); 179 else if (type.isStructType()) 180 { 181 const glu::StructType* structType = type.getStructPtr(); 182 for (int ndx = 0; ndx < structType->getNumMembers(); ++ndx) 183 generateVariableTypeResourceNames(resources, name + "." + structType->getMember(ndx).getName(), structType->getMember(ndx).getType(), childFlags); 184 } 185 else if (type.isArrayType()) 186 { 187 // Bottom-level arrays of basic types of a transform feedback variable will produce only the first 188 // element but without the trailing "[0]" 189 if (type.getElementType().isBasicType() && 190 (resourceNameGenerationFlags & RESOURCE_NAME_GENERATION_FLAG_TRANSFORM_FEEDBACK_VARIABLE) != 0) 191 { 192 resources.push_back(name); 193 } 194 // Bottom-level arrays of basic types and SSBO top-level arrays of any type procude only first element 195 else if (type.getElementType().isBasicType() || 196 (resourceNameGenerationFlags & RESOURCE_NAME_GENERATION_FLAG_TOP_LEVEL_BUFFER_VARIABLE) != 0) 197 { 198 generateVariableTypeResourceNames(resources, name + "[0]", type.getElementType(), childFlags); 199 } 200 // Other arrays of aggregate types are expanded 201 else 202 { 203 for (int ndx = 0; ndx < type.getArraySize(); ++ndx) 204 generateVariableTypeResourceNames(resources, name + "[" + de::toString(ndx) + "]", type.getElementType(), childFlags); 205 } 206 } 207 else 208 DE_ASSERT(false); 209} 210 211// Program source generation 212 213namespace 214{ 215 216using ProgramInterfaceDefinition::VariablePathComponent; 217using ProgramInterfaceDefinition::VariableSearchFilter; 218 219static std::string getShaderExtensionDeclarations (const ProgramInterfaceDefinition::Shader* shader) 220{ 221 std::vector<std::string> extensions; 222 std::ostringstream buf; 223 224 if (shader->getType() == glu::SHADERTYPE_GEOMETRY) 225 { 226 extensions.push_back("GL_EXT_geometry_shader"); 227 } 228 else if (shader->getType() == glu::SHADERTYPE_TESSELLATION_CONTROL || 229 shader->getType() == glu::SHADERTYPE_TESSELLATION_EVALUATION) 230 { 231 extensions.push_back("GL_EXT_tessellation_shader"); 232 } 233 234 if (shaderContainsIOBlocks(shader)) 235 extensions.push_back("GL_EXT_shader_io_blocks"); 236 237 for (int ndx = 0; ndx < (int)extensions.size(); ++ndx) 238 buf << "#extension " << extensions[ndx] << " : require\n"; 239 return buf.str(); 240} 241 242static std::string getShaderTypeDeclarations (const ProgramInterfaceDefinition::Program* program, glu::ShaderType type) 243{ 244 switch (type) 245 { 246 case glu::SHADERTYPE_VERTEX: 247 return ""; 248 249 case glu::SHADERTYPE_FRAGMENT: 250 return ""; 251 252 case glu::SHADERTYPE_GEOMETRY: 253 { 254 std::ostringstream buf; 255 buf << "layout(points) in;\n" 256 "layout(points, max_vertices=" << program->getGeometryNumOutputVertices() << ") out;\n"; 257 return buf.str(); 258 } 259 260 case glu::SHADERTYPE_TESSELLATION_CONTROL: 261 { 262 std::ostringstream buf; 263 buf << "layout(vertices=" << program->getTessellationNumOutputPatchVertices() << ") out;\n"; 264 return buf.str(); 265 } 266 267 case glu::SHADERTYPE_TESSELLATION_EVALUATION: 268 return "layout(triangles, point_mode) in;\n"; 269 270 case glu::SHADERTYPE_COMPUTE: 271 return "layout(local_size_x=1) in;\n"; 272 273 default: 274 DE_ASSERT(false); 275 return ""; 276 } 277} 278 279class StructNameEqualPredicate 280{ 281public: 282 StructNameEqualPredicate (const char* name) : m_name(name) { } 283 bool operator() (const glu::StructType* type) { return type->hasTypeName() && (deStringEqual(m_name, type->getTypeName()) == DE_TRUE); } 284private: 285 const char* m_name; 286}; 287 288static void collectNamedStructureDefinitions (std::vector<const glu::StructType*>& dst, const glu::VarType& type) 289{ 290 if (type.isBasicType()) 291 return; 292 else if (type.isArrayType()) 293 return collectNamedStructureDefinitions(dst, type.getElementType()); 294 else if (type.isStructType()) 295 { 296 if (type.getStructPtr()->hasTypeName()) 297 { 298 // must be unique (may share the the same struct) 299 std::vector<const glu::StructType*>::iterator where = std::find_if(dst.begin(), dst.end(), StructNameEqualPredicate(type.getStructPtr()->getTypeName())); 300 if (where != dst.end()) 301 { 302 DE_ASSERT(**where == *type.getStructPtr()); 303 304 // identical type has been added already, types of members must be added too 305 return; 306 } 307 } 308 309 // Add types of members first 310 for (int ndx = 0; ndx < type.getStructPtr()->getNumMembers(); ++ndx) 311 collectNamedStructureDefinitions(dst, type.getStructPtr()->getMember(ndx).getType()); 312 313 dst.push_back(type.getStructPtr()); 314 } 315 else 316 DE_ASSERT(false); 317} 318 319static void writeStructureDefinitions (std::ostringstream& buf, const ProgramInterfaceDefinition::DefaultBlock& defaultBlock) 320{ 321 std::vector<const glu::StructType*> namedStructs; 322 323 // Collect all structs in post order 324 325 for (int ndx = 0; ndx < (int)defaultBlock.variables.size(); ++ndx) 326 collectNamedStructureDefinitions(namedStructs, defaultBlock.variables[ndx].varType); 327 328 for (int blockNdx = 0; blockNdx < (int)defaultBlock.interfaceBlocks.size(); ++blockNdx) 329 for (int ndx = 0; ndx < (int)defaultBlock.interfaceBlocks[blockNdx].variables.size(); ++ndx) 330 collectNamedStructureDefinitions(namedStructs, defaultBlock.interfaceBlocks[blockNdx].variables[ndx].varType); 331 332 // Write 333 334 for (int structNdx = 0; structNdx < (int)namedStructs.size(); ++structNdx) 335 { 336 buf << "struct " << namedStructs[structNdx]->getTypeName() << "\n" 337 "{\n"; 338 339 for (int memberNdx = 0; memberNdx < namedStructs[structNdx]->getNumMembers(); ++memberNdx) 340 buf << glu::indent(1) << glu::declare(namedStructs[structNdx]->getMember(memberNdx).getType(), namedStructs[structNdx]->getMember(memberNdx).getName(), 1) << ";\n"; 341 342 buf << "};\n"; 343 } 344 345 if (!namedStructs.empty()) 346 buf << "\n"; 347} 348 349static void writeInterfaceBlock (std::ostringstream& buf, const glu::InterfaceBlock& interfaceBlock) 350{ 351 buf << interfaceBlock.layout; 352 353 if (interfaceBlock.layout != glu::Layout()) 354 buf << " "; 355 356 buf << glu::getStorageName(interfaceBlock.storage) << " " << interfaceBlock.interfaceName << "\n" 357 << "{\n"; 358 359 for (int ndx = 0; ndx < (int)interfaceBlock.variables.size(); ++ndx) 360 buf << glu::indent(1) << interfaceBlock.variables[ndx] << ";\n"; 361 362 buf << "}"; 363 364 if (!interfaceBlock.instanceName.empty()) 365 buf << " " << interfaceBlock.instanceName; 366 367 for (int dimensionNdx = 0; dimensionNdx < (int)interfaceBlock.dimensions.size(); ++dimensionNdx) 368 buf << "[" << interfaceBlock.dimensions[dimensionNdx] << "]"; 369 370 buf << ";\n\n"; 371} 372 373static bool isReadableInterface (const glu::InterfaceBlock& interface) 374{ 375 return interface.storage == glu::STORAGE_UNIFORM || 376 interface.storage == glu::STORAGE_IN || 377 interface.storage == glu::STORAGE_PATCH_IN || 378 (interface.storage == glu::STORAGE_BUFFER && (interface.memoryAccessQualifierFlags & glu::MEMORYACCESSQUALIFIER_WRITEONLY_BIT) == 0); 379} 380 381static bool isWritableInterface (const glu::InterfaceBlock& interface) 382{ 383 return interface.storage == glu::STORAGE_OUT || 384 interface.storage == glu::STORAGE_PATCH_OUT || 385 (interface.storage == glu::STORAGE_BUFFER && (interface.memoryAccessQualifierFlags & glu::MEMORYACCESSQUALIFIER_READONLY_BIT) == 0); 386} 387 388 389static void writeVariableReadAccumulateExpression (std::ostringstream& buf, 390 const std::string& accumulatorName, 391 const std::string& name, 392 glu::ShaderType shaderType, 393 glu::Storage storage, 394 const ProgramInterfaceDefinition::Program* program, 395 const glu::VarType& varType) 396{ 397 if (varType.isBasicType()) 398 { 399 buf << "\t" << accumulatorName << " += "; 400 401 if (glu::isDataTypeScalar(varType.getBasicType())) 402 buf << "vec4(float(" << name << "))"; 403 else if (glu::isDataTypeVector(varType.getBasicType())) 404 buf << "vec4(" << name << ".xyxy)"; 405 else if (glu::isDataTypeMatrix(varType.getBasicType())) 406 buf << "vec4(float(" << name << "[0][0]))"; 407 else if (glu::isDataTypeSamplerMultisample(varType.getBasicType())) 408 buf << "vec4(float(textureSize(" << name << ").x))"; 409 else if (glu::isDataTypeSampler(varType.getBasicType())) 410 buf << "vec4(float(textureSize(" << name << ", 0).x))"; 411 else if (glu::isDataTypeImage(varType.getBasicType())) 412 buf << "vec4(float(imageSize(" << name << ").x))"; 413 else if (varType.getBasicType() == glu::TYPE_UINT_ATOMIC_COUNTER) 414 buf << "vec4(float(atomicCounterIncrement(" << name << ")))"; 415 else 416 DE_ASSERT(false); 417 418 buf << ";\n"; 419 } 420 else if (varType.isStructType()) 421 { 422 for (int ndx = 0; ndx < varType.getStructPtr()->getNumMembers(); ++ndx) 423 writeVariableReadAccumulateExpression(buf, 424 accumulatorName, 425 name + "." + varType.getStructPtr()->getMember(ndx).getName(), 426 shaderType, 427 storage, 428 program, 429 varType.getStructPtr()->getMember(ndx).getType()); 430 } 431 else if (varType.isArrayType()) 432 { 433 if (varType.getArraySize() != glu::VarType::UNSIZED_ARRAY) 434 { 435 for (int ndx = 0; ndx < varType.getArraySize(); ++ndx) 436 writeVariableReadAccumulateExpression(buf, 437 accumulatorName, 438 name + "[" + de::toString(ndx) + "]", 439 shaderType, 440 storage, 441 program, 442 varType.getElementType()); 443 } 444 else if (storage == glu::STORAGE_BUFFER) 445 { 446 // run-time sized array, read arbitrary 447 writeVariableReadAccumulateExpression(buf, 448 accumulatorName, 449 name + "[8]", 450 shaderType, 451 storage, 452 program, 453 varType.getElementType()); 454 } 455 else 456 { 457 DE_ASSERT(storage == glu::STORAGE_IN); 458 459 if (shaderType == glu::SHADERTYPE_GEOMETRY) 460 { 461 // implicit sized geometry input array, size = primitive size. Just reading first is enough 462 writeVariableReadAccumulateExpression(buf, 463 accumulatorName, 464 name + "[0]", 465 shaderType, 466 storage, 467 program, 468 varType.getElementType()); 469 } 470 else if (shaderType == glu::SHADERTYPE_TESSELLATION_CONTROL) 471 { 472 // implicit sized tessellation input array, size = input patch max size. Just reading current is enough 473 writeVariableReadAccumulateExpression(buf, 474 accumulatorName, 475 name + "[gl_InvocationID]", 476 shaderType, 477 storage, 478 program, 479 varType.getElementType()); 480 } 481 else if (shaderType == glu::SHADERTYPE_TESSELLATION_EVALUATION) 482 { 483 // implicit sized tessellation input array, size = output patch max size. Read all to prevent optimizations 484 DE_ASSERT(program->getTessellationNumOutputPatchVertices() > 0); 485 for (int ndx = 0; ndx < (int)program->getTessellationNumOutputPatchVertices(); ++ndx) 486 { 487 writeVariableReadAccumulateExpression(buf, 488 accumulatorName, 489 name + "[" + de::toString(ndx) + "]", 490 shaderType, 491 storage, 492 program, 493 varType.getElementType()); 494 } 495 } 496 else 497 DE_ASSERT(false); 498 } 499 } 500 else 501 DE_ASSERT(false); 502} 503 504static void writeInterfaceReadAccumulateExpression (std::ostringstream& buf, 505 const std::string& accumulatorName, 506 const glu::InterfaceBlock& block, 507 glu::ShaderType shaderType, 508 const ProgramInterfaceDefinition::Program* program) 509{ 510 if (block.dimensions.empty()) 511 { 512 const std::string prefix = (block.instanceName.empty()) ? ("") : (block.instanceName + "."); 513 514 for (int ndx = 0; ndx < (int)block.variables.size(); ++ndx) 515 { 516 writeVariableReadAccumulateExpression(buf, 517 accumulatorName, 518 prefix + block.variables[ndx].name, 519 shaderType, 520 block.storage, 521 program, 522 block.variables[ndx].varType); 523 } 524 } 525 else 526 { 527 std::vector<int> index(block.dimensions.size(), 0); 528 529 for (;;) 530 { 531 // access element 532 { 533 std::ostringstream name; 534 name << block.instanceName; 535 536 for (int dimensionNdx = 0; dimensionNdx < (int)block.dimensions.size(); ++dimensionNdx) 537 name << "[" << index[dimensionNdx] << "]"; 538 539 for (int ndx = 0; ndx < (int)block.variables.size(); ++ndx) 540 { 541 writeVariableReadAccumulateExpression(buf, 542 accumulatorName, 543 name.str() + "." + block.variables[ndx].name, 544 shaderType, 545 block.storage, 546 program, 547 block.variables[ndx].varType); 548 } 549 } 550 551 // increment index 552 if (!incrementMultiDimensionIndex(index, block.dimensions)) 553 break; 554 } 555 } 556} 557 558static void writeVariableWriteExpression (std::ostringstream& buf, 559 const std::string& sourceVec4Name, 560 const std::string& name, 561 glu::ShaderType shaderType, 562 glu::Storage storage, 563 const ProgramInterfaceDefinition::Program* program, 564 const glu::VarType& varType) 565{ 566 if (varType.isBasicType()) 567 { 568 buf << "\t" << name << " = "; 569 570 if (glu::isDataTypeScalar(varType.getBasicType())) 571 buf << glu::getDataTypeName(varType.getBasicType()) << "(" << sourceVec4Name << ".y)"; 572 else if (glu::isDataTypeVector(varType.getBasicType()) || glu::isDataTypeMatrix(varType.getBasicType())) 573 buf << glu::getDataTypeName(varType.getBasicType()) << "(" << glu::getDataTypeName(glu::getDataTypeScalarType(varType.getBasicType())) << "(" << sourceVec4Name << ".y))"; 574 else 575 DE_ASSERT(false); 576 577 buf << ";\n"; 578 } 579 else if (varType.isStructType()) 580 { 581 for (int ndx = 0; ndx < varType.getStructPtr()->getNumMembers(); ++ndx) 582 writeVariableWriteExpression(buf, 583 sourceVec4Name, 584 name + "." + varType.getStructPtr()->getMember(ndx).getName(), 585 shaderType, 586 storage, 587 program, 588 varType.getStructPtr()->getMember(ndx).getType()); 589 } 590 else if (varType.isArrayType()) 591 { 592 if (varType.getArraySize() != glu::VarType::UNSIZED_ARRAY) 593 { 594 for (int ndx = 0; ndx < varType.getArraySize(); ++ndx) 595 writeVariableWriteExpression(buf, 596 sourceVec4Name, 597 name + "[" + de::toString(ndx) + "]", 598 shaderType, 599 storage, 600 program, 601 varType.getElementType()); 602 } 603 else if (storage == glu::STORAGE_BUFFER) 604 { 605 // run-time sized array, write arbitrary 606 writeVariableWriteExpression(buf, 607 sourceVec4Name, 608 name + "[9]", 609 shaderType, 610 storage, 611 program, 612 varType.getElementType()); 613 } 614 else 615 { 616 DE_ASSERT(storage == glu::STORAGE_OUT); 617 618 if (shaderType == glu::SHADERTYPE_TESSELLATION_CONTROL) 619 { 620 // implicit sized tessellation onput array, size = output patch max size. Can only write to gl_InvocationID 621 writeVariableWriteExpression(buf, 622 sourceVec4Name, 623 name + "[gl_InvocationID]", 624 shaderType, 625 storage, 626 program, 627 varType.getElementType()); 628 } 629 else 630 DE_ASSERT(false); 631 } 632 } 633 else 634 DE_ASSERT(false); 635} 636 637static void writeInterfaceWriteExpression (std::ostringstream& buf, 638 const std::string& sourceVec4Name, 639 const glu::InterfaceBlock& block, 640 glu::ShaderType shaderType, 641 const ProgramInterfaceDefinition::Program* program) 642{ 643 if (block.dimensions.empty()) 644 { 645 const std::string prefix = (block.instanceName.empty()) ? ("") : (block.instanceName + "."); 646 647 for (int ndx = 0; ndx < (int)block.variables.size(); ++ndx) 648 { 649 writeVariableWriteExpression(buf, 650 sourceVec4Name, 651 prefix + block.variables[ndx].name, 652 shaderType, 653 block.storage, 654 program, 655 block.variables[ndx].varType); 656 } 657 } 658 else 659 { 660 std::vector<int> index(block.dimensions.size(), 0); 661 662 for (;;) 663 { 664 // access element 665 { 666 std::ostringstream name; 667 name << block.instanceName; 668 669 for (int dimensionNdx = 0; dimensionNdx < (int)block.dimensions.size(); ++dimensionNdx) 670 name << "[" << index[dimensionNdx] << "]"; 671 672 for (int ndx = 0; ndx < (int)block.variables.size(); ++ndx) 673 { 674 writeVariableWriteExpression(buf, 675 sourceVec4Name, 676 name.str() + "." + block.variables[ndx].name, 677 shaderType, 678 block.storage, 679 program, 680 block.variables[ndx].varType); 681 } 682 } 683 684 // increment index 685 if (!incrementMultiDimensionIndex(index, block.dimensions)) 686 break; 687 } 688 } 689} 690 691static bool traverseVariablePath (std::vector<VariablePathComponent>& typePath, const char* subPath, const glu::VarType& type) 692{ 693 glu::VarTokenizer tokenizer(subPath); 694 695 typePath.push_back(VariablePathComponent(&type)); 696 697 if (tokenizer.getToken() == glu::VarTokenizer::TOKEN_END) 698 return true; 699 700 if (type.isStructType() && tokenizer.getToken() == glu::VarTokenizer::TOKEN_PERIOD) 701 { 702 tokenizer.advance(); 703 704 // malformed path 705 if (tokenizer.getToken() != glu::VarTokenizer::TOKEN_IDENTIFIER) 706 return false; 707 708 for (int memberNdx = 0; memberNdx < type.getStructPtr()->getNumMembers(); ++memberNdx) 709 if (type.getStructPtr()->getMember(memberNdx).getName() == tokenizer.getIdentifier()) 710 return traverseVariablePath(typePath, subPath + tokenizer.getCurrentTokenEndLocation(), type.getStructPtr()->getMember(memberNdx).getType()); 711 712 // malformed path, no such member 713 return false; 714 } 715 else if (type.isArrayType() && tokenizer.getToken() == glu::VarTokenizer::TOKEN_LEFT_BRACKET) 716 { 717 tokenizer.advance(); 718 719 // malformed path 720 if (tokenizer.getToken() != glu::VarTokenizer::TOKEN_NUMBER) 721 return false; 722 723 tokenizer.advance(); 724 if (tokenizer.getToken() != glu::VarTokenizer::TOKEN_RIGHT_BRACKET) 725 return false; 726 727 return traverseVariablePath(typePath, subPath + tokenizer.getCurrentTokenEndLocation(), type.getElementType()); 728 } 729 730 return false; 731} 732 733static bool traverseVariablePath (std::vector<VariablePathComponent>& typePath, const std::string& path, const glu::VariableDeclaration& var) 734{ 735 if (glu::parseVariableName(path.c_str()) != var.name) 736 return false; 737 738 typePath.push_back(VariablePathComponent(&var)); 739 return traverseVariablePath(typePath, path.c_str() + var.name.length(), var.varType); 740} 741 742static bool traverseShaderVariablePath (std::vector<VariablePathComponent>& typePath, const ProgramInterfaceDefinition::Shader* shader, const std::string& path, const VariableSearchFilter& filter) 743{ 744 // Default block variable? 745 for (int varNdx = 0; varNdx < (int)shader->getDefaultBlock().variables.size(); ++varNdx) 746 if (filter.matchesFilter(shader->getDefaultBlock().variables[varNdx])) 747 if (traverseVariablePath(typePath, path, shader->getDefaultBlock().variables[varNdx])) 748 return true; 749 750 // is variable an interface block variable? 751 { 752 const std::string blockName = glu::parseVariableName(path.c_str()); 753 754 for (int interfaceNdx = 0; interfaceNdx < (int)shader->getDefaultBlock().interfaceBlocks.size(); ++interfaceNdx) 755 { 756 if (!filter.matchesFilter(shader->getDefaultBlock().interfaceBlocks[interfaceNdx])) 757 continue; 758 759 if (shader->getDefaultBlock().interfaceBlocks[interfaceNdx].interfaceName == blockName) 760 { 761 // resource is a member of a named interface block 762 // \note there is no array index specifier even if the interface is declared as an array of instances 763 const std::string blockMemberPath = path.substr(blockName.size() + 1); 764 const std::string blockMemeberName = glu::parseVariableName(blockMemberPath.c_str()); 765 766 for (int varNdx = 0; varNdx < (int)shader->getDefaultBlock().interfaceBlocks[interfaceNdx].variables.size(); ++varNdx) 767 { 768 if (shader->getDefaultBlock().interfaceBlocks[interfaceNdx].variables[varNdx].name == blockMemeberName) 769 { 770 typePath.push_back(VariablePathComponent(&shader->getDefaultBlock().interfaceBlocks[interfaceNdx])); 771 return traverseVariablePath(typePath, blockMemberPath, shader->getDefaultBlock().interfaceBlocks[interfaceNdx].variables[varNdx]); 772 } 773 } 774 775 // terminate search 776 return false; 777 } 778 else if (shader->getDefaultBlock().interfaceBlocks[interfaceNdx].instanceName.empty()) 779 { 780 const std::string blockMemeberName = glu::parseVariableName(path.c_str()); 781 782 // unnamed block contains such variable? 783 for (int varNdx = 0; varNdx < (int)shader->getDefaultBlock().interfaceBlocks[interfaceNdx].variables.size(); ++varNdx) 784 { 785 if (shader->getDefaultBlock().interfaceBlocks[interfaceNdx].variables[varNdx].name == blockMemeberName) 786 { 787 typePath.push_back(VariablePathComponent(&shader->getDefaultBlock().interfaceBlocks[interfaceNdx])); 788 return traverseVariablePath(typePath, path, shader->getDefaultBlock().interfaceBlocks[interfaceNdx].variables[varNdx]); 789 } 790 } 791 792 // continue search 793 } 794 } 795 } 796 797 return false; 798} 799 800static bool traverseProgramVariablePath (std::vector<VariablePathComponent>& typePath, const ProgramInterfaceDefinition::Program* program, const std::string& path, const VariableSearchFilter& filter) 801{ 802 for (int shaderNdx = 0; shaderNdx < (int)program->getShaders().size(); ++shaderNdx) 803 { 804 const ProgramInterfaceDefinition::Shader* shader = program->getShaders()[shaderNdx]; 805 806 if (filter.matchesFilter(shader)) 807 { 808 // \note modifying output variable even when returning false 809 typePath.clear(); 810 if (traverseShaderVariablePath(typePath, shader, path, filter)) 811 return true; 812 } 813 } 814 815 return false; 816} 817 818static bool containsSubType (const glu::VarType& complexType, glu::DataType basicType) 819{ 820 if (complexType.isBasicType()) 821 { 822 return complexType.getBasicType() == basicType; 823 } 824 else if (complexType.isArrayType()) 825 { 826 return containsSubType(complexType.getElementType(), basicType); 827 } 828 else if (complexType.isStructType()) 829 { 830 for (int ndx = 0; ndx < complexType.getStructPtr()->getNumMembers(); ++ndx) 831 if (containsSubType(complexType.getStructPtr()->getMember(ndx).getType(), basicType)) 832 return true; 833 return false; 834 } 835 else 836 { 837 DE_ASSERT(false); 838 return false; 839 } 840} 841 842static int getNumShaderBlocks (const ProgramInterfaceDefinition::Shader* shader, glu::Storage storage) 843{ 844 int retVal = 0; 845 846 for (int ndx = 0; ndx < (int)shader->getDefaultBlock().interfaceBlocks.size(); ++ndx) 847 { 848 if (shader->getDefaultBlock().interfaceBlocks[ndx].storage == storage) 849 { 850 int numInstances = 1; 851 852 for (int dimensionNdx = 0; dimensionNdx < (int)shader->getDefaultBlock().interfaceBlocks[ndx].dimensions.size(); ++dimensionNdx) 853 numInstances *= shader->getDefaultBlock().interfaceBlocks[ndx].dimensions[dimensionNdx]; 854 855 retVal += numInstances; 856 } 857 } 858 859 return retVal; 860} 861 862static int getNumAtomicCounterBuffers (const ProgramInterfaceDefinition::Shader* shader) 863{ 864 std::set<int> buffers; 865 866 for (int ndx = 0; ndx < (int)shader->getDefaultBlock().variables.size(); ++ndx) 867 { 868 if (containsSubType(shader->getDefaultBlock().variables[ndx].varType, glu::TYPE_UINT_ATOMIC_COUNTER)) 869 { 870 DE_ASSERT(shader->getDefaultBlock().variables[ndx].layout.binding != -1); 871 buffers.insert(shader->getDefaultBlock().variables[ndx].layout.binding); 872 } 873 } 874 875 return (int)buffers.size(); 876} 877 878template <typename DataTypeMap> 879static int accumulateComplexType (const glu::VarType& complexType, const DataTypeMap& dTypeMap) 880{ 881 if (complexType.isBasicType()) 882 return dTypeMap(complexType.getBasicType()); 883 else if (complexType.isArrayType()) 884 { 885 const int arraySize = (complexType.getArraySize() == glu::VarType::UNSIZED_ARRAY) ? (1) : (complexType.getArraySize()); 886 return arraySize * accumulateComplexType(complexType.getElementType(), dTypeMap); 887 } 888 else if (complexType.isStructType()) 889 { 890 int sum = 0; 891 for (int ndx = 0; ndx < complexType.getStructPtr()->getNumMembers(); ++ndx) 892 sum += accumulateComplexType(complexType.getStructPtr()->getMember(ndx).getType(), dTypeMap); 893 return sum; 894 } 895 else 896 { 897 DE_ASSERT(false); 898 return false; 899 } 900} 901 902template <typename InterfaceBlockFilter, typename VarDeclFilter, typename DataTypeMap> 903static int accumulateShader (const ProgramInterfaceDefinition::Shader* shader, 904 const InterfaceBlockFilter& ibFilter, 905 const VarDeclFilter& vdFilter, 906 const DataTypeMap& dMap) 907{ 908 int retVal = 0; 909 910 for (int ndx = 0; ndx < (int)shader->getDefaultBlock().interfaceBlocks.size(); ++ndx) 911 { 912 if (ibFilter(shader->getDefaultBlock().interfaceBlocks[ndx])) 913 { 914 int numInstances = 1; 915 916 for (int dimensionNdx = 0; dimensionNdx < (int)shader->getDefaultBlock().interfaceBlocks[ndx].dimensions.size(); ++dimensionNdx) 917 numInstances *= shader->getDefaultBlock().interfaceBlocks[ndx].dimensions[dimensionNdx]; 918 919 for (int varNdx = 0; varNdx < (int)shader->getDefaultBlock().interfaceBlocks[ndx].variables.size(); ++varNdx) 920 retVal += numInstances * accumulateComplexType(shader->getDefaultBlock().interfaceBlocks[ndx].variables[varNdx].varType, dMap); 921 } 922 } 923 924 for (int varNdx = 0; varNdx < (int)shader->getDefaultBlock().variables.size(); ++varNdx) 925 if (vdFilter(shader->getDefaultBlock().variables[varNdx])) 926 retVal += accumulateComplexType(shader->getDefaultBlock().variables[varNdx].varType, dMap); 927 928 return retVal; 929} 930 931static bool dummyTrueConstantTypeFilter (glu::DataType d) 932{ 933 DE_UNREF(d); 934 return true; 935} 936 937class InstanceCounter 938{ 939public: 940 InstanceCounter (bool (*predicate)(glu::DataType)) 941 : m_predicate(predicate) 942 { 943 } 944 945 int operator() (glu::DataType t) const 946 { 947 return (m_predicate(t)) ? (1) : (0); 948 } 949 950private: 951 bool (*const m_predicate)(glu::DataType); 952}; 953 954class InterfaceBlockStorageFilter 955{ 956public: 957 InterfaceBlockStorageFilter (glu::Storage storage) 958 : m_storage(storage) 959 { 960 } 961 962 bool operator() (const glu::InterfaceBlock& b) const 963 { 964 return m_storage == b.storage; 965 } 966 967private: 968 const glu::Storage m_storage; 969}; 970 971class VariableDeclarationStorageFilter 972{ 973public: 974 VariableDeclarationStorageFilter (glu::Storage storage) 975 : m_storage(storage) 976 { 977 } 978 979 bool operator() (const glu::VariableDeclaration& d) const 980 { 981 return m_storage == d.storage; 982 } 983 984private: 985 const glu::Storage m_storage; 986}; 987 988static int getNumTypeInstances (const glu::VarType& complexType, bool (*predicate)(glu::DataType)) 989{ 990 return accumulateComplexType(complexType, InstanceCounter(predicate)); 991} 992 993static int getNumTypeInstances (const ProgramInterfaceDefinition::Shader* shader, glu::Storage storage, bool (*predicate)(glu::DataType)) 994{ 995 return accumulateShader(shader, InterfaceBlockStorageFilter(storage), VariableDeclarationStorageFilter(storage), InstanceCounter(predicate)); 996} 997 998static int getNumTypeInstances (const ProgramInterfaceDefinition::Shader* shader, glu::Storage storage) 999{ 1000 return getNumTypeInstances(shader, storage, dummyTrueConstantTypeFilter); 1001} 1002 1003static int accumulateShaderStorage (const ProgramInterfaceDefinition::Shader* shader, glu::Storage storage, int (*typeMap)(glu::DataType)) 1004{ 1005 return accumulateShader(shader, InterfaceBlockStorageFilter(storage), VariableDeclarationStorageFilter(storage), typeMap); 1006} 1007 1008static int getNumDataTypeComponents (glu::DataType type) 1009{ 1010 if (glu::isDataTypeScalarOrVector(type) || glu::isDataTypeMatrix(type)) 1011 return glu::getDataTypeScalarSize(type); 1012 else 1013 return 0; 1014} 1015 1016static int getNumDataTypeVectors (glu::DataType type) 1017{ 1018 if (glu::isDataTypeScalar(type)) 1019 return 1; 1020 else if (glu::isDataTypeVector(type)) 1021 return 1; 1022 else if (glu::isDataTypeMatrix(type)) 1023 return glu::getDataTypeMatrixNumColumns(type); 1024 else 1025 return 0; 1026} 1027 1028static int getNumComponents (const ProgramInterfaceDefinition::Shader* shader, glu::Storage storage) 1029{ 1030 return accumulateShaderStorage(shader, storage, getNumDataTypeComponents); 1031} 1032 1033static int getNumVectors (const ProgramInterfaceDefinition::Shader* shader, glu::Storage storage) 1034{ 1035 return accumulateShaderStorage(shader, storage, getNumDataTypeVectors); 1036} 1037 1038static int getNumDefaultBlockComponents (const ProgramInterfaceDefinition::Shader* shader, glu::Storage storage) 1039{ 1040 int retVal = 0; 1041 1042 for (int varNdx = 0; varNdx < (int)shader->getDefaultBlock().variables.size(); ++varNdx) 1043 if (shader->getDefaultBlock().variables[varNdx].storage == storage) 1044 retVal += accumulateComplexType(shader->getDefaultBlock().variables[varNdx].varType, getNumDataTypeComponents); 1045 1046 return retVal; 1047} 1048 1049static int getMaxBufferBinding (const ProgramInterfaceDefinition::Shader* shader, glu::Storage storage) 1050{ 1051 int maxBinding = -1; 1052 1053 for (int ndx = 0; ndx < (int)shader->getDefaultBlock().interfaceBlocks.size(); ++ndx) 1054 { 1055 if (shader->getDefaultBlock().interfaceBlocks[ndx].storage == storage) 1056 { 1057 const int binding = (shader->getDefaultBlock().interfaceBlocks[ndx].layout.binding == -1) ? (0) : (shader->getDefaultBlock().interfaceBlocks[ndx].layout.binding); 1058 int numInstances = 1; 1059 1060 for (int dimensionNdx = 0; dimensionNdx < (int)shader->getDefaultBlock().interfaceBlocks[ndx].dimensions.size(); ++dimensionNdx) 1061 numInstances *= shader->getDefaultBlock().interfaceBlocks[ndx].dimensions[dimensionNdx]; 1062 1063 maxBinding = de::max(maxBinding, binding + numInstances - 1); 1064 } 1065 } 1066 1067 return (int)maxBinding; 1068} 1069 1070static int getBufferTypeSize (glu::DataType type, glu::MatrixOrder order) 1071{ 1072 // assume vec4 alignments, should produce values greater than or equal to the actual resource usage 1073 int numVectors = 0; 1074 1075 if (glu::isDataTypeScalarOrVector(type)) 1076 numVectors = 1; 1077 else if (glu::isDataTypeMatrix(type) && order == glu::MATRIXORDER_ROW_MAJOR) 1078 numVectors = glu::getDataTypeMatrixNumRows(type); 1079 else if (glu::isDataTypeMatrix(type) && order != glu::MATRIXORDER_ROW_MAJOR) 1080 numVectors = glu::getDataTypeMatrixNumColumns(type); 1081 else 1082 DE_ASSERT(false); 1083 1084 return 4 * numVectors; 1085} 1086 1087static int getBufferVariableSize (const glu::VarType& type, glu::MatrixOrder order) 1088{ 1089 if (type.isBasicType()) 1090 return getBufferTypeSize(type.getBasicType(), order); 1091 else if (type.isArrayType()) 1092 { 1093 const int arraySize = (type.getArraySize() == glu::VarType::UNSIZED_ARRAY) ? (1) : (type.getArraySize()); 1094 return arraySize * getBufferVariableSize(type.getElementType(), order); 1095 } 1096 else if (type.isStructType()) 1097 { 1098 int sum = 0; 1099 for (int ndx = 0; ndx < type.getStructPtr()->getNumMembers(); ++ndx) 1100 sum += getBufferVariableSize(type.getStructPtr()->getMember(ndx).getType(), order); 1101 return sum; 1102 } 1103 else 1104 { 1105 DE_ASSERT(false); 1106 return false; 1107 } 1108} 1109 1110static int getBufferSize (const glu::InterfaceBlock& block, glu::MatrixOrder blockOrder) 1111{ 1112 int size = 0; 1113 1114 for (int ndx = 0; ndx < (int)block.variables.size(); ++ndx) 1115 size += getBufferVariableSize(block.variables[ndx].varType, (block.variables[ndx].layout.matrixOrder == glu::MATRIXORDER_LAST) ? (blockOrder) : (block.variables[ndx].layout.matrixOrder)); 1116 1117 return size; 1118} 1119 1120static int getBufferMaxSize (const ProgramInterfaceDefinition::Shader* shader, glu::Storage storage) 1121{ 1122 int maxSize = 0; 1123 1124 for (int ndx = 0; ndx < (int)shader->getDefaultBlock().interfaceBlocks.size(); ++ndx) 1125 if (shader->getDefaultBlock().interfaceBlocks[ndx].storage == storage) 1126 maxSize = de::max(maxSize, getBufferSize(shader->getDefaultBlock().interfaceBlocks[ndx], shader->getDefaultBlock().interfaceBlocks[ndx].layout.matrixOrder)); 1127 1128 return (int)maxSize; 1129} 1130 1131static int getAtomicCounterMaxBinding (const ProgramInterfaceDefinition::Shader* shader) 1132{ 1133 int maxBinding = -1; 1134 1135 for (int ndx = 0; ndx < (int)shader->getDefaultBlock().variables.size(); ++ndx) 1136 { 1137 if (containsSubType(shader->getDefaultBlock().variables[ndx].varType, glu::TYPE_UINT_ATOMIC_COUNTER)) 1138 { 1139 DE_ASSERT(shader->getDefaultBlock().variables[ndx].layout.binding != -1); 1140 maxBinding = de::max(maxBinding, shader->getDefaultBlock().variables[ndx].layout.binding); 1141 } 1142 } 1143 1144 return (int)maxBinding; 1145} 1146 1147static int getUniformMaxBinding (const ProgramInterfaceDefinition::Shader* shader, bool (*predicate)(glu::DataType)) 1148{ 1149 int maxBinding = -1; 1150 1151 for (int ndx = 0; ndx < (int)shader->getDefaultBlock().variables.size(); ++ndx) 1152 { 1153 const int binding = (shader->getDefaultBlock().variables[ndx].layout.binding == -1) ? (0) : (shader->getDefaultBlock().variables[ndx].layout.binding); 1154 const int numInstances = getNumTypeInstances(shader->getDefaultBlock().variables[ndx].varType, predicate); 1155 1156 maxBinding = de::max(maxBinding, binding + numInstances - 1); 1157 } 1158 1159 return maxBinding; 1160} 1161 1162static int getAtomicCounterMaxBufferSize (const ProgramInterfaceDefinition::Shader* shader) 1163{ 1164 std::map<int, int> bufferSizes; 1165 int maxSize = 0; 1166 1167 for (int ndx = 0; ndx < (int)shader->getDefaultBlock().variables.size(); ++ndx) 1168 { 1169 if (containsSubType(shader->getDefaultBlock().variables[ndx].varType, glu::TYPE_UINT_ATOMIC_COUNTER)) 1170 { 1171 const int bufferBinding = shader->getDefaultBlock().variables[ndx].layout.binding; 1172 const int offset = (shader->getDefaultBlock().variables[ndx].layout.offset == -1) ? (0) : (shader->getDefaultBlock().variables[ndx].layout.offset); 1173 const int size = offset + 4 * getNumTypeInstances(shader->getDefaultBlock().variables[ndx].varType, glu::isDataTypeAtomicCounter); 1174 1175 DE_ASSERT(shader->getDefaultBlock().variables[ndx].layout.binding != -1); 1176 1177 if (bufferSizes.find(bufferBinding) == bufferSizes.end()) 1178 bufferSizes[bufferBinding] = size; 1179 else 1180 bufferSizes[bufferBinding] = de::max<int>(bufferSizes[bufferBinding], size); 1181 } 1182 } 1183 1184 for (std::map<int, int>::iterator it = bufferSizes.begin(); it != bufferSizes.end(); ++it) 1185 maxSize = de::max<int>(maxSize, it->second); 1186 1187 return maxSize; 1188} 1189 1190static int getNumFeedbackVaryingComponents (const ProgramInterfaceDefinition::Program* program, const std::string& name) 1191{ 1192 std::vector<VariablePathComponent> path; 1193 1194 if (name == "gl_Position") 1195 return 4; 1196 1197 DE_ASSERT(deStringBeginsWith(name.c_str(), "gl_") == DE_FALSE); 1198 1199 if (!traverseProgramVariablePath(path, program, name, VariableSearchFilter::createShaderTypeStorageFilter(getProgramTransformFeedbackStage(program), glu::STORAGE_OUT))) 1200 DE_ASSERT(false); // Program failed validate, invalid operation 1201 1202 return accumulateComplexType(*path.back().getVariableType(), getNumDataTypeComponents); 1203} 1204 1205static int getNumXFBComponents (const ProgramInterfaceDefinition::Program* program) 1206{ 1207 int numComponents = 0; 1208 1209 for (int ndx = 0; ndx < (int)program->getTransformFeedbackVaryings().size(); ++ndx) 1210 numComponents += getNumFeedbackVaryingComponents(program, program->getTransformFeedbackVaryings()[ndx]); 1211 1212 return numComponents; 1213} 1214 1215static int getNumMaxXFBOutputComponents (const ProgramInterfaceDefinition::Program* program) 1216{ 1217 int numComponents = 0; 1218 1219 for (int ndx = 0; ndx < (int)program->getTransformFeedbackVaryings().size(); ++ndx) 1220 numComponents = de::max(numComponents, getNumFeedbackVaryingComponents(program, program->getTransformFeedbackVaryings()[ndx])); 1221 1222 return numComponents; 1223} 1224 1225static int getFragmentOutputMaxLocation (const ProgramInterfaceDefinition::Shader* shader) 1226{ 1227 DE_ASSERT(shader->getType() == glu::SHADERTYPE_FRAGMENT); 1228 1229 int maxOutputLocation = -1; 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 // missing location qualifier means location == 0 1236 const int outputLocation = (shader->getDefaultBlock().variables[ndx].layout.location == -1) 1237 ? (0) 1238 : (shader->getDefaultBlock().variables[ndx].layout.location); 1239 1240 // only basic types or arrays of basic types possible 1241 DE_ASSERT(!shader->getDefaultBlock().variables[ndx].varType.isStructType()); 1242 1243 const int locationSlotsTaken = (shader->getDefaultBlock().variables[ndx].varType.isArrayType()) 1244 ? (shader->getDefaultBlock().variables[ndx].varType.getArraySize()) 1245 : (1); 1246 1247 maxOutputLocation = de::max(maxOutputLocation, outputLocation + locationSlotsTaken - 1); 1248 } 1249 } 1250 1251 return maxOutputLocation; 1252} 1253 1254} // anonymous 1255 1256std::vector<std::string> getProgramInterfaceBlockMemberResourceList (const glu::InterfaceBlock& interfaceBlock) 1257{ 1258 const std::string namePrefix = (!interfaceBlock.instanceName.empty()) ? (interfaceBlock.interfaceName + ".") : (""); 1259 const bool isTopLevelBufferVariable = (interfaceBlock.storage == glu::STORAGE_BUFFER); 1260 std::vector<std::string> resources; 1261 1262 // \note this is defined in the GLSL spec, not in the GL spec 1263 for (int variableNdx = 0; variableNdx < (int)interfaceBlock.variables.size(); ++variableNdx) 1264 generateVariableTypeResourceNames(resources, 1265 namePrefix + interfaceBlock.variables[variableNdx].name, 1266 interfaceBlock.variables[variableNdx].varType, 1267 (isTopLevelBufferVariable) ? 1268 (RESOURCE_NAME_GENERATION_FLAG_TOP_LEVEL_BUFFER_VARIABLE) : 1269 (RESOURCE_NAME_GENERATION_FLAG_DEFAULT)); 1270 1271 return resources; 1272} 1273 1274std::vector<std::string> getProgramInterfaceResourceList (const ProgramInterfaceDefinition::Program* program, ProgramInterface interface) 1275{ 1276 // The same {uniform (block), buffer (variable)} can exist in multiple shaders, remove duplicates but keep order 1277 const bool removeDuplicated = (interface == PROGRAMINTERFACE_UNIFORM) || 1278 (interface == PROGRAMINTERFACE_UNIFORM_BLOCK) || 1279 (interface == PROGRAMINTERFACE_BUFFER_VARIABLE) || 1280 (interface == PROGRAMINTERFACE_SHADER_STORAGE_BLOCK); 1281 std::vector<std::string> resources; 1282 1283 switch (interface) 1284 { 1285 case PROGRAMINTERFACE_UNIFORM: 1286 case PROGRAMINTERFACE_BUFFER_VARIABLE: 1287 { 1288 const glu::Storage storage = (interface == PROGRAMINTERFACE_UNIFORM) ? (glu::STORAGE_UNIFORM) : (glu::STORAGE_BUFFER); 1289 1290 for (int shaderNdx = 0; shaderNdx < (int)program->getShaders().size(); ++shaderNdx) 1291 { 1292 const ProgramInterfaceDefinition::Shader* shader = program->getShaders()[shaderNdx]; 1293 1294 for (int variableNdx = 0; variableNdx < (int)shader->getDefaultBlock().variables.size(); ++variableNdx) 1295 if (shader->getDefaultBlock().variables[variableNdx].storage == storage) 1296 generateVariableTypeResourceNames(resources, 1297 shader->getDefaultBlock().variables[variableNdx].name, 1298 shader->getDefaultBlock().variables[variableNdx].varType, 1299 RESOURCE_NAME_GENERATION_FLAG_DEFAULT); 1300 1301 for (int interfaceNdx = 0; interfaceNdx < (int)shader->getDefaultBlock().interfaceBlocks.size(); ++interfaceNdx) 1302 { 1303 const glu::InterfaceBlock& interfaceBlock = shader->getDefaultBlock().interfaceBlocks[interfaceNdx]; 1304 if (interfaceBlock.storage == storage) 1305 { 1306 const std::vector<std::string> blockResources = getProgramInterfaceBlockMemberResourceList(interfaceBlock); 1307 resources.insert(resources.end(), blockResources.begin(), blockResources.end()); 1308 } 1309 } 1310 } 1311 break; 1312 } 1313 1314 case PROGRAMINTERFACE_UNIFORM_BLOCK: 1315 case PROGRAMINTERFACE_SHADER_STORAGE_BLOCK: 1316 { 1317 const glu::Storage storage = (interface == PROGRAMINTERFACE_UNIFORM_BLOCK) ? (glu::STORAGE_UNIFORM) : (glu::STORAGE_BUFFER); 1318 1319 for (int shaderNdx = 0; shaderNdx < (int)program->getShaders().size(); ++shaderNdx) 1320 { 1321 const ProgramInterfaceDefinition::Shader* shader = program->getShaders()[shaderNdx]; 1322 for (int interfaceNdx = 0; interfaceNdx < (int)shader->getDefaultBlock().interfaceBlocks.size(); ++interfaceNdx) 1323 { 1324 const glu::InterfaceBlock& interfaceBlock = shader->getDefaultBlock().interfaceBlocks[interfaceNdx]; 1325 if (interfaceBlock.storage == storage) 1326 { 1327 std::vector<int> index(interfaceBlock.dimensions.size(), 0); 1328 1329 for (;;) 1330 { 1331 // add resource string for each element 1332 { 1333 std::ostringstream name; 1334 name << interfaceBlock.interfaceName; 1335 1336 for (int dimensionNdx = 0; dimensionNdx < (int)interfaceBlock.dimensions.size(); ++dimensionNdx) 1337 name << "[" << index[dimensionNdx] << "]"; 1338 1339 resources.push_back(name.str()); 1340 } 1341 1342 // increment index 1343 if (!incrementMultiDimensionIndex(index, interfaceBlock.dimensions)) 1344 break; 1345 } 1346 } 1347 } 1348 } 1349 break; 1350 } 1351 1352 case PROGRAMINTERFACE_PROGRAM_INPUT: 1353 case PROGRAMINTERFACE_PROGRAM_OUTPUT: 1354 { 1355 const glu::Storage queryStorage = (interface == PROGRAMINTERFACE_PROGRAM_INPUT) ? (glu::STORAGE_IN) : (glu::STORAGE_OUT); 1356 const glu::Storage queryPatchStorage = (interface == PROGRAMINTERFACE_PROGRAM_INPUT) ? (glu::STORAGE_PATCH_IN) : (glu::STORAGE_PATCH_OUT); 1357 const glu::ShaderType shaderType = (interface == PROGRAMINTERFACE_PROGRAM_INPUT) ? (program->getFirstStage()) : (program->getLastStage()); 1358 1359 for (int shaderNdx = 0; shaderNdx < (int)program->getShaders().size(); ++shaderNdx) 1360 { 1361 const ProgramInterfaceDefinition::Shader* shader = program->getShaders()[shaderNdx]; 1362 1363 if (shader->getType() != shaderType) 1364 continue; 1365 1366 for (int variableNdx = 0; variableNdx < (int)shader->getDefaultBlock().variables.size(); ++variableNdx) 1367 { 1368 const glu::Storage variableStorage = shader->getDefaultBlock().variables[variableNdx].storage; 1369 if (variableStorage == queryStorage || variableStorage == queryPatchStorage) 1370 generateVariableTypeResourceNames(resources, 1371 shader->getDefaultBlock().variables[variableNdx].name, 1372 shader->getDefaultBlock().variables[variableNdx].varType, 1373 RESOURCE_NAME_GENERATION_FLAG_DEFAULT); 1374 } 1375 1376 for (int interfaceNdx = 0; interfaceNdx < (int)shader->getDefaultBlock().interfaceBlocks.size(); ++interfaceNdx) 1377 { 1378 const glu::InterfaceBlock& interfaceBlock = shader->getDefaultBlock().interfaceBlocks[interfaceNdx]; 1379 if (interfaceBlock.storage == queryStorage || interfaceBlock.storage == queryPatchStorage) 1380 { 1381 const std::vector<std::string> blockResources = getProgramInterfaceBlockMemberResourceList(interfaceBlock); 1382 resources.insert(resources.end(), blockResources.begin(), blockResources.end()); 1383 } 1384 } 1385 } 1386 1387 // built-ins 1388 if (interface == PROGRAMINTERFACE_PROGRAM_INPUT) 1389 { 1390 if (shaderType == glu::SHADERTYPE_VERTEX && resources.empty()) 1391 resources.push_back("gl_VertexID"); // only read from when there are no other inputs 1392 else if (shaderType == glu::SHADERTYPE_FRAGMENT && resources.empty()) 1393 resources.push_back("gl_FragCoord"); // only read from when there are no other inputs 1394 else if (shaderType == glu::SHADERTYPE_GEOMETRY) 1395 resources.push_back("gl_PerVertex.gl_Position"); 1396 else if (shaderType == glu::SHADERTYPE_TESSELLATION_CONTROL) 1397 { 1398 resources.push_back("gl_InvocationID"); 1399 resources.push_back("gl_PerVertex.gl_Position"); 1400 } 1401 else if (shaderType == glu::SHADERTYPE_TESSELLATION_EVALUATION) 1402 resources.push_back("gl_PerVertex.gl_Position"); 1403 else if (shaderType == glu::SHADERTYPE_COMPUTE && resources.empty()) 1404 resources.push_back("gl_NumWorkGroups"); // only read from when there are no other inputs 1405 } 1406 else if (interface == PROGRAMINTERFACE_PROGRAM_OUTPUT) 1407 { 1408 if (shaderType == glu::SHADERTYPE_VERTEX) 1409 resources.push_back("gl_Position"); 1410 else if (shaderType == glu::SHADERTYPE_FRAGMENT && resources.empty()) 1411 resources.push_back("gl_FragDepth"); // only written to when there are no other outputs 1412 else if (shaderType == glu::SHADERTYPE_GEOMETRY) 1413 resources.push_back("gl_Position"); 1414 else if (shaderType == glu::SHADERTYPE_TESSELLATION_CONTROL) 1415 { 1416 resources.push_back("gl_PerVertex.gl_Position"); 1417 resources.push_back("gl_TessLevelOuter[0]"); 1418 resources.push_back("gl_TessLevelInner[0]"); 1419 } 1420 else if (shaderType == glu::SHADERTYPE_TESSELLATION_EVALUATION) 1421 resources.push_back("gl_Position"); 1422 } 1423 1424 break; 1425 } 1426 1427 case PROGRAMINTERFACE_TRANSFORM_FEEDBACK_VARYING: 1428 { 1429 const glu::ShaderType xfbStage = getProgramTransformFeedbackStage(program); 1430 1431 for (int varyingNdx = 0; varyingNdx < (int)program->getTransformFeedbackVaryings().size(); ++varyingNdx) 1432 { 1433 const std::string& varyingName = program->getTransformFeedbackVaryings()[varyingNdx]; 1434 1435 if (deStringBeginsWith(varyingName.c_str(), "gl_")) 1436 resources.push_back(varyingName); // builtin 1437 else 1438 { 1439 std::vector<VariablePathComponent> path; 1440 1441 if (!traverseProgramVariablePath(path, program, varyingName, VariableSearchFilter::createShaderTypeStorageFilter(xfbStage, glu::STORAGE_OUT))) 1442 DE_ASSERT(false); // Program failed validate, invalid operation 1443 1444 generateVariableTypeResourceNames(resources, 1445 varyingName, 1446 *path.back().getVariableType(), 1447 RESOURCE_NAME_GENERATION_FLAG_TRANSFORM_FEEDBACK_VARIABLE); 1448 } 1449 } 1450 1451 break; 1452 } 1453 1454 default: 1455 DE_ASSERT(false); 1456 } 1457 1458 if (removeDuplicated) 1459 { 1460 std::set<std::string> addedVariables; 1461 std::vector<std::string> uniqueResouces; 1462 1463 for (int ndx = 0; ndx < (int)resources.size(); ++ndx) 1464 { 1465 if (addedVariables.find(resources[ndx]) == addedVariables.end()) 1466 { 1467 addedVariables.insert(resources[ndx]); 1468 uniqueResouces.push_back(resources[ndx]); 1469 } 1470 } 1471 1472 uniqueResouces.swap(resources); 1473 } 1474 1475 return resources; 1476} 1477 1478/** 1479 * Name of the dummy uniform added by generateProgramInterfaceProgramSources 1480 * 1481 * A uniform named "dummyZero" is added by 1482 * generateProgramInterfaceProgramSources. It is used in expressions to 1483 * prevent various program resources from being eliminated by the GLSL 1484 * compiler's optimizer. 1485 * 1486 * \sa deqp::gles31::Functional::ProgramInterfaceDefinition::generateProgramInterfaceProgramSources 1487 */ 1488const char* getDummyZeroUniformName() 1489{ 1490 return "dummyZero"; 1491} 1492 1493glu::ProgramSources generateProgramInterfaceProgramSources (const ProgramInterfaceDefinition::Program* program) 1494{ 1495 glu::ProgramSources sources; 1496 1497 DE_ASSERT(program->isValid()); 1498 1499 for (int shaderNdx = 0; shaderNdx < (int)program->getShaders().size(); ++shaderNdx) 1500 { 1501 const ProgramInterfaceDefinition::Shader* shader = program->getShaders()[shaderNdx]; 1502 bool containsUserDefinedOutputs = false; 1503 bool containsUserDefinedInputs = false; 1504 std::ostringstream sourceBuf; 1505 std::ostringstream usageBuf; 1506 1507 sourceBuf << glu::getGLSLVersionDeclaration(shader->getVersion()) << "\n" 1508 << getShaderExtensionDeclarations(shader) 1509 << getShaderTypeDeclarations(program, shader->getType()) 1510 << "\n"; 1511 1512 // Struct definitions 1513 1514 writeStructureDefinitions(sourceBuf, shader->getDefaultBlock()); 1515 1516 // variables in the default scope 1517 1518 for (int ndx = 0; ndx < (int)shader->getDefaultBlock().variables.size(); ++ndx) 1519 sourceBuf << shader->getDefaultBlock().variables[ndx] << ";\n"; 1520 1521 if (!shader->getDefaultBlock().variables.empty()) 1522 sourceBuf << "\n"; 1523 1524 // Interface blocks 1525 1526 for (int ndx = 0; ndx < (int)shader->getDefaultBlock().interfaceBlocks.size(); ++ndx) 1527 writeInterfaceBlock(sourceBuf, shader->getDefaultBlock().interfaceBlocks[ndx]); 1528 1529 // Use inputs and outputs so that they won't be removed by the optimizer 1530 1531 usageBuf << "highp uniform vec4 " << getDummyZeroUniformName() << "; // Default value is vec4(0.0).\n" 1532 "highp vec4 readInputs()\n" 1533 "{\n" 1534 " highp vec4 retValue = " << getDummyZeroUniformName() << ";\n"; 1535 1536 // User-defined inputs 1537 1538 for (int ndx = 0; ndx < (int)shader->getDefaultBlock().variables.size(); ++ndx) 1539 { 1540 if (shader->getDefaultBlock().variables[ndx].storage == glu::STORAGE_IN || 1541 shader->getDefaultBlock().variables[ndx].storage == glu::STORAGE_PATCH_IN || 1542 shader->getDefaultBlock().variables[ndx].storage == glu::STORAGE_UNIFORM) 1543 { 1544 writeVariableReadAccumulateExpression(usageBuf, 1545 "retValue", 1546 shader->getDefaultBlock().variables[ndx].name, 1547 shader->getType(), 1548 shader->getDefaultBlock().variables[ndx].storage, 1549 program, 1550 shader->getDefaultBlock().variables[ndx].varType); 1551 containsUserDefinedInputs = true; 1552 } 1553 } 1554 1555 for (int interfaceNdx = 0; interfaceNdx < (int)shader->getDefaultBlock().interfaceBlocks.size(); ++interfaceNdx) 1556 { 1557 const glu::InterfaceBlock& interface = shader->getDefaultBlock().interfaceBlocks[interfaceNdx]; 1558 if (isReadableInterface(interface)) 1559 { 1560 writeInterfaceReadAccumulateExpression(usageBuf, 1561 "retValue", 1562 interface, 1563 shader->getType(), 1564 program); 1565 containsUserDefinedInputs = true; 1566 } 1567 } 1568 1569 // Built-in-inputs 1570 1571 switch (shader->getType()) 1572 { 1573 case glu::SHADERTYPE_VERTEX: 1574 // make readInputs to never be compile time constant 1575 if (!containsUserDefinedInputs) 1576 usageBuf << " retValue += vec4(float(gl_VertexID));\n"; 1577 break; 1578 1579 case glu::SHADERTYPE_FRAGMENT: 1580 // make readInputs to never be compile time constant 1581 if (!containsUserDefinedInputs) 1582 usageBuf << " retValue += gl_FragCoord;\n"; 1583 break; 1584 case glu::SHADERTYPE_GEOMETRY: 1585 // always use previous stage's output values so that previous stage won't be optimized out 1586 usageBuf << " retValue += gl_in[0].gl_Position;\n"; 1587 break; 1588 case glu::SHADERTYPE_TESSELLATION_CONTROL: 1589 // always use previous stage's output values so that previous stage won't be optimized out 1590 usageBuf << " retValue += gl_in[0].gl_Position;\n"; 1591 break; 1592 case glu::SHADERTYPE_TESSELLATION_EVALUATION: 1593 // always use previous stage's output values so that previous stage won't be optimized out 1594 usageBuf << " retValue += gl_in[0].gl_Position;\n"; 1595 break; 1596 1597 case glu::SHADERTYPE_COMPUTE: 1598 // make readInputs to never be compile time constant 1599 if (!containsUserDefinedInputs) 1600 usageBuf << " retValue += vec4(float(gl_NumWorkGroups.x));\n"; 1601 break; 1602 default: 1603 DE_ASSERT(false); 1604 } 1605 1606 usageBuf << " return retValue;\n" 1607 "}\n\n"; 1608 1609 usageBuf << "void writeOutputs(in highp vec4 dummyValue)\n" 1610 "{\n"; 1611 1612 // User-defined outputs 1613 1614 for (int ndx = 0; ndx < (int)shader->getDefaultBlock().variables.size(); ++ndx) 1615 { 1616 if (shader->getDefaultBlock().variables[ndx].storage == glu::STORAGE_OUT || 1617 shader->getDefaultBlock().variables[ndx].storage == glu::STORAGE_PATCH_OUT) 1618 { 1619 writeVariableWriteExpression(usageBuf, 1620 "dummyValue", 1621 shader->getDefaultBlock().variables[ndx].name, 1622 shader->getType(), 1623 shader->getDefaultBlock().variables[ndx].storage, 1624 program, 1625 shader->getDefaultBlock().variables[ndx].varType); 1626 containsUserDefinedOutputs = true; 1627 } 1628 } 1629 1630 for (int interfaceNdx = 0; interfaceNdx < (int)shader->getDefaultBlock().interfaceBlocks.size(); ++interfaceNdx) 1631 { 1632 const glu::InterfaceBlock& interface = shader->getDefaultBlock().interfaceBlocks[interfaceNdx]; 1633 if (isWritableInterface(interface)) 1634 { 1635 writeInterfaceWriteExpression(usageBuf, "dummyValue", interface, shader->getType(), program); 1636 containsUserDefinedOutputs = true; 1637 } 1638 } 1639 1640 // Builtin-outputs that must be written to 1641 1642 if (shader->getType() == glu::SHADERTYPE_VERTEX) 1643 usageBuf << " gl_Position = dummyValue;\n"; 1644 else if (shader->getType() == glu::SHADERTYPE_GEOMETRY) 1645 usageBuf << " gl_Position = dummyValue;\n" 1646 " EmitVertex();\n"; 1647 else if (shader->getType() == glu::SHADERTYPE_TESSELLATION_CONTROL) 1648 usageBuf << " gl_out[gl_InvocationID].gl_Position = dummyValue;\n" 1649 " gl_TessLevelOuter[0] = 2.8;\n" 1650 " gl_TessLevelOuter[1] = 2.8;\n" 1651 " gl_TessLevelOuter[2] = 2.8;\n" 1652 " gl_TessLevelOuter[3] = 2.8;\n" 1653 " gl_TessLevelInner[0] = 2.8;\n" 1654 " gl_TessLevelInner[1] = 2.8;\n"; 1655 else if (shader->getType() == glu::SHADERTYPE_TESSELLATION_EVALUATION) 1656 usageBuf << " gl_Position = dummyValue;\n"; 1657 1658 // Output to sink input data to 1659 1660 if (!containsUserDefinedOutputs) 1661 { 1662 if (shader->getType() == glu::SHADERTYPE_FRAGMENT) 1663 usageBuf << " gl_FragDepth = dot(dummyValue.xy, dummyValue.xw);\n"; 1664 else if (shader->getType() == glu::SHADERTYPE_COMPUTE) 1665 usageBuf << " dummyOutputBlock.dummyValue = dummyValue;\n"; 1666 } 1667 1668 usageBuf << "}\n\n" 1669 "void main()\n" 1670 "{\n" 1671 " writeOutputs(readInputs());\n" 1672 "}\n"; 1673 1674 // Interface for dummy output 1675 1676 if (shader->getType() == glu::SHADERTYPE_COMPUTE && !containsUserDefinedOutputs) 1677 { 1678 sourceBuf << "writeonly buffer DummyOutputInterface\n" 1679 << "{\n" 1680 << " highp vec4 dummyValue;\n" 1681 << "} dummyOutputBlock;\n\n"; 1682 } 1683 1684 sources << glu::ShaderSource(shader->getType(), sourceBuf.str() + usageBuf.str()); 1685 } 1686 1687 if (program->isSeparable()) 1688 sources << glu::ProgramSeparable(true); 1689 1690 for (int ndx = 0; ndx < (int)program->getTransformFeedbackVaryings().size(); ++ndx) 1691 sources << glu::TransformFeedbackVarying(program->getTransformFeedbackVaryings()[ndx]); 1692 1693 if (program->getTransformFeedbackMode()) 1694 sources << glu::TransformFeedbackMode(program->getTransformFeedbackMode()); 1695 1696 return sources; 1697} 1698 1699bool findProgramVariablePathByPathName (std::vector<VariablePathComponent>& typePath, const ProgramInterfaceDefinition::Program* program, const std::string& pathName, const VariableSearchFilter& filter) 1700{ 1701 std::vector<VariablePathComponent> modifiedPath; 1702 1703 if (!traverseProgramVariablePath(modifiedPath, program, pathName, filter)) 1704 return false; 1705 1706 // modify param only on success 1707 typePath.swap(modifiedPath); 1708 return true; 1709} 1710 1711ProgramInterfaceDefinition::ShaderResourceUsage getShaderResourceUsage (const ProgramInterfaceDefinition::Program* program, const ProgramInterfaceDefinition::Shader* shader) 1712{ 1713 ProgramInterfaceDefinition::ShaderResourceUsage retVal; 1714 1715 retVal.numInputs = getNumTypeInstances(shader, glu::STORAGE_IN); 1716 retVal.numInputVectors = getNumVectors(shader, glu::STORAGE_IN); 1717 retVal.numInputComponents = getNumComponents(shader, glu::STORAGE_IN); 1718 1719 retVal.numOutputs = getNumTypeInstances(shader, glu::STORAGE_OUT); 1720 retVal.numOutputVectors = getNumVectors(shader, glu::STORAGE_OUT); 1721 retVal.numOutputComponents = getNumComponents(shader, glu::STORAGE_OUT); 1722 1723 retVal.numPatchInputComponents = getNumComponents(shader, glu::STORAGE_PATCH_IN); 1724 retVal.numPatchOutputComponents = getNumComponents(shader, glu::STORAGE_PATCH_OUT); 1725 1726 retVal.numDefaultBlockUniformComponents = getNumDefaultBlockComponents(shader, glu::STORAGE_UNIFORM); 1727 retVal.numCombinedUniformComponents = getNumComponents(shader, glu::STORAGE_UNIFORM); 1728 retVal.numUniformVectors = getNumVectors(shader, glu::STORAGE_UNIFORM); 1729 1730 retVal.numSamplers = getNumTypeInstances(shader, glu::STORAGE_UNIFORM, glu::isDataTypeSampler); 1731 retVal.numImages = getNumTypeInstances(shader, glu::STORAGE_UNIFORM, glu::isDataTypeImage); 1732 1733 retVal.numAtomicCounterBuffers = getNumAtomicCounterBuffers(shader); 1734 retVal.numAtomicCounters = getNumTypeInstances(shader, glu::STORAGE_UNIFORM, glu::isDataTypeAtomicCounter); 1735 1736 retVal.numUniformBlocks = getNumShaderBlocks(shader, glu::STORAGE_UNIFORM); 1737 retVal.numShaderStorageBlocks = getNumShaderBlocks(shader, glu::STORAGE_BUFFER); 1738 1739 // add builtins 1740 switch (shader->getType()) 1741 { 1742 case glu::SHADERTYPE_VERTEX: 1743 // gl_Position is not counted 1744 break; 1745 1746 case glu::SHADERTYPE_FRAGMENT: 1747 // nada 1748 break; 1749 1750 case glu::SHADERTYPE_GEOMETRY: 1751 // gl_Position in (point mode => size 1) 1752 retVal.numInputs += 1; 1753 retVal.numInputVectors += 1; 1754 retVal.numInputComponents += 4; 1755 1756 // gl_Position out 1757 retVal.numOutputs += 1; 1758 retVal.numOutputVectors += 1; 1759 retVal.numOutputComponents += 4; 1760 break; 1761 1762 case glu::SHADERTYPE_TESSELLATION_CONTROL: 1763 // gl_Position in is read up to gl_InstanceID 1764 retVal.numInputs += 1 * program->getTessellationNumOutputPatchVertices(); 1765 retVal.numInputVectors += 1 * program->getTessellationNumOutputPatchVertices(); 1766 retVal.numInputComponents += 4 * program->getTessellationNumOutputPatchVertices(); 1767 1768 // gl_Position out, size = num patch out vertices 1769 retVal.numOutputs += 1 * program->getTessellationNumOutputPatchVertices(); 1770 retVal.numOutputVectors += 1 * program->getTessellationNumOutputPatchVertices(); 1771 retVal.numOutputComponents += 4 * program->getTessellationNumOutputPatchVertices(); 1772 break; 1773 1774 case glu::SHADERTYPE_TESSELLATION_EVALUATION: 1775 // gl_Position in is read up to gl_InstanceID 1776 retVal.numInputs += 1 * program->getTessellationNumOutputPatchVertices(); 1777 retVal.numInputVectors += 1 * program->getTessellationNumOutputPatchVertices(); 1778 retVal.numInputComponents += 4 * program->getTessellationNumOutputPatchVertices(); 1779 1780 // gl_Position out 1781 retVal.numOutputs += 1; 1782 retVal.numOutputVectors += 1; 1783 retVal.numOutputComponents += 4; 1784 break; 1785 1786 case glu::SHADERTYPE_COMPUTE: 1787 // nada 1788 break; 1789 1790 default: 1791 DE_ASSERT(false); 1792 break; 1793 } 1794 return retVal; 1795} 1796 1797ProgramInterfaceDefinition::ProgramResourceUsage getCombinedProgramResourceUsage (const ProgramInterfaceDefinition::Program* program) 1798{ 1799 ProgramInterfaceDefinition::ProgramResourceUsage retVal; 1800 int numVertexOutputComponents = 0; 1801 int numFragmentInputComponents = 0; 1802 int numVertexOutputVectors = 0; 1803 int numFragmentInputVectors = 0; 1804 1805 retVal.uniformBufferMaxBinding = -1; // max binding is inclusive upper bound. Allow 0 bindings by using negative value 1806 retVal.uniformBufferMaxSize = 0; 1807 retVal.numUniformBlocks = 0; 1808 retVal.numCombinedVertexUniformComponents = 0; 1809 retVal.numCombinedFragmentUniformComponents = 0; 1810 retVal.numCombinedGeometryUniformComponents = 0; 1811 retVal.numCombinedTessControlUniformComponents = 0; 1812 retVal.numCombinedTessEvalUniformComponents = 0; 1813 retVal.shaderStorageBufferMaxBinding = -1; // see above 1814 retVal.shaderStorageBufferMaxSize = 0; 1815 retVal.numShaderStorageBlocks = 0; 1816 retVal.numVaryingComponents = 0; 1817 retVal.numVaryingVectors = 0; 1818 retVal.numCombinedSamplers = 0; 1819 retVal.atomicCounterBufferMaxBinding = -1; // see above 1820 retVal.atomicCounterBufferMaxSize = 0; 1821 retVal.numAtomicCounterBuffers = 0; 1822 retVal.numAtomicCounters = 0; 1823 retVal.maxImageBinding = -1; // see above 1824 retVal.numCombinedImages = 0; 1825 retVal.numCombinedOutputResources = 0; 1826 retVal.numXFBInterleavedComponents = 0; 1827 retVal.numXFBSeparateAttribs = 0; 1828 retVal.numXFBSeparateComponents = 0; 1829 retVal.fragmentOutputMaxBinding = -1; // see above 1830 1831 for (int shaderNdx = 0; shaderNdx < (int)program->getShaders().size(); ++shaderNdx) 1832 { 1833 const ProgramInterfaceDefinition::Shader* const shader = program->getShaders()[shaderNdx]; 1834 1835 retVal.uniformBufferMaxBinding = de::max(retVal.uniformBufferMaxBinding, getMaxBufferBinding(shader, glu::STORAGE_UNIFORM)); 1836 retVal.uniformBufferMaxSize = de::max(retVal.uniformBufferMaxSize, getBufferMaxSize(shader, glu::STORAGE_UNIFORM)); 1837 retVal.numUniformBlocks += getNumShaderBlocks(shader, glu::STORAGE_UNIFORM); 1838 1839 switch (shader->getType()) 1840 { 1841 case glu::SHADERTYPE_VERTEX: retVal.numCombinedVertexUniformComponents += getNumComponents(shader, glu::STORAGE_UNIFORM); break; 1842 case glu::SHADERTYPE_FRAGMENT: retVal.numCombinedFragmentUniformComponents += getNumComponents(shader, glu::STORAGE_UNIFORM); break; 1843 case glu::SHADERTYPE_GEOMETRY: retVal.numCombinedGeometryUniformComponents += getNumComponents(shader, glu::STORAGE_UNIFORM); break; 1844 case glu::SHADERTYPE_TESSELLATION_CONTROL: retVal.numCombinedTessControlUniformComponents += getNumComponents(shader, glu::STORAGE_UNIFORM); break; 1845 case glu::SHADERTYPE_TESSELLATION_EVALUATION: retVal.numCombinedTessEvalUniformComponents += getNumComponents(shader, glu::STORAGE_UNIFORM); break; 1846 default: break; 1847 } 1848 1849 retVal.shaderStorageBufferMaxBinding = de::max(retVal.shaderStorageBufferMaxBinding, getMaxBufferBinding(shader, glu::STORAGE_BUFFER)); 1850 retVal.shaderStorageBufferMaxSize = de::max(retVal.shaderStorageBufferMaxSize, getBufferMaxSize(shader, glu::STORAGE_BUFFER)); 1851 retVal.numShaderStorageBlocks += getNumShaderBlocks(shader, glu::STORAGE_BUFFER); 1852 1853 if (shader->getType() == glu::SHADERTYPE_VERTEX) 1854 { 1855 numVertexOutputComponents += getNumComponents(shader, glu::STORAGE_OUT); 1856 numVertexOutputVectors += getNumVectors(shader, glu::STORAGE_OUT); 1857 } 1858 else if (shader->getType() == glu::SHADERTYPE_FRAGMENT) 1859 { 1860 numFragmentInputComponents += getNumComponents(shader, glu::STORAGE_IN); 1861 numFragmentInputVectors += getNumVectors(shader, glu::STORAGE_IN); 1862 } 1863 1864 retVal.numCombinedSamplers += getNumTypeInstances(shader, glu::STORAGE_UNIFORM, glu::isDataTypeSampler); 1865 1866 retVal.atomicCounterBufferMaxBinding = de::max(retVal.atomicCounterBufferMaxBinding, getAtomicCounterMaxBinding(shader)); 1867 retVal.atomicCounterBufferMaxSize = de::max(retVal.atomicCounterBufferMaxSize, getAtomicCounterMaxBufferSize(shader)); 1868 retVal.numAtomicCounterBuffers += getNumAtomicCounterBuffers(shader); 1869 retVal.numAtomicCounters += getNumTypeInstances(shader, glu::STORAGE_UNIFORM, glu::isDataTypeAtomicCounter); 1870 retVal.maxImageBinding = de::max(retVal.maxImageBinding, getUniformMaxBinding(shader, glu::isDataTypeImage)); 1871 retVal.numCombinedImages += getNumTypeInstances(shader, glu::STORAGE_UNIFORM, glu::isDataTypeImage); 1872 1873 retVal.numCombinedOutputResources += getNumTypeInstances(shader, glu::STORAGE_UNIFORM, glu::isDataTypeImage); 1874 retVal.numCombinedOutputResources += getNumShaderBlocks(shader, glu::STORAGE_BUFFER); 1875 1876 if (shader->getType() == glu::SHADERTYPE_FRAGMENT) 1877 { 1878 retVal.numCombinedOutputResources += getNumVectors(shader, glu::STORAGE_OUT); 1879 retVal.fragmentOutputMaxBinding = de::max(retVal.fragmentOutputMaxBinding, getFragmentOutputMaxLocation(shader)); 1880 } 1881 } 1882 1883 if (program->getTransformFeedbackMode() == GL_INTERLEAVED_ATTRIBS) 1884 retVal.numXFBInterleavedComponents = getNumXFBComponents(program); 1885 else if (program->getTransformFeedbackMode() == GL_SEPARATE_ATTRIBS) 1886 { 1887 retVal.numXFBSeparateAttribs = (int)program->getTransformFeedbackVaryings().size(); 1888 retVal.numXFBSeparateComponents = getNumMaxXFBOutputComponents(program); 1889 } 1890 1891 // legacy limits 1892 retVal.numVaryingComponents = de::max(numVertexOutputComponents, numFragmentInputComponents); 1893 retVal.numVaryingVectors = de::max(numVertexOutputVectors, numFragmentInputVectors); 1894 1895 return retVal; 1896} 1897 1898} // Functional 1899} // gles31 1900} // deqp 1901