es31fProgramInterfaceQueryTestCase.cpp revision 6a1979c5e502d1403cbccf122b6dab8dd05b3c63
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 query test case 22 *//*--------------------------------------------------------------------*/ 23 24#include "es31fProgramInterfaceQueryTestCase.hpp" 25#include "es31fProgramInterfaceDefinitionUtil.hpp" 26#include "tcuTestLog.hpp" 27#include "gluVarTypeUtil.hpp" 28#include "gluStrUtil.hpp" 29#include "gluContextInfo.hpp" 30#include "gluShaderProgram.hpp" 31#include "glwFunctions.hpp" 32#include "glwEnums.hpp" 33#include "deString.h" 34#include "deStringUtil.hpp" 35#include "deSTLUtil.hpp" 36 37namespace deqp 38{ 39namespace gles31 40{ 41namespace Functional 42{ 43namespace 44{ 45 46using ProgramInterfaceDefinition::VariablePathComponent; 47using ProgramInterfaceDefinition::VariableSearchFilter; 48 49static glw::GLenum getProgramDefaultBlockInterfaceFromStorage (glu::Storage storage) 50{ 51 switch (storage) 52 { 53 case glu::STORAGE_IN: 54 case glu::STORAGE_PATCH_IN: 55 return GL_PROGRAM_INPUT; 56 57 case glu::STORAGE_OUT: 58 case glu::STORAGE_PATCH_OUT: 59 return GL_PROGRAM_OUTPUT; 60 61 case glu::STORAGE_UNIFORM: 62 return GL_UNIFORM; 63 64 default: 65 DE_ASSERT(false); 66 return 0; 67 } 68} 69 70static bool isBufferBackedInterfaceBlockStorage (glu::Storage storage) 71{ 72 return storage == glu::STORAGE_BUFFER || storage == glu::STORAGE_UNIFORM; 73} 74 75const char* getRequiredExtensionForStage (glu::ShaderType stage) 76{ 77 switch (stage) 78 { 79 case glu::SHADERTYPE_COMPUTE: 80 case glu::SHADERTYPE_VERTEX: 81 case glu::SHADERTYPE_FRAGMENT: 82 return DE_NULL; 83 84 case glu::SHADERTYPE_GEOMETRY: 85 return "GL_EXT_geometry_shader"; 86 87 case glu::SHADERTYPE_TESSELLATION_CONTROL: 88 case glu::SHADERTYPE_TESSELLATION_EVALUATION: 89 return "GL_EXT_tessellation_shader"; 90 91 default: 92 DE_ASSERT(false); 93 return DE_NULL; 94 } 95} 96 97static int getTypeSize (glu::DataType type) 98{ 99 if (type == glu::TYPE_FLOAT) 100 return 4; 101 else if (type == glu::TYPE_INT || type == glu::TYPE_UINT) 102 return 4; 103 else if (type == glu::TYPE_BOOL) 104 return 4; // uint 105 106 DE_ASSERT(false); 107 return 0; 108} 109 110static int getVarTypeSize (const glu::VarType& type) 111{ 112 if (type.isBasicType()) 113 { 114 // return in basic machine units 115 return glu::getDataTypeScalarSize(type.getBasicType()) * getTypeSize(glu::getDataTypeScalarType(type.getBasicType())); 116 } 117 else if (type.isStructType()) 118 { 119 int size = 0; 120 for (int ndx = 0; ndx < type.getStructPtr()->getNumMembers(); ++ndx) 121 size += getVarTypeSize(type.getStructPtr()->getMember(ndx).getType()); 122 return size; 123 } 124 else if (type.isArrayType()) 125 { 126 // unsized arrays are handled as if they had only one element 127 if (type.getArraySize() == glu::VarType::UNSIZED_ARRAY) 128 return getVarTypeSize(type.getElementType()); 129 else 130 return type.getArraySize() * getVarTypeSize(type.getElementType()); 131 } 132 else 133 { 134 DE_ASSERT(false); 135 return 0; 136 } 137} 138 139static glu::MatrixOrder getMatrixOrderFromPath (const std::vector<VariablePathComponent>& path) 140{ 141 glu::MatrixOrder order = glu::MATRIXORDER_LAST; 142 143 // inherit majority 144 for (int pathNdx = 0; pathNdx < (int)path.size(); ++pathNdx) 145 { 146 glu::MatrixOrder matOrder; 147 148 if (path[pathNdx].isInterfaceBlock()) 149 matOrder = path[pathNdx].getInterfaceBlock()->layout.matrixOrder; 150 else if (path[pathNdx].isDeclaration()) 151 matOrder = path[pathNdx].getDeclaration()->layout.matrixOrder; 152 else if (path[pathNdx].isVariableType()) 153 matOrder = glu::MATRIXORDER_LAST; 154 else 155 { 156 DE_ASSERT(false); 157 return glu::MATRIXORDER_LAST; 158 } 159 160 if (matOrder != glu::MATRIXORDER_LAST) 161 order = matOrder; 162 } 163 164 return order; 165} 166 167class PropValidator 168{ 169public: 170 PropValidator (Context& context, ProgramResourcePropFlags validationProp, const char* requiredExtension); 171 172 virtual std::string getHumanReadablePropertyString (glw::GLint propVal) const; 173 virtual void validate (const ProgramInterfaceDefinition::Program* program, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const = 0; 174 175 bool isSupported (void) const; 176 bool isSelected (deUint32 caseFlags) const; 177 178protected: 179 void setError (const std::string& err) const; 180 181 tcu::TestContext& m_testCtx; 182 const glu::RenderContext& m_renderContext; 183 184private: 185 const glu::ContextInfo& m_contextInfo; 186 const char* m_extension; 187 const ProgramResourcePropFlags m_validationProp; 188}; 189 190PropValidator::PropValidator (Context& context, ProgramResourcePropFlags validationProp, const char* requiredExtension) 191 : m_testCtx (context.getTestContext()) 192 , m_renderContext (context.getRenderContext()) 193 , m_contextInfo (context.getContextInfo()) 194 , m_extension (requiredExtension) 195 , m_validationProp (validationProp) 196{ 197} 198 199std::string PropValidator::getHumanReadablePropertyString (glw::GLint propVal) const 200{ 201 return de::toString(propVal); 202} 203 204bool PropValidator::isSupported (void) const 205{ 206 return m_extension == DE_NULL || m_contextInfo.isExtensionSupported(m_extension); 207} 208 209bool PropValidator::isSelected (deUint32 caseFlags) const 210{ 211 return (caseFlags & (deUint32)m_validationProp) != 0; 212} 213 214void PropValidator::setError (const std::string& err) const 215{ 216 // don't overwrite earlier errors 217 if (m_testCtx.getTestResult() == QP_TEST_RESULT_PASS) 218 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, err.c_str()); 219} 220 221class SingleVariableValidator : public PropValidator 222{ 223public: 224 SingleVariableValidator (Context& context, ProgramResourcePropFlags validationProp, glw::GLuint programID, const VariableSearchFilter& filter, const char* requiredExtension); 225 226 void validate (const ProgramInterfaceDefinition::Program* program, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const; 227 virtual void validateSingleVariable (const std::vector<VariablePathComponent>& path, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const = 0; 228 virtual void validateBuiltinVariable (const std::string& resource, glw::GLint propValue, const std::string& implementationName) const; 229 230protected: 231 const VariableSearchFilter m_filter; 232 const glw::GLuint m_programID; 233}; 234 235SingleVariableValidator::SingleVariableValidator (Context& context, ProgramResourcePropFlags validationProp, glw::GLuint programID, const VariableSearchFilter& filter, const char* requiredExtension) 236 : PropValidator (context, validationProp, requiredExtension) 237 , m_filter (filter) 238 , m_programID (programID) 239{ 240} 241 242void SingleVariableValidator::validate (const ProgramInterfaceDefinition::Program* program, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const 243{ 244 std::vector<VariablePathComponent> path; 245 246 if (findProgramVariablePathByPathName(path, program, resource, m_filter)) 247 { 248 const glu::VarType* variable = (path.back().isVariableType()) ? (path.back().getVariableType()) : (DE_NULL); 249 250 if (!variable || !variable->isBasicType()) 251 { 252 m_testCtx.getLog() << tcu::TestLog::Message << "Error, resource name \"" << resource << "\" refers to a non-basic type." << tcu::TestLog::EndMessage; 253 setError("resource not basic type"); 254 } 255 else 256 validateSingleVariable(path, resource, propValue, implementationName); 257 258 // finding matching variable in any shader is sufficient 259 return; 260 } 261 else if (deStringBeginsWith(resource.c_str(), "gl_")) 262 { 263 // special case for builtins 264 validateBuiltinVariable(resource, propValue, implementationName); 265 return; 266 } 267 268 // we are only supplied good names, generated by ourselves 269 DE_ASSERT(false); 270 throw tcu::InternalError("Resource name consistency error"); 271} 272 273void SingleVariableValidator::validateBuiltinVariable (const std::string& resource, glw::GLint propValue, const std::string& implementationName) const 274{ 275 DE_UNREF(resource); 276 DE_UNREF(propValue); 277 DE_UNREF(implementationName); 278 DE_ASSERT(false); 279} 280 281class SingleBlockValidator : public PropValidator 282{ 283public: 284 SingleBlockValidator (Context& context, ProgramResourcePropFlags validationProp, glw::GLuint programID, const VariableSearchFilter& filter, const char* requiredExtension); 285 286 void validate (const ProgramInterfaceDefinition::Program* program, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const; 287 virtual void validateSingleBlock (const glu::InterfaceBlock& block, const std::vector<int>& instanceIndex, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const = 0; 288 289protected: 290 const VariableSearchFilter m_filter; 291 const glw::GLuint m_programID; 292}; 293 294SingleBlockValidator::SingleBlockValidator (Context& context, ProgramResourcePropFlags validationProp, glw::GLuint programID, const VariableSearchFilter& filter, const char* requiredExtension) 295 : PropValidator (context, validationProp, requiredExtension) 296 , m_filter (filter) 297 , m_programID (programID) 298{ 299} 300 301void SingleBlockValidator::validate (const ProgramInterfaceDefinition::Program* program, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const 302{ 303 glu::VarTokenizer tokenizer (resource.c_str()); 304 const std::string blockName = tokenizer.getIdentifier(); 305 std::vector<int> instanceIndex; 306 307 tokenizer.advance(); 308 309 // array index 310 while (tokenizer.getToken() == glu::VarTokenizer::TOKEN_LEFT_BRACKET) 311 { 312 tokenizer.advance(); 313 DE_ASSERT(tokenizer.getToken() == glu::VarTokenizer::TOKEN_NUMBER); 314 315 instanceIndex.push_back(tokenizer.getNumber()); 316 317 tokenizer.advance(); 318 DE_ASSERT(tokenizer.getToken() == glu::VarTokenizer::TOKEN_RIGHT_BRACKET); 319 320 tokenizer.advance(); 321 } 322 323 // no trailing garbage 324 DE_ASSERT(tokenizer.getToken() == glu::VarTokenizer::TOKEN_END); 325 326 for (int shaderNdx = 0; shaderNdx < (int)program->getShaders().size(); ++shaderNdx) 327 { 328 const ProgramInterfaceDefinition::Shader* const shader = program->getShaders()[shaderNdx]; 329 if (!m_filter.matchesFilter(shader)) 330 continue; 331 332 for (int blockNdx = 0; blockNdx < (int)shader->getDefaultBlock().interfaceBlocks.size(); ++blockNdx) 333 { 334 const glu::InterfaceBlock& block = shader->getDefaultBlock().interfaceBlocks[blockNdx]; 335 336 if (m_filter.matchesFilter(block) && block.interfaceName == blockName) 337 { 338 // dimensions match 339 DE_ASSERT(instanceIndex.size() == block.dimensions.size()); 340 341 validateSingleBlock(block, instanceIndex, resource, propValue, implementationName); 342 return; 343 } 344 } 345 } 346 347 // we are only supplied good names, generated by ourselves 348 DE_ASSERT(false); 349 throw tcu::InternalError("Resource name consistency error"); 350} 351 352class TypeValidator : public SingleVariableValidator 353{ 354public: 355 TypeValidator (Context& context, glw::GLuint programID, const VariableSearchFilter& filter); 356 357 std::string getHumanReadablePropertyString (glw::GLint propVal) const; 358 void validateSingleVariable (const std::vector<VariablePathComponent>& path, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const; 359 void validateBuiltinVariable (const std::string& resource, glw::GLint propValue, const std::string& implementationName) const; 360}; 361 362TypeValidator::TypeValidator (Context& context, glw::GLuint programID, const VariableSearchFilter& filter) 363 : SingleVariableValidator(context, PROGRAMRESOURCEPROP_TYPE, programID, filter, DE_NULL) 364{ 365} 366 367std::string TypeValidator::getHumanReadablePropertyString (glw::GLint propVal) const 368{ 369 return de::toString(glu::getShaderVarTypeStr(propVal)); 370} 371 372void TypeValidator::validateSingleVariable (const std::vector<VariablePathComponent>& path, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const 373{ 374 const glu::VarType* variable = path.back().getVariableType(); 375 376 DE_UNREF(resource); 377 DE_UNREF(implementationName); 378 379 m_testCtx.getLog() << tcu::TestLog::Message << "Verifying type, expecting " << glu::getDataTypeName(variable->getBasicType()) << tcu::TestLog::EndMessage; 380 381 if (variable->getBasicType() != glu::getDataTypeFromGLType(propValue)) 382 { 383 m_testCtx.getLog() << tcu::TestLog::Message << "\tError, got " << glu::getDataTypeName(glu::getDataTypeFromGLType(propValue)) << tcu::TestLog::EndMessage; 384 setError("resource type invalid"); 385 } 386} 387 388void TypeValidator::validateBuiltinVariable (const std::string& resource, glw::GLint propValue, const std::string& implementationName) const 389{ 390 DE_UNREF(implementationName); 391 392 static const struct 393 { 394 const char* name; 395 glu::DataType type; 396 } builtins[] = 397 { 398 { "gl_Position", glu::TYPE_FLOAT_VEC4 }, 399 { "gl_FragCoord", glu::TYPE_FLOAT_VEC4 }, 400 { "gl_PerVertex.gl_Position", glu::TYPE_FLOAT_VEC4 }, 401 { "gl_VertexID", glu::TYPE_INT }, 402 { "gl_InvocationID", glu::TYPE_INT }, 403 { "gl_NumWorkGroups", glu::TYPE_UINT_VEC3 }, 404 { "gl_FragDepth", glu::TYPE_FLOAT }, 405 { "gl_TessLevelOuter[0]", glu::TYPE_FLOAT }, 406 { "gl_TessLevelInner[0]", glu::TYPE_FLOAT }, 407 }; 408 409 for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(builtins); ++ndx) 410 { 411 if (resource == builtins[ndx].name) 412 { 413 m_testCtx.getLog() << tcu::TestLog::Message << "Verifying type, expecting " << glu::getDataTypeName(builtins[ndx].type) << tcu::TestLog::EndMessage; 414 415 if (glu::getDataTypeFromGLType(propValue) != builtins[ndx].type) 416 { 417 m_testCtx.getLog() << tcu::TestLog::Message << "\tError, got " << glu::getDataTypeName(glu::getDataTypeFromGLType(propValue)) << tcu::TestLog::EndMessage; 418 setError("resource type invalid"); 419 } 420 return; 421 } 422 } 423 424 DE_ASSERT(false); 425} 426 427class ArraySizeValidator : public SingleVariableValidator 428{ 429public: 430 ArraySizeValidator (Context& context, glw::GLuint programID, int unsizedArraySize, const VariableSearchFilter& filter); 431 432 void validateSingleVariable (const std::vector<VariablePathComponent>& path, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const; 433 void validateBuiltinVariable (const std::string& resource, glw::GLint propValue, const std::string& implementationName) const; 434 435private: 436 const int m_unsizedArraySize; 437}; 438 439ArraySizeValidator::ArraySizeValidator (Context& context, glw::GLuint programID, int unsizedArraySize, const VariableSearchFilter& filter) 440 : SingleVariableValidator (context, PROGRAMRESOURCEPROP_ARRAY_SIZE, programID, filter, DE_NULL) 441 , m_unsizedArraySize (unsizedArraySize) 442{ 443} 444 445void ArraySizeValidator::validateSingleVariable (const std::vector<VariablePathComponent>& path, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const 446{ 447 const VariablePathComponent nullComponent; 448 const VariablePathComponent& enclosingcomponent = (path.size() > 1) ? (path[path.size()-2]) : (nullComponent); 449 450 const bool isArray = enclosingcomponent.isVariableType() && enclosingcomponent.getVariableType()->isArrayType(); 451 const bool inUnsizedArray = isArray && (enclosingcomponent.getVariableType()->getArraySize() == glu::VarType::UNSIZED_ARRAY); 452 const int arraySize = (!isArray) ? (1) : (inUnsizedArray) ? (m_unsizedArraySize) : (enclosingcomponent.getVariableType()->getArraySize()); 453 454 DE_ASSERT(arraySize >= 0); 455 DE_UNREF(resource); 456 DE_UNREF(implementationName); 457 458 m_testCtx.getLog() << tcu::TestLog::Message << "Verifying array size, expecting " << arraySize << tcu::TestLog::EndMessage; 459 460 if (arraySize != propValue) 461 { 462 m_testCtx.getLog() << tcu::TestLog::Message << "\tError, got " << propValue << tcu::TestLog::EndMessage; 463 setError("resource array size invalid"); 464 } 465} 466 467void ArraySizeValidator::validateBuiltinVariable (const std::string& resource, glw::GLint propValue, const std::string& implementationName) const 468{ 469 DE_UNREF(implementationName); 470 471 static const struct 472 { 473 const char* name; 474 int arraySize; 475 } builtins[] = 476 { 477 { "gl_Position", 1 }, 478 { "gl_VertexID", 1 }, 479 { "gl_FragCoord", 1 }, 480 { "gl_PerVertex.gl_Position", 1 }, 481 { "gl_InvocationID", 1 }, 482 { "gl_NumWorkGroups", 1 }, 483 { "gl_FragDepth", 1 }, 484 { "gl_TessLevelOuter[0]", 4 }, 485 { "gl_TessLevelInner[0]", 2 }, 486 }; 487 488 for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(builtins); ++ndx) 489 { 490 if (resource == builtins[ndx].name) 491 { 492 m_testCtx.getLog() << tcu::TestLog::Message << "Verifying array size, expecting " << builtins[ndx].arraySize << tcu::TestLog::EndMessage; 493 494 if (propValue != builtins[ndx].arraySize) 495 { 496 m_testCtx.getLog() << tcu::TestLog::Message << "\tError, got " << propValue << tcu::TestLog::EndMessage; 497 setError("resource array size invalid"); 498 } 499 return; 500 } 501 } 502 503 DE_ASSERT(false); 504} 505 506class ArrayStrideValidator : public SingleVariableValidator 507{ 508public: 509 ArrayStrideValidator (Context& context, glw::GLuint programID, const VariableSearchFilter& filter); 510 511 void validateSingleVariable (const std::vector<VariablePathComponent>& path, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const; 512}; 513 514ArrayStrideValidator::ArrayStrideValidator (Context& context, glw::GLuint programID, const VariableSearchFilter& filter) 515 : SingleVariableValidator(context, PROGRAMRESOURCEPROP_ARRAY_STRIDE, programID, filter, DE_NULL) 516{ 517} 518 519void ArrayStrideValidator::validateSingleVariable (const std::vector<VariablePathComponent>& path, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const 520{ 521 const VariablePathComponent nullComponent; 522 const VariablePathComponent& component = path.back(); 523 const VariablePathComponent& enclosingcomponent = (path.size() > 1) ? (path[path.size()-2]) : (nullComponent); 524 const VariablePathComponent& firstComponent = path.front(); 525 526 const bool isBufferBlock = firstComponent.isInterfaceBlock() && isBufferBackedInterfaceBlockStorage(firstComponent.getInterfaceBlock()->storage); 527 const bool isArray = enclosingcomponent.isVariableType() && enclosingcomponent.getVariableType()->isArrayType(); 528 const bool isAtomicCounter = glu::isDataTypeAtomicCounter(component.getVariableType()->getBasicType()); // atomic counters are buffer backed with a stride of 4 basic machine units 529 530 DE_UNREF(resource); 531 DE_UNREF(implementationName); 532 533 // Layout tests will verify layouts of buffer backed arrays properly. Here we just check values are greater or equal to the element size 534 if (isBufferBlock && isArray) 535 { 536 const int elementSize = glu::getDataTypeScalarSize(component.getVariableType()->getBasicType()) * getTypeSize(glu::getDataTypeScalarType(component.getVariableType()->getBasicType())); 537 m_testCtx.getLog() << tcu::TestLog::Message << "Verifying array stride, expecting greater or equal to " << elementSize << tcu::TestLog::EndMessage; 538 539 if (propValue < elementSize) 540 { 541 m_testCtx.getLog() << tcu::TestLog::Message << "\tError, got " << propValue << tcu::TestLog::EndMessage; 542 setError("resource array stride invalid"); 543 } 544 } 545 else 546 { 547 // Atomics are buffer backed with stride of 4 even though they are not in an interface block 548 const int arrayStride = (isAtomicCounter && isArray) ? (4) : (!isBufferBlock && !isAtomicCounter) ? (-1) : (0); 549 550 m_testCtx.getLog() << tcu::TestLog::Message << "Verifying array stride, expecting " << arrayStride << tcu::TestLog::EndMessage; 551 552 if (arrayStride != propValue) 553 { 554 m_testCtx.getLog() << tcu::TestLog::Message << "\tError, got " << propValue << tcu::TestLog::EndMessage; 555 setError("resource array stride invalid"); 556 } 557 } 558} 559 560class BlockIndexValidator : public SingleVariableValidator 561{ 562public: 563 BlockIndexValidator (Context& context, glw::GLuint programID, const VariableSearchFilter& filter); 564 565 void validateSingleVariable (const std::vector<VariablePathComponent>& path, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const; 566}; 567 568BlockIndexValidator::BlockIndexValidator (Context& context, glw::GLuint programID, const VariableSearchFilter& filter) 569 : SingleVariableValidator(context, PROGRAMRESOURCEPROP_BLOCK_INDEX, programID, filter, DE_NULL) 570{ 571} 572 573void BlockIndexValidator::validateSingleVariable (const std::vector<VariablePathComponent>& path, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const 574{ 575 const VariablePathComponent& firstComponent = path.front(); 576 577 DE_UNREF(resource); 578 DE_UNREF(implementationName); 579 580 if (!firstComponent.isInterfaceBlock()) 581 { 582 m_testCtx.getLog() << tcu::TestLog::Message << "Verifying block index, expecting -1" << tcu::TestLog::EndMessage; 583 584 if (propValue != -1) 585 { 586 m_testCtx.getLog() << tcu::TestLog::Message << "\tError, got " << propValue << tcu::TestLog::EndMessage; 587 setError("resource block index invalid"); 588 } 589 } 590 else 591 { 592 m_testCtx.getLog() << tcu::TestLog::Message << "Verifying block index, expecting a valid block index" << tcu::TestLog::EndMessage; 593 594 if (propValue == -1) 595 { 596 m_testCtx.getLog() << tcu::TestLog::Message << "\tError, got " << propValue << tcu::TestLog::EndMessage; 597 setError("resource block index invalid"); 598 } 599 else 600 { 601 const glw::Functions& gl = m_renderContext.getFunctions(); 602 const glw::GLenum interface = (firstComponent.getInterfaceBlock()->storage == glu::STORAGE_UNIFORM) ? (GL_UNIFORM_BLOCK) : 603 (firstComponent.getInterfaceBlock()->storage == glu::STORAGE_BUFFER) ? (GL_SHADER_STORAGE_BLOCK) : 604 (0); 605 glw::GLint written = 0; 606 std::vector<char> nameBuffer (firstComponent.getInterfaceBlock()->interfaceName.size() + 3 * firstComponent.getInterfaceBlock()->dimensions.size() + 2, '\0'); // +3 for appended "[N]", +1 for '\0' and +1 just for safety 607 608 gl.getProgramResourceName(m_programID, interface, propValue, (int)nameBuffer.size() - 1, &written, &nameBuffer[0]); 609 GLU_EXPECT_NO_ERROR(gl.getError(), "query block name"); 610 TCU_CHECK(written < (int)nameBuffer.size()); 611 TCU_CHECK(nameBuffer.back() == '\0'); 612 613 { 614 const std::string blockName (&nameBuffer[0], written); 615 std::ostringstream expectedName; 616 617 expectedName << firstComponent.getInterfaceBlock()->interfaceName; 618 for (int dimensionNdx = 0; dimensionNdx < (int)firstComponent.getInterfaceBlock()->dimensions.size(); ++dimensionNdx) 619 expectedName << "[0]"; 620 621 m_testCtx.getLog() << tcu::TestLog::Message << "Block name with index " << propValue << " is \"" << blockName << "\"" << tcu::TestLog::EndMessage; 622 if (blockName != expectedName.str()) 623 { 624 m_testCtx.getLog() << tcu::TestLog::Message << "\tError, expected " << expectedName.str() << tcu::TestLog::EndMessage; 625 setError("resource block index invalid"); 626 } 627 } 628 } 629 } 630} 631 632class IsRowMajorValidator : public SingleVariableValidator 633{ 634public: 635 IsRowMajorValidator (Context& context, glw::GLuint programID, const VariableSearchFilter& filter); 636 637 std::string getHumanReadablePropertyString (glw::GLint propVal) const; 638 void validateSingleVariable (const std::vector<VariablePathComponent>& path, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const; 639}; 640 641IsRowMajorValidator::IsRowMajorValidator (Context& context, glw::GLuint programID, const VariableSearchFilter& filter) 642 : SingleVariableValidator(context, PROGRAMRESOURCEPROP_MATRIX_ROW_MAJOR, programID, filter, DE_NULL) 643{ 644} 645 646std::string IsRowMajorValidator::getHumanReadablePropertyString (glw::GLint propVal) const 647{ 648 return de::toString(glu::getBooleanStr(propVal)); 649} 650 651void IsRowMajorValidator::validateSingleVariable (const std::vector<VariablePathComponent>& path, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const 652{ 653 const VariablePathComponent& component = path.back(); 654 const VariablePathComponent& firstComponent = path.front(); 655 656 const bool isBufferBlock = firstComponent.isInterfaceBlock() && isBufferBackedInterfaceBlockStorage(firstComponent.getInterfaceBlock()->storage); 657 const bool isMatrix = glu::isDataTypeMatrix(component.getVariableType()->getBasicType()); 658 const int expected = (isBufferBlock && isMatrix && getMatrixOrderFromPath(path) == glu::MATRIXORDER_ROW_MAJOR) ? (1) : (0); 659 660 DE_UNREF(resource); 661 DE_UNREF(implementationName); 662 663 m_testCtx.getLog() << tcu::TestLog::Message << "Verifying matrix order, expecting IS_ROW_MAJOR = " << expected << tcu::TestLog::EndMessage; 664 665 if (propValue != expected) 666 { 667 m_testCtx.getLog() << tcu::TestLog::Message << "\tError, got " << propValue << tcu::TestLog::EndMessage; 668 setError("resource matrix order invalid"); 669 } 670} 671 672class MatrixStrideValidator : public SingleVariableValidator 673{ 674public: 675 MatrixStrideValidator (Context& context, glw::GLuint programID, const VariableSearchFilter& filter); 676 677 void validateSingleVariable (const std::vector<VariablePathComponent>& path, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const; 678}; 679 680MatrixStrideValidator::MatrixStrideValidator (Context& context, glw::GLuint programID, const VariableSearchFilter& filter) 681 : SingleVariableValidator(context, PROGRAMRESOURCEPROP_MATRIX_STRIDE, programID, filter, DE_NULL) 682{ 683} 684 685void MatrixStrideValidator::validateSingleVariable (const std::vector<VariablePathComponent>& path, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const 686{ 687 const VariablePathComponent& component = path.back(); 688 const VariablePathComponent& firstComponent = path.front(); 689 690 const bool isBufferBlock = firstComponent.isInterfaceBlock() && isBufferBackedInterfaceBlockStorage(firstComponent.getInterfaceBlock()->storage); 691 const bool isMatrix = glu::isDataTypeMatrix(component.getVariableType()->getBasicType()); 692 693 DE_UNREF(resource); 694 DE_UNREF(implementationName); 695 696 // Layout tests will verify layouts of buffer backed arrays properly. Here we just check the stride is is greater or equal to the row/column size 697 if (isBufferBlock && isMatrix) 698 { 699 const bool columnMajor = getMatrixOrderFromPath(path) != glu::MATRIXORDER_ROW_MAJOR; 700 const int numMajorElements = (columnMajor) ? (glu::getDataTypeMatrixNumRows(component.getVariableType()->getBasicType())) : (glu::getDataTypeMatrixNumColumns(component.getVariableType()->getBasicType())); 701 const int majorSize = numMajorElements * getTypeSize(glu::getDataTypeScalarType(component.getVariableType()->getBasicType())); 702 703 m_testCtx.getLog() << tcu::TestLog::Message << "Verifying matrix stride, expecting greater or equal to " << majorSize << tcu::TestLog::EndMessage; 704 705 if (propValue < majorSize) 706 { 707 m_testCtx.getLog() << tcu::TestLog::Message << "\tError, got " << propValue << tcu::TestLog::EndMessage; 708 setError("resource matrix stride invalid"); 709 } 710 } 711 else 712 { 713 const int matrixStride = (!isBufferBlock && !glu::isDataTypeAtomicCounter(component.getVariableType()->getBasicType())) ? (-1) : (0); 714 715 m_testCtx.getLog() << tcu::TestLog::Message << "Verifying matrix stride, expecting " << matrixStride << tcu::TestLog::EndMessage; 716 717 if (matrixStride != propValue) 718 { 719 m_testCtx.getLog() << tcu::TestLog::Message << "\tError, got " << propValue << tcu::TestLog::EndMessage; 720 setError("resource matrix stride invalid"); 721 } 722 } 723} 724 725class AtomicCounterBufferIndexVerifier : public SingleVariableValidator 726{ 727public: 728 AtomicCounterBufferIndexVerifier (Context& context, glw::GLuint programID, const VariableSearchFilter& filter); 729 730 void validateSingleVariable (const std::vector<VariablePathComponent>& path, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const; 731}; 732 733AtomicCounterBufferIndexVerifier::AtomicCounterBufferIndexVerifier (Context& context, glw::GLuint programID, const VariableSearchFilter& filter) 734 : SingleVariableValidator(context, PROGRAMRESOURCEPROP_ATOMIC_COUNTER_BUFFER_INDEX, programID, filter, DE_NULL) 735{ 736} 737 738void AtomicCounterBufferIndexVerifier::validateSingleVariable (const std::vector<VariablePathComponent>& path, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const 739{ 740 DE_UNREF(resource); 741 DE_UNREF(implementationName); 742 743 if (!glu::isDataTypeAtomicCounter(path.back().getVariableType()->getBasicType())) 744 { 745 m_testCtx.getLog() << tcu::TestLog::Message << "Verifying atomic counter buffer index, expecting -1" << tcu::TestLog::EndMessage; 746 747 if (propValue != -1) 748 { 749 m_testCtx.getLog() << tcu::TestLog::Message << "\tError, got " << propValue << tcu::TestLog::EndMessage; 750 setError("resource atomic counter buffer index invalid"); 751 } 752 } 753 else 754 { 755 m_testCtx.getLog() << tcu::TestLog::Message << "Verifying atomic counter buffer index, expecting a valid index" << tcu::TestLog::EndMessage; 756 757 if (propValue == -1) 758 { 759 m_testCtx.getLog() << tcu::TestLog::Message << "\tError, got " << propValue << tcu::TestLog::EndMessage; 760 setError("resource atomic counter buffer index invalid"); 761 } 762 else 763 { 764 const glw::Functions& gl = m_renderContext.getFunctions(); 765 glw::GLint numActiveResources = 0; 766 767 gl.getProgramInterfaceiv(m_programID, GL_ATOMIC_COUNTER_BUFFER, GL_ACTIVE_RESOURCES, &numActiveResources); 768 GLU_EXPECT_NO_ERROR(gl.getError(), "getProgramInterfaceiv(..., GL_ATOMIC_COUNTER_BUFFER, GL_ACTIVE_RESOURCES, ...)"); 769 770 if (propValue >= numActiveResources) 771 { 772 m_testCtx.getLog() << tcu::TestLog::Message << "\tError, got " << propValue << ", GL_ACTIVE_RESOURCES = " << numActiveResources << tcu::TestLog::EndMessage; 773 setError("resource atomic counter buffer index invalid"); 774 } 775 } 776 } 777} 778 779class LocationValidator : public SingleVariableValidator 780{ 781public: 782 LocationValidator (Context& context, glw::GLuint programID, const VariableSearchFilter& filter); 783 784 void validateSingleVariable (const std::vector<VariablePathComponent>& path, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const; 785 void validateBuiltinVariable (const std::string& resource, glw::GLint propValue, const std::string& implementationName) const; 786}; 787 788LocationValidator::LocationValidator (Context& context, glw::GLuint programID, const VariableSearchFilter& filter) 789 : SingleVariableValidator(context, PROGRAMRESOURCEPROP_LOCATION, programID, filter, DE_NULL) 790{ 791} 792 793static int getVariableLocationLength (const glu::VarType& type) 794{ 795 if (type.isBasicType()) 796 { 797 if (glu::isDataTypeMatrix(type.getBasicType())) 798 return glu::getDataTypeMatrixNumColumns(type.getBasicType()); 799 else 800 return 1; 801 } 802 else if (type.isStructType()) 803 { 804 int size = 0; 805 for (int ndx = 0; ndx < type.getStructPtr()->getNumMembers(); ++ndx) 806 size += getVariableLocationLength(type.getStructPtr()->getMember(ndx).getType()); 807 return size; 808 } 809 else if (type.isArrayType()) 810 return type.getArraySize() * getVariableLocationLength(type.getElementType()); 811 else 812 { 813 DE_ASSERT(false); 814 return 0; 815 } 816} 817 818static int getIOSubVariableLocation (const std::vector<VariablePathComponent>& path, int startNdx, int currentLocation) 819{ 820 if (currentLocation == -1) 821 return -1; 822 823 if (path[startNdx].getVariableType()->isBasicType()) 824 return currentLocation; 825 else if (path[startNdx].getVariableType()->isArrayType()) 826 return getIOSubVariableLocation(path, startNdx+1, currentLocation); 827 else if (path[startNdx].getVariableType()->isStructType()) 828 { 829 for (int ndx = 0; ndx < path[startNdx].getVariableType()->getStructPtr()->getNumMembers(); ++ndx) 830 { 831 if (&path[startNdx].getVariableType()->getStructPtr()->getMember(ndx).getType() == path[startNdx + 1].getVariableType()) 832 return getIOSubVariableLocation(path, startNdx + 1, currentLocation); 833 834 if (currentLocation != -1) 835 currentLocation += getVariableLocationLength(path[startNdx].getVariableType()->getStructPtr()->getMember(ndx).getType()); 836 } 837 838 // could not find member, never happens 839 DE_ASSERT(false); 840 return -1; 841 } 842 else 843 { 844 DE_ASSERT(false); 845 return -1; 846 } 847} 848 849static int getIOBlockVariableLocation (const std::vector<VariablePathComponent>& path) 850{ 851 const glu::InterfaceBlock* block = path.front().getInterfaceBlock(); 852 int currentLocation = block->layout.location; 853 854 // Find the block member 855 for (int memberNdx = 0; memberNdx < (int)block->variables.size(); ++memberNdx) 856 { 857 if (block->variables[memberNdx].layout.location != -1) 858 currentLocation = block->variables[memberNdx].layout.location; 859 860 if (&block->variables[memberNdx] == path[1].getDeclaration()) 861 break; 862 863 // unspecified + unspecified = unspecified 864 if (currentLocation != -1) 865 currentLocation += getVariableLocationLength(block->variables[memberNdx].varType); 866 } 867 868 // Find subtype location in the complex type 869 return getIOSubVariableLocation(path, 2, currentLocation); 870} 871 872static int getExplicitLocationFromPath (const std::vector<VariablePathComponent>& path) 873{ 874 const glu::VariableDeclaration* varDecl = (path[0].isInterfaceBlock()) ? (path[1].getDeclaration()) : (path[0].getDeclaration()); 875 876 if (path.front().isInterfaceBlock() && path.front().getInterfaceBlock()->storage == glu::STORAGE_UNIFORM) 877 { 878 // inside uniform block 879 return -1; 880 } 881 else if (path.front().isInterfaceBlock() && (path.front().getInterfaceBlock()->storage == glu::STORAGE_IN || 882 path.front().getInterfaceBlock()->storage == glu::STORAGE_OUT || 883 path.front().getInterfaceBlock()->storage == glu::STORAGE_PATCH_IN || 884 path.front().getInterfaceBlock()->storage == glu::STORAGE_PATCH_OUT)) 885 { 886 // inside ioblock 887 return getIOBlockVariableLocation(path); 888 } 889 else if (varDecl->storage == glu::STORAGE_UNIFORM) 890 { 891 // default block uniform 892 return varDecl->layout.location; 893 } 894 else if (varDecl->storage == glu::STORAGE_IN || 895 varDecl->storage == glu::STORAGE_OUT || 896 varDecl->storage == glu::STORAGE_PATCH_IN || 897 varDecl->storage == glu::STORAGE_PATCH_OUT) 898 { 899 // default block input/output 900 return getIOSubVariableLocation(path, 1, varDecl->layout.location); 901 } 902 else 903 { 904 DE_ASSERT(false); 905 return -1; 906 } 907} 908 909void LocationValidator::validateSingleVariable (const std::vector<VariablePathComponent>& path, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const 910{ 911 const bool isAtomicCounterUniform = glu::isDataTypeAtomicCounter(path.back().getVariableType()->getBasicType()); 912 const bool isUniformBlockVariable = path.front().isInterfaceBlock() && path.front().getInterfaceBlock()->storage == glu::STORAGE_UNIFORM; 913 const bool isVertexShader = m_filter.getShaderTypeBits() == (1u << glu::SHADERTYPE_VERTEX); 914 const bool isFragmentShader = m_filter.getShaderTypeBits() == (1u << glu::SHADERTYPE_FRAGMENT); 915 const glu::Storage storage = (path.front().isInterfaceBlock()) ? (path.front().getInterfaceBlock()->storage) : (path.front().getDeclaration()->storage); 916 const bool isInputVariable = (storage == glu::STORAGE_IN || storage == glu::STORAGE_PATCH_IN); 917 const bool isOutputVariable = (storage == glu::STORAGE_OUT || storage == glu::STORAGE_PATCH_OUT); 918 const int explicitLayoutLocation = getExplicitLocationFromPath(path); 919 920 bool expectLocation; 921 std::string reasonStr; 922 923 DE_UNREF(resource); 924 925 if (isAtomicCounterUniform) 926 { 927 expectLocation = false; 928 reasonStr = "Atomic counter uniforms have effective location of -1"; 929 } 930 else if (isUniformBlockVariable) 931 { 932 expectLocation = false; 933 reasonStr = "Uniform block variables have effective location of -1"; 934 } 935 else if (isInputVariable && !isVertexShader && explicitLayoutLocation == -1) 936 { 937 expectLocation = false; 938 reasonStr = "Inputs (except for vertex shader inputs) not declared with a location layout qualifier have effective location of -1"; 939 } 940 else if (isOutputVariable && !isFragmentShader && explicitLayoutLocation == -1) 941 { 942 expectLocation = false; 943 reasonStr = "Outputs (except for fragment shader outputs) not declared with a location layout qualifier have effective location of -1"; 944 } 945 else 946 { 947 expectLocation = true; 948 } 949 950 if (!expectLocation) 951 { 952 m_testCtx.getLog() << tcu::TestLog::Message << "Verifying uniform location, expecting -1. (" << reasonStr << ")" << tcu::TestLog::EndMessage; 953 954 if (propValue != -1) 955 { 956 m_testCtx.getLog() << tcu::TestLog::Message << "\tError, got " << propValue << tcu::TestLog::EndMessage; 957 setError("resource location invalid"); 958 } 959 } 960 else 961 { 962 bool locationOk; 963 964 if (explicitLayoutLocation == -1) 965 { 966 m_testCtx.getLog() << tcu::TestLog::Message << "Verifying location, expecting a valid location" << tcu::TestLog::EndMessage; 967 locationOk = (propValue != -1); 968 } 969 else 970 { 971 m_testCtx.getLog() << tcu::TestLog::Message << "Verifying location, expecting " << explicitLayoutLocation << tcu::TestLog::EndMessage; 972 locationOk = (propValue == explicitLayoutLocation); 973 } 974 975 if (!locationOk) 976 { 977 m_testCtx.getLog() << tcu::TestLog::Message << "\tError, got " << propValue << tcu::TestLog::EndMessage; 978 setError("resource location invalid"); 979 } 980 else 981 { 982 const VariablePathComponent nullComponent; 983 const VariablePathComponent& enclosingcomponent = (path.size() > 1) ? (path[path.size()-2]) : (nullComponent); 984 const bool isArray = enclosingcomponent.isVariableType() && enclosingcomponent.getVariableType()->isArrayType(); 985 986 const glw::Functions& gl = m_renderContext.getFunctions(); 987 const glw::GLenum interface = getProgramDefaultBlockInterfaceFromStorage(storage); 988 989 m_testCtx.getLog() << tcu::TestLog::Message << "Comparing location to the values returned by GetProgramResourceLocation" << tcu::TestLog::EndMessage; 990 991 // Test all bottom-level array elements 992 if (isArray) 993 { 994 const std::string arrayResourceName = (implementationName.size() > 3) ? (implementationName.substr(0, implementationName.size() - 3)) : (""); // chop "[0]" 995 996 for (int arrayElementNdx = 0; arrayElementNdx < enclosingcomponent.getVariableType()->getArraySize(); ++arrayElementNdx) 997 { 998 const std::string elementResourceName = arrayResourceName + "[" + de::toString(arrayElementNdx) + "]"; 999 const glw::GLint location = gl.getProgramResourceLocation(m_programID, interface, elementResourceName.c_str()); 1000 1001 if (location != propValue+arrayElementNdx) 1002 { 1003 m_testCtx.getLog() 1004 << tcu::TestLog::Message 1005 << "\tError, getProgramResourceLocation (resource=\"" << elementResourceName << "\") returned location " << location 1006 << ", expected " << (propValue+arrayElementNdx) 1007 << tcu::TestLog::EndMessage; 1008 setError("resource location invalid"); 1009 } 1010 else 1011 m_testCtx.getLog() << tcu::TestLog::Message << "\tLocation of \"" << elementResourceName << "\":\t" << location << tcu::TestLog::EndMessage; 1012 } 1013 } 1014 else 1015 { 1016 const glw::GLint location = gl.getProgramResourceLocation(m_programID, interface, implementationName.c_str()); 1017 1018 if (location != propValue) 1019 { 1020 m_testCtx.getLog() << tcu::TestLog::Message << "\tError, getProgramResourceLocation returned location " << location << ", expected " << propValue << tcu::TestLog::EndMessage; 1021 setError("resource location invalid"); 1022 } 1023 } 1024 1025 } 1026 } 1027} 1028 1029void LocationValidator::validateBuiltinVariable (const std::string& resource, glw::GLint propValue, const std::string& implementationName) const 1030{ 1031 DE_UNREF(resource); 1032 DE_UNREF(implementationName); 1033 1034 // built-ins have no location 1035 1036 m_testCtx.getLog() << tcu::TestLog::Message << "Verifying location, expecting -1" << tcu::TestLog::EndMessage; 1037 1038 if (propValue != -1) 1039 { 1040 m_testCtx.getLog() << tcu::TestLog::Message << "\tError, got " << propValue << tcu::TestLog::EndMessage; 1041 setError("resource location invalid"); 1042 } 1043} 1044 1045class VariableNameLengthValidator : public SingleVariableValidator 1046{ 1047public: 1048 VariableNameLengthValidator (Context& context, glw::GLuint programID, const VariableSearchFilter& filter); 1049 1050 void validateSingleVariable (const std::vector<VariablePathComponent>& path, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const; 1051 void validateBuiltinVariable (const std::string& resource, glw::GLint propValue, const std::string& implementationName) const; 1052 void validateNameLength (const std::string& implementationName, glw::GLint propValue) const; 1053}; 1054 1055VariableNameLengthValidator::VariableNameLengthValidator (Context& context, glw::GLuint programID, const VariableSearchFilter& filter) 1056 : SingleVariableValidator(context, PROGRAMRESOURCEPROP_NAME_LENGTH, programID, filter, DE_NULL) 1057{ 1058} 1059 1060void VariableNameLengthValidator::validateSingleVariable (const std::vector<VariablePathComponent>& path, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const 1061{ 1062 DE_UNREF(path); 1063 DE_UNREF(resource); 1064 validateNameLength(implementationName, propValue); 1065} 1066 1067void VariableNameLengthValidator::validateBuiltinVariable (const std::string& resource, glw::GLint propValue, const std::string& implementationName) const 1068{ 1069 DE_UNREF(resource); 1070 validateNameLength(implementationName, propValue); 1071} 1072 1073void VariableNameLengthValidator::validateNameLength (const std::string& implementationName, glw::GLint propValue) const 1074{ 1075 const int expected = (int)implementationName.length() + 1; // includes null byte 1076 m_testCtx.getLog() << tcu::TestLog::Message << "Verifying name length, expecting " << expected << " (" << (int)implementationName.length() << " for \"" << implementationName << "\" + 1 byte for terminating null character)" << tcu::TestLog::EndMessage; 1077 1078 if (propValue != expected) 1079 { 1080 m_testCtx.getLog() << tcu::TestLog::Message << "\tError, invalid name length, got " << propValue << tcu::TestLog::EndMessage; 1081 setError("name length invalid"); 1082 } 1083} 1084 1085class OffsetValidator : public SingleVariableValidator 1086{ 1087public: 1088 OffsetValidator (Context& context, glw::GLuint programID, const VariableSearchFilter& filter); 1089 1090 void validateSingleVariable (const std::vector<VariablePathComponent>& path, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const; 1091}; 1092 1093OffsetValidator::OffsetValidator (Context& context, glw::GLuint programID, const VariableSearchFilter& filter) 1094 : SingleVariableValidator(context, PROGRAMRESOURCEPROP_OFFSET, programID, filter, DE_NULL) 1095{ 1096} 1097 1098void OffsetValidator::validateSingleVariable (const std::vector<VariablePathComponent>& path, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const 1099{ 1100 const bool isAtomicCounterUniform = glu::isDataTypeAtomicCounter(path.back().getVariableType()->getBasicType()); 1101 const bool isBufferBackedBlockStorage = path.front().isInterfaceBlock() && isBufferBackedInterfaceBlockStorage(path.front().getInterfaceBlock()->storage); 1102 1103 DE_UNREF(resource); 1104 DE_UNREF(implementationName); 1105 1106 if (!isAtomicCounterUniform && !isBufferBackedBlockStorage) 1107 { 1108 // Not buffer backed 1109 m_testCtx.getLog() << tcu::TestLog::Message << "Verifying offset, expecting -1" << tcu::TestLog::EndMessage; 1110 1111 if (propValue != -1) 1112 { 1113 m_testCtx.getLog() << tcu::TestLog::Message << "\tError, invalid offset, got " << propValue << tcu::TestLog::EndMessage; 1114 setError("offset invalid"); 1115 } 1116 } 1117 else 1118 { 1119 // Expect a valid offset 1120 m_testCtx.getLog() << tcu::TestLog::Message << "Verifying offset, expecting a valid offset" << tcu::TestLog::EndMessage; 1121 1122 if (propValue < 0) 1123 { 1124 m_testCtx.getLog() << tcu::TestLog::Message << "\tError, invalid offset, got " << propValue << tcu::TestLog::EndMessage; 1125 setError("offset invalid"); 1126 } 1127 } 1128} 1129 1130class VariableReferencedByShaderValidator : public PropValidator 1131{ 1132public: 1133 VariableReferencedByShaderValidator (Context& context, glu::ShaderType shaderType, const VariableSearchFilter& searchFilter); 1134 1135 std::string getHumanReadablePropertyString (glw::GLint propVal) const; 1136 void validate (const ProgramInterfaceDefinition::Program* program, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const; 1137 1138private: 1139 const VariableSearchFilter m_filter; 1140 const glu::ShaderType m_shaderType; 1141}; 1142 1143VariableReferencedByShaderValidator::VariableReferencedByShaderValidator (Context& context, glu::ShaderType shaderType, const VariableSearchFilter& searchFilter) 1144 : PropValidator (context, PROGRAMRESOURCEPROP_REFERENCED_BY_SHADER, getRequiredExtensionForStage(shaderType)) 1145 , m_filter (VariableSearchFilter::logicalAnd(VariableSearchFilter::createShaderTypeFilter(shaderType), searchFilter)) 1146 , m_shaderType (shaderType) 1147{ 1148 DE_ASSERT(m_shaderType < glu::SHADERTYPE_LAST); 1149} 1150 1151std::string VariableReferencedByShaderValidator::getHumanReadablePropertyString (glw::GLint propVal) const 1152{ 1153 return de::toString(glu::getBooleanStr(propVal)); 1154} 1155 1156void VariableReferencedByShaderValidator::validate (const ProgramInterfaceDefinition::Program* program, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const 1157{ 1158 DE_UNREF(implementationName); 1159 1160 std::vector<VariablePathComponent> dummyPath; 1161 const bool referencedByShader = findProgramVariablePathByPathName(dummyPath, program, resource, m_filter); 1162 1163 m_testCtx.getLog() 1164 << tcu::TestLog::Message 1165 << "Verifying referenced by " << glu::getShaderTypeName(m_shaderType) << " shader, expecting " 1166 << ((referencedByShader) ? ("GL_TRUE") : ("GL_FALSE")) 1167 << tcu::TestLog::EndMessage; 1168 1169 if (propValue != ((referencedByShader) ? (1) : (0))) 1170 { 1171 m_testCtx.getLog() << tcu::TestLog::Message << "\tError, invalid referenced_by_" << glu::getShaderTypeName(m_shaderType) << ", got " << propValue << tcu::TestLog::EndMessage; 1172 setError("referenced_by_" + std::string(glu::getShaderTypeName(m_shaderType)) + " invalid"); 1173 } 1174} 1175 1176class BlockNameLengthValidator : public SingleBlockValidator 1177{ 1178public: 1179 BlockNameLengthValidator (Context& context, const glw::GLuint programID, const VariableSearchFilter& filter); 1180 1181 void validateSingleBlock (const glu::InterfaceBlock& block, const std::vector<int>& instanceIndex, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const; 1182}; 1183 1184BlockNameLengthValidator::BlockNameLengthValidator (Context& context, const glw::GLuint programID, const VariableSearchFilter& filter) 1185 : SingleBlockValidator(context, PROGRAMRESOURCEPROP_NAME_LENGTH, programID, filter, DE_NULL) 1186{ 1187} 1188 1189void BlockNameLengthValidator::validateSingleBlock (const glu::InterfaceBlock& block, const std::vector<int>& instanceIndex, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const 1190{ 1191 DE_UNREF(instanceIndex); 1192 DE_UNREF(block); 1193 DE_UNREF(resource); 1194 1195 const int expected = (int)implementationName.length() + 1; // includes null byte 1196 m_testCtx.getLog() << tcu::TestLog::Message << "Verifying name length, expecting " << expected << " (" << (int)implementationName.length() << " for \"" << implementationName << "\" + 1 byte for terminating null character)" << tcu::TestLog::EndMessage; 1197 1198 if (propValue != expected) 1199 { 1200 m_testCtx.getLog() << tcu::TestLog::Message << "\tError, invalid name length, got " << propValue << tcu::TestLog::EndMessage; 1201 setError("name length invalid"); 1202 } 1203} 1204 1205class BufferBindingValidator : public SingleBlockValidator 1206{ 1207public: 1208 BufferBindingValidator (Context& context, const glw::GLuint programID, const VariableSearchFilter& filter); 1209 1210 void validateSingleBlock (const glu::InterfaceBlock& block, const std::vector<int>& instanceIndex, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const; 1211}; 1212 1213BufferBindingValidator::BufferBindingValidator (Context& context, const glw::GLuint programID, const VariableSearchFilter& filter) 1214 : SingleBlockValidator(context, PROGRAMRESOURCEPROP_BUFFER_BINDING, programID, filter, DE_NULL) 1215{ 1216} 1217 1218void BufferBindingValidator::validateSingleBlock (const glu::InterfaceBlock& block, const std::vector<int>& instanceIndex, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const 1219{ 1220 DE_UNREF(resource); 1221 DE_UNREF(implementationName); 1222 1223 if (block.layout.binding != -1) 1224 { 1225 int flatIndex = 0; 1226 int dimensionSize = 1; 1227 1228 for (int dimensionNdx = (int)(block.dimensions.size()) - 1; dimensionNdx >= 0; --dimensionNdx) 1229 { 1230 flatIndex += dimensionSize * instanceIndex[dimensionNdx]; 1231 dimensionSize *= block.dimensions[dimensionNdx]; 1232 } 1233 1234 const int expected = (block.dimensions.empty()) ? (block.layout.binding) : (block.layout.binding + flatIndex); 1235 m_testCtx.getLog() << tcu::TestLog::Message << "Verifying block binding, expecting " << expected << tcu::TestLog::EndMessage; 1236 1237 if (propValue != expected) 1238 { 1239 m_testCtx.getLog() << tcu::TestLog::Message << "\tError, invalid buffer binding, got " << propValue << tcu::TestLog::EndMessage; 1240 setError("buffer binding invalid"); 1241 } 1242 } 1243 else 1244 { 1245 m_testCtx.getLog() << tcu::TestLog::Message << "Verifying buffer binding, expecting a valid binding" << tcu::TestLog::EndMessage; 1246 1247 if (propValue < 0) 1248 { 1249 m_testCtx.getLog() << tcu::TestLog::Message << "\tError, invalid buffer binding, got " << propValue << tcu::TestLog::EndMessage; 1250 setError("buffer binding invalid"); 1251 } 1252 } 1253} 1254 1255class BlockReferencedByShaderValidator : public PropValidator 1256{ 1257public: 1258 BlockReferencedByShaderValidator (Context& context, glu::ShaderType shaderType, const VariableSearchFilter& searchFilter); 1259 1260 std::string getHumanReadablePropertyString (glw::GLint propVal) const; 1261 void validate (const ProgramInterfaceDefinition::Program* program, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const; 1262 1263private: 1264 const VariableSearchFilter m_filter; 1265 const glu::ShaderType m_shaderType; 1266}; 1267 1268BlockReferencedByShaderValidator::BlockReferencedByShaderValidator (Context& context, glu::ShaderType shaderType, const VariableSearchFilter& searchFilter) 1269 : PropValidator (context, PROGRAMRESOURCEPROP_REFERENCED_BY_SHADER, getRequiredExtensionForStage(shaderType)) 1270 , m_filter (VariableSearchFilter::logicalAnd(VariableSearchFilter::createShaderTypeFilter(shaderType), searchFilter)) 1271 , m_shaderType (shaderType) 1272{ 1273 DE_ASSERT(m_shaderType < glu::SHADERTYPE_LAST); 1274} 1275 1276std::string BlockReferencedByShaderValidator::getHumanReadablePropertyString (glw::GLint propVal) const 1277{ 1278 return de::toString(glu::getBooleanStr(propVal)); 1279} 1280 1281void BlockReferencedByShaderValidator::validate (const ProgramInterfaceDefinition::Program* program, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const 1282{ 1283 const std::string blockName = glu::parseVariableName(resource.c_str()); 1284 bool referencedByShader = false; 1285 1286 DE_UNREF(implementationName); 1287 1288 for (int shaderNdx = 0; shaderNdx < (int)program->getShaders().size(); ++shaderNdx) 1289 { 1290 const ProgramInterfaceDefinition::Shader* const shader = program->getShaders()[shaderNdx]; 1291 if (!m_filter.matchesFilter(shader)) 1292 continue; 1293 1294 for (int blockNdx = 0; blockNdx < (int)shader->getDefaultBlock().interfaceBlocks.size(); ++blockNdx) 1295 { 1296 const glu::InterfaceBlock& block = shader->getDefaultBlock().interfaceBlocks[blockNdx]; 1297 1298 if (m_filter.matchesFilter(block) && block.interfaceName == blockName) 1299 referencedByShader = true; 1300 } 1301 } 1302 1303 m_testCtx.getLog() 1304 << tcu::TestLog::Message 1305 << "Verifying referenced by " << glu::getShaderTypeName(m_shaderType) << " shader, expecting " 1306 << ((referencedByShader) ? ("GL_TRUE") : ("GL_FALSE")) 1307 << tcu::TestLog::EndMessage; 1308 1309 if (propValue != ((referencedByShader) ? (1) : (0))) 1310 { 1311 m_testCtx.getLog() << tcu::TestLog::Message << "\tError, invalid referenced_by_" << glu::getShaderTypeName(m_shaderType) << ", got " << propValue << tcu::TestLog::EndMessage; 1312 setError("referenced_by_" + std::string(glu::getShaderTypeName(m_shaderType)) + " invalid"); 1313 } 1314} 1315 1316class TopLevelArraySizeValidator : public SingleVariableValidator 1317{ 1318public: 1319 TopLevelArraySizeValidator (Context& context, glw::GLuint programID, const VariableSearchFilter& filter); 1320 1321 void validateSingleVariable (const std::vector<VariablePathComponent>& path, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const; 1322}; 1323 1324TopLevelArraySizeValidator::TopLevelArraySizeValidator (Context& context, glw::GLuint programID, const VariableSearchFilter& filter) 1325 : SingleVariableValidator(context, PROGRAMRESOURCEPROP_TOP_LEVEL_ARRAY_SIZE, programID, filter, DE_NULL) 1326{ 1327} 1328 1329void TopLevelArraySizeValidator::validateSingleVariable (const std::vector<VariablePathComponent>& path, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const 1330{ 1331 int expected; 1332 std::string reason; 1333 1334 DE_ASSERT(path.front().isInterfaceBlock() && path.front().getInterfaceBlock()->storage == glu::STORAGE_BUFFER); 1335 DE_UNREF(resource); 1336 DE_UNREF(implementationName); 1337 1338 if (!path[1].getDeclaration()->varType.isArrayType()) 1339 { 1340 expected = 1; 1341 reason = "Top-level block member is not an array"; 1342 } 1343 else if (path[1].getDeclaration()->varType.getElementType().isBasicType()) 1344 { 1345 expected = 1; 1346 reason = "Top-level block member is not an array of an aggregate type"; 1347 } 1348 else if (path[1].getDeclaration()->varType.getArraySize() == glu::VarType::UNSIZED_ARRAY) 1349 { 1350 expected = 0; 1351 reason = "Top-level block member is an unsized top-level array"; 1352 } 1353 else 1354 { 1355 expected = path[1].getDeclaration()->varType.getArraySize(); 1356 reason = "Top-level block member is a sized top-level array"; 1357 } 1358 1359 m_testCtx.getLog() << tcu::TestLog::Message << "Verifying top level array size, expecting " << expected << ". (" << reason << ")." << tcu::TestLog::EndMessage; 1360 1361 if (propValue != expected) 1362 { 1363 m_testCtx.getLog() << tcu::TestLog::Message << "\tError, invalid top level array size, got " << propValue << tcu::TestLog::EndMessage; 1364 setError("top level array size invalid"); 1365 } 1366} 1367 1368class TopLevelArrayStrideValidator : public SingleVariableValidator 1369{ 1370public: 1371 TopLevelArrayStrideValidator (Context& context, glw::GLuint programID, const VariableSearchFilter& filter); 1372 1373 void validateSingleVariable (const std::vector<VariablePathComponent>& path, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const; 1374}; 1375 1376TopLevelArrayStrideValidator::TopLevelArrayStrideValidator (Context& context, glw::GLuint programID, const VariableSearchFilter& filter) 1377 : SingleVariableValidator(context, PROGRAMRESOURCEPROP_TOP_LEVEL_ARRAY_STRIDE, programID, filter, DE_NULL) 1378{ 1379} 1380 1381void TopLevelArrayStrideValidator::validateSingleVariable (const std::vector<VariablePathComponent>& path, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const 1382{ 1383 DE_ASSERT(path.front().isInterfaceBlock() && path.front().getInterfaceBlock()->storage == glu::STORAGE_BUFFER); 1384 DE_UNREF(resource); 1385 DE_UNREF(implementationName); 1386 1387 if (!path[1].getDeclaration()->varType.isArrayType()) 1388 { 1389 m_testCtx.getLog() << tcu::TestLog::Message << "Verifying top level array stride, expecting 0. (Top-level block member is not an array)." << tcu::TestLog::EndMessage; 1390 1391 if (propValue != 0) 1392 { 1393 m_testCtx.getLog() << tcu::TestLog::Message << "\tError, top level array stride, got " << propValue << tcu::TestLog::EndMessage; 1394 setError("top level array stride invalid"); 1395 } 1396 } 1397 else if (path[1].getDeclaration()->varType.getElementType().isBasicType()) 1398 { 1399 m_testCtx.getLog() << tcu::TestLog::Message << "Verifying top level array stride, expecting 0. (Top-level block member is not an array of an aggregate type)." << tcu::TestLog::EndMessage; 1400 1401 if (propValue != 0) 1402 { 1403 m_testCtx.getLog() << tcu::TestLog::Message << "\tError, top level array stride, got " << propValue << tcu::TestLog::EndMessage; 1404 setError("top level array stride invalid"); 1405 } 1406 } 1407 else 1408 { 1409 const int minimumStride = getVarTypeSize(path[1].getDeclaration()->varType.getElementType()); 1410 1411 m_testCtx.getLog() << tcu::TestLog::Message << "Verifying top level array stride, expecting greater or equal to " << minimumStride << "." << tcu::TestLog::EndMessage; 1412 1413 if (propValue < minimumStride) 1414 { 1415 m_testCtx.getLog() << tcu::TestLog::Message << "\tError, invalid top level array stride, got " << propValue << tcu::TestLog::EndMessage; 1416 setError("top level array stride invalid"); 1417 } 1418 } 1419} 1420 1421class TransformFeedbackResourceValidator : public PropValidator 1422{ 1423public: 1424 TransformFeedbackResourceValidator (Context& context, ProgramResourcePropFlags validationProp); 1425 1426 void validate (const ProgramInterfaceDefinition::Program* program, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const; 1427 1428private: 1429 virtual void validateBuiltinVariable (const std::string& resource, glw::GLint propValue, const std::string& implementationName) const = 0; 1430 virtual void validateSingleVariable (const std::vector<VariablePathComponent>& path, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const = 0; 1431}; 1432 1433 1434TransformFeedbackResourceValidator::TransformFeedbackResourceValidator (Context& context, ProgramResourcePropFlags validationProp) 1435 : PropValidator(context, validationProp, DE_NULL) 1436{ 1437} 1438 1439void TransformFeedbackResourceValidator::validate (const ProgramInterfaceDefinition::Program* program, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const 1440{ 1441 if (deStringBeginsWith(resource.c_str(), "gl_")) 1442 { 1443 validateBuiltinVariable(resource, propValue, implementationName); 1444 } 1445 else 1446 { 1447 // Check resource name is a xfb output. (sanity check) 1448#if defined(DE_DEBUG) 1449 bool generatorFound = false; 1450 1451 // Check the resource name is a valid transform feedback resource and find the name generating resource 1452 for (int varyingNdx = 0; varyingNdx < (int)program->getTransformFeedbackVaryings().size(); ++varyingNdx) 1453 { 1454 const std::string varyingName = program->getTransformFeedbackVaryings()[varyingNdx]; 1455 std::vector<VariablePathComponent> path; 1456 std::vector<std::string> resources; 1457 1458 if (!findProgramVariablePathByPathName(path, program, varyingName, VariableSearchFilter::createShaderTypeStorageFilter(getProgramTransformFeedbackStage(program), glu::STORAGE_OUT))) 1459 { 1460 // program does not contain feedback varying, not valid program 1461 DE_ASSERT(false); 1462 return; 1463 } 1464 1465 generateVariableTypeResourceNames(resources, varyingName, *path.back().getVariableType(), RESOURCE_NAME_GENERATION_FLAG_TRANSFORM_FEEDBACK_VARIABLE); 1466 1467 if (de::contains(resources.begin(), resources.end(), resource)) 1468 { 1469 generatorFound = true; 1470 break; 1471 } 1472 } 1473 1474 // resource name was not found, should never happen 1475 DE_ASSERT(generatorFound); 1476 DE_UNREF(generatorFound); 1477#endif 1478 1479 // verify resource 1480 { 1481 std::vector<VariablePathComponent> path; 1482 1483 if (!findProgramVariablePathByPathName(path, program, resource, VariableSearchFilter::createShaderTypeStorageFilter(getProgramTransformFeedbackStage(program), glu::STORAGE_OUT))) 1484 DE_ASSERT(false); 1485 1486 validateSingleVariable(path, resource, propValue, implementationName); 1487 } 1488 } 1489} 1490 1491class TransformFeedbackArraySizeValidator : public TransformFeedbackResourceValidator 1492{ 1493public: 1494 TransformFeedbackArraySizeValidator (Context& context); 1495 1496 void validateBuiltinVariable (const std::string& resource, glw::GLint propValue, const std::string& implementationName) const; 1497 void validateSingleVariable (const std::vector<VariablePathComponent>& path, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const; 1498}; 1499 1500TransformFeedbackArraySizeValidator::TransformFeedbackArraySizeValidator (Context& context) 1501 : TransformFeedbackResourceValidator(context, PROGRAMRESOURCEPROP_ARRAY_SIZE) 1502{ 1503} 1504 1505void TransformFeedbackArraySizeValidator::validateBuiltinVariable (const std::string& resource, glw::GLint propValue, const std::string& implementationName) const 1506{ 1507 DE_UNREF(implementationName); 1508 1509 int arraySize = 0; 1510 1511 if (resource == "gl_Position") 1512 arraySize = 1; 1513 else 1514 DE_ASSERT(false); 1515 1516 m_testCtx.getLog() << tcu::TestLog::Message << "Verifying array size, expecting " << arraySize << tcu::TestLog::EndMessage; 1517 if (arraySize != propValue) 1518 { 1519 m_testCtx.getLog() << tcu::TestLog::Message << "\tError, got " << propValue << tcu::TestLog::EndMessage; 1520 setError("resource array size invalid"); 1521 } 1522} 1523 1524void TransformFeedbackArraySizeValidator::validateSingleVariable (const std::vector<VariablePathComponent>& path, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const 1525{ 1526 DE_UNREF(resource); 1527 DE_UNREF(implementationName); 1528 1529 const int arraySize = (path.back().getVariableType()->isArrayType()) ? (path.back().getVariableType()->getArraySize()) : (1); 1530 1531 m_testCtx.getLog() << tcu::TestLog::Message << "Verifying array size, expecting " << arraySize << tcu::TestLog::EndMessage; 1532 if (arraySize != propValue) 1533 { 1534 m_testCtx.getLog() << tcu::TestLog::Message << "\tError, got " << propValue << tcu::TestLog::EndMessage; 1535 setError("resource array size invalid"); 1536 } 1537} 1538 1539class TransformFeedbackNameLengthValidator : public TransformFeedbackResourceValidator 1540{ 1541public: 1542 TransformFeedbackNameLengthValidator (Context& context); 1543 1544private: 1545 void validateBuiltinVariable (const std::string& resource, glw::GLint propValue, const std::string& implementationName) const; 1546 void validateSingleVariable (const std::vector<VariablePathComponent>& path, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const; 1547 void validateVariable (const std::string& implementationName, glw::GLint propValue) const; 1548}; 1549 1550TransformFeedbackNameLengthValidator::TransformFeedbackNameLengthValidator (Context& context) 1551 : TransformFeedbackResourceValidator(context, PROGRAMRESOURCEPROP_NAME_LENGTH) 1552{ 1553} 1554 1555void TransformFeedbackNameLengthValidator::validateBuiltinVariable (const std::string& resource, glw::GLint propValue, const std::string& implementationName) const 1556{ 1557 DE_UNREF(resource); 1558 validateVariable(implementationName, propValue); 1559} 1560 1561void TransformFeedbackNameLengthValidator::validateSingleVariable (const std::vector<VariablePathComponent>& path, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const 1562{ 1563 DE_UNREF(path); 1564 DE_UNREF(resource); 1565 validateVariable(implementationName, propValue); 1566} 1567 1568void TransformFeedbackNameLengthValidator::validateVariable (const std::string& implementationName, glw::GLint propValue) const 1569{ 1570 const int expected = (int)implementationName.length() + 1; // includes null byte 1571 m_testCtx.getLog() << tcu::TestLog::Message << "Verifying name length, expecting " << expected << " (" << (int)implementationName.length() << " for \"" << implementationName << "\" + 1 byte for terminating null character)" << tcu::TestLog::EndMessage; 1572 1573 if (propValue != expected) 1574 { 1575 m_testCtx.getLog() << tcu::TestLog::Message << "\tError, invalid name length, got " << propValue << tcu::TestLog::EndMessage; 1576 setError("name length invalid"); 1577 } 1578} 1579 1580class TransformFeedbackTypeValidator : public TransformFeedbackResourceValidator 1581{ 1582public: 1583 TransformFeedbackTypeValidator (Context& context); 1584 1585 void validateBuiltinVariable (const std::string& resource, glw::GLint propValue, const std::string& implementationName) const; 1586 void validateSingleVariable (const std::vector<VariablePathComponent>& path, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const; 1587}; 1588 1589TransformFeedbackTypeValidator::TransformFeedbackTypeValidator (Context& context) 1590 : TransformFeedbackResourceValidator(context, PROGRAMRESOURCEPROP_TYPE) 1591{ 1592} 1593 1594void TransformFeedbackTypeValidator::validateBuiltinVariable (const std::string& resource, glw::GLint propValue, const std::string& implementationName) const 1595{ 1596 DE_UNREF(implementationName); 1597 1598 glu::DataType varType = glu::TYPE_INVALID; 1599 1600 if (resource == "gl_Position") 1601 varType = glu::TYPE_FLOAT_VEC4; 1602 else 1603 DE_ASSERT(false); 1604 1605 m_testCtx.getLog() << tcu::TestLog::Message << "Verifying type, expecting " << glu::getDataTypeName(varType) << tcu::TestLog::EndMessage; 1606 if (glu::getDataTypeFromGLType(propValue) != varType) 1607 { 1608 m_testCtx.getLog() << tcu::TestLog::Message << "\tError, got " << glu::getDataTypeName(glu::getDataTypeFromGLType(propValue)) << tcu::TestLog::EndMessage; 1609 setError("resource type invalid"); 1610 } 1611 return; 1612} 1613 1614void TransformFeedbackTypeValidator::validateSingleVariable (const std::vector<VariablePathComponent>& path, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const 1615{ 1616 DE_UNREF(resource); 1617 DE_UNREF(implementationName); 1618 1619 // Unlike other interfaces, xfb program interface uses just variable name to refer to arrays of basic types. (Others use "variable[0]") 1620 // Thus we might end up querying a type for an array. In this case, return the type of an array element. 1621 const glu::VarType& variable = *path.back().getVariableType(); 1622 const glu::VarType& elementType = (variable.isArrayType()) ? (variable.getElementType()) : (variable); 1623 1624 DE_ASSERT(elementType.isBasicType()); 1625 1626 m_testCtx.getLog() << tcu::TestLog::Message << "Verifying type, expecting " << glu::getDataTypeName(elementType.getBasicType()) << tcu::TestLog::EndMessage; 1627 if (elementType.getBasicType() != glu::getDataTypeFromGLType(propValue)) 1628 { 1629 m_testCtx.getLog() << tcu::TestLog::Message << "\tError, got " << glu::getDataTypeName(glu::getDataTypeFromGLType(propValue)) << tcu::TestLog::EndMessage; 1630 setError("resource type invalid"); 1631 } 1632} 1633 1634class PerPatchValidator : public SingleVariableValidator 1635{ 1636public: 1637 PerPatchValidator (Context& context, glw::GLuint programID, const VariableSearchFilter& filter); 1638 1639 std::string getHumanReadablePropertyString (glw::GLint propVal) const; 1640 void validateSingleVariable (const std::vector<VariablePathComponent>& path, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const; 1641 void validateBuiltinVariable (const std::string& resource, glw::GLint propValue, const std::string& implementationName) const; 1642}; 1643 1644PerPatchValidator::PerPatchValidator (Context& context, glw::GLuint programID, const VariableSearchFilter& filter) 1645 : SingleVariableValidator(context, PROGRAMRESOURCEPROP_IS_PER_PATCH, programID, filter, "GL_EXT_tessellation_shader") 1646{ 1647} 1648 1649std::string PerPatchValidator::getHumanReadablePropertyString (glw::GLint propVal) const 1650{ 1651 return de::toString(glu::getBooleanStr(propVal)); 1652} 1653 1654void PerPatchValidator::validateSingleVariable (const std::vector<VariablePathComponent>& path, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const 1655{ 1656 const glu::Storage storage = (path.front().isInterfaceBlock()) ? (path.front().getInterfaceBlock()->storage) : (path.front().getDeclaration()->storage); 1657 const int expected = (storage == glu::STORAGE_PATCH_IN || storage == glu::STORAGE_PATCH_OUT) ? (1) : (0); 1658 1659 DE_UNREF(resource); 1660 DE_UNREF(implementationName); 1661 1662 m_testCtx.getLog() << tcu::TestLog::Message << "Verifying if is per patch, expecting IS_PER_PATCH = " << expected << tcu::TestLog::EndMessage; 1663 1664 if (propValue != expected) 1665 { 1666 m_testCtx.getLog() << tcu::TestLog::Message << "\tError, got " << propValue << tcu::TestLog::EndMessage; 1667 setError("resource is per patch invalid"); 1668 } 1669} 1670 1671void PerPatchValidator::validateBuiltinVariable (const std::string& resource, glw::GLint propValue, const std::string& implementationName) const 1672{ 1673 DE_UNREF(implementationName); 1674 1675 static const struct 1676 { 1677 const char* name; 1678 int isPerPatch; 1679 } builtins[] = 1680 { 1681 { "gl_Position", 0 }, 1682 { "gl_PerVertex.gl_Position", 0 }, 1683 { "gl_InvocationID", 0 }, 1684 { "gl_TessLevelOuter[0]", 1 }, 1685 { "gl_TessLevelInner[0]", 1 }, 1686 }; 1687 1688 for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(builtins); ++ndx) 1689 { 1690 if (resource == builtins[ndx].name) 1691 { 1692 m_testCtx.getLog() << tcu::TestLog::Message << "Verifying if is per patch, expecting IS_PER_PATCH = " << builtins[ndx].isPerPatch << tcu::TestLog::EndMessage; 1693 1694 if (propValue != builtins[ndx].isPerPatch) 1695 { 1696 m_testCtx.getLog() << tcu::TestLog::Message << "\tError, got " << propValue << tcu::TestLog::EndMessage; 1697 setError("resource is per patch invalid"); 1698 } 1699 return; 1700 } 1701 } 1702 1703 DE_ASSERT(false); 1704} 1705 1706} // anonymous 1707 1708ProgramResourceQueryTestTarget::ProgramResourceQueryTestTarget (ProgramInterface interface_, deUint32 propFlags_) 1709 : interface(interface_) 1710 , propFlags(propFlags_) 1711{ 1712 switch (interface) 1713 { 1714 case PROGRAMINTERFACE_UNIFORM: DE_ASSERT((propFlags & PROGRAMRESOURCEPROP_UNIFORM_INTERFACE_MASK) == propFlags); break; 1715 case PROGRAMINTERFACE_UNIFORM_BLOCK: DE_ASSERT((propFlags & PROGRAMRESOURCEPROP_UNIFORM_BLOCK_INTERFACE_MASK) == propFlags); break; 1716 case PROGRAMINTERFACE_SHADER_STORAGE_BLOCK: DE_ASSERT((propFlags & PROGRAMRESOURCEPROP_SHADER_STORAGE_BLOCK_MASK) == propFlags); break; 1717 case PROGRAMINTERFACE_PROGRAM_INPUT: DE_ASSERT((propFlags & PROGRAMRESOURCEPROP_PROGRAM_INPUT_MASK) == propFlags); break; 1718 case PROGRAMINTERFACE_PROGRAM_OUTPUT: DE_ASSERT((propFlags & PROGRAMRESOURCEPROP_PROGRAM_OUTPUT_MASK) == propFlags); break; 1719 case PROGRAMINTERFACE_BUFFER_VARIABLE: DE_ASSERT((propFlags & PROGRAMRESOURCEPROP_BUFFER_VARIABLE_MASK) == propFlags); break; 1720 case PROGRAMINTERFACE_TRANSFORM_FEEDBACK_VARYING: DE_ASSERT((propFlags & PROGRAMRESOURCEPROP_TRANSFORM_FEEDBACK_VARYING_MASK) == propFlags); break; 1721 1722 default: 1723 DE_ASSERT(false); 1724 } 1725} 1726 1727ProgramInterfaceQueryTestCase::ProgramInterfaceQueryTestCase (Context& context, const char* name, const char* description, ProgramResourceQueryTestTarget queryTarget) 1728 : TestCase (context, name, description) 1729 , m_queryTarget (queryTarget) 1730{ 1731} 1732 1733ProgramInterfaceQueryTestCase::~ProgramInterfaceQueryTestCase (void) 1734{ 1735} 1736 1737ProgramInterface ProgramInterfaceQueryTestCase::getTargetInterface (void) const 1738{ 1739 return m_queryTarget.interface; 1740} 1741 1742static glw::GLenum getGLInterfaceEnumValue (ProgramInterface interface) 1743{ 1744 switch (interface) 1745 { 1746 case PROGRAMINTERFACE_UNIFORM: return GL_UNIFORM; 1747 case PROGRAMINTERFACE_UNIFORM_BLOCK: return GL_UNIFORM_BLOCK; 1748 case PROGRAMINTERFACE_ATOMIC_COUNTER_BUFFER: return GL_ATOMIC_COUNTER_BUFFER; 1749 case PROGRAMINTERFACE_PROGRAM_INPUT: return GL_PROGRAM_INPUT; 1750 case PROGRAMINTERFACE_PROGRAM_OUTPUT: return GL_PROGRAM_OUTPUT; 1751 case PROGRAMINTERFACE_TRANSFORM_FEEDBACK_VARYING: return GL_TRANSFORM_FEEDBACK_VARYING; 1752 case PROGRAMINTERFACE_BUFFER_VARIABLE: return GL_BUFFER_VARIABLE; 1753 case PROGRAMINTERFACE_SHADER_STORAGE_BLOCK: return GL_SHADER_STORAGE_BLOCK; 1754 default: 1755 DE_ASSERT(false); 1756 return 0; 1757 }; 1758} 1759 1760static bool isInterfaceBlockInterfaceName (const ProgramInterfaceDefinition::Program* program, ProgramInterface interface, const std::string& blockInterfaceName) 1761{ 1762 deUint32 validStorageBits; 1763 deUint32 searchStageBits; 1764 1765 DE_STATIC_ASSERT(glu::STORAGE_LAST < 32); 1766 DE_STATIC_ASSERT(glu::SHADERTYPE_LAST < 32); 1767 1768 switch (interface) 1769 { 1770 case PROGRAMINTERFACE_UNIFORM_BLOCK: 1771 case PROGRAMINTERFACE_SHADER_STORAGE_BLOCK: 1772 case PROGRAMINTERFACE_ATOMIC_COUNTER_BUFFER: 1773 return false; 1774 1775 case PROGRAMINTERFACE_PROGRAM_INPUT: 1776 validStorageBits = (1u << glu::STORAGE_IN) | (1u << glu::STORAGE_PATCH_IN); 1777 searchStageBits = (1u << program->getFirstStage()); 1778 break; 1779 1780 case PROGRAMINTERFACE_PROGRAM_OUTPUT: 1781 validStorageBits = (1u << glu::STORAGE_OUT) | (1u << glu::STORAGE_PATCH_OUT); 1782 searchStageBits = (1u << program->getLastStage()); 1783 break; 1784 1785 case PROGRAMINTERFACE_TRANSFORM_FEEDBACK_VARYING: 1786 validStorageBits = (1u << glu::STORAGE_OUT); 1787 searchStageBits = (1u << getProgramTransformFeedbackStage(program)); 1788 break; 1789 1790 case PROGRAMINTERFACE_UNIFORM: 1791 validStorageBits = (1u << glu::STORAGE_UNIFORM); 1792 searchStageBits = 0xFFFFFFFFu; 1793 break; 1794 1795 case PROGRAMINTERFACE_BUFFER_VARIABLE: 1796 validStorageBits = (1u << glu::STORAGE_BUFFER); 1797 searchStageBits = 0xFFFFFFFFu; 1798 break; 1799 1800 default: 1801 DE_ASSERT(false); 1802 return false; 1803 } 1804 1805 for (int shaderNdx = 0; shaderNdx < (int)program->getShaders().size(); ++shaderNdx) 1806 { 1807 const ProgramInterfaceDefinition::Shader* const shader = program->getShaders()[shaderNdx]; 1808 if (((1u << shader->getType()) & searchStageBits) == 0) 1809 continue; 1810 1811 for (int blockNdx = 0; blockNdx < (int)shader->getDefaultBlock().interfaceBlocks.size(); ++blockNdx) 1812 { 1813 const glu::InterfaceBlock& block = shader->getDefaultBlock().interfaceBlocks[blockNdx]; 1814 1815 if (((1u << block.storage) & validStorageBits) == 0) 1816 continue; 1817 1818 if (block.interfaceName == blockInterfaceName) 1819 return true; 1820 } 1821 } 1822 return false; 1823} 1824 1825static std::string getInterfaceBlockInteraceNameByMember (const ProgramInterfaceDefinition::Program* program, ProgramInterface interface, const std::string& memberName) 1826{ 1827 deUint32 validStorageBits; 1828 deUint32 searchStageBits; 1829 1830 DE_STATIC_ASSERT(glu::STORAGE_LAST < 32); 1831 DE_STATIC_ASSERT(glu::SHADERTYPE_LAST < 32); 1832 1833 switch (interface) 1834 { 1835 case PROGRAMINTERFACE_UNIFORM_BLOCK: 1836 case PROGRAMINTERFACE_SHADER_STORAGE_BLOCK: 1837 case PROGRAMINTERFACE_ATOMIC_COUNTER_BUFFER: 1838 return ""; 1839 1840 case PROGRAMINTERFACE_PROGRAM_INPUT: 1841 validStorageBits = (1u << glu::STORAGE_IN) | (1u << glu::STORAGE_PATCH_IN); 1842 searchStageBits = (1u << program->getFirstStage()); 1843 break; 1844 1845 case PROGRAMINTERFACE_PROGRAM_OUTPUT: 1846 validStorageBits = (1u << glu::STORAGE_OUT) | (1u << glu::STORAGE_PATCH_OUT); 1847 searchStageBits = (1u << program->getLastStage()); 1848 break; 1849 1850 case PROGRAMINTERFACE_TRANSFORM_FEEDBACK_VARYING: 1851 validStorageBits = (1u << glu::STORAGE_OUT); 1852 searchStageBits = (1u << getProgramTransformFeedbackStage(program)); 1853 break; 1854 1855 case PROGRAMINTERFACE_UNIFORM: 1856 validStorageBits = (1u << glu::STORAGE_UNIFORM); 1857 searchStageBits = 0xFFFFFFFFu; 1858 break; 1859 1860 case PROGRAMINTERFACE_BUFFER_VARIABLE: 1861 validStorageBits = (1u << glu::STORAGE_BUFFER); 1862 searchStageBits = 0xFFFFFFFFu; 1863 break; 1864 1865 default: 1866 DE_ASSERT(false); 1867 return ""; 1868 } 1869 1870 for (int shaderNdx = 0; shaderNdx < (int)program->getShaders().size(); ++shaderNdx) 1871 { 1872 const ProgramInterfaceDefinition::Shader* const shader = program->getShaders()[shaderNdx]; 1873 if (((1u << shader->getType()) & searchStageBits) == 0) 1874 continue; 1875 1876 for (int blockNdx = 0; blockNdx < (int)shader->getDefaultBlock().interfaceBlocks.size(); ++blockNdx) 1877 { 1878 const glu::InterfaceBlock& block = shader->getDefaultBlock().interfaceBlocks[blockNdx]; 1879 1880 if (((1u << block.storage) & validStorageBits) == 0) 1881 continue; 1882 1883 for (int varNdx = 0; varNdx < (int)block.variables.size(); ++varNdx) 1884 { 1885 if (block.variables[varNdx].name == memberName) 1886 return block.interfaceName; 1887 } 1888 } 1889 } 1890 return ""; 1891} 1892 1893static void queryAndValidateProps (tcu::TestContext& testCtx, 1894 const glw::Functions& gl, 1895 glw::GLuint programID, 1896 ProgramInterface interface, 1897 const char* targetResourceName, 1898 const ProgramInterfaceDefinition::Program* programDefinition, 1899 const std::vector<glw::GLenum>& props, 1900 const std::vector<const PropValidator*>& validators) 1901{ 1902 const glw::GLenum glInterface = getGLInterfaceEnumValue(interface); 1903 std::string implementationResourceName = targetResourceName; 1904 glw::GLuint resourceNdx; 1905 glw::GLint written = -1; 1906 1907 // prefill result buffer with an invalid value. -1 might be valid sometimes, avoid it. Make buffer one larger 1908 // to allow detection of too many return values 1909 std::vector<glw::GLint> propValues (props.size() + 1, -2); 1910 1911 DE_ASSERT(props.size() == validators.size()); 1912 1913 // query 1914 1915 resourceNdx = gl.getProgramResourceIndex(programID, glInterface, targetResourceName); 1916 GLU_EXPECT_NO_ERROR(gl.getError(), "get resource index"); 1917 1918 if (resourceNdx == GL_INVALID_INDEX) 1919 { 1920 static const struct 1921 { 1922 bool removeTrailingArray; // convert from "target[0]" -> "target" 1923 bool removeTrailingMember; // convert from "target.member" -> "target" 1924 bool removeIOBlock; // convert from "InterfaceName.target" -> "target" 1925 bool addIOBlock; // convert from "target" -> "InterfaceName.target" 1926 bool addIOBlockArray; // convert from "target" -> "InterfaceName[0].target" 1927 } recoveryStrategies[] = 1928 { 1929 // try one patch 1930 { true, false, false, false, false }, 1931 { false, true, false, false, false }, 1932 { false, false, true, false, false }, 1933 { false, false, false, true, false }, 1934 { false, false, false, false, true }, 1935 // patch both ends 1936 { true, false, true, false, false }, 1937 { true, false, false, true, false }, 1938 { true, false, false, false, true }, 1939 { false, true, true, false, false }, 1940 { false, true, false, true, false }, 1941 { false, true, false, false, true }, 1942 }; 1943 1944 // The resource name generation in the GL implementations is very commonly broken. Try to 1945 // keep the tests producing useful data even in these cases by attempting to recover from 1946 // common naming bugs. Set test result to failure even if recovery succeeded to signal 1947 // incorrect name generation. 1948 1949 testCtx.getLog() << tcu::TestLog::Message << "getProgramResourceIndex returned GL_INVALID_INDEX for \"" << targetResourceName << "\"" << tcu::TestLog::EndMessage; 1950 testCtx.setTestResult(QP_TEST_RESULT_FAIL, "could not find target resource"); 1951 1952 for (int strategyNdx = 0; strategyNdx < DE_LENGTH_OF_ARRAY(recoveryStrategies); ++strategyNdx) 1953 { 1954 const std::string resourceName = std::string(targetResourceName); 1955 const size_t rootNameEnd = resourceName.find_first_of(".["); 1956 const std::string rootName = resourceName.substr(0, rootNameEnd); 1957 std::string simplifiedResourceName; 1958 1959 if (recoveryStrategies[strategyNdx].removeTrailingArray) 1960 { 1961 if (de::endsWith(resourceName, "[0]")) 1962 simplifiedResourceName = resourceName.substr(0, resourceName.length() - 3); 1963 else 1964 continue; 1965 } 1966 1967 if (recoveryStrategies[strategyNdx].removeTrailingMember) 1968 { 1969 const size_t lastMember = resourceName.find_last_of('.'); 1970 if (lastMember != std::string::npos) 1971 simplifiedResourceName = resourceName.substr(0, lastMember); 1972 else 1973 continue; 1974 } 1975 1976 if (recoveryStrategies[strategyNdx].removeIOBlock) 1977 { 1978 if (deStringBeginsWith(resourceName.c_str(), "gl_PerVertex.")) 1979 { 1980 // builtin interface bock, remove block name 1981 simplifiedResourceName = resourceName.substr(13); 1982 } 1983 else if (isInterfaceBlockInterfaceName(programDefinition, interface, rootName)) 1984 { 1985 // user-defined inteface block, remove name 1986 const size_t accessorEnd = resourceName.find('.'); // includes potential array accessor 1987 1988 if (accessorEnd != std::string::npos) 1989 simplifiedResourceName = resourceName.substr(0, accessorEnd+1); 1990 else 1991 continue; 1992 } 1993 else 1994 { 1995 // recovery not applicable 1996 continue; 1997 } 1998 } 1999 2000 if (recoveryStrategies[strategyNdx].addIOBlock || recoveryStrategies[strategyNdx].addIOBlockArray) 2001 { 2002 const std::string arrayAccessor = (recoveryStrategies[strategyNdx].addIOBlockArray) ? ("[0]") : (""); 2003 2004 if (deStringBeginsWith(resourceName.c_str(), "gl_") && resourceName.find('.') == std::string::npos) 2005 { 2006 // free builtin variable, add block name 2007 simplifiedResourceName = "gl_PerVertex" + arrayAccessor + "." + resourceName; 2008 } 2009 else 2010 { 2011 const std::string interafaceName = getInterfaceBlockInteraceNameByMember(programDefinition, interface, rootName); 2012 2013 if (!interafaceName.empty()) 2014 { 2015 // free user variable, add block name 2016 simplifiedResourceName = interafaceName + arrayAccessor + "." + resourceName; 2017 } 2018 else 2019 { 2020 // recovery not applicable 2021 continue; 2022 } 2023 } 2024 } 2025 2026 if (simplifiedResourceName.empty()) 2027 continue; 2028 2029 resourceNdx = gl.getProgramResourceIndex(programID, glInterface, simplifiedResourceName.c_str()); 2030 GLU_EXPECT_NO_ERROR(gl.getError(), "get resource index"); 2031 2032 // recovery succeeded 2033 if (resourceNdx != GL_INVALID_INDEX) 2034 { 2035 implementationResourceName = simplifiedResourceName; 2036 testCtx.getLog() << tcu::TestLog::Message << "\tResource not found, continuing anyway using index obtained for resource \"" << simplifiedResourceName << "\"" << tcu::TestLog::EndMessage; 2037 break; 2038 } 2039 } 2040 2041 if (resourceNdx == GL_INVALID_INDEX) 2042 return; 2043 } 2044 2045 gl.getProgramResourceiv(programID, glInterface, resourceNdx, (int)props.size(), &props[0], (int)propValues.size(), &written, &propValues[0]); 2046 GLU_EXPECT_NO_ERROR(gl.getError(), "get props"); 2047 2048 if (written != (int)props.size()) 2049 { 2050 testCtx.getLog() << tcu::TestLog::Message << "getProgramResourceiv returned unexpected number of values, expected " << (int)props.size() << ", got " << written << tcu::TestLog::EndMessage; 2051 testCtx.setTestResult(QP_TEST_RESULT_FAIL, "getProgramResourceiv returned unexpected number of values"); 2052 return; 2053 } 2054 2055 if (propValues.back() != -2) 2056 { 2057 testCtx.getLog() << tcu::TestLog::Message << "getProgramResourceiv post write buffer guard value was modified, too many return values" << tcu::TestLog::EndMessage; 2058 testCtx.setTestResult(QP_TEST_RESULT_FAIL, "getProgramResourceiv returned unexpected number of values"); 2059 return; 2060 } 2061 propValues.pop_back(); 2062 DE_ASSERT(validators.size() == propValues.size()); 2063 2064 // log 2065 2066 { 2067 tcu::MessageBuilder message(&testCtx.getLog()); 2068 message << "For resource index " << resourceNdx << " (\"" << targetResourceName << "\") got following properties:\n"; 2069 2070 for (int propNdx = 0; propNdx < (int)propValues.size(); ++propNdx) 2071 message << "\t" << glu::getProgramResourcePropertyName(props[propNdx]) << ":\t" << validators[propNdx]->getHumanReadablePropertyString(propValues[propNdx]) << "\n"; 2072 2073 message << tcu::TestLog::EndMessage; 2074 } 2075 2076 // validate 2077 2078 for (int propNdx = 0; propNdx < (int)propValues.size(); ++propNdx) 2079 validators[propNdx]->validate(programDefinition, targetResourceName, propValues[propNdx], implementationResourceName); 2080} 2081 2082const ProgramInterfaceDefinition::Program* ProgramInterfaceQueryTestCase::getAndCheckProgramDefinition (void) 2083{ 2084 const ProgramInterfaceDefinition::Program* programDefinition = getProgramDefinition(); 2085 DE_ASSERT(programDefinition->isValid()); 2086 2087 if (programDefinition->hasStage(glu::SHADERTYPE_TESSELLATION_CONTROL) || 2088 programDefinition->hasStage(glu::SHADERTYPE_TESSELLATION_EVALUATION)) 2089 { 2090 if (!m_context.getContextInfo().isExtensionSupported("GL_EXT_tessellation_shader")) 2091 throw tcu::NotSupportedError("Test requires GL_EXT_tessellation_shader extension"); 2092 } 2093 2094 // Testing IS_PER_PATCH as a part of a larger set is ok, since the extension is checked 2095 // before query. However, we don't want IS_PER_PATCH-specific tests to become noop and pass. 2096 if (m_queryTarget.propFlags == PROGRAMRESOURCEPROP_IS_PER_PATCH) 2097 { 2098 if (!m_context.getContextInfo().isExtensionSupported("GL_EXT_tessellation_shader")) 2099 throw tcu::NotSupportedError("Test requires GL_EXT_tessellation_shader extension"); 2100 } 2101 2102 if (programDefinition->hasStage(glu::SHADERTYPE_GEOMETRY)) 2103 { 2104 if (!m_context.getContextInfo().isExtensionSupported("GL_EXT_geometry_shader")) 2105 throw tcu::NotSupportedError("Test requires GL_EXT_geometry_shader extension"); 2106 } 2107 2108 if (programContainsIOBlocks(programDefinition)) 2109 { 2110 if (!m_context.getContextInfo().isExtensionSupported("GL_EXT_shader_io_blocks")) 2111 throw tcu::NotSupportedError("Test requires GL_EXT_shader_io_blocks extension"); 2112 } 2113 2114 return programDefinition; 2115} 2116 2117int ProgramInterfaceQueryTestCase::getMaxPatchVertices (void) 2118{ 2119 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 2120 glw::GLint maxPatchVertices = 0; 2121 2122 gl.getIntegerv(GL_MAX_PATCH_VERTICES, &maxPatchVertices); 2123 GLU_EXPECT_NO_ERROR(gl.getError(), "getIntegerv(GL_MAX_PATCH_VERTICES)"); 2124 return maxPatchVertices; 2125} 2126 2127ProgramInterfaceQueryTestCase::IterateResult ProgramInterfaceQueryTestCase::iterate (void) 2128{ 2129 struct TestProperty 2130 { 2131 glw::GLenum prop; 2132 const PropValidator* validator; 2133 }; 2134 2135 const ProgramInterfaceDefinition::Program* programDefinition = getAndCheckProgramDefinition(); 2136 const std::vector<std::string> targetResources = getQueryTargetResources(); 2137 glu::ShaderProgram program (m_context.getRenderContext(), generateProgramInterfaceProgramSources(programDefinition)); 2138 2139 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); 2140 2141 // Log program 2142 { 2143 const tcu::ScopedLogSection section(m_testCtx.getLog(), "Program", "Program"); 2144 2145 // Feedback varyings 2146 if (!programDefinition->getTransformFeedbackVaryings().empty()) 2147 { 2148 tcu::MessageBuilder builder(&m_testCtx.getLog()); 2149 builder << "Transform feedback varyings: {"; 2150 for (int ndx = 0; ndx < (int)programDefinition->getTransformFeedbackVaryings().size(); ++ndx) 2151 { 2152 if (ndx) 2153 builder << ", "; 2154 builder << "\"" << programDefinition->getTransformFeedbackVaryings()[ndx] << "\""; 2155 } 2156 builder << "}" << tcu::TestLog::EndMessage; 2157 } 2158 2159 m_testCtx.getLog() << program; 2160 if (!program.isOk()) 2161 { 2162 m_testCtx.getLog() << tcu::TestLog::Message << "Program build failed, checking if program exceeded implementation limits" << tcu::TestLog::EndMessage; 2163 checkProgramResourceUsage(programDefinition, m_context.getRenderContext().getFunctions(), m_testCtx.getLog()); 2164 2165 // within limits 2166 throw tcu::TestError("could not build program"); 2167 } 2168 } 2169 2170 // Check interface props 2171 2172 switch (m_queryTarget.interface) 2173 { 2174 case PROGRAMINTERFACE_UNIFORM: 2175 { 2176 const VariableSearchFilter uniformFilter = VariableSearchFilter::createStorageFilter(glu::STORAGE_UNIFORM); 2177 2178 const TypeValidator typeValidator (m_context, program.getProgram(), uniformFilter); 2179 const ArraySizeValidator arraySizeValidator (m_context, program.getProgram(), -1, uniformFilter); 2180 const ArrayStrideValidator arrayStrideValidator (m_context, program.getProgram(), uniformFilter); 2181 const BlockIndexValidator blockIndexValidator (m_context, program.getProgram(), uniformFilter); 2182 const IsRowMajorValidator isRowMajorValidator (m_context, program.getProgram(), uniformFilter); 2183 const MatrixStrideValidator matrixStrideValidator (m_context, program.getProgram(), uniformFilter); 2184 const AtomicCounterBufferIndexVerifier atomicCounterBufferIndexVerifier (m_context, program.getProgram(), uniformFilter); 2185 const LocationValidator locationValidator (m_context, program.getProgram(), uniformFilter); 2186 const VariableNameLengthValidator nameLengthValidator (m_context, program.getProgram(), uniformFilter); 2187 const OffsetValidator offsetVerifier (m_context, program.getProgram(), uniformFilter); 2188 const VariableReferencedByShaderValidator referencedByVertexVerifier (m_context, glu::SHADERTYPE_VERTEX, uniformFilter); 2189 const VariableReferencedByShaderValidator referencedByFragmentVerifier (m_context, glu::SHADERTYPE_FRAGMENT, uniformFilter); 2190 const VariableReferencedByShaderValidator referencedByComputeVerifier (m_context, glu::SHADERTYPE_COMPUTE, uniformFilter); 2191 const VariableReferencedByShaderValidator referencedByGeometryVerifier (m_context, glu::SHADERTYPE_GEOMETRY, uniformFilter); 2192 const VariableReferencedByShaderValidator referencedByTessControlVerifier (m_context, glu::SHADERTYPE_TESSELLATION_CONTROL, uniformFilter); 2193 const VariableReferencedByShaderValidator referencedByTessEvaluationVerifier (m_context, glu::SHADERTYPE_TESSELLATION_EVALUATION, uniformFilter); 2194 2195 const TestProperty allProperties[] = 2196 { 2197 { GL_ARRAY_SIZE, &arraySizeValidator }, 2198 { GL_ARRAY_STRIDE, &arrayStrideValidator }, 2199 { GL_ATOMIC_COUNTER_BUFFER_INDEX, &atomicCounterBufferIndexVerifier }, 2200 { GL_BLOCK_INDEX, &blockIndexValidator }, 2201 { GL_IS_ROW_MAJOR, &isRowMajorValidator }, 2202 { GL_LOCATION, &locationValidator }, 2203 { GL_MATRIX_STRIDE, &matrixStrideValidator }, 2204 { GL_NAME_LENGTH, &nameLengthValidator }, 2205 { GL_OFFSET, &offsetVerifier }, 2206 { GL_REFERENCED_BY_VERTEX_SHADER, &referencedByVertexVerifier }, 2207 { GL_REFERENCED_BY_FRAGMENT_SHADER, &referencedByFragmentVerifier }, 2208 { GL_REFERENCED_BY_COMPUTE_SHADER, &referencedByComputeVerifier }, 2209 { GL_REFERENCED_BY_GEOMETRY_SHADER, &referencedByGeometryVerifier }, 2210 { GL_REFERENCED_BY_TESS_CONTROL_SHADER, &referencedByTessControlVerifier }, 2211 { GL_REFERENCED_BY_TESS_EVALUATION_SHADER, &referencedByTessEvaluationVerifier }, 2212 { GL_TYPE, &typeValidator }, 2213 }; 2214 2215 for (int targetResourceNdx = 0; targetResourceNdx < (int)targetResources.size(); ++targetResourceNdx) 2216 { 2217 const tcu::ScopedLogSection section (m_testCtx.getLog(), "UniformResource", "Uniform resource \"" + targetResources[targetResourceNdx] + "\""); 2218 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 2219 std::vector<glw::GLenum> props; 2220 std::vector<const PropValidator*> validators; 2221 2222 for (int propNdx = 0; propNdx < DE_LENGTH_OF_ARRAY(allProperties); ++propNdx) 2223 { 2224 if (allProperties[propNdx].validator->isSelected(m_queryTarget.propFlags) && 2225 allProperties[propNdx].validator->isSupported()) 2226 { 2227 props.push_back(allProperties[propNdx].prop); 2228 validators.push_back(allProperties[propNdx].validator); 2229 } 2230 } 2231 2232 DE_ASSERT(!props.empty()); 2233 2234 queryAndValidateProps(m_testCtx, gl, program.getProgram(), m_queryTarget.interface, targetResources[targetResourceNdx].c_str(), programDefinition, props, validators); 2235 } 2236 2237 break; 2238 } 2239 2240 case PROGRAMINTERFACE_UNIFORM_BLOCK: 2241 case PROGRAMINTERFACE_SHADER_STORAGE_BLOCK: 2242 { 2243 const glu::Storage storage = (m_queryTarget.interface == PROGRAMINTERFACE_UNIFORM_BLOCK) ? (glu::STORAGE_UNIFORM) : (glu::STORAGE_BUFFER); 2244 const VariableSearchFilter blockFilter = VariableSearchFilter::createStorageFilter(storage); 2245 2246 const BlockNameLengthValidator nameLengthValidator (m_context, program.getProgram(), blockFilter); 2247 const BlockReferencedByShaderValidator referencedByVertexVerifier (m_context, glu::SHADERTYPE_VERTEX, blockFilter); 2248 const BlockReferencedByShaderValidator referencedByFragmentVerifier (m_context, glu::SHADERTYPE_FRAGMENT, blockFilter); 2249 const BlockReferencedByShaderValidator referencedByComputeVerifier (m_context, glu::SHADERTYPE_COMPUTE, blockFilter); 2250 const BlockReferencedByShaderValidator referencedByGeometryVerifier (m_context, glu::SHADERTYPE_GEOMETRY, blockFilter); 2251 const BlockReferencedByShaderValidator referencedByTessControlVerifier (m_context, glu::SHADERTYPE_TESSELLATION_CONTROL, blockFilter); 2252 const BlockReferencedByShaderValidator referencedByTessEvaluationVerifier (m_context, glu::SHADERTYPE_TESSELLATION_EVALUATION, blockFilter); 2253 const BufferBindingValidator bufferBindingValidator (m_context, program.getProgram(), blockFilter); 2254 2255 const TestProperty allProperties[] = 2256 { 2257 { GL_NAME_LENGTH, &nameLengthValidator }, 2258 { GL_REFERENCED_BY_VERTEX_SHADER, &referencedByVertexVerifier }, 2259 { GL_REFERENCED_BY_FRAGMENT_SHADER, &referencedByFragmentVerifier }, 2260 { GL_REFERENCED_BY_COMPUTE_SHADER, &referencedByComputeVerifier }, 2261 { GL_REFERENCED_BY_GEOMETRY_SHADER, &referencedByGeometryVerifier }, 2262 { GL_REFERENCED_BY_TESS_CONTROL_SHADER, &referencedByTessControlVerifier }, 2263 { GL_REFERENCED_BY_TESS_EVALUATION_SHADER, &referencedByTessEvaluationVerifier }, 2264 { GL_BUFFER_BINDING, &bufferBindingValidator }, 2265 }; 2266 2267 for (int targetResourceNdx = 0; targetResourceNdx < (int)targetResources.size(); ++targetResourceNdx) 2268 { 2269 const tcu::ScopedLogSection section (m_testCtx.getLog(), "BlockResource", "Interface block \"" + targetResources[targetResourceNdx] + "\""); 2270 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 2271 std::vector<glw::GLenum> props; 2272 std::vector<const PropValidator*> validators; 2273 2274 for (int propNdx = 0; propNdx < DE_LENGTH_OF_ARRAY(allProperties); ++propNdx) 2275 { 2276 if (allProperties[propNdx].validator->isSelected(m_queryTarget.propFlags) && 2277 allProperties[propNdx].validator->isSupported()) 2278 { 2279 props.push_back(allProperties[propNdx].prop); 2280 validators.push_back(allProperties[propNdx].validator); 2281 } 2282 } 2283 2284 DE_ASSERT(!props.empty()); 2285 2286 queryAndValidateProps(m_testCtx, gl, program.getProgram(), m_queryTarget.interface, targetResources[targetResourceNdx].c_str(), programDefinition, props, validators); 2287 } 2288 2289 break; 2290 } 2291 2292 case PROGRAMINTERFACE_PROGRAM_INPUT: 2293 case PROGRAMINTERFACE_PROGRAM_OUTPUT: 2294 { 2295 const bool isInputCase = (m_queryTarget.interface == PROGRAMINTERFACE_PROGRAM_INPUT); 2296 const glu::Storage varyingStorage = (isInputCase) ? (glu::STORAGE_IN) : (glu::STORAGE_OUT); 2297 const glu::Storage patchStorage = (isInputCase) ? (glu::STORAGE_PATCH_IN) : (glu::STORAGE_PATCH_OUT); 2298 const glu::ShaderType shaderType = (isInputCase) ? (programDefinition->getFirstStage()) : (programDefinition->getLastStage()); 2299 const int unsizedArraySize = (isInputCase && shaderType == glu::SHADERTYPE_GEOMETRY) ? (1) // input points 2300 : (isInputCase && shaderType == glu::SHADERTYPE_TESSELLATION_CONTROL) ? (getMaxPatchVertices()) // input batch size 2301 : (!isInputCase && shaderType == glu::SHADERTYPE_TESSELLATION_CONTROL) ? (programDefinition->getTessellationNumOutputPatchVertices()) // output batch size 2302 : (isInputCase && shaderType == glu::SHADERTYPE_TESSELLATION_EVALUATION) ? (getMaxPatchVertices()) // input batch size 2303 : (-1); 2304 const VariableSearchFilter variableFilter = VariableSearchFilter::logicalAnd(VariableSearchFilter::createShaderTypeFilter(shaderType), 2305 VariableSearchFilter::logicalOr(VariableSearchFilter::createStorageFilter(varyingStorage), 2306 VariableSearchFilter::createStorageFilter(patchStorage))); 2307 2308 const TypeValidator typeValidator (m_context, program.getProgram(), variableFilter); 2309 const ArraySizeValidator arraySizeValidator (m_context, program.getProgram(), unsizedArraySize, variableFilter); 2310 const LocationValidator locationValidator (m_context, program.getProgram(), variableFilter); 2311 const VariableNameLengthValidator nameLengthValidator (m_context, program.getProgram(), variableFilter); 2312 const VariableReferencedByShaderValidator referencedByVertexVerifier (m_context, glu::SHADERTYPE_VERTEX, variableFilter); 2313 const VariableReferencedByShaderValidator referencedByFragmentVerifier (m_context, glu::SHADERTYPE_FRAGMENT, variableFilter); 2314 const VariableReferencedByShaderValidator referencedByComputeVerifier (m_context, glu::SHADERTYPE_COMPUTE, variableFilter); 2315 const VariableReferencedByShaderValidator referencedByGeometryVerifier (m_context, glu::SHADERTYPE_GEOMETRY, variableFilter); 2316 const VariableReferencedByShaderValidator referencedByTessControlVerifier (m_context, glu::SHADERTYPE_TESSELLATION_CONTROL, variableFilter); 2317 const VariableReferencedByShaderValidator referencedByTessEvaluationVerifier (m_context, glu::SHADERTYPE_TESSELLATION_EVALUATION, variableFilter); 2318 const PerPatchValidator perPatchValidator (m_context, program.getProgram(), variableFilter); 2319 2320 const TestProperty allProperties[] = 2321 { 2322 { GL_ARRAY_SIZE, &arraySizeValidator }, 2323 { GL_LOCATION, &locationValidator }, 2324 { GL_NAME_LENGTH, &nameLengthValidator }, 2325 { GL_REFERENCED_BY_VERTEX_SHADER, &referencedByVertexVerifier }, 2326 { GL_REFERENCED_BY_FRAGMENT_SHADER, &referencedByFragmentVerifier }, 2327 { GL_REFERENCED_BY_COMPUTE_SHADER, &referencedByComputeVerifier }, 2328 { GL_REFERENCED_BY_GEOMETRY_SHADER, &referencedByGeometryVerifier }, 2329 { GL_REFERENCED_BY_TESS_CONTROL_SHADER, &referencedByTessControlVerifier }, 2330 { GL_REFERENCED_BY_TESS_EVALUATION_SHADER, &referencedByTessEvaluationVerifier }, 2331 { GL_TYPE, &typeValidator }, 2332 { GL_IS_PER_PATCH, &perPatchValidator }, 2333 }; 2334 2335 for (int targetResourceNdx = 0; targetResourceNdx < (int)targetResources.size(); ++targetResourceNdx) 2336 { 2337 const std::string resourceInterfaceName = (m_queryTarget.interface == PROGRAMINTERFACE_PROGRAM_INPUT) ? ("Input") : ("Output"); 2338 const tcu::ScopedLogSection section (m_testCtx.getLog(), "BlockResource", resourceInterfaceName + " resource \"" + targetResources[targetResourceNdx] + "\""); 2339 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 2340 std::vector<glw::GLenum> props; 2341 std::vector<const PropValidator*> validators; 2342 2343 for (int propNdx = 0; propNdx < DE_LENGTH_OF_ARRAY(allProperties); ++propNdx) 2344 { 2345 if (allProperties[propNdx].validator->isSelected(m_queryTarget.propFlags) && 2346 allProperties[propNdx].validator->isSupported()) 2347 { 2348 props.push_back(allProperties[propNdx].prop); 2349 validators.push_back(allProperties[propNdx].validator); 2350 } 2351 } 2352 2353 DE_ASSERT(!props.empty()); 2354 2355 queryAndValidateProps(m_testCtx, gl, program.getProgram(), m_queryTarget.interface, targetResources[targetResourceNdx].c_str(), programDefinition, props, validators); 2356 } 2357 2358 break; 2359 } 2360 2361 case PROGRAMINTERFACE_BUFFER_VARIABLE: 2362 { 2363 const VariableSearchFilter variableFilter = VariableSearchFilter::createStorageFilter(glu::STORAGE_BUFFER); 2364 2365 const TypeValidator typeValidator (m_context, program.getProgram(), variableFilter); 2366 const ArraySizeValidator arraySizeValidator (m_context, program.getProgram(), 0, variableFilter); 2367 const ArrayStrideValidator arrayStrideValidator (m_context, program.getProgram(), variableFilter); 2368 const BlockIndexValidator blockIndexValidator (m_context, program.getProgram(), variableFilter); 2369 const IsRowMajorValidator isRowMajorValidator (m_context, program.getProgram(), variableFilter); 2370 const MatrixStrideValidator matrixStrideValidator (m_context, program.getProgram(), variableFilter); 2371 const OffsetValidator offsetValidator (m_context, program.getProgram(), variableFilter); 2372 const VariableNameLengthValidator nameLengthValidator (m_context, program.getProgram(), variableFilter); 2373 const VariableReferencedByShaderValidator referencedByVertexVerifier (m_context, glu::SHADERTYPE_VERTEX, variableFilter); 2374 const VariableReferencedByShaderValidator referencedByFragmentVerifier (m_context, glu::SHADERTYPE_FRAGMENT, variableFilter); 2375 const VariableReferencedByShaderValidator referencedByComputeVerifier (m_context, glu::SHADERTYPE_COMPUTE, variableFilter); 2376 const VariableReferencedByShaderValidator referencedByGeometryVerifier (m_context, glu::SHADERTYPE_GEOMETRY, variableFilter); 2377 const VariableReferencedByShaderValidator referencedByTessControlVerifier (m_context, glu::SHADERTYPE_TESSELLATION_CONTROL, variableFilter); 2378 const VariableReferencedByShaderValidator referencedByTessEvaluationVerifier (m_context, glu::SHADERTYPE_TESSELLATION_EVALUATION, variableFilter); 2379 const TopLevelArraySizeValidator topLevelArraySizeValidator (m_context, program.getProgram(), variableFilter); 2380 const TopLevelArrayStrideValidator topLevelArrayStrideValidator (m_context, program.getProgram(), variableFilter); 2381 2382 const TestProperty allProperties[] = 2383 { 2384 { GL_ARRAY_SIZE, &arraySizeValidator }, 2385 { GL_ARRAY_STRIDE, &arrayStrideValidator }, 2386 { GL_BLOCK_INDEX, &blockIndexValidator }, 2387 { GL_IS_ROW_MAJOR, &isRowMajorValidator }, 2388 { GL_MATRIX_STRIDE, &matrixStrideValidator }, 2389 { GL_NAME_LENGTH, &nameLengthValidator }, 2390 { GL_OFFSET, &offsetValidator }, 2391 { GL_REFERENCED_BY_VERTEX_SHADER, &referencedByVertexVerifier }, 2392 { GL_REFERENCED_BY_FRAGMENT_SHADER, &referencedByFragmentVerifier }, 2393 { GL_REFERENCED_BY_COMPUTE_SHADER, &referencedByComputeVerifier }, 2394 { GL_REFERENCED_BY_GEOMETRY_SHADER, &referencedByGeometryVerifier }, 2395 { GL_REFERENCED_BY_TESS_CONTROL_SHADER, &referencedByTessControlVerifier }, 2396 { GL_REFERENCED_BY_TESS_EVALUATION_SHADER, &referencedByTessEvaluationVerifier }, 2397 { GL_TOP_LEVEL_ARRAY_SIZE, &topLevelArraySizeValidator }, 2398 { GL_TOP_LEVEL_ARRAY_STRIDE, &topLevelArrayStrideValidator }, 2399 { GL_TYPE, &typeValidator }, 2400 }; 2401 2402 for (int targetResourceNdx = 0; targetResourceNdx < (int)targetResources.size(); ++targetResourceNdx) 2403 { 2404 const tcu::ScopedLogSection section (m_testCtx.getLog(), "BufferVariableResource", "Buffer variable \"" + targetResources[targetResourceNdx] + "\""); 2405 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 2406 std::vector<glw::GLenum> props; 2407 std::vector<const PropValidator*> validators; 2408 2409 for (int propNdx = 0; propNdx < DE_LENGTH_OF_ARRAY(allProperties); ++propNdx) 2410 { 2411 if (allProperties[propNdx].validator->isSelected(m_queryTarget.propFlags) && 2412 allProperties[propNdx].validator->isSupported()) 2413 { 2414 props.push_back(allProperties[propNdx].prop); 2415 validators.push_back(allProperties[propNdx].validator); 2416 } 2417 } 2418 2419 DE_ASSERT(!props.empty()); 2420 2421 queryAndValidateProps(m_testCtx, gl, program.getProgram(), m_queryTarget.interface, targetResources[targetResourceNdx].c_str(), programDefinition, props, validators); 2422 } 2423 2424 break; 2425 } 2426 2427 case PROGRAMINTERFACE_TRANSFORM_FEEDBACK_VARYING: 2428 { 2429 const TransformFeedbackTypeValidator typeValidator (m_context); 2430 const TransformFeedbackArraySizeValidator arraySizeValidator (m_context); 2431 const TransformFeedbackNameLengthValidator nameLengthValidator (m_context); 2432 2433 const TestProperty allProperties[] = 2434 { 2435 { GL_ARRAY_SIZE, &arraySizeValidator }, 2436 { GL_NAME_LENGTH, &nameLengthValidator }, 2437 { GL_TYPE, &typeValidator }, 2438 }; 2439 2440 for (int targetResourceNdx = 0; targetResourceNdx < (int)targetResources.size(); ++targetResourceNdx) 2441 { 2442 const tcu::ScopedLogSection section (m_testCtx.getLog(), "XFBVariableResource", "Transform feedback varying \"" + targetResources[targetResourceNdx] + "\""); 2443 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 2444 std::vector<glw::GLenum> props; 2445 std::vector<const PropValidator*> validators; 2446 2447 for (int propNdx = 0; propNdx < DE_LENGTH_OF_ARRAY(allProperties); ++propNdx) 2448 { 2449 if (allProperties[propNdx].validator->isSelected(m_queryTarget.propFlags) && 2450 allProperties[propNdx].validator->isSupported()) 2451 { 2452 props.push_back(allProperties[propNdx].prop); 2453 validators.push_back(allProperties[propNdx].validator); 2454 } 2455 } 2456 2457 DE_ASSERT(!props.empty()); 2458 2459 queryAndValidateProps(m_testCtx, gl, program.getProgram(), m_queryTarget.interface, targetResources[targetResourceNdx].c_str(), programDefinition, props, validators); 2460 } 2461 2462 break; 2463 } 2464 2465 default: 2466 DE_ASSERT(false); 2467 } 2468 2469 return STOP; 2470} 2471 2472static bool checkLimit (glw::GLenum pname, int usage, const glw::Functions& gl, tcu::TestLog& log) 2473{ 2474 if (usage > 0) 2475 { 2476 glw::GLint limit = 0; 2477 gl.getIntegerv(pname, &limit); 2478 GLU_EXPECT_NO_ERROR(gl.getError(), "query limits"); 2479 2480 log << tcu::TestLog::Message << "\t" << glu::getGettableStateStr(pname) << " = " << limit << ", test requires " << usage << tcu::TestLog::EndMessage; 2481 2482 if (limit < usage) 2483 { 2484 log << tcu::TestLog::Message << "\t\tLimit exceeded" << tcu::TestLog::EndMessage; 2485 return false; 2486 } 2487 } 2488 2489 return true; 2490} 2491 2492static bool checkShaderResourceUsage (const ProgramInterfaceDefinition::Program* program, const ProgramInterfaceDefinition::Shader* shader, const glw::Functions& gl, tcu::TestLog& log) 2493{ 2494 const ProgramInterfaceDefinition::ShaderResourceUsage usage = getShaderResourceUsage(program, shader); 2495 2496 switch (shader->getType()) 2497 { 2498 case glu::SHADERTYPE_VERTEX: 2499 { 2500 const struct 2501 { 2502 glw::GLenum pname; 2503 int usage; 2504 } restrictions[] = 2505 { 2506 { GL_MAX_VERTEX_ATTRIBS, usage.numInputVectors }, 2507 { GL_MAX_VERTEX_UNIFORM_COMPONENTS, usage.numDefaultBlockUniformComponents }, 2508 { GL_MAX_VERTEX_UNIFORM_VECTORS, usage.numUniformVectors }, 2509 { GL_MAX_VERTEX_UNIFORM_BLOCKS, usage.numUniformBlocks }, 2510 { GL_MAX_VERTEX_OUTPUT_COMPONENTS, usage.numOutputComponents }, 2511 { GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS, usage.numSamplers }, 2512 { GL_MAX_VERTEX_ATOMIC_COUNTER_BUFFERS, usage.numAtomicCounterBuffers }, 2513 { GL_MAX_VERTEX_ATOMIC_COUNTERS, usage.numAtomicCounters }, 2514 { GL_MAX_VERTEX_IMAGE_UNIFORMS, usage.numImages }, 2515 { GL_MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS, usage.numCombinedUniformComponents }, 2516 { GL_MAX_VERTEX_SHADER_STORAGE_BLOCKS, usage.numShaderStorageBlocks }, 2517 }; 2518 2519 bool allOk = true; 2520 2521 log << tcu::TestLog::Message << "Vertex shader:" << tcu::TestLog::EndMessage; 2522 for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(restrictions); ++ndx) 2523 allOk &= checkLimit(restrictions[ndx].pname, restrictions[ndx].usage, gl, log); 2524 2525 return allOk; 2526 } 2527 2528 case glu::SHADERTYPE_FRAGMENT: 2529 { 2530 const struct 2531 { 2532 glw::GLenum pname; 2533 int usage; 2534 } restrictions[] = 2535 { 2536 { GL_MAX_FRAGMENT_UNIFORM_COMPONENTS, usage.numDefaultBlockUniformComponents }, 2537 { GL_MAX_FRAGMENT_UNIFORM_VECTORS, usage.numUniformVectors }, 2538 { GL_MAX_FRAGMENT_UNIFORM_BLOCKS, usage.numUniformBlocks }, 2539 { GL_MAX_FRAGMENT_INPUT_COMPONENTS, usage.numInputComponents }, 2540 { GL_MAX_TEXTURE_IMAGE_UNITS, usage.numSamplers }, 2541 { GL_MAX_FRAGMENT_ATOMIC_COUNTER_BUFFERS, usage.numAtomicCounterBuffers }, 2542 { GL_MAX_FRAGMENT_ATOMIC_COUNTERS, usage.numAtomicCounters }, 2543 { GL_MAX_FRAGMENT_IMAGE_UNIFORMS, usage.numImages }, 2544 { GL_MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS, usage.numCombinedUniformComponents }, 2545 { GL_MAX_FRAGMENT_SHADER_STORAGE_BLOCKS, usage.numShaderStorageBlocks }, 2546 }; 2547 2548 bool allOk = true; 2549 2550 log << tcu::TestLog::Message << "Fragment shader:" << tcu::TestLog::EndMessage; 2551 for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(restrictions); ++ndx) 2552 allOk &= checkLimit(restrictions[ndx].pname, restrictions[ndx].usage, gl, log); 2553 2554 return allOk; 2555 } 2556 2557 case glu::SHADERTYPE_COMPUTE: 2558 { 2559 const struct 2560 { 2561 glw::GLenum pname; 2562 int usage; 2563 } restrictions[] = 2564 { 2565 { GL_MAX_COMPUTE_UNIFORM_BLOCKS, usage.numUniformBlocks }, 2566 { GL_MAX_COMPUTE_TEXTURE_IMAGE_UNITS, usage.numSamplers }, 2567 { GL_MAX_COMPUTE_UNIFORM_COMPONENTS, usage.numDefaultBlockUniformComponents }, 2568 { GL_MAX_COMPUTE_ATOMIC_COUNTER_BUFFERS, usage.numAtomicCounterBuffers }, 2569 { GL_MAX_COMPUTE_ATOMIC_COUNTERS, usage.numAtomicCounters }, 2570 { GL_MAX_COMPUTE_IMAGE_UNIFORMS, usage.numImages }, 2571 { GL_MAX_COMBINED_COMPUTE_UNIFORM_COMPONENTS, usage.numCombinedUniformComponents }, 2572 { GL_MAX_COMPUTE_SHADER_STORAGE_BLOCKS, usage.numShaderStorageBlocks }, 2573 }; 2574 2575 bool allOk = true; 2576 2577 log << tcu::TestLog::Message << "Compute shader:" << tcu::TestLog::EndMessage; 2578 for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(restrictions); ++ndx) 2579 allOk &= checkLimit(restrictions[ndx].pname, restrictions[ndx].usage, gl, log); 2580 2581 return allOk; 2582 } 2583 2584 case glu::SHADERTYPE_GEOMETRY: 2585 { 2586 const int totalOutputComponents = program->getGeometryNumOutputVertices() * usage.numOutputComponents; 2587 const struct 2588 { 2589 glw::GLenum pname; 2590 int usage; 2591 } restrictions[] = 2592 { 2593 { GL_MAX_GEOMETRY_UNIFORM_COMPONENTS, usage.numDefaultBlockUniformComponents }, 2594 { GL_MAX_GEOMETRY_UNIFORM_BLOCKS, usage.numUniformBlocks }, 2595 { GL_MAX_GEOMETRY_INPUT_COMPONENTS, usage.numInputComponents }, 2596 { GL_MAX_GEOMETRY_OUTPUT_COMPONENTS, usage.numOutputComponents }, 2597 { GL_MAX_GEOMETRY_OUTPUT_VERTICES, (int)program->getGeometryNumOutputVertices() }, 2598 { GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS, totalOutputComponents }, 2599 { GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS, usage.numSamplers }, 2600 { GL_MAX_GEOMETRY_ATOMIC_COUNTER_BUFFERS, usage.numAtomicCounterBuffers }, 2601 { GL_MAX_GEOMETRY_ATOMIC_COUNTERS, usage.numAtomicCounters }, 2602 { GL_MAX_GEOMETRY_IMAGE_UNIFORMS, usage.numImages }, 2603 { GL_MAX_GEOMETRY_SHADER_STORAGE_BLOCKS, usage.numShaderStorageBlocks }, 2604 }; 2605 2606 bool allOk = true; 2607 2608 log << tcu::TestLog::Message << "Geometry shader:" << tcu::TestLog::EndMessage; 2609 for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(restrictions); ++ndx) 2610 allOk &= checkLimit(restrictions[ndx].pname, restrictions[ndx].usage, gl, log); 2611 2612 return allOk; 2613 } 2614 2615 case glu::SHADERTYPE_TESSELLATION_CONTROL: 2616 { 2617 const int totalOutputComponents = program->getTessellationNumOutputPatchVertices() * usage.numOutputComponents + usage.numPatchOutputComponents; 2618 const struct 2619 { 2620 glw::GLenum pname; 2621 int usage; 2622 } restrictions[] = 2623 { 2624 { GL_MAX_PATCH_VERTICES, (int)program->getTessellationNumOutputPatchVertices() }, 2625 { GL_MAX_TESS_PATCH_COMPONENTS, usage.numPatchOutputComponents }, 2626 { GL_MAX_TESS_CONTROL_UNIFORM_COMPONENTS, usage.numDefaultBlockUniformComponents }, 2627 { GL_MAX_TESS_CONTROL_UNIFORM_BLOCKS, usage.numUniformBlocks }, 2628 { GL_MAX_TESS_CONTROL_INPUT_COMPONENTS, usage.numInputComponents }, 2629 { GL_MAX_TESS_CONTROL_OUTPUT_COMPONENTS, usage.numOutputComponents }, 2630 { GL_MAX_TESS_CONTROL_TOTAL_OUTPUT_COMPONENTS, totalOutputComponents }, 2631 { GL_MAX_TESS_CONTROL_TEXTURE_IMAGE_UNITS, usage.numSamplers }, 2632 { GL_MAX_TESS_CONTROL_ATOMIC_COUNTER_BUFFERS, usage.numAtomicCounterBuffers }, 2633 { GL_MAX_TESS_CONTROL_ATOMIC_COUNTERS, usage.numAtomicCounters }, 2634 { GL_MAX_TESS_CONTROL_SHADER_STORAGE_BLOCKS, usage.numShaderStorageBlocks }, 2635 }; 2636 2637 bool allOk = true; 2638 2639 log << tcu::TestLog::Message << "Tessellation control shader:" << tcu::TestLog::EndMessage; 2640 for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(restrictions); ++ndx) 2641 allOk &= checkLimit(restrictions[ndx].pname, restrictions[ndx].usage, gl, log); 2642 2643 return allOk; 2644 } 2645 2646 case glu::SHADERTYPE_TESSELLATION_EVALUATION: 2647 { 2648 const struct 2649 { 2650 glw::GLenum pname; 2651 int usage; 2652 } restrictions[] = 2653 { 2654 { GL_MAX_PATCH_VERTICES, (int)program->getTessellationNumOutputPatchVertices() }, 2655 { GL_MAX_TESS_PATCH_COMPONENTS, usage.numPatchInputComponents }, 2656 { GL_MAX_TESS_EVALUATION_UNIFORM_COMPONENTS, usage.numDefaultBlockUniformComponents }, 2657 { GL_MAX_TESS_EVALUATION_UNIFORM_BLOCKS, usage.numUniformBlocks }, 2658 { GL_MAX_TESS_EVALUATION_INPUT_COMPONENTS, usage.numInputComponents }, 2659 { GL_MAX_TESS_EVALUATION_OUTPUT_COMPONENTS, usage.numOutputComponents }, 2660 { GL_MAX_TESS_EVALUATION_TEXTURE_IMAGE_UNITS, usage.numSamplers }, 2661 { GL_MAX_TESS_EVALUATION_ATOMIC_COUNTER_BUFFERS, usage.numAtomicCounterBuffers }, 2662 { GL_MAX_TESS_EVALUATION_ATOMIC_COUNTERS, usage.numAtomicCounters }, 2663 { GL_MAX_TESS_EVALUATION_SHADER_STORAGE_BLOCKS, usage.numShaderStorageBlocks }, 2664 }; 2665 2666 bool allOk = true; 2667 2668 log << tcu::TestLog::Message << "Tessellation evaluation shader:" << tcu::TestLog::EndMessage; 2669 for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(restrictions); ++ndx) 2670 allOk &= checkLimit(restrictions[ndx].pname, restrictions[ndx].usage, gl, log); 2671 2672 return allOk; 2673 } 2674 2675 default: 2676 DE_ASSERT(false); 2677 return false; 2678 } 2679} 2680 2681static bool checkProgramCombinedResourceUsage (const ProgramInterfaceDefinition::Program* program, const glw::Functions& gl, tcu::TestLog& log) 2682{ 2683 const ProgramInterfaceDefinition::ProgramResourceUsage usage = getCombinedProgramResourceUsage(program); 2684 2685 const struct 2686 { 2687 glw::GLenum pname; 2688 int usage; 2689 } restrictions[] = 2690 { 2691 { GL_MAX_UNIFORM_BUFFER_BINDINGS, usage.uniformBufferMaxBinding+1 }, 2692 { GL_MAX_UNIFORM_BLOCK_SIZE, usage.uniformBufferMaxSize }, 2693 { GL_MAX_COMBINED_UNIFORM_BLOCKS, usage.numUniformBlocks }, 2694 { GL_MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS, usage.numCombinedVertexUniformComponents }, 2695 { GL_MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS, usage.numCombinedFragmentUniformComponents }, 2696 { GL_MAX_COMBINED_GEOMETRY_UNIFORM_COMPONENTS, usage.numCombinedGeometryUniformComponents }, 2697 { GL_MAX_COMBINED_TESS_CONTROL_UNIFORM_COMPONENTS, usage.numCombinedTessControlUniformComponents }, 2698 { GL_MAX_COMBINED_TESS_EVALUATION_UNIFORM_COMPONENTS, usage.numCombinedTessEvalUniformComponents }, 2699 { GL_MAX_VARYING_COMPONENTS, usage.numVaryingComponents }, 2700 { GL_MAX_VARYING_VECTORS, usage.numVaryingVectors }, 2701 { GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, usage.numCombinedSamplers }, 2702 { GL_MAX_COMBINED_SHADER_OUTPUT_RESOURCES, usage.numCombinedOutputResources }, 2703 { GL_MAX_ATOMIC_COUNTER_BUFFER_BINDINGS, usage.atomicCounterBufferMaxBinding+1 }, 2704 { GL_MAX_ATOMIC_COUNTER_BUFFER_SIZE, usage.atomicCounterBufferMaxSize }, 2705 { GL_MAX_COMBINED_ATOMIC_COUNTER_BUFFERS, usage.numAtomicCounterBuffers }, 2706 { GL_MAX_COMBINED_ATOMIC_COUNTERS, usage.numAtomicCounters }, 2707 { GL_MAX_IMAGE_UNITS, usage.maxImageBinding+1 }, 2708 { GL_MAX_COMBINED_IMAGE_UNIFORMS, usage.numCombinedImages }, 2709 { GL_MAX_SHADER_STORAGE_BUFFER_BINDINGS, usage.shaderStorageBufferMaxBinding+1 }, 2710 { GL_MAX_SHADER_STORAGE_BLOCK_SIZE, usage.shaderStorageBufferMaxSize }, 2711 { GL_MAX_COMBINED_SHADER_STORAGE_BLOCKS, usage.numShaderStorageBlocks }, 2712 { GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS, usage.numXFBInterleavedComponents }, 2713 { GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS, usage.numXFBSeparateAttribs }, 2714 { GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS, usage.numXFBSeparateComponents }, 2715 { GL_MAX_DRAW_BUFFERS, usage.fragmentOutputMaxBinding+1 }, 2716 }; 2717 2718 bool allOk = true; 2719 2720 log << tcu::TestLog::Message << "Program combined:" << tcu::TestLog::EndMessage; 2721 for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(restrictions); ++ndx) 2722 allOk &= checkLimit(restrictions[ndx].pname, restrictions[ndx].usage, gl, log); 2723 2724 return allOk; 2725} 2726 2727void checkProgramResourceUsage (const ProgramInterfaceDefinition::Program* program, const glw::Functions& gl, tcu::TestLog& log) 2728{ 2729 bool limitExceeded = false; 2730 2731 for (int shaderNdx = 0; shaderNdx < (int)program->getShaders().size(); ++shaderNdx) 2732 limitExceeded |= !checkShaderResourceUsage(program, program->getShaders()[shaderNdx], gl, log); 2733 2734 limitExceeded |= !checkProgramCombinedResourceUsage(program, gl, log); 2735 2736 if (limitExceeded) 2737 { 2738 log << tcu::TestLog::Message << "One or more resource limits exceeded" << tcu::TestLog::EndMessage; 2739 throw tcu::NotSupportedError("one or more resource limits exceeded"); 2740 } 2741} 2742 2743} // Functional 2744} // gles31 2745} // deqp 2746