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 37 namespace deqp 38 { 39 namespace gles31 40 { 41 namespace Functional 42 { 43 namespace 44 { 45 46 using ProgramInterfaceDefinition::VariablePathComponent; 47 using ProgramInterfaceDefinition::VariableSearchFilter; 48 49 static 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 70 static bool isBufferBackedInterfaceBlockStorage (glu::Storage storage) 71 { 72 return storage == glu::STORAGE_BUFFER || storage == glu::STORAGE_UNIFORM; 73 } 74 75 const 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 97 static 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 110 static 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 139 static 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 167 class PropValidator 168 { 169 public: 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 178 protected: 179 void setError (const std::string& err) const; 180 181 tcu::TestContext& m_testCtx; 182 const glu::RenderContext& m_renderContext; 183 184 private: 185 const glu::ContextInfo& m_contextInfo; 186 const char* m_extension; 187 const ProgramResourcePropFlags m_validationProp; 188 }; 189 190 PropValidator::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 199 std::string PropValidator::getHumanReadablePropertyString (glw::GLint propVal) const 200 { 201 return de::toString(propVal); 202 } 203 204 bool PropValidator::isSupported (void) const 205 { 206 return m_extension == DE_NULL || m_contextInfo.isExtensionSupported(m_extension); 207 } 208 209 bool PropValidator::isSelected (deUint32 caseFlags) const 210 { 211 return (caseFlags & (deUint32)m_validationProp) != 0; 212 } 213 214 void 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 221 class SingleVariableValidator : public PropValidator 222 { 223 public: 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 230 protected: 231 const VariableSearchFilter m_filter; 232 const glw::GLuint m_programID; 233 }; 234 235 SingleVariableValidator::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 242 void 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 273 void 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 281 class SingleBlockValidator : public PropValidator 282 { 283 public: 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 289 protected: 290 const VariableSearchFilter m_filter; 291 const glw::GLuint m_programID; 292 }; 293 294 SingleBlockValidator::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 301 void 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 352 class TypeValidator : public SingleVariableValidator 353 { 354 public: 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 362 TypeValidator::TypeValidator (Context& context, glw::GLuint programID, const VariableSearchFilter& filter) 363 : SingleVariableValidator(context, PROGRAMRESOURCEPROP_TYPE, programID, filter, DE_NULL) 364 { 365 } 366 367 std::string TypeValidator::getHumanReadablePropertyString (glw::GLint propVal) const 368 { 369 return de::toString(glu::getShaderVarTypeStr(propVal)); 370 } 371 372 void 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 388 void 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 427 class ArraySizeValidator : public SingleVariableValidator 428 { 429 public: 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 435 private: 436 const int m_unsizedArraySize; 437 }; 438 439 ArraySizeValidator::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 445 void 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 467 void 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 506 class ArrayStrideValidator : public SingleVariableValidator 507 { 508 public: 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 514 ArrayStrideValidator::ArrayStrideValidator (Context& context, glw::GLuint programID, const VariableSearchFilter& filter) 515 : SingleVariableValidator(context, PROGRAMRESOURCEPROP_ARRAY_STRIDE, programID, filter, DE_NULL) 516 { 517 } 518 519 void 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 560 class BlockIndexValidator : public SingleVariableValidator 561 { 562 public: 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 568 BlockIndexValidator::BlockIndexValidator (Context& context, glw::GLuint programID, const VariableSearchFilter& filter) 569 : SingleVariableValidator(context, PROGRAMRESOURCEPROP_BLOCK_INDEX, programID, filter, DE_NULL) 570 { 571 } 572 573 void 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 632 class IsRowMajorValidator : public SingleVariableValidator 633 { 634 public: 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 641 IsRowMajorValidator::IsRowMajorValidator (Context& context, glw::GLuint programID, const VariableSearchFilter& filter) 642 : SingleVariableValidator(context, PROGRAMRESOURCEPROP_MATRIX_ROW_MAJOR, programID, filter, DE_NULL) 643 { 644 } 645 646 std::string IsRowMajorValidator::getHumanReadablePropertyString (glw::GLint propVal) const 647 { 648 return de::toString(glu::getBooleanStr(propVal)); 649 } 650 651 void 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 672 class MatrixStrideValidator : public SingleVariableValidator 673 { 674 public: 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 680 MatrixStrideValidator::MatrixStrideValidator (Context& context, glw::GLuint programID, const VariableSearchFilter& filter) 681 : SingleVariableValidator(context, PROGRAMRESOURCEPROP_MATRIX_STRIDE, programID, filter, DE_NULL) 682 { 683 } 684 685 void 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 725 class AtomicCounterBufferIndexVerifier : public SingleVariableValidator 726 { 727 public: 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 733 AtomicCounterBufferIndexVerifier::AtomicCounterBufferIndexVerifier (Context& context, glw::GLuint programID, const VariableSearchFilter& filter) 734 : SingleVariableValidator(context, PROGRAMRESOURCEPROP_ATOMIC_COUNTER_BUFFER_INDEX, programID, filter, DE_NULL) 735 { 736 } 737 738 void 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 779 class LocationValidator : public SingleVariableValidator 780 { 781 public: 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 788 LocationValidator::LocationValidator (Context& context, glw::GLuint programID, const VariableSearchFilter& filter) 789 : SingleVariableValidator(context, PROGRAMRESOURCEPROP_LOCATION, programID, filter, DE_NULL) 790 { 791 } 792 793 static 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 818 static 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 849 static 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 872 static 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 909 void 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 1029 void 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 1045 class VariableNameLengthValidator : public SingleVariableValidator 1046 { 1047 public: 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 1055 VariableNameLengthValidator::VariableNameLengthValidator (Context& context, glw::GLuint programID, const VariableSearchFilter& filter) 1056 : SingleVariableValidator(context, PROGRAMRESOURCEPROP_NAME_LENGTH, programID, filter, DE_NULL) 1057 { 1058 } 1059 1060 void 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 1067 void 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 1073 void 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 1085 class OffsetValidator : public SingleVariableValidator 1086 { 1087 public: 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 1093 OffsetValidator::OffsetValidator (Context& context, glw::GLuint programID, const VariableSearchFilter& filter) 1094 : SingleVariableValidator(context, PROGRAMRESOURCEPROP_OFFSET, programID, filter, DE_NULL) 1095 { 1096 } 1097 1098 void 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 1130 class VariableReferencedByShaderValidator : public PropValidator 1131 { 1132 public: 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 1138 private: 1139 const VariableSearchFilter m_filter; 1140 const glu::ShaderType m_shaderType; 1141 }; 1142 1143 VariableReferencedByShaderValidator::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 1151 std::string VariableReferencedByShaderValidator::getHumanReadablePropertyString (glw::GLint propVal) const 1152 { 1153 return de::toString(glu::getBooleanStr(propVal)); 1154 } 1155 1156 void 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 1176 class BlockNameLengthValidator : public SingleBlockValidator 1177 { 1178 public: 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 1184 BlockNameLengthValidator::BlockNameLengthValidator (Context& context, const glw::GLuint programID, const VariableSearchFilter& filter) 1185 : SingleBlockValidator(context, PROGRAMRESOURCEPROP_NAME_LENGTH, programID, filter, DE_NULL) 1186 { 1187 } 1188 1189 void 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 1205 class BufferBindingValidator : public SingleBlockValidator 1206 { 1207 public: 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 1213 BufferBindingValidator::BufferBindingValidator (Context& context, const glw::GLuint programID, const VariableSearchFilter& filter) 1214 : SingleBlockValidator(context, PROGRAMRESOURCEPROP_BUFFER_BINDING, programID, filter, DE_NULL) 1215 { 1216 } 1217 1218 void 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 1255 class BlockReferencedByShaderValidator : public PropValidator 1256 { 1257 public: 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 1263 private: 1264 const VariableSearchFilter m_filter; 1265 const glu::ShaderType m_shaderType; 1266 }; 1267 1268 BlockReferencedByShaderValidator::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 1276 std::string BlockReferencedByShaderValidator::getHumanReadablePropertyString (glw::GLint propVal) const 1277 { 1278 return de::toString(glu::getBooleanStr(propVal)); 1279 } 1280 1281 void 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 1316 class TopLevelArraySizeValidator : public SingleVariableValidator 1317 { 1318 public: 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 1324 TopLevelArraySizeValidator::TopLevelArraySizeValidator (Context& context, glw::GLuint programID, const VariableSearchFilter& filter) 1325 : SingleVariableValidator(context, PROGRAMRESOURCEPROP_TOP_LEVEL_ARRAY_SIZE, programID, filter, DE_NULL) 1326 { 1327 } 1328 1329 void 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 1368 class TopLevelArrayStrideValidator : public SingleVariableValidator 1369 { 1370 public: 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 1376 TopLevelArrayStrideValidator::TopLevelArrayStrideValidator (Context& context, glw::GLuint programID, const VariableSearchFilter& filter) 1377 : SingleVariableValidator(context, PROGRAMRESOURCEPROP_TOP_LEVEL_ARRAY_STRIDE, programID, filter, DE_NULL) 1378 { 1379 } 1380 1381 void 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 1421 class TransformFeedbackResourceValidator : public PropValidator 1422 { 1423 public: 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 1428 private: 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 1434 TransformFeedbackResourceValidator::TransformFeedbackResourceValidator (Context& context, ProgramResourcePropFlags validationProp) 1435 : PropValidator(context, validationProp, DE_NULL) 1436 { 1437 } 1438 1439 void 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 1491 class TransformFeedbackArraySizeValidator : public TransformFeedbackResourceValidator 1492 { 1493 public: 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 1500 TransformFeedbackArraySizeValidator::TransformFeedbackArraySizeValidator (Context& context) 1501 : TransformFeedbackResourceValidator(context, PROGRAMRESOURCEPROP_ARRAY_SIZE) 1502 { 1503 } 1504 1505 void 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 1524 void 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 1539 class TransformFeedbackNameLengthValidator : public TransformFeedbackResourceValidator 1540 { 1541 public: 1542 TransformFeedbackNameLengthValidator (Context& context); 1543 1544 private: 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 1550 TransformFeedbackNameLengthValidator::TransformFeedbackNameLengthValidator (Context& context) 1551 : TransformFeedbackResourceValidator(context, PROGRAMRESOURCEPROP_NAME_LENGTH) 1552 { 1553 } 1554 1555 void 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 1561 void 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 1568 void 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 1580 class TransformFeedbackTypeValidator : public TransformFeedbackResourceValidator 1581 { 1582 public: 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 1589 TransformFeedbackTypeValidator::TransformFeedbackTypeValidator (Context& context) 1590 : TransformFeedbackResourceValidator(context, PROGRAMRESOURCEPROP_TYPE) 1591 { 1592 } 1593 1594 void 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 1614 void 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 1634 class PerPatchValidator : public SingleVariableValidator 1635 { 1636 public: 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 1644 PerPatchValidator::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 1649 std::string PerPatchValidator::getHumanReadablePropertyString (glw::GLint propVal) const 1650 { 1651 return de::toString(glu::getBooleanStr(propVal)); 1652 } 1653 1654 void 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 1671 void 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 1708 ProgramResourceQueryTestTarget::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 1727 ProgramInterfaceQueryTestCase::ProgramInterfaceQueryTestCase (Context& context, const char* name, const char* description, ProgramResourceQueryTestTarget queryTarget) 1728 : TestCase (context, name, description) 1729 , m_queryTarget (queryTarget) 1730 { 1731 } 1732 1733 ProgramInterfaceQueryTestCase::~ProgramInterfaceQueryTestCase (void) 1734 { 1735 } 1736 1737 ProgramInterface ProgramInterfaceQueryTestCase::getTargetInterface (void) const 1738 { 1739 return m_queryTarget.interface; 1740 } 1741 1742 static 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 1760 static 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 1825 static 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 1893 static 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 2082 const 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 2117 int 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 2127 ProgramInterfaceQueryTestCase::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 2472 static 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 2492 static 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_IMAGE_UNIFORMS, usage.numImages }, 2635 { GL_MAX_TESS_CONTROL_SHADER_STORAGE_BLOCKS, usage.numShaderStorageBlocks }, 2636 }; 2637 2638 bool allOk = true; 2639 2640 log << tcu::TestLog::Message << "Tessellation control shader:" << tcu::TestLog::EndMessage; 2641 for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(restrictions); ++ndx) 2642 allOk &= checkLimit(restrictions[ndx].pname, restrictions[ndx].usage, gl, log); 2643 2644 return allOk; 2645 } 2646 2647 case glu::SHADERTYPE_TESSELLATION_EVALUATION: 2648 { 2649 const struct 2650 { 2651 glw::GLenum pname; 2652 int usage; 2653 } restrictions[] = 2654 { 2655 { GL_MAX_PATCH_VERTICES, (int)program->getTessellationNumOutputPatchVertices() }, 2656 { GL_MAX_TESS_PATCH_COMPONENTS, usage.numPatchInputComponents }, 2657 { GL_MAX_TESS_EVALUATION_UNIFORM_COMPONENTS, usage.numDefaultBlockUniformComponents }, 2658 { GL_MAX_TESS_EVALUATION_UNIFORM_BLOCKS, usage.numUniformBlocks }, 2659 { GL_MAX_TESS_EVALUATION_INPUT_COMPONENTS, usage.numInputComponents }, 2660 { GL_MAX_TESS_EVALUATION_OUTPUT_COMPONENTS, usage.numOutputComponents }, 2661 { GL_MAX_TESS_EVALUATION_TEXTURE_IMAGE_UNITS, usage.numSamplers }, 2662 { GL_MAX_TESS_EVALUATION_ATOMIC_COUNTER_BUFFERS, usage.numAtomicCounterBuffers }, 2663 { GL_MAX_TESS_EVALUATION_ATOMIC_COUNTERS, usage.numAtomicCounters }, 2664 { GL_MAX_TESS_EVALUATION_IMAGE_UNIFORMS, usage.numImages }, 2665 { GL_MAX_TESS_EVALUATION_SHADER_STORAGE_BLOCKS, usage.numShaderStorageBlocks }, 2666 }; 2667 2668 bool allOk = true; 2669 2670 log << tcu::TestLog::Message << "Tessellation evaluation shader:" << tcu::TestLog::EndMessage; 2671 for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(restrictions); ++ndx) 2672 allOk &= checkLimit(restrictions[ndx].pname, restrictions[ndx].usage, gl, log); 2673 2674 return allOk; 2675 } 2676 2677 default: 2678 DE_ASSERT(false); 2679 return false; 2680 } 2681 } 2682 2683 static bool checkProgramCombinedResourceUsage (const ProgramInterfaceDefinition::Program* program, const glw::Functions& gl, tcu::TestLog& log) 2684 { 2685 const ProgramInterfaceDefinition::ProgramResourceUsage usage = getCombinedProgramResourceUsage(program); 2686 2687 const struct 2688 { 2689 glw::GLenum pname; 2690 int usage; 2691 } restrictions[] = 2692 { 2693 { GL_MAX_UNIFORM_BUFFER_BINDINGS, usage.uniformBufferMaxBinding+1 }, 2694 { GL_MAX_UNIFORM_BLOCK_SIZE, usage.uniformBufferMaxSize }, 2695 { GL_MAX_COMBINED_UNIFORM_BLOCKS, usage.numUniformBlocks }, 2696 { GL_MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS, usage.numCombinedVertexUniformComponents }, 2697 { GL_MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS, usage.numCombinedFragmentUniformComponents }, 2698 { GL_MAX_COMBINED_GEOMETRY_UNIFORM_COMPONENTS, usage.numCombinedGeometryUniformComponents }, 2699 { GL_MAX_COMBINED_TESS_CONTROL_UNIFORM_COMPONENTS, usage.numCombinedTessControlUniformComponents }, 2700 { GL_MAX_COMBINED_TESS_EVALUATION_UNIFORM_COMPONENTS, usage.numCombinedTessEvalUniformComponents }, 2701 { GL_MAX_VARYING_COMPONENTS, usage.numVaryingComponents }, 2702 { GL_MAX_VARYING_VECTORS, usage.numVaryingVectors }, 2703 { GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, usage.numCombinedSamplers }, 2704 { GL_MAX_COMBINED_SHADER_OUTPUT_RESOURCES, usage.numCombinedOutputResources }, 2705 { GL_MAX_ATOMIC_COUNTER_BUFFER_BINDINGS, usage.atomicCounterBufferMaxBinding+1 }, 2706 { GL_MAX_ATOMIC_COUNTER_BUFFER_SIZE, usage.atomicCounterBufferMaxSize }, 2707 { GL_MAX_COMBINED_ATOMIC_COUNTER_BUFFERS, usage.numAtomicCounterBuffers }, 2708 { GL_MAX_COMBINED_ATOMIC_COUNTERS, usage.numAtomicCounters }, 2709 { GL_MAX_IMAGE_UNITS, usage.maxImageBinding+1 }, 2710 { GL_MAX_COMBINED_IMAGE_UNIFORMS, usage.numCombinedImages }, 2711 { GL_MAX_SHADER_STORAGE_BUFFER_BINDINGS, usage.shaderStorageBufferMaxBinding+1 }, 2712 { GL_MAX_SHADER_STORAGE_BLOCK_SIZE, usage.shaderStorageBufferMaxSize }, 2713 { GL_MAX_COMBINED_SHADER_STORAGE_BLOCKS, usage.numShaderStorageBlocks }, 2714 { GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS, usage.numXFBInterleavedComponents }, 2715 { GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS, usage.numXFBSeparateAttribs }, 2716 { GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS, usage.numXFBSeparateComponents }, 2717 { GL_MAX_DRAW_BUFFERS, usage.fragmentOutputMaxBinding+1 }, 2718 }; 2719 2720 bool allOk = true; 2721 2722 log << tcu::TestLog::Message << "Program combined:" << tcu::TestLog::EndMessage; 2723 for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(restrictions); ++ndx) 2724 allOk &= checkLimit(restrictions[ndx].pname, restrictions[ndx].usage, gl, log); 2725 2726 return allOk; 2727 } 2728 2729 void checkProgramResourceUsage (const ProgramInterfaceDefinition::Program* program, const glw::Functions& gl, tcu::TestLog& log) 2730 { 2731 bool limitExceeded = false; 2732 2733 for (int shaderNdx = 0; shaderNdx < (int)program->getShaders().size(); ++shaderNdx) 2734 limitExceeded |= !checkShaderResourceUsage(program, program->getShaders()[shaderNdx], gl, log); 2735 2736 limitExceeded |= !checkProgramCombinedResourceUsage(program, gl, log); 2737 2738 if (limitExceeded) 2739 { 2740 log << tcu::TestLog::Message << "One or more resource limits exceeded" << tcu::TestLog::EndMessage; 2741 throw tcu::NotSupportedError("one or more resource limits exceeded"); 2742 } 2743 } 2744 2745 } // Functional 2746 } // gles31 2747 } // deqp 2748