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 Debug output (KHR_debug) tests 22 *//*--------------------------------------------------------------------*/ 23 24 #include "es31fDebugTests.hpp" 25 26 #include "es31fNegativeTestShared.hpp" 27 #include "es31fNegativeBufferApiTests.hpp" 28 #include "es31fNegativeTextureApiTests.hpp" 29 #include "es31fNegativeShaderApiTests.hpp" 30 #include "es31fNegativeFragmentApiTests.hpp" 31 #include "es31fNegativeVertexArrayApiTests.hpp" 32 #include "es31fNegativeStateApiTests.hpp" 33 #include "es31fNegativeAtomicCounterTests.hpp" 34 #include "es31fNegativeShaderImageLoadStoreTests.hpp" 35 #include "es31fNegativeShaderFunctionTests.hpp" 36 #include "es31fNegativeShaderDirectiveTests.hpp" 37 #include "es31fNegativePreciseTests.hpp" 38 #include "es31fNegativeAdvancedBlendEquationTests.hpp" 39 40 #include "deUniquePtr.hpp" 41 #include "deRandom.hpp" 42 #include "deStringUtil.hpp" 43 #include "deSTLUtil.hpp" 44 #include "deMutex.hpp" 45 #include "deThread.h" 46 47 #include "gluRenderContext.hpp" 48 #include "gluContextInfo.hpp" 49 #include "gluCallLogWrapper.hpp" 50 #include "gluStrUtil.hpp" 51 52 #include "glwDefs.hpp" 53 #include "glwEnums.hpp" 54 #include "glwFunctions.hpp" 55 56 #include "tes31Context.hpp" 57 #include "tcuTestContext.hpp" 58 #include "tcuCommandLine.hpp" 59 #include "tcuResultCollector.hpp" 60 61 #include "glsStateQueryUtil.hpp" 62 63 namespace deqp 64 { 65 namespace gles31 66 { 67 namespace Functional 68 { 69 namespace 70 { 71 using namespace glw; 72 73 using std::string; 74 using std::vector; 75 using std::set; 76 using std::map; 77 using de::MovePtr; 78 79 using tcu::ResultCollector; 80 using tcu::TestLog; 81 using glu::CallLogWrapper; 82 83 using NegativeTestShared::NegativeTestContext; 84 85 static const GLenum s_debugTypes[] = 86 { 87 GL_DEBUG_TYPE_ERROR, 88 GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR, 89 GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR, 90 GL_DEBUG_TYPE_PORTABILITY, 91 GL_DEBUG_TYPE_PERFORMANCE, 92 GL_DEBUG_TYPE_OTHER, 93 GL_DEBUG_TYPE_MARKER, 94 GL_DEBUG_TYPE_PUSH_GROUP, 95 GL_DEBUG_TYPE_POP_GROUP, 96 }; 97 98 static const GLenum s_debugSeverities[] = 99 { 100 GL_DEBUG_SEVERITY_HIGH, 101 GL_DEBUG_SEVERITY_MEDIUM, 102 GL_DEBUG_SEVERITY_LOW, 103 GL_DEBUG_SEVERITY_NOTIFICATION, 104 }; 105 106 static bool isKHRDebugSupported (Context& ctx) 107 { 108 const bool isES32 = glu::contextSupports(ctx.getRenderContext().getType(), glu::ApiType::es(3, 2)); 109 return isES32 || ctx.getContextInfo().isExtensionSupported("GL_KHR_debug"); 110 } 111 112 class BaseCase; 113 114 class DebugMessageTestContext : public NegativeTestContext 115 { 116 public: 117 DebugMessageTestContext (BaseCase& host, 118 glu::RenderContext& renderCtx, 119 const glu::ContextInfo& ctxInfo, 120 tcu::TestLog& log, 121 tcu::ResultCollector& results, 122 bool enableLog); 123 ~DebugMessageTestContext (void); 124 125 void expectMessage (GLenum source, GLenum type); 126 127 private: 128 BaseCase& m_debugHost; 129 }; 130 131 class TestFunctionWrapper 132 { 133 public: 134 typedef void (*CoreTestFunc)(NegativeTestContext& ctx); 135 typedef void (*DebugTestFunc)(DebugMessageTestContext& ctx); 136 137 TestFunctionWrapper (void); 138 explicit TestFunctionWrapper (CoreTestFunc func); 139 explicit TestFunctionWrapper (DebugTestFunc func); 140 141 void call (DebugMessageTestContext& ctx) const; 142 143 private: 144 enum FuncType 145 { 146 TYPE_NULL = 0, 147 TYPE_CORE, 148 TYPE_DEBUG, 149 }; 150 FuncType m_type; 151 152 union 153 { 154 CoreTestFunc coreFn; 155 DebugTestFunc debugFn; 156 } m_func; 157 }; 158 159 TestFunctionWrapper::TestFunctionWrapper (void) 160 : m_type(TYPE_NULL) 161 { 162 } 163 164 TestFunctionWrapper::TestFunctionWrapper (CoreTestFunc func) 165 : m_type(TYPE_CORE) 166 { 167 m_func.coreFn = func; 168 } 169 170 TestFunctionWrapper::TestFunctionWrapper (DebugTestFunc func) 171 : m_type(TYPE_DEBUG) 172 { 173 m_func.debugFn = func; 174 } 175 176 void TestFunctionWrapper::call (DebugMessageTestContext& ctx) const 177 { 178 if (m_type == TYPE_CORE) 179 m_func.coreFn(static_cast<NegativeTestContext&>(ctx)); 180 else if (m_type == TYPE_DEBUG) 181 m_func.debugFn(ctx); 182 else 183 DE_ASSERT(false); 184 } 185 186 void emitMessages (DebugMessageTestContext& ctx, GLenum source) 187 { 188 for (int typeNdx = 0; typeNdx < DE_LENGTH_OF_ARRAY(s_debugTypes); typeNdx++) 189 { 190 for (int severityNdx = 0; severityNdx < DE_LENGTH_OF_ARRAY(s_debugSeverities); severityNdx++) 191 { 192 const GLenum type = s_debugTypes[typeNdx]; 193 const GLenum severity = s_debugSeverities[severityNdx]; 194 const string msg = string("Application generated message with type ") + glu::getDebugMessageTypeName(type) 195 + " and severity " + glu::getDebugMessageSeverityName(severity); 196 197 // Use severity as ID, guaranteed unique 198 ctx.glDebugMessageInsert(source, type, severity, severity, -1, msg.c_str()); 199 ctx.expectMessage(source, type); 200 } 201 } 202 } 203 204 void application_messages (DebugMessageTestContext& ctx) 205 { 206 ctx.beginSection("Messages with source of GL_DEBUG_SOURCE_APPLICATION"); 207 emitMessages(ctx, GL_DEBUG_SOURCE_APPLICATION); 208 ctx.endSection(); 209 } 210 211 void thirdparty_messages (DebugMessageTestContext& ctx) 212 { 213 ctx.beginSection("Messages with source of GL_DEBUG_SOURCE_THIRD_PARTY"); 214 emitMessages(ctx, GL_DEBUG_SOURCE_THIRD_PARTY); 215 ctx.endSection(); 216 } 217 218 void push_pop_messages (DebugMessageTestContext& ctx) 219 { 220 ctx.beginSection("Push/Pop Debug Group"); 221 222 ctx.glPushDebugGroup(GL_DEBUG_SOURCE_APPLICATION, 1, -1, "Application group 1"); 223 ctx.expectMessage(GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_PUSH_GROUP); 224 ctx.glPushDebugGroup(GL_DEBUG_SOURCE_APPLICATION, 2, -1, "Application group 1-1"); 225 ctx.expectMessage(GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_PUSH_GROUP); 226 ctx.glPushDebugGroup(GL_DEBUG_SOURCE_APPLICATION, 3, -1, "Application group 1-1-1"); 227 ctx.expectMessage(GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_PUSH_GROUP); 228 ctx.glPopDebugGroup(); 229 ctx.expectMessage(GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_POP_GROUP); 230 ctx.glPopDebugGroup(); 231 ctx.expectMessage(GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_POP_GROUP); 232 233 ctx.glPushDebugGroup(GL_DEBUG_SOURCE_APPLICATION, 4, -1, "Application group 1-2"); 234 ctx.expectMessage(GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_PUSH_GROUP); 235 ctx.glPopDebugGroup(); 236 ctx.expectMessage(GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_POP_GROUP); 237 238 ctx.glPushDebugGroup(GL_DEBUG_SOURCE_THIRD_PARTY, 4, -1, "3rd Party group 1-3"); 239 ctx.expectMessage(GL_DEBUG_SOURCE_THIRD_PARTY, GL_DEBUG_TYPE_PUSH_GROUP); 240 ctx.glPopDebugGroup(); 241 ctx.expectMessage(GL_DEBUG_SOURCE_THIRD_PARTY, GL_DEBUG_TYPE_POP_GROUP); 242 ctx.glPopDebugGroup(); 243 ctx.expectMessage(GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_POP_GROUP); 244 245 ctx.glPushDebugGroup(GL_DEBUG_SOURCE_THIRD_PARTY, 4, -1, "3rd Party group 2"); 246 ctx.expectMessage(GL_DEBUG_SOURCE_THIRD_PARTY, GL_DEBUG_TYPE_PUSH_GROUP); 247 ctx.glPopDebugGroup(); 248 ctx.expectMessage(GL_DEBUG_SOURCE_THIRD_PARTY, GL_DEBUG_TYPE_POP_GROUP); 249 250 ctx.endSection(); 251 } 252 253 struct FunctionContainer 254 { 255 TestFunctionWrapper function; 256 const char* name; 257 const char* desc; 258 }; 259 260 vector<FunctionContainer> getUserMessageFuncs (void) 261 { 262 FunctionContainer funcs[] = 263 { 264 { TestFunctionWrapper(application_messages), "application_messages", "Externally generated messages from the application" }, 265 { TestFunctionWrapper(thirdparty_messages), "third_party_messages", "Externally generated messages from a third party" }, 266 { TestFunctionWrapper(push_pop_messages), "push_pop_stack", "Messages from pushing/popping debug groups" }, 267 }; 268 269 return std::vector<FunctionContainer>(DE_ARRAY_BEGIN(funcs), DE_ARRAY_END(funcs)); 270 } 271 272 // Data required to uniquely identify a debug message 273 struct MessageID 274 { 275 GLenum source; 276 GLenum type; 277 GLuint id; 278 279 MessageID (void) : source(GL_NONE), type(GL_NONE), id(0) {} 280 MessageID (GLenum source_, GLenum type_, GLuint id_) : source(source_), type(type_), id(id_) {} 281 282 bool operator== (const MessageID& rhs) const { return source == rhs.source && type == rhs.type && id == rhs.id;} 283 bool operator!= (const MessageID& rhs) const { return source != rhs.source || type != rhs.type || id != rhs.id;} 284 bool operator< (const MessageID& rhs) const 285 { 286 return source < rhs.source || (source == rhs.source && (type < rhs.type || (type == rhs.type && id < rhs.id))); 287 } 288 }; 289 290 std::ostream& operator<< (std::ostream& str, const MessageID &id) 291 { 292 return str << glu::getDebugMessageSourceStr(id.source) << ", " << glu::getDebugMessageTypeStr(id.type) << ", " << id.id; 293 } 294 295 // All info from a single debug message 296 struct MessageData 297 { 298 MessageID id; 299 GLenum severity; 300 string message; 301 302 MessageData (void) : id(MessageID()), severity(GL_NONE) {} 303 MessageData (const MessageID& id_, GLenum severity_, const string& message_) : id(id_) , severity(severity_) , message(message_) {} 304 }; 305 306 extern "C" typedef void GLW_APIENTRY DebugCallbackFunc(GLenum, GLenum, GLuint, GLenum, GLsizei, const char*, void*); 307 308 // Base class 309 class BaseCase : public NegativeTestShared::ErrorCase 310 { 311 public: 312 BaseCase (Context& ctx, 313 const char* name, 314 const char* desc); 315 virtual ~BaseCase (void) {} 316 317 virtual IterateResult iterate (void) = 0; 318 319 virtual void expectMessage (GLenum source, GLenum type); 320 virtual void expectError (GLenum error0, GLenum error1); 321 322 protected: 323 struct VerificationResult { 324 const qpTestResult result; 325 const string resultMessage; 326 const string logMessage; 327 328 VerificationResult (qpTestResult result_, const string& resultMessage_, const string& logMessage_) 329 : result(result_), resultMessage(resultMessage_), logMessage(logMessage_) {} 330 }; 331 332 static DebugCallbackFunc callbackHandle; 333 virtual void callback (GLenum source, GLenum type, GLuint id, GLenum severity, const std::string& message); 334 335 336 VerificationResult verifyMessageCount (const MessageID& id, GLenum severity, int refCount, int resCount, bool messageEnabled) const; 337 338 // Verify a single message instance against expected attributes 339 void verifyMessage (const MessageData& message, GLenum source, GLenum type, GLuint id, GLenum severity); 340 void verifyMessage (const MessageData& message, GLenum source, GLenum type); 341 342 bool verifyMessageExists (const MessageData& message, GLenum source, GLenum type); 343 void verifyMessageGroup (const MessageData& message, GLenum source, GLenum type); 344 void verifyMessageString (const MessageData& message); 345 346 bool isDebugContext (void) const; 347 348 tcu::ResultCollector m_results; 349 }; 350 351 void BaseCase::callbackHandle (GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const char* message, void* userParam) 352 { 353 static_cast<BaseCase*>(userParam)->callback(source, type, id, severity, string(message, &message[length])); 354 } 355 356 BaseCase::BaseCase (Context& ctx, const char* name, const char* desc) 357 : ErrorCase(ctx, name, desc) 358 { 359 } 360 361 void BaseCase::expectMessage (GLenum source, GLenum type) 362 { 363 DE_UNREF(source); 364 DE_UNREF(type); 365 } 366 367 void BaseCase::expectError (GLenum error0, GLenum error1) 368 { 369 if (error0 != GL_NO_ERROR || error1 != GL_NO_ERROR) 370 expectMessage(GL_DEBUG_SOURCE_API, GL_DEBUG_TYPE_ERROR); 371 else 372 expectMessage(GL_DONT_CARE, GL_DONT_CARE); 373 } 374 375 void BaseCase::callback (GLenum source, GLenum type, GLuint id, GLenum severity, const string& message) 376 { 377 DE_UNREF(source); 378 DE_UNREF(type); 379 DE_UNREF(id); 380 DE_UNREF(severity); 381 DE_UNREF(message); 382 } 383 384 BaseCase::VerificationResult BaseCase::verifyMessageCount (const MessageID& id, GLenum severity, int refCount, int resCount, bool messageEnabled) const 385 { 386 std::stringstream log; 387 388 // This message should not be filtered out 389 if (messageEnabled) 390 { 391 if (resCount != refCount) 392 { 393 /* 394 * Technically nothing requires the implementation to be consistent in terms 395 * of the messages it produces in most situations, allowing the set of messages 396 * produced to vary between executions. This function splits messages 397 * into deterministic and non-deterministic to facilitate handling of such messages. 398 * 399 * Non-deterministic messages that are present in differing quantities in filtered and 400 * unfiltered runs will not fail the test case unless in direct violation of a filter: 401 * the implementation may produce an arbitrary number of such messages when they are 402 * not filtered out and none when they are filtered. 403 * 404 * A list of error source/type combinations with their assumed behaviour and 405 * the rationale for expecting such behaviour follows 406 * 407 * For API/shader messages we assume that the following types are deterministic: 408 * DEBUG_TYPE_ERROR Errors specified by spec and should always be produced 409 * 410 * For API messages the following types are assumed to be non-deterministic 411 * and treated as quality warnings since the underlying reported issue does not change between calls: 412 * DEBUG_TYPE_DEPRECATED_BEHAVIOR Reasonable to only report first instance 413 * DEBUG_TYPE_UNDEFINED_BEHAVIOR Reasonable to only report first instance 414 * DEBUG_TYPE_PORTABILITY Reasonable to only report first instance 415 * 416 * For API messages the following types are assumed to be non-deterministic 417 * and do not affect test results. 418 * DEBUG_TYPE_PERFORMANCE May be tied to arbitrary factors, reasonable to report only first instance 419 * DEBUG_TYPE_OTHER Definition allows arbitrary contents 420 * 421 * For 3rd party and application messages the following types are deterministic: 422 * DEBUG_TYPE_MARKER Only generated by test 423 * DEBUG_TYPE_PUSH_GROUP Only generated by test 424 * DEBUG_TYPE_POP_GROUP Only generated by test 425 * All others Only generated by test 426 * 427 * All messages with category of window system or other are treated as non-deterministic 428 * and do not effect test results since they can be assumed to be outside control of 429 * both the implementation and test case 430 * 431 */ 432 433 const bool isDeterministic = id.source == GL_DEBUG_SOURCE_APPLICATION || 434 id.source == GL_DEBUG_SOURCE_THIRD_PARTY || 435 ((id.source == GL_DEBUG_SOURCE_API || id.source == GL_DEBUG_SOURCE_SHADER_COMPILER) && id.type == GL_DEBUG_TYPE_ERROR); 436 437 const bool canIgnore = id.source == GL_DEBUG_SOURCE_WINDOW_SYSTEM || id.source == GL_DEBUG_SOURCE_OTHER; 438 439 if (isDeterministic) 440 { 441 if (resCount > refCount) 442 { 443 log << "Extra instances of message were found: (" << id << ") with " 444 << glu::getDebugMessageSeverityStr(severity) 445 << " (got " << resCount << ", expected " << refCount << ")"; 446 return VerificationResult(QP_TEST_RESULT_FAIL, "Extra instances of a deterministic message were present", log.str()); 447 } 448 else 449 { 450 log << "Instances of message were missing: (" << id << ") with " 451 << glu::getDebugMessageSeverityStr(severity) 452 << " (got " << resCount << ", expected " << refCount << ")"; 453 return VerificationResult(QP_TEST_RESULT_FAIL, "Message missing", log.str()); 454 } 455 } 456 else if(!canIgnore) 457 { 458 if (resCount > refCount) 459 { 460 log << "Extra instances of message were found but the message is non-deterministic(warning): (" << id << ") with " 461 << glu::getDebugMessageSeverityStr(severity) 462 << " (got " << resCount << ", expected " << refCount << ")"; 463 return VerificationResult(QP_TEST_RESULT_QUALITY_WARNING, "Extra instances of a message were present", log.str()); 464 } 465 else 466 { 467 log << "Instances of message were missing but the message is non-deterministic(warning): (" << id << ") with " 468 << glu::getDebugMessageSeverityStr(severity) 469 << " (got " << resCount << ", expected " << refCount << ")"; 470 return VerificationResult(QP_TEST_RESULT_QUALITY_WARNING, "Message missing", log.str()); 471 } 472 } 473 else 474 { 475 if (resCount > refCount) 476 { 477 log << "Extra instances of message were found but the message is non-deterministic(ignored): (" << id << ") with " 478 << glu::getDebugMessageSeverityStr(severity) 479 << " (got " << resCount << ", expected " << refCount << ")"; 480 return VerificationResult(QP_TEST_RESULT_PASS, "", log.str()); 481 } 482 else 483 { 484 log << "Instances of message were missing but the message is non-deterministic(ignored): (" << id << ") with " 485 << glu::getDebugMessageSeverityStr(severity) 486 << " (got " << resCount << ", expected " << refCount << ")"; 487 return VerificationResult(QP_TEST_RESULT_PASS, "", log.str()); 488 } 489 } 490 } 491 else // Passed as appropriate 492 { 493 log << "Message was found when expected: ("<< id << ") with " 494 << glu::getDebugMessageSeverityStr(severity); 495 return VerificationResult(QP_TEST_RESULT_PASS, "", log.str()); 496 } 497 } 498 // Message should be filtered out 499 else 500 { 501 // Filtered out 502 if (resCount == 0) 503 { 504 log << "Message was excluded correctly: (" << id << ") with " 505 << glu::getDebugMessageSeverityStr(severity); 506 return VerificationResult(QP_TEST_RESULT_PASS, "", log.str()); 507 } 508 // Only present in filtered run (ERROR) 509 else if (resCount > 0 && refCount == 0) 510 { 511 log << "A message was not excluded as it should have been: (" << id << ") with " 512 << glu::getDebugMessageSeverityStr(severity) 513 << ". This message was not present in the reference run"; 514 return VerificationResult(QP_TEST_RESULT_FAIL, "A message was not filtered out", log.str()); 515 } 516 // Present in both runs (ERROR) 517 else 518 { 519 log << "A message was not excluded as it should have been: (" << id << ") with " 520 << glu::getDebugMessageSeverityStr(severity); 521 return VerificationResult(QP_TEST_RESULT_FAIL, "A message was not filtered out", log.str()); 522 } 523 } 524 } 525 526 // Return true if message needs further verification 527 bool BaseCase::verifyMessageExists (const MessageData& message, GLenum source, GLenum type) 528 { 529 TestLog& log = m_testCtx.getLog(); 530 531 if (source == GL_DONT_CARE || type == GL_DONT_CARE) 532 return false; 533 else if (message.id.source == GL_NONE || message.id.type == GL_NONE) 534 { 535 if (isDebugContext()) 536 { 537 m_results.addResult(QP_TEST_RESULT_FAIL, "Message was not reported as expected"); 538 log << TestLog::Message << "A message was expected but none was reported" << TestLog::EndMessage; 539 } 540 else 541 { 542 m_results.addResult(QP_TEST_RESULT_QUALITY_WARNING, "Verification accuracy is lacking without a debug context"); 543 log << TestLog::Message << "A message was expected but none was reported. Running without a debug context" << TestLog::EndMessage; 544 } 545 return false; 546 } 547 else 548 return true; 549 } 550 551 void BaseCase::verifyMessageGroup (const MessageData& message, GLenum source, GLenum type) 552 { 553 TestLog& log = m_testCtx.getLog(); 554 555 if (message.id.source != source) 556 { 557 m_results.addResult(QP_TEST_RESULT_FAIL, "Incorrect message source"); 558 log << TestLog::Message << "Message source was " << glu::getDebugMessageSourceStr(message.id.source) 559 << " when it should have been " << glu::getDebugMessageSourceStr(source) << TestLog::EndMessage; 560 } 561 562 if (message.id.type != type) 563 { 564 m_results.addResult(QP_TEST_RESULT_FAIL, "Incorrect message type"); 565 log << TestLog::Message << "Message type was " << glu::getDebugMessageTypeStr(message.id.type) 566 << " when it should have been " << glu::getDebugMessageTypeStr(type) << TestLog::EndMessage; 567 } 568 } 569 570 void BaseCase::verifyMessageString (const MessageData& message) 571 { 572 TestLog& log = m_testCtx.getLog(); 573 574 log << TestLog::Message << "Driver says: \"" << message.message << "\"" << TestLog::EndMessage; 575 576 if (message.message.empty()) 577 { 578 m_results.addResult(QP_TEST_RESULT_QUALITY_WARNING, "Empty message"); 579 log << TestLog::Message << "Message message was empty" << TestLog::EndMessage; 580 } 581 } 582 583 void BaseCase::verifyMessage (const MessageData& message, GLenum source, GLenum type) 584 { 585 if (verifyMessageExists(message, source, type)) 586 { 587 verifyMessageString(message); 588 verifyMessageGroup(message, source, type); 589 } 590 } 591 592 void BaseCase::verifyMessage (const MessageData& message, GLenum source, GLenum type, GLuint id, GLenum severity) 593 { 594 TestLog& log = m_testCtx.getLog(); 595 596 if (verifyMessageExists(message, source, type)) 597 { 598 verifyMessageString(message); 599 verifyMessageGroup(message, source, type); 600 601 if (message.id.id != id) 602 { 603 m_results.addResult(QP_TEST_RESULT_FAIL, "Incorrect message id"); 604 log << TestLog::Message << "Message id was " << message.id.id 605 << " when it should have been " << id << TestLog::EndMessage; 606 } 607 608 if (message.severity != severity) 609 { 610 m_results.addResult(QP_TEST_RESULT_FAIL, "Incorrect message severity"); 611 log << TestLog::Message << "Message severity was " << glu::getDebugMessageSeverityStr(message.severity) 612 << " when it should have been " << glu::getDebugMessageSeverityStr(severity) << TestLog::EndMessage; 613 } 614 } 615 } 616 617 bool BaseCase::isDebugContext (void) const 618 { 619 return (m_context.getRenderContext().getType().getFlags() & glu::CONTEXT_DEBUG) != 0; 620 } 621 622 // Generate errors, verify that each error results in a callback call 623 class CallbackErrorCase : public BaseCase 624 { 625 public: 626 CallbackErrorCase (Context& ctx, 627 const char* name, 628 const char* desc, 629 TestFunctionWrapper errorFunc); 630 virtual ~CallbackErrorCase (void) {} 631 632 virtual IterateResult iterate (void); 633 634 virtual void expectMessage (GLenum source, GLenum type); 635 636 private: 637 virtual void callback (GLenum source, GLenum type, GLuint id, GLenum severity, const string& message); 638 639 const TestFunctionWrapper m_errorFunc; 640 MessageData m_lastMessage; 641 }; 642 643 CallbackErrorCase::CallbackErrorCase (Context& ctx, 644 const char* name, 645 const char* desc, 646 TestFunctionWrapper errorFunc) 647 : BaseCase (ctx, name, desc) 648 , m_errorFunc (errorFunc) 649 { 650 } 651 652 CallbackErrorCase::IterateResult CallbackErrorCase::iterate (void) 653 { 654 TCU_CHECK_AND_THROW(NotSupportedError, isKHRDebugSupported(m_context), "GL_KHR_debug is not supported"); 655 656 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 657 tcu::TestLog& log = m_testCtx.getLog(); 658 DebugMessageTestContext context = DebugMessageTestContext(*this, m_context.getRenderContext(), m_context.getContextInfo(), log, m_results, true); 659 660 gl.enable(GL_DEBUG_OUTPUT); 661 gl.enable(GL_DEBUG_OUTPUT_SYNCHRONOUS); 662 gl.debugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, DE_NULL, false); // disable all 663 gl.debugMessageControl(GL_DEBUG_SOURCE_API, GL_DEBUG_TYPE_ERROR, GL_DONT_CARE, 0, DE_NULL, true); // enable API errors 664 gl.debugMessageControl(GL_DEBUG_SOURCE_APPLICATION, GL_DONT_CARE, GL_DONT_CARE, 0, DE_NULL, true); // enable application messages 665 gl.debugMessageControl(GL_DEBUG_SOURCE_THIRD_PARTY, GL_DONT_CARE, GL_DONT_CARE, 0, DE_NULL, true); // enable third party messages 666 gl.debugMessageCallback(callbackHandle, this); 667 668 m_errorFunc.call(context); 669 670 gl.debugMessageCallback(DE_NULL, DE_NULL); 671 gl.disable(GL_DEBUG_OUTPUT); 672 673 m_results.setTestContextResult(m_testCtx); 674 675 return STOP; 676 } 677 678 void CallbackErrorCase::expectMessage (GLenum source, GLenum type) 679 { 680 verifyMessage(m_lastMessage, source, type); 681 m_lastMessage = MessageData(); 682 683 // Reset error so that code afterwards (such as glu::ShaderProgram) doesn't break because of 684 // lingering error state. 685 m_context.getRenderContext().getFunctions().getError(); 686 } 687 688 void CallbackErrorCase::callback (GLenum source, GLenum type, GLuint id, GLenum severity, const string& message) 689 { 690 m_lastMessage = MessageData(MessageID(source, type, id), severity, message); 691 } 692 693 // Generate errors, verify that each error results in a log entry 694 class LogErrorCase : public BaseCase 695 { 696 public: 697 LogErrorCase (Context& context, 698 const char* name, 699 const char* desc, 700 TestFunctionWrapper errorFunc); 701 virtual ~LogErrorCase (void) {} 702 703 virtual IterateResult iterate (void); 704 705 virtual void expectMessage (GLenum source, GLenum type); 706 707 private: 708 const TestFunctionWrapper m_errorFunc; 709 MessageData m_lastMessage; 710 }; 711 712 LogErrorCase::LogErrorCase (Context& ctx, 713 const char* name, 714 const char* desc, 715 TestFunctionWrapper errorFunc) 716 : BaseCase (ctx, name, desc) 717 , m_errorFunc (errorFunc) 718 { 719 } 720 721 LogErrorCase::IterateResult LogErrorCase::iterate (void) 722 { 723 TCU_CHECK_AND_THROW(NotSupportedError, isKHRDebugSupported(m_context), "GL_KHR_debug is not supported"); 724 725 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 726 tcu::TestLog& log = m_testCtx.getLog(); 727 DebugMessageTestContext context = DebugMessageTestContext(*this, m_context.getRenderContext(), m_context.getContextInfo(), log, m_results, true); 728 GLint numMsg = 0; 729 730 gl.enable(GL_DEBUG_OUTPUT); 731 gl.enable(GL_DEBUG_OUTPUT_SYNCHRONOUS); 732 gl.debugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, DE_NULL, false); // disable all 733 gl.debugMessageControl(GL_DEBUG_SOURCE_API, GL_DEBUG_TYPE_ERROR, GL_DONT_CARE, 0, DE_NULL, true); // enable API errors 734 gl.debugMessageCallback(DE_NULL, DE_NULL); // enable logging 735 gl.getIntegerv(GL_DEBUG_LOGGED_MESSAGES, &numMsg); 736 gl.getDebugMessageLog(numMsg, 0, DE_NULL, DE_NULL, DE_NULL, DE_NULL, DE_NULL, DE_NULL); // clear log 737 738 m_errorFunc.call(context); 739 740 gl.disable(GL_DEBUG_OUTPUT); 741 m_results.setTestContextResult(m_testCtx); 742 743 return STOP; 744 } 745 746 void LogErrorCase::expectMessage (GLenum source, GLenum type) 747 { 748 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 749 int numMsg = 0; 750 TestLog& log = m_testCtx.getLog(); 751 MessageData lastMsg; 752 753 if (source == GL_DONT_CARE || type == GL_DONT_CARE) 754 return; 755 756 gl.getIntegerv(GL_DEBUG_LOGGED_MESSAGES, &numMsg); 757 758 if (numMsg == 0) 759 { 760 if (isDebugContext()) 761 { 762 m_results.addResult(QP_TEST_RESULT_FAIL, "Error was not reported as expected"); 763 log << TestLog::Message << "A message was expected but none was reported (empty message log)" << TestLog::EndMessage; 764 } 765 else 766 { 767 m_results.addResult(QP_TEST_RESULT_QUALITY_WARNING, "Verification accuracy is lacking without a debug context"); 768 log << TestLog::Message << "A message was expected but none was reported (empty message log). Running without a debug context" << TestLog::EndMessage; 769 } 770 return; 771 } 772 773 // There may be messages other than the error we are looking for in the log. 774 // Strictly nothing prevents the implementation from producing more than the 775 // required error from an API call with a defined error. however we assume that 776 // since calls that produce an error should not change GL state the implementation 777 // should have nothing else to report. 778 if (numMsg > 1) 779 gl.getDebugMessageLog(numMsg-1, 0, DE_NULL, DE_NULL, DE_NULL, DE_NULL, DE_NULL, DE_NULL); // Clear all but last 780 781 { 782 int msgLen = 0; 783 gl.getIntegerv(GL_DEBUG_NEXT_LOGGED_MESSAGE_LENGTH, &msgLen); 784 785 TCU_CHECK_MSG(msgLen >= 0, "Negative message length"); 786 TCU_CHECK_MSG(msgLen < 100000, "Excessively long message"); 787 788 lastMsg.message.resize(msgLen); 789 gl.getDebugMessageLog(1, msgLen, &lastMsg.id.source, &lastMsg.id.type, &lastMsg.id.id, &lastMsg.severity, &msgLen, &lastMsg.message[0]); 790 } 791 792 log << TestLog::Message << "Driver says: \"" << lastMsg.message << "\"" << TestLog::EndMessage; 793 794 verifyMessage(lastMsg, source, type); 795 796 // Reset error so that code afterwards (such as glu::ShaderProgram) doesn't break because of 797 // lingering error state. 798 m_context.getRenderContext().getFunctions().getError(); 799 } 800 801 // Generate errors, verify that calling glGetError afterwards produces desired result 802 class GetErrorCase : public BaseCase 803 { 804 public: 805 GetErrorCase (Context& ctx, 806 const char* name, 807 const char* desc, 808 TestFunctionWrapper errorFunc); 809 virtual ~GetErrorCase (void) {} 810 811 virtual IterateResult iterate (void); 812 813 virtual void expectMessage (GLenum source, GLenum type); 814 virtual void expectError (glw::GLenum error0, glw::GLenum error1); 815 816 private: 817 const TestFunctionWrapper m_errorFunc; 818 }; 819 820 GetErrorCase::GetErrorCase (Context& ctx, 821 const char* name, 822 const char* desc, 823 TestFunctionWrapper errorFunc) 824 : BaseCase (ctx, name, desc) 825 , m_errorFunc (errorFunc) 826 { 827 } 828 829 GetErrorCase::IterateResult GetErrorCase::iterate (void) 830 { 831 tcu::TestLog& log = m_testCtx.getLog(); 832 DebugMessageTestContext context = DebugMessageTestContext(*this, m_context.getRenderContext(), m_context.getContextInfo(), log, m_results, true); 833 834 m_errorFunc.call(context); 835 836 m_results.setTestContextResult(m_testCtx); 837 838 return STOP; 839 } 840 841 void GetErrorCase::expectMessage (GLenum source, GLenum type) 842 { 843 DE_UNREF(source); 844 DE_UNREF(type); 845 DE_FATAL("GetErrorCase cannot handle anything other than error codes"); 846 } 847 848 void GetErrorCase::expectError (glw::GLenum error0, glw::GLenum error1) 849 { 850 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 851 TestLog& log = m_testCtx.getLog(); 852 853 const GLenum result = gl.getError(); 854 855 if (result != error0 && result != error1) 856 { 857 m_results.addResult(QP_TEST_RESULT_FAIL, "Incorrect error was reported"); 858 if (error0 == error1) 859 log << TestLog::Message 860 << glu::getErrorStr(error0) << " was expected but got " 861 << glu::getErrorStr(result) 862 << TestLog::EndMessage; 863 else 864 log << TestLog::Message 865 << glu::getErrorStr(error0) << " or " 866 << glu::getErrorStr(error1) << " was expected but got " 867 << glu::getErrorStr(result) 868 << TestLog::EndMessage; 869 return; 870 } 871 } 872 873 // Generate errors, log the types, disable some, regenerate errors, verify correct errors (not)reported 874 class FilterCase : public BaseCase 875 { 876 public: 877 FilterCase (Context& ctx, 878 const char* name, 879 const char* desc, 880 const vector<TestFunctionWrapper>& errorFuncs); 881 virtual ~FilterCase (void) {} 882 883 virtual IterateResult iterate (void); 884 885 virtual void expectMessage (GLenum source, GLenum type); 886 887 protected: 888 struct MessageFilter 889 { 890 MessageFilter() : source(GL_DONT_CARE), type(GL_DONT_CARE), severity(GL_DONT_CARE), enabled(true) {} // Default to enable all 891 MessageFilter(GLenum source_, GLenum type_, GLenum severity_, const vector<GLuint>& ids_, bool enabled_) : source(source_), type(type_), severity(severity_), ids(ids_), enabled(enabled_) {} 892 893 GLenum source; 894 GLenum type; 895 GLenum severity; 896 vector<GLuint> ids; 897 bool enabled; 898 }; 899 900 virtual void callback (GLenum source, GLenum type, GLuint id, GLenum severity, const string& message); 901 902 vector<MessageData> genMessages (bool uselog, const string& desc); 903 904 vector<MessageFilter> genFilters (const vector<MessageData>& messages, const vector<MessageFilter>& initial, deUint32 seed, int iterations) const; 905 void applyFilters (const vector<MessageFilter>& filters) const; 906 bool isEnabled (const vector<MessageFilter>& filters, const MessageData& message) const; 907 908 void verify (const vector<MessageData>& refMessages, 909 const vector<MessageData>& filteredMessages, 910 const vector<MessageFilter>& filters); 911 912 const vector<TestFunctionWrapper> m_errorFuncs; 913 914 vector<MessageData>* m_currentErrors; 915 }; 916 917 FilterCase::FilterCase (Context& ctx, 918 const char* name, 919 const char* desc, 920 const vector<TestFunctionWrapper>& errorFuncs) 921 : BaseCase (ctx, name, desc) 922 , m_errorFuncs (errorFuncs) 923 , m_currentErrors (DE_NULL) 924 { 925 } 926 927 FilterCase::IterateResult FilterCase::iterate (void) 928 { 929 TCU_CHECK_AND_THROW(NotSupportedError, isKHRDebugSupported(m_context), "GL_KHR_debug is not supported"); 930 931 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 932 933 gl.enable(GL_DEBUG_OUTPUT); 934 gl.enable(GL_DEBUG_OUTPUT_SYNCHRONOUS); 935 gl.debugMessageCallback(callbackHandle, this); 936 937 try 938 { 939 gl.debugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, DE_NULL, true); 940 941 { 942 const vector<MessageData> refMessages = genMessages(true, "Reference run"); 943 const MessageFilter baseFilter (GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, vector<GLuint>(), true); 944 const deUint32 baseSeed = deStringHash(getName()) ^ m_testCtx.getCommandLine().getBaseSeed(); 945 const vector<MessageFilter> filters = genFilters(refMessages, vector<MessageFilter>(1, baseFilter), baseSeed, 4); 946 vector<MessageData> filteredMessages; 947 948 applyFilters(filters); 949 950 // Generate errors 951 filteredMessages = genMessages(false, "Filtered run"); 952 953 // Verify 954 verify(refMessages, filteredMessages, filters); 955 956 if (!isDebugContext() && refMessages.empty()) 957 m_results.addResult(QP_TEST_RESULT_QUALITY_WARNING, "Verification accuracy is lacking without a debug context"); 958 } 959 } 960 catch (...) 961 { 962 gl.disable(GL_DEBUG_OUTPUT); 963 gl.debugMessageCallback(DE_NULL, DE_NULL); 964 throw; 965 } 966 967 gl.disable(GL_DEBUG_OUTPUT); 968 gl.debugMessageCallback(DE_NULL, DE_NULL); 969 m_results.setTestContextResult(m_testCtx); 970 971 return STOP; 972 } 973 974 void FilterCase::expectMessage (GLenum source, GLenum type) 975 { 976 DE_UNREF(source); 977 DE_UNREF(type); 978 } 979 980 void FilterCase::callback (GLenum source, GLenum type, GLuint id, GLenum severity, const string& message) 981 { 982 if (m_currentErrors) 983 m_currentErrors->push_back(MessageData(MessageID(source, type, id), severity, message)); 984 } 985 986 vector<MessageData> FilterCase::genMessages (bool uselog, const string& desc) 987 { 988 tcu::TestLog& log = m_testCtx.getLog(); 989 DebugMessageTestContext context = DebugMessageTestContext(*this, m_context.getRenderContext(), m_context.getContextInfo(), log, m_results, uselog); 990 tcu::ScopedLogSection section (log, "message gen", desc); 991 vector<MessageData> messages; 992 993 m_currentErrors = &messages; 994 995 for (int ndx = 0; ndx < int(m_errorFuncs.size()); ndx++) 996 m_errorFuncs[ndx].call(context); 997 998 m_currentErrors = DE_NULL; 999 1000 return messages; 1001 } 1002 1003 vector<FilterCase::MessageFilter> FilterCase::genFilters (const vector<MessageData>& messages, const vector<MessageFilter>& initial, deUint32 seed, int iterations) const 1004 { 1005 de::Random rng (seed ^ deInt32Hash(deStringHash(getName()))); 1006 1007 set<MessageID> tempMessageIds; 1008 set<GLenum> tempSources; 1009 set<GLenum> tempTypes; 1010 set<GLenum> tempSeverities; 1011 1012 if (messages.empty()) 1013 return initial; 1014 1015 for (int ndx = 0; ndx < int(messages.size()); ndx++) 1016 { 1017 const MessageData& msg = messages[ndx]; 1018 1019 tempMessageIds.insert(msg.id); 1020 tempSources.insert(msg.id.source); 1021 tempTypes.insert(msg.id.type); 1022 tempSeverities.insert(msg.severity); 1023 } 1024 1025 { 1026 // Fetchable by index 1027 const vector<MessageID> messageIds (tempMessageIds.begin(), tempMessageIds.end()); 1028 const vector<GLenum> sources (tempSources.begin(), tempSources.end()); 1029 const vector<GLenum> types (tempTypes.begin(), tempTypes.end()); 1030 const vector<GLenum> severities (tempSeverities.begin(), tempSeverities.end()); 1031 1032 vector<MessageFilter> filters = initial; 1033 1034 for (int iteration = 0; iteration < iterations; iteration++) 1035 { 1036 switch(rng.getInt(0, 8)) // Distribute so that per-message randomization (the default branch) is prevalent 1037 { 1038 case 0: 1039 { 1040 const GLenum source = sources[rng.getInt(0, int(sources.size()-1))]; 1041 const bool enabled = rng.getBool(); 1042 1043 filters.push_back(MessageFilter(source, GL_DONT_CARE, GL_DONT_CARE, vector<GLuint>(), enabled)); 1044 break; 1045 } 1046 1047 case 1: 1048 { 1049 const GLenum type = types[rng.getUint32()%types.size()]; 1050 const bool enabled = rng.getBool(); 1051 1052 filters.push_back(MessageFilter(GL_DONT_CARE, type, GL_DONT_CARE, vector<GLuint>(), enabled)); 1053 break; 1054 } 1055 1056 case 2: 1057 { 1058 const GLenum severity = severities[rng.getUint32()%severities.size()]; 1059 const bool enabled = rng.getBool(); 1060 1061 filters.push_back(MessageFilter(GL_DONT_CARE, GL_DONT_CARE, severity, vector<GLuint>(), enabled)); 1062 break; 1063 } 1064 1065 default: 1066 { 1067 const int start = rng.getInt(0, int(messageIds.size())); 1068 1069 for (int itr = 0; itr < 4; itr++) 1070 { 1071 const MessageID& id = messageIds[(start+itr)%messageIds.size()]; 1072 const bool enabled = rng.getBool(); 1073 1074 filters.push_back(MessageFilter(id.source, id.type, GL_DONT_CARE, vector<GLuint>(1, id.id), enabled)); 1075 } 1076 } 1077 } 1078 } 1079 1080 return filters; 1081 } 1082 } 1083 1084 void FilterCase::applyFilters (const vector<MessageFilter>& filters) const 1085 { 1086 TestLog& log = m_testCtx.getLog(); 1087 const tcu::ScopedLogSection section (log, "", "Setting message filters"); 1088 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 1089 1090 for (size_t filterNdx = 0; filterNdx < filters.size(); filterNdx++) 1091 { 1092 const MessageFilter& filter = filters[filterNdx]; 1093 1094 if (filter.ids.empty()) 1095 log << TestLog::Message << "Setting messages with" 1096 << " source " << glu::getDebugMessageSourceStr(filter.source) 1097 << ", type " << glu::getDebugMessageTypeStr(filter.type) 1098 << " and severity " << glu::getDebugMessageSeverityStr(filter.severity) 1099 << (filter.enabled ? " to enabled" : " to disabled") 1100 << TestLog::EndMessage; 1101 else 1102 { 1103 for (size_t ndx = 0; ndx < filter.ids.size(); ndx++) 1104 log << TestLog::Message << "Setting message (" << MessageID(filter.source, filter.type, filter.ids[ndx]) << ") to " << (filter.enabled ? "enabled" : "disabled") << TestLog::EndMessage; 1105 } 1106 1107 gl.debugMessageControl(filter.source, filter.type, filter.severity, GLsizei(filter.ids.size()), filter.ids.empty() ? DE_NULL : &filter.ids[0], filter.enabled); 1108 } 1109 } 1110 1111 bool FilterCase::isEnabled (const vector<MessageFilter>& filters, const MessageData& message) const 1112 { 1113 bool retval = true; 1114 1115 for (size_t filterNdx = 0; filterNdx < filters.size(); filterNdx++) 1116 { 1117 const MessageFilter& filter = filters[filterNdx]; 1118 1119 if (filter.ids.empty()) 1120 { 1121 if (filter.source != GL_DONT_CARE && filter.source != message.id.source) 1122 continue; 1123 1124 if (filter.type != GL_DONT_CARE && filter.type != message.id.type) 1125 continue; 1126 1127 if (filter.severity != GL_DONT_CARE && filter.severity != message.severity) 1128 continue; 1129 } 1130 else 1131 { 1132 DE_ASSERT(filter.source != GL_DONT_CARE); 1133 DE_ASSERT(filter.type != GL_DONT_CARE); 1134 DE_ASSERT(filter.severity == GL_DONT_CARE); 1135 1136 if (filter.source != message.id.source || filter.type != message.id.type) 1137 continue; 1138 1139 if (!de::contains(filter.ids.begin(), filter.ids.end(), message.id.id)) 1140 continue; 1141 } 1142 1143 retval = filter.enabled; 1144 } 1145 1146 return retval; 1147 } 1148 1149 struct MessageMeta 1150 { 1151 int refCount; 1152 int resCount; 1153 GLenum severity; 1154 1155 MessageMeta (void) : refCount(0), resCount(0), severity(GL_NONE) {} 1156 }; 1157 1158 void FilterCase::verify (const vector<MessageData>& refMessages, const vector<MessageData>& resMessages, const vector<MessageFilter>& filters) 1159 { 1160 TestLog& log = m_testCtx.getLog(); 1161 map<MessageID, MessageMeta> counts; 1162 1163 log << TestLog::Section("verification", "Verifying"); 1164 1165 // Gather message counts & severities, report severity mismatches if found 1166 for (size_t refNdx = 0; refNdx < refMessages.size(); refNdx++) 1167 { 1168 const MessageData& msg = refMessages[refNdx]; 1169 MessageMeta& meta = counts[msg.id]; 1170 1171 if (meta.severity != GL_NONE && meta.severity != msg.severity) 1172 { 1173 log << TestLog::Message << "A message has variable severity between instances: (" << msg.id << ") with severity " 1174 << glu::getDebugMessageSeverityStr(meta.severity) << " and " << glu::getDebugMessageSeverityStr(msg.severity) << TestLog::EndMessage; 1175 m_results.addResult(QP_TEST_RESULT_FAIL, "Message severity changed between instances of the same message"); 1176 } 1177 1178 meta.refCount++; 1179 meta.severity = msg.severity; 1180 } 1181 1182 for (size_t resNdx = 0; resNdx < resMessages.size(); resNdx++) 1183 { 1184 const MessageData& msg = resMessages[resNdx]; 1185 MessageMeta& meta = counts[msg.id]; 1186 1187 if (meta.severity != GL_NONE && meta.severity != msg.severity) 1188 { 1189 log << TestLog::Message << "A message has variable severity between instances: (" << msg.id << ") with severity " 1190 << glu::getDebugMessageSeverityStr(meta.severity) << " and " << glu::getDebugMessageSeverityStr(msg.severity) << TestLog::EndMessage; 1191 m_results.addResult(QP_TEST_RESULT_FAIL, "Message severity changed between instances of the same message"); 1192 } 1193 1194 meta.resCount++; 1195 meta.severity = msg.severity; 1196 } 1197 1198 for (map<MessageID, MessageMeta>::const_iterator itr = counts.begin(); itr != counts.end(); itr++) 1199 { 1200 const MessageID& id = itr->first; 1201 const GLenum severity = itr->second.severity; 1202 1203 const int refCount = itr->second.refCount; 1204 const int resCount = itr->second.resCount; 1205 const bool enabled = isEnabled(filters, MessageData(id, severity, "")); 1206 1207 VerificationResult result = verifyMessageCount(id, severity, refCount, resCount, enabled); 1208 1209 log << TestLog::Message << result.logMessage << TestLog::EndMessage; 1210 1211 if (result.result != QP_TEST_RESULT_PASS) 1212 m_results.addResult(result.result, result.resultMessage); 1213 } 1214 1215 log << TestLog::EndSection; 1216 } 1217 1218 // Filter case that uses debug groups 1219 class GroupFilterCase : public FilterCase 1220 { 1221 public: 1222 GroupFilterCase (Context& ctx, 1223 const char* name, 1224 const char* desc, 1225 const vector<TestFunctionWrapper>& errorFuncs); 1226 virtual ~GroupFilterCase (void) {} 1227 1228 virtual IterateResult iterate (void); 1229 }; 1230 1231 GroupFilterCase::GroupFilterCase (Context& ctx, 1232 const char* name, 1233 const char* desc, 1234 const vector<TestFunctionWrapper>& errorFuncs) 1235 : FilterCase(ctx, name, desc, errorFuncs) 1236 { 1237 } 1238 1239 template<typename T> 1240 vector<T> join(const vector<T>& a, const vector<T>&b) 1241 { 1242 vector<T> retval; 1243 1244 retval.reserve(a.size()+b.size()); 1245 retval.insert(retval.end(), a.begin(), a.end()); 1246 retval.insert(retval.end(), b.begin(), b.end()); 1247 return retval; 1248 } 1249 1250 GroupFilterCase::IterateResult GroupFilterCase::iterate (void) 1251 { 1252 TCU_CHECK_AND_THROW(NotSupportedError, isKHRDebugSupported(m_context), "GL_KHR_debug is not supported"); 1253 1254 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 1255 tcu::TestLog& log = m_testCtx.getLog(); 1256 1257 gl.enable(GL_DEBUG_OUTPUT); 1258 gl.enable(GL_DEBUG_OUTPUT_SYNCHRONOUS); 1259 gl.debugMessageCallback(callbackHandle, this); 1260 1261 try 1262 { 1263 gl.debugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, DE_NULL, true); 1264 1265 { 1266 1267 // Generate reference (all errors) 1268 const vector<MessageData> refMessages = genMessages(true, "Reference run"); 1269 const deUint32 baseSeed = deStringHash(getName()) ^ m_testCtx.getCommandLine().getBaseSeed(); 1270 const MessageFilter baseFilter (GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, vector<GLuint>(), true); 1271 const vector<MessageFilter> filter0 = genFilters(refMessages, vector<MessageFilter>(1, baseFilter), baseSeed, 4); 1272 vector<MessageData> resMessages0; 1273 1274 applyFilters(filter0); 1275 1276 resMessages0 = genMessages(false, "Filtered run, default debug group"); 1277 1278 // Initial verification 1279 verify(refMessages, resMessages0, filter0); 1280 1281 { 1282 // Generate reference (filters inherited from parent) 1283 const vector<MessageFilter> filter1base = genFilters(refMessages, vector<MessageFilter>(), baseSeed ^ 0xDEADBEEF, 4); 1284 const vector<MessageFilter> filter1full = join(filter0, filter1base); 1285 tcu::ScopedLogSection section1 (log, "", "Pushing Debug Group"); 1286 vector<MessageData> resMessages1; 1287 1288 gl.pushDebugGroup(GL_DEBUG_SOURCE_APPLICATION, 1, -1, "Test Group"); 1289 applyFilters(filter1base); 1290 1291 // First nested verification 1292 resMessages1 = genMessages(false, "Filtered run, pushed one debug group"); 1293 verify(refMessages, resMessages1, filter1full); 1294 1295 { 1296 // Generate reference (filters iherited again) 1297 const vector<MessageFilter> filter2base = genFilters(refMessages, vector<MessageFilter>(), baseSeed ^ 0x43211234, 4); 1298 const vector<MessageFilter> filter2full = join(filter1full, filter2base); 1299 tcu::ScopedLogSection section2 (log, "", "Pushing Debug Group"); 1300 vector<MessageData> resMessages2; 1301 1302 gl.pushDebugGroup(GL_DEBUG_SOURCE_APPLICATION, 1, -1, "Nested Test Group"); 1303 applyFilters(filter2base); 1304 1305 // Second nested verification 1306 resMessages2 = genMessages(false, "Filtered run, pushed two debug groups"); 1307 verify(refMessages, resMessages2, filter2full); 1308 1309 gl.popDebugGroup(); 1310 } 1311 1312 // First restore verification 1313 resMessages1 = genMessages(false, "Filtered run, popped second debug group"); 1314 verify(refMessages, resMessages1, filter1full); 1315 1316 gl.popDebugGroup(); 1317 } 1318 1319 // restore verification 1320 resMessages0 = genMessages(false, "Filtered run, popped first debug group"); 1321 verify(refMessages, resMessages0, filter0); 1322 1323 if (!isDebugContext() && refMessages.empty()) 1324 m_results.addResult(QP_TEST_RESULT_QUALITY_WARNING, "Verification accuracy is lacking without a debug context"); 1325 } 1326 } 1327 catch (...) 1328 { 1329 gl.disable(GL_DEBUG_OUTPUT); 1330 gl.debugMessageCallback(DE_NULL, DE_NULL); 1331 throw; 1332 } 1333 1334 gl.disable(GL_DEBUG_OUTPUT); 1335 gl.debugMessageCallback(DE_NULL, DE_NULL); 1336 m_results.setTestContextResult(m_testCtx); 1337 return STOP; 1338 } 1339 1340 // Basic grouping functionality 1341 class GroupCase : public BaseCase 1342 { 1343 public: 1344 GroupCase (Context& ctx, 1345 const char* name, 1346 const char* desc); 1347 virtual ~GroupCase () {} 1348 1349 virtual IterateResult iterate (void); 1350 1351 private: 1352 virtual void callback (GLenum source, GLenum type, GLuint id, GLenum severity, const string& message); 1353 1354 MessageData m_lastMessage; 1355 }; 1356 1357 GroupCase::GroupCase (Context& ctx, 1358 const char* name, 1359 const char* desc) 1360 : BaseCase(ctx, name, desc) 1361 { 1362 } 1363 1364 GroupCase::IterateResult GroupCase::iterate (void) 1365 { 1366 TCU_CHECK_AND_THROW(NotSupportedError, isKHRDebugSupported(m_context), "GL_KHR_debug is not supported"); 1367 1368 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 1369 tcu::TestLog& log = m_testCtx.getLog(); 1370 glu::CallLogWrapper wrapper (gl, log); 1371 1372 gl.enable(GL_DEBUG_OUTPUT); 1373 gl.enable(GL_DEBUG_OUTPUT_SYNCHRONOUS); 1374 gl.debugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, DE_NULL, false); // disable all 1375 gl.debugMessageControl(GL_DEBUG_SOURCE_API, GL_DEBUG_TYPE_ERROR, GL_DONT_CARE, 0, DE_NULL, true); // enable API errors 1376 gl.debugMessageControl(GL_DEBUG_SOURCE_APPLICATION, GL_DONT_CARE, GL_DONT_CARE, 0, DE_NULL, true); // enable application messages 1377 gl.debugMessageControl(GL_DEBUG_SOURCE_THIRD_PARTY, GL_DONT_CARE, GL_DONT_CARE, 0, DE_NULL, true); // enable third party messages 1378 gl.debugMessageCallback(callbackHandle, this); 1379 1380 wrapper.enableLogging(true); 1381 wrapper.glPushDebugGroup(GL_DEBUG_SOURCE_APPLICATION, 1234, -1, "Pushed debug stack"); 1382 verifyMessage(m_lastMessage, GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_PUSH_GROUP, 1234, GL_DEBUG_SEVERITY_NOTIFICATION); 1383 wrapper.glPopDebugGroup(); 1384 verifyMessage(m_lastMessage, GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_POP_GROUP, 1234, GL_DEBUG_SEVERITY_NOTIFICATION); 1385 1386 wrapper.glPushDebugGroup(GL_DEBUG_SOURCE_THIRD_PARTY, 4231, -1, "Pushed debug stack"); 1387 verifyMessage(m_lastMessage, GL_DEBUG_SOURCE_THIRD_PARTY, GL_DEBUG_TYPE_PUSH_GROUP, 4231, GL_DEBUG_SEVERITY_NOTIFICATION); 1388 wrapper.glPopDebugGroup(); 1389 verifyMessage(m_lastMessage, GL_DEBUG_SOURCE_THIRD_PARTY, GL_DEBUG_TYPE_POP_GROUP, 4231, GL_DEBUG_SEVERITY_NOTIFICATION); 1390 1391 gl.debugMessageCallback(DE_NULL, DE_NULL); 1392 gl.disable(GL_DEBUG_OUTPUT); 1393 1394 m_results.setTestContextResult(m_testCtx); 1395 1396 return STOP; 1397 } 1398 1399 void GroupCase::callback (GLenum source, GLenum type, GLuint id, GLenum severity, const string& message) 1400 { 1401 m_lastMessage = MessageData(MessageID(source, type, id), severity, message); 1402 } 1403 1404 // Asynchronous debug output 1405 class AsyncCase : public BaseCase 1406 { 1407 public: 1408 AsyncCase (Context& ctx, 1409 const char* name, 1410 const char* desc, 1411 const vector<TestFunctionWrapper>& errorFuncs, 1412 bool useCallbacks); 1413 virtual ~AsyncCase (void) {} 1414 1415 virtual IterateResult iterate (void); 1416 1417 virtual void expectMessage (glw::GLenum source, glw::GLenum type); 1418 1419 private: 1420 struct MessageCount 1421 { 1422 int received; 1423 int expected; 1424 1425 MessageCount(void) : received(0), expected(0) {} 1426 }; 1427 typedef map<MessageID, MessageCount> MessageCounter; 1428 1429 enum VerifyState 1430 { 1431 VERIFY_PASS = 0, 1432 VERIFY_MINIMUM, 1433 VERIFY_FAIL, 1434 1435 VERIFY_LAST 1436 }; 1437 1438 virtual void callback (glw::GLenum source, glw::GLenum type, glw::GLuint id, glw::GLenum severity, const std::string& message); 1439 VerifyState verify (bool uselog); 1440 void fetchLogMessages (void); 1441 1442 const vector<TestFunctionWrapper> m_errorFuncs; 1443 const bool m_useCallbacks; 1444 1445 MessageCounter m_counts; 1446 1447 de::Mutex m_mutex; 1448 }; 1449 1450 AsyncCase::AsyncCase (Context& ctx, 1451 const char* name, 1452 const char* desc, 1453 const vector<TestFunctionWrapper>& errorFuncs, 1454 bool useCallbacks) 1455 : BaseCase (ctx, name, desc) 1456 , m_errorFuncs (errorFuncs) 1457 , m_useCallbacks (useCallbacks) 1458 { 1459 } 1460 1461 AsyncCase::IterateResult AsyncCase::iterate (void) 1462 { 1463 TCU_CHECK_AND_THROW(NotSupportedError, isKHRDebugSupported(m_context), "GL_KHR_debug is not supported"); 1464 1465 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 1466 tcu::TestLog& log = m_testCtx.getLog(); 1467 DebugMessageTestContext context = DebugMessageTestContext(*this, m_context.getRenderContext(), m_context.getContextInfo(), log, m_results, true); 1468 const int maxWait = 10000; // ms 1469 const int warnWait = 100; 1470 1471 // Clear log from earlier messages 1472 { 1473 GLint numMessages = 0; 1474 gl.getIntegerv(GL_DEBUG_LOGGED_MESSAGES, &numMessages); 1475 gl.getDebugMessageLog(numMessages, 0, DE_NULL, DE_NULL, DE_NULL, DE_NULL, DE_NULL, DE_NULL); 1476 } 1477 1478 gl.enable(GL_DEBUG_OUTPUT); 1479 gl.enable(GL_DEBUG_OUTPUT_SYNCHRONOUS); 1480 gl.debugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, DE_NULL, false); 1481 1482 // Some messages could be dependent on the value of DEBUG_OUTPUT_SYNCHRONOUS so only use API errors which should be generated in all cases 1483 gl.debugMessageControl(GL_DEBUG_SOURCE_API, GL_DEBUG_TYPE_ERROR, GL_DONT_CARE, 0, DE_NULL, true); 1484 1485 if (m_useCallbacks) // will use log otherwise 1486 gl.debugMessageCallback(callbackHandle, this); 1487 else 1488 gl.debugMessageCallback(DE_NULL, DE_NULL); 1489 1490 // Reference run (synchoronous) 1491 { 1492 tcu::ScopedLogSection section(log, "reference run", "Reference run (synchronous)"); 1493 1494 for (int ndx = 0; ndx < int(m_errorFuncs.size()); ndx++) 1495 m_errorFuncs[ndx].call(context); 1496 } 1497 1498 if (m_counts.empty()) 1499 { 1500 if (!isDebugContext()) 1501 m_results.addResult(QP_TEST_RESULT_QUALITY_WARNING, "Need debug context to guarantee implementation behaviour (see command line options)"); 1502 1503 log << TestLog::Message << "Reference run produced no messages, nothing to verify" << TestLog::EndMessage; 1504 1505 gl.debugMessageCallback(DE_NULL, DE_NULL); 1506 gl.disable(GL_DEBUG_OUTPUT); 1507 1508 m_results.setTestContextResult(m_testCtx); 1509 return STOP; 1510 } 1511 1512 for (MessageCounter::iterator itr = m_counts.begin(); itr != m_counts.end(); itr++) 1513 { 1514 itr->second.expected = itr->second.received; 1515 itr->second.received = 0; 1516 } 1517 1518 gl.disable(GL_DEBUG_OUTPUT_SYNCHRONOUS); 1519 1520 // Result run (async) 1521 for (int ndx = 0; ndx < int(m_errorFuncs.size()); ndx++) 1522 m_errorFuncs[ndx].call(context); 1523 1524 // Repatedly try verification, new results may be added to m_receivedMessages at any time 1525 { 1526 tcu::ScopedLogSection section (log, "result run", "Result run (asynchronous)"); 1527 VerifyState lastTimelyState = VERIFY_FAIL; 1528 1529 for (int waited = 0;;) 1530 { 1531 const VerifyState pass = verify(false); 1532 const int wait = de::max(50, waited>>2); 1533 1534 // Pass (possibly due to time limit) 1535 if (pass == VERIFY_PASS || (pass == VERIFY_MINIMUM && waited >= maxWait)) 1536 { 1537 verify(true); // log 1538 1539 // State changed late 1540 if (waited >= warnWait && lastTimelyState != pass) 1541 m_results.addResult(QP_TEST_RESULT_QUALITY_WARNING, "Async messages were returned to application somewhat slowly"); 1542 1543 log << TestLog::Message << "Passed after ~" << waited << "ms of waiting" << TestLog::EndMessage; 1544 break; 1545 } 1546 // fail 1547 else if (waited >= maxWait) 1548 { 1549 verify(true); // log 1550 1551 log << TestLog::Message << "Waited for ~" << waited << "ms without getting all expected messages" << TestLog::EndMessage; 1552 m_results.addResult(QP_TEST_RESULT_FAIL, "Async messages were not returned to application within a reasonable timeframe"); 1553 break; 1554 } 1555 1556 if (waited < warnWait) 1557 lastTimelyState = pass; 1558 1559 deSleep(wait); 1560 waited += wait; 1561 1562 if (!m_useCallbacks) 1563 fetchLogMessages(); 1564 } 1565 } 1566 1567 gl.debugMessageCallback(DE_NULL, DE_NULL); 1568 1569 gl.disable(GL_DEBUG_OUTPUT); 1570 m_results.setTestContextResult(m_testCtx); 1571 1572 return STOP; 1573 } 1574 1575 void AsyncCase::expectMessage (GLenum source, GLenum type) 1576 { 1577 // Good time to clean up the queue as this should be called after most messages are generated 1578 if (!m_useCallbacks) 1579 fetchLogMessages(); 1580 1581 DE_UNREF(source); 1582 DE_UNREF(type); 1583 } 1584 1585 void AsyncCase::callback (GLenum source, GLenum type, GLuint id, GLenum severity, const string& message) 1586 { 1587 DE_ASSERT(m_useCallbacks); 1588 DE_UNREF(severity); 1589 DE_UNREF(message); 1590 1591 de::ScopedLock lock(m_mutex); 1592 1593 m_counts[MessageID(source, type, id)].received++; 1594 } 1595 1596 // Note that we can never guarantee getting all messages back when using logs/fetching as the GL may create more than its log size limit during an arbitrary period of time 1597 void AsyncCase::fetchLogMessages (void) 1598 { 1599 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 1600 GLint numMsg = 0; 1601 1602 gl.getIntegerv(GL_DEBUG_LOGGED_MESSAGES, &numMsg); 1603 1604 for(int msgNdx = 0; msgNdx < numMsg; msgNdx++) 1605 { 1606 int msgLen = 0; 1607 MessageData msg; 1608 1609 gl.getIntegerv(GL_DEBUG_NEXT_LOGGED_MESSAGE_LENGTH, &msgLen); 1610 1611 TCU_CHECK_MSG(msgLen >= 0, "Negative message length"); 1612 TCU_CHECK_MSG(msgLen < 100000, "Excessively long message"); 1613 1614 msg.message.resize(msgLen); 1615 gl.getDebugMessageLog(1, msgLen, &msg.id.source, &msg.id.type, &msg.id.id, &msg.severity, &msgLen, &msg.message[0]); 1616 1617 { 1618 const de::ScopedLock lock(m_mutex); // Don't block during API call 1619 1620 m_counts[MessageID(msg.id)].received++; 1621 } 1622 } 1623 } 1624 1625 AsyncCase::VerifyState AsyncCase::verify (bool uselog) 1626 { 1627 using std::map; 1628 1629 VerifyState retval = VERIFY_PASS; 1630 TestLog& log = m_testCtx.getLog(); 1631 1632 const de::ScopedLock lock(m_mutex); 1633 1634 for (map<MessageID, MessageCount>::const_iterator itr = m_counts.begin(); itr != m_counts.end(); itr++) 1635 { 1636 const MessageID& id = itr->first; 1637 1638 const int refCount = itr->second.expected; 1639 const int resCount = itr->second.received; 1640 const bool enabled = true; 1641 1642 VerificationResult result = verifyMessageCount(id, GL_DONT_CARE, refCount, resCount, enabled); 1643 1644 if (uselog) 1645 log << TestLog::Message << result.logMessage << TestLog::EndMessage; 1646 1647 if (result.result == QP_TEST_RESULT_FAIL) 1648 retval = VERIFY_FAIL; 1649 else if (result.result != QP_TEST_RESULT_PASS && retval == VERIFY_PASS) 1650 retval = VERIFY_MINIMUM; 1651 } 1652 1653 return retval; 1654 } 1655 1656 // Tests debug labels 1657 class LabelCase : public TestCase 1658 { 1659 public: 1660 LabelCase (Context& ctx, 1661 const char* name, 1662 const char* desc, 1663 GLenum identifier); 1664 virtual ~LabelCase (void) {} 1665 1666 virtual IterateResult iterate (void); 1667 1668 private: 1669 GLenum m_identifier; 1670 }; 1671 1672 LabelCase::LabelCase (Context& ctx, 1673 const char* name, 1674 const char* desc, 1675 GLenum identifier) 1676 : TestCase (ctx, name, desc) 1677 , m_identifier (identifier) 1678 { 1679 } 1680 1681 LabelCase::IterateResult LabelCase::iterate (void) 1682 { 1683 TCU_CHECK_AND_THROW(NotSupportedError, isKHRDebugSupported(m_context), "GL_KHR_debug is not supported"); 1684 1685 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 1686 const char* const msg = "This is a debug label"; 1687 GLuint object = 0; 1688 int outlen = -1; 1689 char buffer[64]; 1690 1691 switch(m_identifier) 1692 { 1693 case GL_BUFFER: 1694 gl.genBuffers(1, &object); 1695 gl.bindBuffer(GL_ARRAY_BUFFER, object); 1696 gl.bindBuffer(GL_ARRAY_BUFFER, 0); 1697 break; 1698 1699 case GL_SHADER: 1700 object = gl.createShader(GL_FRAGMENT_SHADER); 1701 break; 1702 1703 case GL_PROGRAM: 1704 object = gl.createProgram(); 1705 break; 1706 1707 case GL_QUERY: 1708 gl.genQueries(1, &object); 1709 gl.beginQuery(GL_ANY_SAMPLES_PASSED, object); // Create 1710 gl.endQuery(GL_ANY_SAMPLES_PASSED); // Cleanup 1711 break; 1712 1713 case GL_PROGRAM_PIPELINE: 1714 gl.genProgramPipelines(1, &object); 1715 gl.bindProgramPipeline(object); // Create 1716 gl.bindProgramPipeline(0); // Cleanup 1717 break; 1718 1719 case GL_TRANSFORM_FEEDBACK: 1720 gl.genTransformFeedbacks(1, &object); 1721 gl.bindTransformFeedback(GL_TRANSFORM_FEEDBACK, object); 1722 gl.bindTransformFeedback(GL_TRANSFORM_FEEDBACK, 0); 1723 break; 1724 1725 case GL_SAMPLER: 1726 gl.genSamplers(1, &object); 1727 gl.bindSampler(0, object); 1728 gl.bindSampler(0, 0); 1729 break; 1730 1731 case GL_TEXTURE: 1732 gl.genTextures(1, &object); 1733 gl.bindTexture(GL_TEXTURE_2D, object); 1734 gl.bindTexture(GL_TEXTURE_2D, 0); 1735 break; 1736 1737 case GL_RENDERBUFFER: 1738 gl.genRenderbuffers(1, &object); 1739 gl.bindRenderbuffer(GL_RENDERBUFFER, object); 1740 gl.bindRenderbuffer(GL_RENDERBUFFER, 0); 1741 break; 1742 1743 case GL_FRAMEBUFFER: 1744 gl.genFramebuffers(1, &object); 1745 gl.bindFramebuffer(GL_DRAW_FRAMEBUFFER, object); 1746 gl.bindFramebuffer(GL_DRAW_FRAMEBUFFER, m_context.getRenderContext().getDefaultFramebuffer()); 1747 break; 1748 1749 default: 1750 DE_FATAL("Invalid identifier"); 1751 } 1752 1753 gl.objectLabel(m_identifier, object, -1, msg); 1754 1755 deMemset(buffer, 'X', sizeof(buffer)); 1756 gl.getObjectLabel(m_identifier, object, sizeof(buffer), &outlen, buffer); 1757 1758 if (outlen == 0) 1759 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Failed to query debug label from object"); 1760 else if (deStringEqual(msg, buffer)) 1761 { 1762 m_testCtx.getLog() << TestLog::Message << "Query returned string: \"" << buffer << "\"" << TestLog::EndMessage; 1763 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); 1764 } 1765 else 1766 { 1767 buffer[63] = '\0'; // make sure buffer is null terminated before printing 1768 m_testCtx.getLog() << TestLog::Message << "Query returned wrong string: expected \"" << msg << "\" but got \"" << buffer << "\"" << TestLog::EndMessage; 1769 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Query returned wrong label"); 1770 } 1771 1772 switch(m_identifier) 1773 { 1774 case GL_BUFFER: gl.deleteBuffers(1, &object); break; 1775 case GL_SHADER: gl.deleteShader(object); break; 1776 case GL_PROGRAM: gl.deleteProgram(object); break; 1777 case GL_QUERY: gl.deleteQueries(1, &object); break; 1778 case GL_PROGRAM_PIPELINE: gl.deleteProgramPipelines(1, &object); break; 1779 case GL_TRANSFORM_FEEDBACK: gl.deleteTransformFeedbacks(1, &object); break; 1780 case GL_SAMPLER: gl.deleteSamplers(1, &object); break; 1781 case GL_TEXTURE: gl.deleteTextures(1, &object); break; 1782 case GL_RENDERBUFFER: gl.deleteRenderbuffers(1, &object); break; 1783 case GL_FRAMEBUFFER: gl.deleteFramebuffers(1, &object); break; 1784 1785 default: 1786 DE_FATAL("Invalid identifier"); 1787 } 1788 1789 return STOP; 1790 } 1791 1792 1793 DebugMessageTestContext::DebugMessageTestContext (BaseCase& host, 1794 glu::RenderContext& renderCtx, 1795 const glu::ContextInfo& ctxInfo, 1796 tcu::TestLog& log, 1797 tcu::ResultCollector& results, 1798 bool enableLog) 1799 : NegativeTestContext (host, renderCtx, ctxInfo, log, results, enableLog) 1800 , m_debugHost (host) 1801 { 1802 } 1803 1804 DebugMessageTestContext::~DebugMessageTestContext (void) 1805 { 1806 } 1807 1808 void DebugMessageTestContext::expectMessage (GLenum source, GLenum type) 1809 { 1810 m_debugHost.expectMessage(source, type); 1811 } 1812 1813 class SyncLabelCase : public TestCase 1814 { 1815 public: 1816 SyncLabelCase (Context& ctx, const char* name, const char* desc); 1817 virtual IterateResult iterate (void); 1818 }; 1819 1820 SyncLabelCase::SyncLabelCase (Context& ctx, const char* name, const char* desc) 1821 : TestCase(ctx, name, desc) 1822 { 1823 } 1824 1825 SyncLabelCase::IterateResult SyncLabelCase::iterate (void) 1826 { 1827 TCU_CHECK_AND_THROW(NotSupportedError, isKHRDebugSupported(m_context), "GL_KHR_debug is not supported"); 1828 1829 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 1830 const char* const msg = "This is a debug label"; 1831 int outlen = -1; 1832 char buffer[64]; 1833 1834 glw::GLsync sync = gl.fenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0); 1835 GLU_EXPECT_NO_ERROR(gl.getError(), "fenceSync"); 1836 1837 gl.objectPtrLabel(sync, -1, msg); 1838 1839 deMemset(buffer, 'X', sizeof(buffer)); 1840 gl.getObjectPtrLabel(sync, sizeof(buffer), &outlen, buffer); 1841 1842 if (outlen == 0) 1843 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Failed to query debug label from object"); 1844 else if (deStringEqual(msg, buffer)) 1845 { 1846 m_testCtx.getLog() << TestLog::Message << "Query returned string: \"" << buffer << "\"" << TestLog::EndMessage; 1847 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); 1848 } 1849 else 1850 { 1851 buffer[63] = '\0'; // make sure buffer is null terminated before printing 1852 m_testCtx.getLog() << TestLog::Message << "Query returned wrong string: expected \"" << msg << "\" but got \"" << buffer << "\"" << TestLog::EndMessage; 1853 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Query returned wrong label"); 1854 } 1855 1856 gl.deleteSync(sync); 1857 1858 return STOP; 1859 } 1860 1861 class InitialLabelCase : public TestCase 1862 { 1863 public: 1864 InitialLabelCase (Context& ctx, const char* name, const char* desc); 1865 virtual IterateResult iterate (void); 1866 }; 1867 1868 InitialLabelCase::InitialLabelCase (Context& ctx, const char* name, const char* desc) 1869 : TestCase(ctx, name, desc) 1870 { 1871 } 1872 1873 InitialLabelCase::IterateResult InitialLabelCase::iterate (void) 1874 { 1875 TCU_CHECK_AND_THROW(NotSupportedError, isKHRDebugSupported(m_context), "GL_KHR_debug is not supported"); 1876 1877 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 1878 tcu::ResultCollector result (m_testCtx.getLog(), " // ERROR: "); 1879 int outlen = -1; 1880 GLuint shader; 1881 glw::GLsync sync; 1882 char buffer[64]; 1883 1884 sync = gl.fenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0); 1885 GLS_COLLECT_GL_ERROR(result, gl.getError(), "fenceSync"); 1886 1887 shader = gl.createShader(GL_FRAGMENT_SHADER); 1888 GLS_COLLECT_GL_ERROR(result, gl.getError(), "createShader"); 1889 1890 { 1891 const tcu::ScopedLogSection section(m_testCtx.getLog(), "Shader", "Shader object"); 1892 m_testCtx.getLog() << TestLog::Message << "Querying initial value" << TestLog::EndMessage; 1893 1894 buffer[0] = 'X'; 1895 outlen = -1; 1896 gl.getObjectLabel(GL_SHADER, shader, sizeof(buffer), &outlen, buffer); 1897 GLS_COLLECT_GL_ERROR(result, gl.getError(), "getObjectLabel"); 1898 1899 if (outlen != 0) 1900 result.fail("'length' was not zero, got " + de::toString(outlen)); 1901 else if (buffer[0] != '\0') 1902 result.fail("label was not null terminated"); 1903 else 1904 m_testCtx.getLog() << TestLog::Message << "Got 0-sized null-terminated string." << TestLog::EndMessage; 1905 } 1906 1907 { 1908 const tcu::ScopedLogSection section(m_testCtx.getLog(), "Sync", "Sync object"); 1909 m_testCtx.getLog() << TestLog::Message << "Querying initial value" << TestLog::EndMessage; 1910 1911 buffer[0] = 'X'; 1912 outlen = -1; 1913 gl.getObjectPtrLabel(sync, sizeof(buffer), &outlen, buffer); 1914 GLS_COLLECT_GL_ERROR(result, gl.getError(), "getObjectPtrLabel"); 1915 1916 if (outlen != 0) 1917 result.fail("'length' was not zero, got " + de::toString(outlen)); 1918 else if (buffer[0] != '\0') 1919 result.fail("label was not null terminated"); 1920 else 1921 m_testCtx.getLog() << TestLog::Message << "Got 0-sized null-terminated string." << TestLog::EndMessage; 1922 } 1923 1924 gl.deleteShader(shader); 1925 gl.deleteSync(sync); 1926 1927 result.setTestContextResult(m_testCtx); 1928 return STOP; 1929 } 1930 1931 class ClearLabelCase : public TestCase 1932 { 1933 public: 1934 ClearLabelCase (Context& ctx, const char* name, const char* desc); 1935 virtual IterateResult iterate (void); 1936 }; 1937 1938 ClearLabelCase::ClearLabelCase (Context& ctx, const char* name, const char* desc) 1939 : TestCase(ctx, name, desc) 1940 { 1941 } 1942 1943 ClearLabelCase::IterateResult ClearLabelCase::iterate (void) 1944 { 1945 TCU_CHECK_AND_THROW(NotSupportedError, isKHRDebugSupported(m_context), "GL_KHR_debug is not supported"); 1946 1947 static const struct 1948 { 1949 const char* description; 1950 int length; 1951 } s_clearMethods[] = 1952 { 1953 { " with NULL label and 0 length", 0 }, 1954 { " with NULL label and 1 length", 1 }, 1955 { " with NULL label and negative length", -1 }, 1956 }; 1957 1958 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 1959 tcu::ResultCollector result (m_testCtx.getLog(), " // ERROR: "); 1960 const char* const msg = "This is a debug label"; 1961 int outlen = -1; 1962 GLuint shader; 1963 glw::GLsync sync; 1964 char buffer[64]; 1965 1966 sync = gl.fenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0); 1967 GLS_COLLECT_GL_ERROR(result, gl.getError(), "fenceSync"); 1968 1969 shader = gl.createShader(GL_FRAGMENT_SHADER); 1970 GLS_COLLECT_GL_ERROR(result, gl.getError(), "createShader"); 1971 1972 { 1973 const tcu::ScopedLogSection section(m_testCtx.getLog(), "Shader", "Shader object"); 1974 1975 for (int methodNdx = 0; methodNdx < DE_LENGTH_OF_ARRAY(s_clearMethods); ++methodNdx) 1976 { 1977 m_testCtx.getLog() << TestLog::Message << "Setting label to string: \"" << msg << "\"" << TestLog::EndMessage; 1978 gl.objectLabel(GL_SHADER, shader, -2, msg); 1979 GLS_COLLECT_GL_ERROR(result, gl.getError(), "objectLabel"); 1980 1981 m_testCtx.getLog() << TestLog::Message << "Clearing label " << s_clearMethods[methodNdx].description << TestLog::EndMessage; 1982 gl.objectLabel(GL_SHADER, shader, s_clearMethods[methodNdx].length, DE_NULL); 1983 GLS_COLLECT_GL_ERROR(result, gl.getError(), "objectLabel"); 1984 1985 m_testCtx.getLog() << TestLog::Message << "Querying label" << TestLog::EndMessage; 1986 buffer[0] = 'X'; 1987 outlen = -1; 1988 gl.getObjectLabel(GL_SHADER, shader, sizeof(buffer), &outlen, buffer); 1989 GLS_COLLECT_GL_ERROR(result, gl.getError(), "getObjectLabel"); 1990 1991 if (outlen != 0) 1992 result.fail("'length' was not zero, got " + de::toString(outlen)); 1993 else if (buffer[0] != '\0') 1994 result.fail("label was not null terminated"); 1995 else 1996 m_testCtx.getLog() << TestLog::Message << "Got 0-sized null-terminated string." << TestLog::EndMessage; 1997 } 1998 } 1999 2000 { 2001 const tcu::ScopedLogSection section(m_testCtx.getLog(), "Sync", "Sync object"); 2002 2003 for (int methodNdx = 0; methodNdx < DE_LENGTH_OF_ARRAY(s_clearMethods); ++methodNdx) 2004 { 2005 m_testCtx.getLog() << TestLog::Message << "Setting label to string: \"" << msg << "\"" << TestLog::EndMessage; 2006 gl.objectPtrLabel(sync, -2, msg); 2007 GLS_COLLECT_GL_ERROR(result, gl.getError(), "objectPtrLabel"); 2008 2009 m_testCtx.getLog() << TestLog::Message << "Clearing label " << s_clearMethods[methodNdx].description << TestLog::EndMessage; 2010 gl.objectPtrLabel(sync, s_clearMethods[methodNdx].length, DE_NULL); 2011 GLS_COLLECT_GL_ERROR(result, gl.getError(), "objectPtrLabel"); 2012 2013 m_testCtx.getLog() << TestLog::Message << "Querying label" << TestLog::EndMessage; 2014 buffer[0] = 'X'; 2015 outlen = -1; 2016 gl.getObjectPtrLabel(sync, sizeof(buffer), &outlen, buffer); 2017 GLS_COLLECT_GL_ERROR(result, gl.getError(), "getObjectPtrLabel"); 2018 2019 if (outlen != 0) 2020 result.fail("'length' was not zero, got " + de::toString(outlen)); 2021 else if (buffer[0] != '\0') 2022 result.fail("label was not null terminated"); 2023 else 2024 m_testCtx.getLog() << TestLog::Message << "Got 0-sized null-terminated string." << TestLog::EndMessage; 2025 } 2026 } 2027 2028 gl.deleteShader(shader); 2029 gl.deleteSync(sync); 2030 2031 result.setTestContextResult(m_testCtx); 2032 return STOP; 2033 } 2034 2035 class SpecifyWithLengthCase : public TestCase 2036 { 2037 public: 2038 SpecifyWithLengthCase (Context& ctx, const char* name, const char* desc); 2039 virtual IterateResult iterate (void); 2040 }; 2041 2042 SpecifyWithLengthCase::SpecifyWithLengthCase (Context& ctx, const char* name, const char* desc) 2043 : TestCase(ctx, name, desc) 2044 { 2045 } 2046 2047 SpecifyWithLengthCase::IterateResult SpecifyWithLengthCase::iterate (void) 2048 { 2049 TCU_CHECK_AND_THROW(NotSupportedError, isKHRDebugSupported(m_context), "GL_KHR_debug is not supported"); 2050 2051 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 2052 tcu::ResultCollector result (m_testCtx.getLog(), " // ERROR: "); 2053 const char* const msg = "This is a debug label"; 2054 const char* const clipMsg = "This is a de"; 2055 int outlen = -1; 2056 GLuint shader; 2057 glw::GLsync sync; 2058 char buffer[64]; 2059 2060 sync = gl.fenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0); 2061 GLS_COLLECT_GL_ERROR(result, gl.getError(), "fenceSync"); 2062 2063 shader = gl.createShader(GL_FRAGMENT_SHADER); 2064 GLS_COLLECT_GL_ERROR(result, gl.getError(), "createShader"); 2065 2066 { 2067 const tcu::ScopedLogSection section(m_testCtx.getLog(), "Shader", "Shader object"); 2068 2069 m_testCtx.getLog() << TestLog::Message << "Setting label to string: \"" << msg << "\" with length 12" << TestLog::EndMessage; 2070 gl.objectLabel(GL_SHADER, shader, 12, msg); 2071 GLS_COLLECT_GL_ERROR(result, gl.getError(), "objectLabel"); 2072 2073 m_testCtx.getLog() << TestLog::Message << "Querying label" << TestLog::EndMessage; 2074 deMemset(buffer, 'X', sizeof(buffer)); 2075 gl.getObjectLabel(GL_SHADER, shader, sizeof(buffer), &outlen, buffer); 2076 GLS_COLLECT_GL_ERROR(result, gl.getError(), "getObjectLabel"); 2077 2078 if (outlen != 12) 2079 result.fail("'length' was not 12, got " + de::toString(outlen)); 2080 else if (deStringEqual(clipMsg, buffer)) 2081 { 2082 m_testCtx.getLog() << TestLog::Message << "Query returned string: \"" << buffer << "\"" << TestLog::EndMessage; 2083 } 2084 else 2085 { 2086 buffer[63] = '\0'; // make sure buffer is null terminated before printing 2087 m_testCtx.getLog() << TestLog::Message << "Query returned wrong string: expected \"" << clipMsg << "\" but got \"" << buffer << "\"" << TestLog::EndMessage; 2088 result.fail("Query returned wrong label"); 2089 } 2090 } 2091 2092 { 2093 const tcu::ScopedLogSection section(m_testCtx.getLog(), "Sync", "Sync object"); 2094 2095 m_testCtx.getLog() << TestLog::Message << "Setting label to string: \"" << msg << "\" with length 12" << TestLog::EndMessage; 2096 gl.objectPtrLabel(sync, 12, msg); 2097 GLS_COLLECT_GL_ERROR(result, gl.getError(), "objectPtrLabel"); 2098 2099 m_testCtx.getLog() << TestLog::Message << "Querying label" << TestLog::EndMessage; 2100 deMemset(buffer, 'X', sizeof(buffer)); 2101 gl.getObjectPtrLabel(sync, sizeof(buffer), &outlen, buffer); 2102 GLS_COLLECT_GL_ERROR(result, gl.getError(), "getObjectPtrLabel"); 2103 2104 if (outlen != 12) 2105 result.fail("'length' was not 12, got " + de::toString(outlen)); 2106 else if (deStringEqual(clipMsg, buffer)) 2107 { 2108 m_testCtx.getLog() << TestLog::Message << "Query returned string: \"" << buffer << "\"" << TestLog::EndMessage; 2109 } 2110 else 2111 { 2112 buffer[63] = '\0'; // make sure buffer is null terminated before printing 2113 m_testCtx.getLog() << TestLog::Message << "Query returned wrong string: expected \"" << clipMsg << "\" but got \"" << buffer << "\"" << TestLog::EndMessage; 2114 result.fail("Query returned wrong label"); 2115 } 2116 } 2117 2118 { 2119 const tcu::ScopedLogSection section(m_testCtx.getLog(), "ZeroSized", "ZeroSized"); 2120 2121 m_testCtx.getLog() << TestLog::Message << "Setting label to string: \"" << msg << "\" with length 0" << TestLog::EndMessage; 2122 gl.objectLabel(GL_SHADER, shader, 0, msg); 2123 GLS_COLLECT_GL_ERROR(result, gl.getError(), "objectLabel"); 2124 2125 m_testCtx.getLog() << TestLog::Message << "Querying label" << TestLog::EndMessage; 2126 deMemset(buffer, 'X', sizeof(buffer)); 2127 gl.getObjectLabel(GL_SHADER, shader, sizeof(buffer), &outlen, buffer); 2128 GLS_COLLECT_GL_ERROR(result, gl.getError(), "getObjectLabel"); 2129 2130 if (outlen != 0) 2131 result.fail("'length' was not zero, got " + de::toString(outlen)); 2132 else if (buffer[0] != '\0') 2133 result.fail("label was not null terminated"); 2134 else 2135 m_testCtx.getLog() << TestLog::Message << "Got 0-sized null-terminated string." << TestLog::EndMessage; 2136 } 2137 2138 gl.deleteShader(shader); 2139 gl.deleteSync(sync); 2140 2141 result.setTestContextResult(m_testCtx); 2142 return STOP; 2143 } 2144 2145 class BufferLimitedLabelCase : public TestCase 2146 { 2147 public: 2148 BufferLimitedLabelCase (Context& ctx, const char* name, const char* desc); 2149 virtual IterateResult iterate (void); 2150 }; 2151 2152 BufferLimitedLabelCase::BufferLimitedLabelCase (Context& ctx, const char* name, const char* desc) 2153 : TestCase(ctx, name, desc) 2154 { 2155 } 2156 2157 BufferLimitedLabelCase::IterateResult BufferLimitedLabelCase::iterate (void) 2158 { 2159 TCU_CHECK_AND_THROW(NotSupportedError, isKHRDebugSupported(m_context), "GL_KHR_debug is not supported"); 2160 2161 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 2162 tcu::ResultCollector result (m_testCtx.getLog(), " // ERROR: "); 2163 const char* const msg = "This is a debug label"; 2164 int outlen = -1; 2165 GLuint shader; 2166 glw::GLsync sync; 2167 char buffer[64]; 2168 2169 sync = gl.fenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0); 2170 GLS_COLLECT_GL_ERROR(result, gl.getError(), "fenceSync"); 2171 2172 shader = gl.createShader(GL_FRAGMENT_SHADER); 2173 GLS_COLLECT_GL_ERROR(result, gl.getError(), "createShader"); 2174 2175 { 2176 const tcu::ScopedLogSection superSection(m_testCtx.getLog(), "Shader", "Shader object"); 2177 2178 m_testCtx.getLog() << TestLog::Message << "Setting label to string: \"" << msg << "\"" << TestLog::EndMessage; 2179 gl.objectLabel(GL_SHADER, shader, -1, msg); 2180 GLS_COLLECT_GL_ERROR(result, gl.getError(), "objectLabel"); 2181 2182 { 2183 const tcu::ScopedLogSection section(m_testCtx.getLog(), "QueryAll", "Query All"); 2184 2185 m_testCtx.getLog() << TestLog::Message << "Querying whole label, buffer size = 22" << TestLog::EndMessage; 2186 deMemset(buffer, 'X', sizeof(buffer)); 2187 gl.getObjectLabel(GL_SHADER, shader, 22, &outlen, buffer); 2188 GLS_COLLECT_GL_ERROR(result, gl.getError(), "getObjectLabel"); 2189 2190 if (outlen != 21) 2191 result.fail("'length' was not 21, got " + de::toString(outlen)); 2192 else if (buffer[outlen] != '\0') 2193 result.fail("Buffer was not null-terminated"); 2194 else if (buffer[outlen+1] != 'X') 2195 result.fail("Query wrote over buffer bound"); 2196 else if (!deStringEqual(msg, buffer)) 2197 { 2198 buffer[63] = '\0'; // make sure buffer is null terminated before printing 2199 m_testCtx.getLog() << TestLog::Message << "Query returned string: \"" << buffer << "\"" << TestLog::EndMessage; 2200 result.fail("Query returned wrong label"); 2201 } 2202 else 2203 m_testCtx.getLog() << TestLog::Message << "Query returned string: \"" << buffer << "\"" << TestLog::EndMessage; 2204 } 2205 { 2206 const tcu::ScopedLogSection section(m_testCtx.getLog(), "QueryAllNoSize", "Query all without size"); 2207 2208 m_testCtx.getLog() << TestLog::Message << "Querying whole label, buffer size = 22" << TestLog::EndMessage; 2209 deMemset(buffer, 'X', sizeof(buffer)); 2210 gl.getObjectLabel(GL_SHADER, shader, 22, DE_NULL, buffer); 2211 GLS_COLLECT_GL_ERROR(result, gl.getError(), "getObjectLabel"); 2212 2213 buffer[63] = '\0'; // make sure buffer is null terminated before strlen 2214 2215 if (strlen(buffer) != 21) 2216 result.fail("Buffer length was not 21"); 2217 else if (buffer[21] != '\0') 2218 result.fail("Buffer was not null-terminated"); 2219 else if (buffer[22] != 'X') 2220 result.fail("Query wrote over buffer bound"); 2221 else if (!deStringEqual(msg, buffer)) 2222 { 2223 m_testCtx.getLog() << TestLog::Message << "Query returned string: \"" << buffer << "\"" << TestLog::EndMessage; 2224 result.fail("Query returned wrong label"); 2225 } 2226 else 2227 m_testCtx.getLog() << TestLog::Message << "Query returned string: \"" << buffer << "\"" << TestLog::EndMessage; 2228 } 2229 { 2230 const tcu::ScopedLogSection section(m_testCtx.getLog(), "QueryLess", "Query substring"); 2231 2232 m_testCtx.getLog() << TestLog::Message << "Querying whole label, buffer size = 2" << TestLog::EndMessage; 2233 deMemset(buffer, 'X', sizeof(buffer)); 2234 gl.getObjectLabel(GL_SHADER, shader, 2, &outlen, buffer); 2235 GLS_COLLECT_GL_ERROR(result, gl.getError(), "getObjectLabel"); 2236 2237 if (outlen != 1) 2238 result.fail("'length' was not 1, got " + de::toString(outlen)); 2239 else if (buffer[outlen] != '\0') 2240 result.fail("Buffer was not null-terminated"); 2241 else if (buffer[outlen+1] != 'X') 2242 result.fail("Query wrote over buffer bound"); 2243 else if (!deStringBeginsWith(msg, buffer)) 2244 { 2245 buffer[63] = '\0'; // make sure buffer is null terminated before printing 2246 m_testCtx.getLog() << TestLog::Message << "Query returned string: \"" << buffer << "\"" << TestLog::EndMessage; 2247 result.fail("Query returned wrong label"); 2248 } 2249 else 2250 m_testCtx.getLog() << TestLog::Message << "Query returned string: \"" << buffer << "\"" << TestLog::EndMessage; 2251 } 2252 { 2253 const tcu::ScopedLogSection section(m_testCtx.getLog(), "QueryNone", "Query one character"); 2254 2255 m_testCtx.getLog() << TestLog::Message << "Querying whole label, buffer size = 1" << TestLog::EndMessage; 2256 deMemset(buffer, 'X', sizeof(buffer)); 2257 gl.getObjectLabel(GL_SHADER, shader, 1, &outlen, buffer); 2258 GLS_COLLECT_GL_ERROR(result, gl.getError(), "getObjectLabel"); 2259 2260 if (outlen != 0) 2261 result.fail("'length' was not 0, got " + de::toString(outlen)); 2262 else if (buffer[outlen] != '\0') 2263 result.fail("Buffer was not null-terminated"); 2264 else if (buffer[outlen+1] != 'X') 2265 result.fail("Query wrote over buffer bound"); 2266 else 2267 m_testCtx.getLog() << TestLog::Message << "Query returned zero-sized null-terminated string" << TestLog::EndMessage; 2268 } 2269 } 2270 2271 { 2272 const tcu::ScopedLogSection superSection(m_testCtx.getLog(), "Sync", "Sync object"); 2273 2274 m_testCtx.getLog() << TestLog::Message << "Setting label to string: \"" << msg << "\"" << TestLog::EndMessage; 2275 gl.objectPtrLabel(sync, -1, msg); 2276 GLS_COLLECT_GL_ERROR(result, gl.getError(), "objectPtrLabel"); 2277 2278 { 2279 const tcu::ScopedLogSection section(m_testCtx.getLog(), "QueryAll", "Query All"); 2280 2281 m_testCtx.getLog() << TestLog::Message << "Querying whole label, buffer size = 22" << TestLog::EndMessage; 2282 deMemset(buffer, 'X', sizeof(buffer)); 2283 gl.getObjectPtrLabel(sync, 22, &outlen, buffer); 2284 GLS_COLLECT_GL_ERROR(result, gl.getError(), "getObjectPtrLabel"); 2285 2286 if (outlen != 21) 2287 result.fail("'length' was not 21, got " + de::toString(outlen)); 2288 else if (buffer[outlen] != '\0') 2289 result.fail("Buffer was not null-terminated"); 2290 else if (buffer[outlen+1] != 'X') 2291 result.fail("Query wrote over buffer bound"); 2292 else if (!deStringEqual(msg, buffer)) 2293 { 2294 buffer[63] = '\0'; // make sure buffer is null terminated before printing 2295 m_testCtx.getLog() << TestLog::Message << "Query returned string: \"" << buffer << "\"" << TestLog::EndMessage; 2296 result.fail("Query returned wrong label"); 2297 } 2298 else 2299 m_testCtx.getLog() << TestLog::Message << "Query returned string: \"" << buffer << "\"" << TestLog::EndMessage; 2300 } 2301 { 2302 const tcu::ScopedLogSection section(m_testCtx.getLog(), "QueryAllNoSize", "Query all without size"); 2303 2304 m_testCtx.getLog() << TestLog::Message << "Querying whole label, buffer size = 22" << TestLog::EndMessage; 2305 deMemset(buffer, 'X', sizeof(buffer)); 2306 gl.getObjectPtrLabel(sync, 22, DE_NULL, buffer); 2307 GLS_COLLECT_GL_ERROR(result, gl.getError(), "getObjectPtrLabel"); 2308 2309 buffer[63] = '\0'; // make sure buffer is null terminated before strlen 2310 2311 if (strlen(buffer) != 21) 2312 result.fail("Buffer length was not 21"); 2313 else if (buffer[21] != '\0') 2314 result.fail("Buffer was not null-terminated"); 2315 else if (buffer[22] != 'X') 2316 result.fail("Query wrote over buffer bound"); 2317 else if (!deStringEqual(msg, buffer)) 2318 { 2319 m_testCtx.getLog() << TestLog::Message << "Query returned string: \"" << buffer << "\"" << TestLog::EndMessage; 2320 result.fail("Query returned wrong label"); 2321 } 2322 else 2323 m_testCtx.getLog() << TestLog::Message << "Query returned string: \"" << buffer << "\"" << TestLog::EndMessage; 2324 } 2325 { 2326 const tcu::ScopedLogSection section(m_testCtx.getLog(), "QueryLess", "Query substring"); 2327 2328 m_testCtx.getLog() << TestLog::Message << "Querying whole label, buffer size = 2" << TestLog::EndMessage; 2329 deMemset(buffer, 'X', sizeof(buffer)); 2330 gl.getObjectPtrLabel(sync, 2, &outlen, buffer); 2331 GLS_COLLECT_GL_ERROR(result, gl.getError(), "getObjectPtrLabel"); 2332 2333 if (outlen != 1) 2334 result.fail("'length' was not 1, got " + de::toString(outlen)); 2335 else if (buffer[outlen] != '\0') 2336 result.fail("Buffer was not null-terminated"); 2337 else if (buffer[outlen+1] != 'X') 2338 result.fail("Query wrote over buffer bound"); 2339 else if (!deStringBeginsWith(msg, buffer)) 2340 { 2341 buffer[63] = '\0'; // make sure buffer is null terminated before printing 2342 m_testCtx.getLog() << TestLog::Message << "Query returned string: \"" << buffer << "\"" << TestLog::EndMessage; 2343 result.fail("Query returned wrong label"); 2344 } 2345 else 2346 m_testCtx.getLog() << TestLog::Message << "Query returned string: \"" << buffer << "\"" << TestLog::EndMessage; 2347 } 2348 { 2349 const tcu::ScopedLogSection section(m_testCtx.getLog(), "QueryNone", "Query one character"); 2350 2351 m_testCtx.getLog() << TestLog::Message << "Querying whole label, buffer size = 1" << TestLog::EndMessage; 2352 deMemset(buffer, 'X', sizeof(buffer)); 2353 gl.getObjectPtrLabel(sync, 1, &outlen, buffer); 2354 GLS_COLLECT_GL_ERROR(result, gl.getError(), "getObjectPtrLabel"); 2355 2356 if (outlen != 0) 2357 result.fail("'length' was not 0, got " + de::toString(outlen)); 2358 else if (buffer[outlen] != '\0') 2359 result.fail("Buffer was not null-terminated"); 2360 else if (buffer[outlen+1] != 'X') 2361 result.fail("Query wrote over buffer bound"); 2362 else 2363 m_testCtx.getLog() << TestLog::Message << "Query returned zero-sized null-terminated string" << TestLog::EndMessage; 2364 } 2365 } 2366 2367 gl.deleteShader(shader); 2368 gl.deleteSync(sync); 2369 2370 result.setTestContextResult(m_testCtx); 2371 return STOP; 2372 } 2373 2374 class LabelMaxSizeCase : public TestCase 2375 { 2376 public: 2377 LabelMaxSizeCase (Context& ctx, const char* name, const char* desc); 2378 virtual IterateResult iterate (void); 2379 }; 2380 2381 LabelMaxSizeCase::LabelMaxSizeCase (Context& ctx, const char* name, const char* desc) 2382 : TestCase(ctx, name, desc) 2383 { 2384 } 2385 2386 LabelMaxSizeCase::IterateResult LabelMaxSizeCase::iterate (void) 2387 { 2388 TCU_CHECK_AND_THROW(NotSupportedError, isKHRDebugSupported(m_context), "GL_KHR_debug is not supported"); 2389 2390 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 2391 tcu::ResultCollector result (m_testCtx.getLog(), " // ERROR: "); 2392 int maxLabelLen = -1; 2393 int outlen = -1; 2394 GLuint shader; 2395 glw::GLsync sync; 2396 2397 gl.getIntegerv(GL_MAX_LABEL_LENGTH, &maxLabelLen); 2398 GLS_COLLECT_GL_ERROR(result, gl.getError(), "GL_MAX_LABEL_LENGTH"); 2399 2400 m_testCtx.getLog() << TestLog::Message << "GL_MAX_LABEL_LENGTH = " << maxLabelLen << TestLog::EndMessage; 2401 2402 if (maxLabelLen < 256) 2403 throw tcu::TestError("maxLabelLen was less than required (256)"); 2404 if (maxLabelLen > 8192) 2405 { 2406 m_testCtx.getLog() 2407 << TestLog::Message 2408 << "GL_MAX_LABEL_LENGTH is very large. Application having larger labels is unlikely, skipping test." 2409 << TestLog::EndMessage; 2410 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); 2411 return STOP; 2412 } 2413 2414 sync = gl.fenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0); 2415 GLS_COLLECT_GL_ERROR(result, gl.getError(), "fenceSync"); 2416 2417 shader = gl.createShader(GL_FRAGMENT_SHADER); 2418 GLS_COLLECT_GL_ERROR(result, gl.getError(), "createShader"); 2419 2420 { 2421 const tcu::ScopedLogSection section (m_testCtx.getLog(), "Shader", "Shader object"); 2422 std::vector<char> buffer (maxLabelLen, 'X'); 2423 std::vector<char> readBuffer (maxLabelLen, 'X'); 2424 2425 buffer[maxLabelLen-1] = '\0'; 2426 2427 m_testCtx.getLog() << TestLog::Message << "Setting max length label, with implicit size. (length = -1)" << TestLog::EndMessage; 2428 gl.objectLabel(GL_SHADER, shader, -1, &buffer[0]); 2429 GLS_COLLECT_GL_ERROR(result, gl.getError(), "objectLabel"); 2430 2431 m_testCtx.getLog() << TestLog::Message << "Querying label back" << TestLog::EndMessage; 2432 outlen = -1; 2433 gl.getObjectLabel(GL_SHADER, shader, maxLabelLen, &outlen, &readBuffer[0]); 2434 GLS_COLLECT_GL_ERROR(result, gl.getError(), "getObjectLabel"); 2435 2436 if (outlen != maxLabelLen-1) 2437 result.fail("'length' was not " + de::toString(maxLabelLen-1) + ", got " + de::toString(outlen)); 2438 else if (readBuffer[outlen] != '\0') 2439 result.fail("Buffer was not null-terminated"); 2440 2441 m_testCtx.getLog() << TestLog::Message << "Setting max length label, with explicit size. (length = " << (maxLabelLen-1) << ")" << TestLog::EndMessage; 2442 gl.objectLabel(GL_SHADER, shader, maxLabelLen-1, &buffer[0]); 2443 GLS_COLLECT_GL_ERROR(result, gl.getError(), "objectLabel"); 2444 2445 m_testCtx.getLog() << TestLog::Message << "Querying label back" << TestLog::EndMessage; 2446 outlen = -1; 2447 readBuffer[maxLabelLen-1] = 'X'; 2448 gl.getObjectLabel(GL_SHADER, shader, maxLabelLen, &outlen, &readBuffer[0]); 2449 GLS_COLLECT_GL_ERROR(result, gl.getError(), "getObjectLabel"); 2450 2451 if (outlen != maxLabelLen-1) 2452 result.fail("'length' was not " + de::toString(maxLabelLen-1) + ", got " + de::toString(outlen)); 2453 else if (readBuffer[outlen] != '\0') 2454 result.fail("Buffer was not null-terminated"); 2455 } 2456 2457 { 2458 const tcu::ScopedLogSection section (m_testCtx.getLog(), "Sync", "Sync object"); 2459 std::vector<char> buffer (maxLabelLen, 'X'); 2460 std::vector<char> readBuffer (maxLabelLen, 'X'); 2461 2462 buffer[maxLabelLen-1] = '\0'; 2463 2464 m_testCtx.getLog() << TestLog::Message << "Setting max length label, with implicit size. (length = -1)" << TestLog::EndMessage; 2465 gl.objectPtrLabel(sync, -1, &buffer[0]); 2466 GLS_COLLECT_GL_ERROR(result, gl.getError(), "objectPtrLabel"); 2467 2468 m_testCtx.getLog() << TestLog::Message << "Querying label back" << TestLog::EndMessage; 2469 outlen = -1; 2470 gl.getObjectPtrLabel(sync, maxLabelLen, &outlen, &readBuffer[0]); 2471 GLS_COLLECT_GL_ERROR(result, gl.getError(), "getObjectPtrLabel"); 2472 2473 if (outlen != maxLabelLen-1) 2474 result.fail("'length' was not " + de::toString(maxLabelLen-1) + ", got " + de::toString(outlen)); 2475 else if (readBuffer[outlen] != '\0') 2476 result.fail("Buffer was not null-terminated"); 2477 2478 m_testCtx.getLog() << TestLog::Message << "Setting max length label, with explicit size. (length = " << (maxLabelLen-1) << ")" << TestLog::EndMessage; 2479 gl.objectPtrLabel(sync, maxLabelLen-1, &buffer[0]); 2480 GLS_COLLECT_GL_ERROR(result, gl.getError(), "objectPtrLabel"); 2481 2482 m_testCtx.getLog() << TestLog::Message << "Querying label back" << TestLog::EndMessage; 2483 outlen = -1; 2484 readBuffer[maxLabelLen-1] = 'X'; 2485 gl.getObjectPtrLabel(sync, maxLabelLen, &outlen, &readBuffer[0]); 2486 GLS_COLLECT_GL_ERROR(result, gl.getError(), "getObjectPtrLabel"); 2487 2488 if (outlen != maxLabelLen-1) 2489 result.fail("'length' was not " + de::toString(maxLabelLen-1) + ", got " + de::toString(outlen)); 2490 else if (readBuffer[outlen] != '\0') 2491 result.fail("Buffer was not null-terminated"); 2492 } 2493 2494 gl.deleteShader(shader); 2495 gl.deleteSync(sync); 2496 2497 result.setTestContextResult(m_testCtx); 2498 return STOP; 2499 } 2500 2501 class LabelLengthCase : public TestCase 2502 { 2503 public: 2504 LabelLengthCase (Context& ctx, const char* name, const char* desc); 2505 virtual IterateResult iterate (void); 2506 }; 2507 2508 LabelLengthCase::LabelLengthCase (Context& ctx, const char* name, const char* desc) 2509 : TestCase(ctx, name, desc) 2510 { 2511 } 2512 2513 LabelLengthCase::IterateResult LabelLengthCase::iterate (void) 2514 { 2515 TCU_CHECK_AND_THROW(NotSupportedError, isKHRDebugSupported(m_context), "GL_KHR_debug is not supported"); 2516 2517 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 2518 tcu::ResultCollector result (m_testCtx.getLog(), " // ERROR: "); 2519 const char* const msg = "This is a debug label"; 2520 int outlen = -1; 2521 GLuint shader; 2522 glw::GLsync sync; 2523 2524 sync = gl.fenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0); 2525 GLS_COLLECT_GL_ERROR(result, gl.getError(), "fenceSync"); 2526 2527 shader = gl.createShader(GL_FRAGMENT_SHADER); 2528 GLS_COLLECT_GL_ERROR(result, gl.getError(), "createShader"); 2529 2530 { 2531 const tcu::ScopedLogSection section(m_testCtx.getLog(), "Shader", "Shader object"); 2532 2533 m_testCtx.getLog() << TestLog::Message << "Querying label length" << TestLog::EndMessage; 2534 outlen = -1; 2535 gl.getObjectLabel(GL_SHADER, shader, 0, &outlen, DE_NULL); 2536 GLS_COLLECT_GL_ERROR(result, gl.getError(), "getObjectLabel"); 2537 2538 if (outlen != 0) 2539 result.fail("'length' was not 0, got " + de::toString(outlen)); 2540 else 2541 m_testCtx.getLog() << TestLog::Message << "Query returned length: " << outlen << TestLog::EndMessage; 2542 2543 m_testCtx.getLog() << TestLog::Message << "Setting label to string: \"" << msg << "\"" << TestLog::EndMessage; 2544 gl.objectLabel(GL_SHADER, shader, -1, msg); 2545 GLS_COLLECT_GL_ERROR(result, gl.getError(), "objectLabel"); 2546 2547 m_testCtx.getLog() << TestLog::Message << "Querying label length" << TestLog::EndMessage; 2548 outlen = -1; 2549 gl.getObjectLabel(GL_SHADER, shader, 0, &outlen, DE_NULL); 2550 GLS_COLLECT_GL_ERROR(result, gl.getError(), "getObjectLabel"); 2551 2552 if (outlen != 21) 2553 result.fail("'length' was not 21, got " + de::toString(outlen)); 2554 else 2555 m_testCtx.getLog() << TestLog::Message << "Query returned length: " << outlen << TestLog::EndMessage; 2556 } 2557 2558 { 2559 const tcu::ScopedLogSection section(m_testCtx.getLog(), "Sync", "Sync object"); 2560 2561 m_testCtx.getLog() << TestLog::Message << "Querying label length" << TestLog::EndMessage; 2562 outlen = -1; 2563 gl.getObjectPtrLabel(sync, 0, &outlen, DE_NULL); 2564 GLS_COLLECT_GL_ERROR(result, gl.getError(), "getObjectPtrLabel"); 2565 2566 if (outlen != 0) 2567 result.fail("'length' was not 0, got " + de::toString(outlen)); 2568 else 2569 m_testCtx.getLog() << TestLog::Message << "Query returned length: " << outlen << TestLog::EndMessage; 2570 2571 m_testCtx.getLog() << TestLog::Message << "Setting label to string: \"" << msg << "\"" << TestLog::EndMessage; 2572 gl.objectPtrLabel(sync, -1, msg); 2573 GLS_COLLECT_GL_ERROR(result, gl.getError(), "objectPtrLabel"); 2574 2575 m_testCtx.getLog() << TestLog::Message << "Querying label length" << TestLog::EndMessage; 2576 outlen = -1; 2577 gl.getObjectPtrLabel(sync, 0, &outlen, DE_NULL); 2578 GLS_COLLECT_GL_ERROR(result, gl.getError(), "getObjectPtrLabel"); 2579 2580 if (outlen != 21) 2581 result.fail("'length' was not 21, got " + de::toString(outlen)); 2582 else 2583 m_testCtx.getLog() << TestLog::Message << "Query returned length: " << outlen << TestLog::EndMessage; 2584 } 2585 2586 gl.deleteShader(shader); 2587 gl.deleteSync(sync); 2588 2589 result.setTestContextResult(m_testCtx); 2590 return STOP; 2591 } 2592 2593 class LimitQueryCase : public TestCase 2594 { 2595 public: 2596 LimitQueryCase (Context& context, 2597 const char* name, 2598 const char* description, 2599 glw::GLenum target, 2600 int limit, 2601 gls::StateQueryUtil::QueryType type); 2602 2603 IterateResult iterate (void); 2604 private: 2605 const gls::StateQueryUtil::QueryType m_type; 2606 const int m_limit; 2607 const glw::GLenum m_target; 2608 }; 2609 2610 LimitQueryCase::LimitQueryCase (Context& context, 2611 const char* name, 2612 const char* description, 2613 glw::GLenum target, 2614 int limit, 2615 gls::StateQueryUtil::QueryType type) 2616 : TestCase (context, name, description) 2617 , m_type (type) 2618 , m_limit (limit) 2619 , m_target (target) 2620 { 2621 } 2622 2623 LimitQueryCase::IterateResult LimitQueryCase::iterate (void) 2624 { 2625 TCU_CHECK_AND_THROW(NotSupportedError, isKHRDebugSupported(m_context), "GL_KHR_debug is not supported"); 2626 2627 glu::CallLogWrapper gl (m_context.getRenderContext().getFunctions(), m_testCtx.getLog()); 2628 tcu::ResultCollector result (m_testCtx.getLog(), " // ERROR: "); 2629 2630 gl.enableLogging(true); 2631 gls::StateQueryUtil::verifyStateIntegerMin(result, gl, m_target, m_limit, m_type); 2632 2633 result.setTestContextResult(m_testCtx); 2634 return STOP; 2635 } 2636 2637 class IsEnabledCase : public TestCase 2638 { 2639 public: 2640 enum InitialValue 2641 { 2642 INITIAL_CTX_IS_DEBUG = 0, 2643 INITIAL_FALSE, 2644 }; 2645 2646 IsEnabledCase (Context& context, 2647 const char* name, 2648 const char* description, 2649 glw::GLenum target, 2650 InitialValue initial, 2651 gls::StateQueryUtil::QueryType type); 2652 2653 IterateResult iterate (void); 2654 private: 2655 const gls::StateQueryUtil::QueryType m_type; 2656 const glw::GLenum m_target; 2657 const InitialValue m_initial; 2658 }; 2659 2660 IsEnabledCase::IsEnabledCase (Context& context, 2661 const char* name, 2662 const char* description, 2663 glw::GLenum target, 2664 InitialValue initial, 2665 gls::StateQueryUtil::QueryType type) 2666 : TestCase (context, name, description) 2667 , m_type (type) 2668 , m_target (target) 2669 , m_initial (initial) 2670 { 2671 } 2672 2673 IsEnabledCase::IterateResult IsEnabledCase::iterate (void) 2674 { 2675 TCU_CHECK_AND_THROW(NotSupportedError, isKHRDebugSupported(m_context), "GL_KHR_debug is not supported"); 2676 2677 glu::CallLogWrapper gl (m_context.getRenderContext().getFunctions(), m_testCtx.getLog()); 2678 tcu::ResultCollector result (m_testCtx.getLog(), " // ERROR: "); 2679 bool initial; 2680 2681 gl.enableLogging(true); 2682 2683 if (m_initial == INITIAL_FALSE) 2684 initial = false; 2685 else 2686 { 2687 DE_ASSERT(m_initial == INITIAL_CTX_IS_DEBUG); 2688 initial = (m_context.getRenderContext().getType().getFlags() & glu::CONTEXT_DEBUG) != 0; 2689 } 2690 2691 // check inital value 2692 gls::StateQueryUtil::verifyStateBoolean(result, gl, m_target, initial, m_type); 2693 2694 // check toggle 2695 2696 gl.glEnable(m_target); 2697 GLS_COLLECT_GL_ERROR(result, gl.glGetError(), "glEnable"); 2698 2699 gls::StateQueryUtil::verifyStateBoolean(result, gl, m_target, true, m_type); 2700 2701 gl.glDisable(m_target); 2702 GLS_COLLECT_GL_ERROR(result, gl.glGetError(), "glDisable"); 2703 2704 gls::StateQueryUtil::verifyStateBoolean(result, gl, m_target, false, m_type); 2705 2706 result.setTestContextResult(m_testCtx); 2707 return STOP; 2708 } 2709 2710 class PositiveIntegerCase : public TestCase 2711 { 2712 public: 2713 PositiveIntegerCase (Context& context, 2714 const char* name, 2715 const char* description, 2716 glw::GLenum target, 2717 gls::StateQueryUtil::QueryType type); 2718 2719 IterateResult iterate (void); 2720 private: 2721 const gls::StateQueryUtil::QueryType m_type; 2722 const glw::GLenum m_target; 2723 }; 2724 2725 PositiveIntegerCase::PositiveIntegerCase (Context& context, 2726 const char* name, 2727 const char* description, 2728 glw::GLenum target, 2729 gls::StateQueryUtil::QueryType type) 2730 : TestCase (context, name, description) 2731 , m_type (type) 2732 , m_target (target) 2733 { 2734 } 2735 2736 PositiveIntegerCase::IterateResult PositiveIntegerCase::iterate (void) 2737 { 2738 TCU_CHECK_AND_THROW(NotSupportedError, isKHRDebugSupported(m_context), "GL_KHR_debug is not supported"); 2739 2740 glu::CallLogWrapper gl (m_context.getRenderContext().getFunctions(), m_testCtx.getLog()); 2741 tcu::ResultCollector result (m_testCtx.getLog(), " // ERROR: "); 2742 2743 gl.enableLogging(true); 2744 gls::StateQueryUtil::verifyStateIntegerMin(result, gl, m_target, 0, m_type); 2745 2746 result.setTestContextResult(m_testCtx); 2747 return STOP; 2748 } 2749 2750 class GroupStackDepthQueryCase : public TestCase 2751 { 2752 public: 2753 GroupStackDepthQueryCase (Context& context, 2754 const char* name, 2755 const char* description, 2756 gls::StateQueryUtil::QueryType type); 2757 2758 IterateResult iterate (void); 2759 private: 2760 const gls::StateQueryUtil::QueryType m_type; 2761 }; 2762 2763 GroupStackDepthQueryCase::GroupStackDepthQueryCase (Context& context, 2764 const char* name, 2765 const char* description, 2766 gls::StateQueryUtil::QueryType type) 2767 : TestCase (context, name, description) 2768 , m_type (type) 2769 { 2770 } 2771 2772 GroupStackDepthQueryCase::IterateResult GroupStackDepthQueryCase::iterate (void) 2773 { 2774 TCU_CHECK_AND_THROW(NotSupportedError, isKHRDebugSupported(m_context), "GL_KHR_debug is not supported"); 2775 2776 glu::CallLogWrapper gl (m_context.getRenderContext().getFunctions(), m_testCtx.getLog()); 2777 tcu::ResultCollector result (m_testCtx.getLog(), " // ERROR: "); 2778 2779 gl.enableLogging(true); 2780 2781 { 2782 const tcu::ScopedLogSection section(m_testCtx.getLog(), "Initial", "Initial"); 2783 2784 gls::StateQueryUtil::verifyStateInteger(result, gl, GL_DEBUG_GROUP_STACK_DEPTH, 1, m_type); 2785 } 2786 2787 { 2788 const tcu::ScopedLogSection section(m_testCtx.getLog(), "Scoped", "Scoped"); 2789 2790 gl.glPushDebugGroup(GL_DEBUG_SOURCE_APPLICATION, 1, -1, "Application group 1"); 2791 gls::StateQueryUtil::verifyStateInteger(result, gl, GL_DEBUG_GROUP_STACK_DEPTH, 2, m_type); 2792 gl.glPopDebugGroup(); 2793 } 2794 2795 result.setTestContextResult(m_testCtx); 2796 return STOP; 2797 } 2798 2799 extern "C" void GLW_APIENTRY dummyCallback(GLenum, GLenum, GLuint, GLenum, GLsizei, const char*, void*) 2800 { 2801 // dummy 2802 } 2803 2804 class DebugCallbackFunctionCase : public TestCase 2805 { 2806 public: 2807 DebugCallbackFunctionCase (Context& context, const char* name, const char* description); 2808 IterateResult iterate (void); 2809 }; 2810 2811 DebugCallbackFunctionCase::DebugCallbackFunctionCase (Context& context, const char* name, const char* description) 2812 : TestCase (context, name, description) 2813 { 2814 } 2815 2816 DebugCallbackFunctionCase::IterateResult DebugCallbackFunctionCase::iterate (void) 2817 { 2818 using namespace gls::StateQueryUtil; 2819 TCU_CHECK_AND_THROW(NotSupportedError, isKHRDebugSupported(m_context), "GL_KHR_debug is not supported"); 2820 2821 glu::CallLogWrapper gl (m_context.getRenderContext().getFunctions(), m_testCtx.getLog()); 2822 tcu::ResultCollector result (m_testCtx.getLog(), " // ERROR: "); 2823 2824 gl.enableLogging(true); 2825 2826 { 2827 const tcu::ScopedLogSection section(m_testCtx.getLog(), "Initial", "Initial"); 2828 2829 verifyStatePointer(result, gl, GL_DEBUG_CALLBACK_FUNCTION, 0, QUERY_POINTER); 2830 } 2831 2832 { 2833 const tcu::ScopedLogSection section(m_testCtx.getLog(), "Set", "Set"); 2834 2835 gl.glDebugMessageCallback(dummyCallback, DE_NULL); 2836 verifyStatePointer(result, gl, GL_DEBUG_CALLBACK_FUNCTION, (const void*)dummyCallback, QUERY_POINTER); 2837 } 2838 2839 result.setTestContextResult(m_testCtx); 2840 return STOP; 2841 } 2842 2843 class DebugCallbackUserParamCase : public TestCase 2844 { 2845 public: 2846 DebugCallbackUserParamCase (Context& context, const char* name, const char* description); 2847 IterateResult iterate (void); 2848 }; 2849 2850 DebugCallbackUserParamCase::DebugCallbackUserParamCase (Context& context, const char* name, const char* description) 2851 : TestCase (context, name, description) 2852 { 2853 } 2854 2855 DebugCallbackUserParamCase::IterateResult DebugCallbackUserParamCase::iterate (void) 2856 { 2857 using namespace gls::StateQueryUtil; 2858 2859 TCU_CHECK_AND_THROW(NotSupportedError, isKHRDebugSupported(m_context), "GL_KHR_debug is not supported"); 2860 2861 glu::CallLogWrapper gl (m_context.getRenderContext().getFunctions(), m_testCtx.getLog()); 2862 tcu::ResultCollector result (m_testCtx.getLog(), " // ERROR: "); 2863 2864 gl.enableLogging(true); 2865 2866 { 2867 const tcu::ScopedLogSection section(m_testCtx.getLog(), "Initial", "Initial"); 2868 2869 verifyStatePointer(result, gl, GL_DEBUG_CALLBACK_USER_PARAM, 0, QUERY_POINTER); 2870 } 2871 2872 { 2873 const tcu::ScopedLogSection section (m_testCtx.getLog(), "Set", "Set"); 2874 const void* param = (void*)(int*)0x123; 2875 2876 gl.glDebugMessageCallback(dummyCallback, param); 2877 verifyStatePointer(result, gl, GL_DEBUG_CALLBACK_USER_PARAM, param, QUERY_POINTER); 2878 } 2879 2880 result.setTestContextResult(m_testCtx); 2881 return STOP; 2882 } 2883 2884 } // anonymous 2885 2886 DebugTests::DebugTests (Context& context) 2887 : TestCaseGroup(context, "debug", "Debug tests") 2888 { 2889 } 2890 2891 enum CaseType 2892 { 2893 CASETYPE_CALLBACK = 0, 2894 CASETYPE_LOG, 2895 CASETYPE_GETERROR, 2896 2897 CASETYPE_LAST 2898 }; 2899 2900 tcu::TestNode* createCase (CaseType type, Context& ctx, const char* name, const char* desc, TestFunctionWrapper function) 2901 { 2902 switch(type) 2903 { 2904 case CASETYPE_CALLBACK: return new CallbackErrorCase(ctx, name, desc, function); 2905 case CASETYPE_LOG: return new LogErrorCase(ctx, name, desc, function); 2906 case CASETYPE_GETERROR: return new GetErrorCase(ctx, name, desc, function); 2907 2908 default: 2909 DE_FATAL("Invalid type"); 2910 } 2911 2912 return DE_NULL; 2913 } 2914 2915 tcu::TestCaseGroup* createChildCases (CaseType type, Context& ctx, const char* name, const char* desc, const vector<FunctionContainer>& funcs) 2916 { 2917 tcu::TestCaseGroup* host = new tcu::TestCaseGroup(ctx.getTestContext(), name, desc); 2918 2919 for (size_t ndx = 0; ndx < funcs.size(); ndx++) 2920 host->addChild(createCase(type, ctx, funcs[ndx].name, funcs[ndx].desc, funcs[ndx].function)); 2921 2922 return host; 2923 } 2924 2925 vector<FunctionContainer> wrapCoreFunctions (const vector<NegativeTestShared::FunctionContainer>& fns) 2926 { 2927 vector<FunctionContainer> retVal; 2928 2929 retVal.resize(fns.size()); 2930 for (int ndx = 0; ndx < (int)fns.size(); ++ndx) 2931 { 2932 retVal[ndx].function = TestFunctionWrapper(fns[ndx].function); 2933 retVal[ndx].name = fns[ndx].name; 2934 retVal[ndx].desc = fns[ndx].desc; 2935 } 2936 2937 return retVal; 2938 } 2939 2940 void DebugTests::init (void) 2941 { 2942 const vector<FunctionContainer> bufferFuncs = wrapCoreFunctions(NegativeTestShared::getNegativeBufferApiTestFunctions()); 2943 const vector<FunctionContainer> textureFuncs = wrapCoreFunctions(NegativeTestShared::getNegativeTextureApiTestFunctions()); 2944 const vector<FunctionContainer> shaderFuncs = wrapCoreFunctions(NegativeTestShared::getNegativeShaderApiTestFunctions()); 2945 const vector<FunctionContainer> fragmentFuncs = wrapCoreFunctions(NegativeTestShared::getNegativeFragmentApiTestFunctions()); 2946 const vector<FunctionContainer> vaFuncs = wrapCoreFunctions(NegativeTestShared::getNegativeVertexArrayApiTestFunctions()); 2947 const vector<FunctionContainer> stateFuncs = wrapCoreFunctions(NegativeTestShared::getNegativeStateApiTestFunctions()); 2948 const vector<FunctionContainer> atomicCounterFuncs = wrapCoreFunctions(NegativeTestShared::getNegativeAtomicCounterTestFunctions()); 2949 const vector<FunctionContainer> imageLoadFuncs = wrapCoreFunctions(NegativeTestShared::getNegativeShaderImageLoadTestFunctions()); 2950 const vector<FunctionContainer> imageStoreFuncs = wrapCoreFunctions(NegativeTestShared::getNegativeShaderImageStoreTestFunctions()); 2951 const vector<FunctionContainer> imageAtomicFuncs = wrapCoreFunctions(NegativeTestShared::getNegativeShaderImageAtomicTestFunctions()); 2952 const vector<FunctionContainer> imageAtomicExchangeFuncs = wrapCoreFunctions(NegativeTestShared::getNegativeShaderImageAtomicExchangeTestFunctions()); 2953 const vector<FunctionContainer> shaderFunctionFuncs = wrapCoreFunctions(NegativeTestShared::getNegativeShaderFunctionTestFunctions()); 2954 const vector<FunctionContainer> shaderDirectiveFuncs = wrapCoreFunctions(NegativeTestShared::getNegativeShaderDirectiveTestFunctions()); 2955 const vector<FunctionContainer> preciseFuncs = wrapCoreFunctions(NegativeTestShared::getNegativePreciseTestFunctions()); 2956 const vector<FunctionContainer> advancedBlendFuncs = wrapCoreFunctions(NegativeTestShared::getNegativeAdvancedBlendEquationTestFunctions()); 2957 const vector<FunctionContainer> externalFuncs = getUserMessageFuncs(); 2958 2959 { 2960 using namespace gls::StateQueryUtil; 2961 2962 tcu::TestCaseGroup* const queries = new tcu::TestCaseGroup(m_testCtx, "state_query", "State query"); 2963 2964 static const struct 2965 { 2966 const char* name; 2967 const char* targetName; 2968 glw::GLenum target; 2969 int limit; 2970 } limits[] = 2971 { 2972 { "max_debug_message_length", "MAX_DEBUG_MESSAGE_LENGTH", GL_MAX_DEBUG_MESSAGE_LENGTH, 1 }, 2973 { "max_debug_logged_messages", "MAX_DEBUG_LOGGED_MESSAGES", GL_MAX_DEBUG_LOGGED_MESSAGES, 1 }, 2974 { "max_debug_group_stack_depth", "MAX_DEBUG_GROUP_STACK_DEPTH", GL_MAX_DEBUG_GROUP_STACK_DEPTH, 64 }, 2975 { "max_label_length", "MAX_LABEL_LENGTH", GL_MAX_LABEL_LENGTH, 256 }, 2976 }; 2977 2978 addChild(queries); 2979 2980 #define FOR_ALL_TYPES(X) \ 2981 do \ 2982 { \ 2983 { \ 2984 const char* const postfix = "_getboolean"; \ 2985 const QueryType queryType = QUERY_BOOLEAN; \ 2986 X; \ 2987 } \ 2988 { \ 2989 const char* const postfix = "_getinteger"; \ 2990 const QueryType queryType = QUERY_INTEGER; \ 2991 X; \ 2992 } \ 2993 { \ 2994 const char* const postfix = "_getinteger64"; \ 2995 const QueryType queryType = QUERY_INTEGER64; \ 2996 X; \ 2997 } \ 2998 { \ 2999 const char* const postfix = "_getfloat"; \ 3000 const QueryType queryType = QUERY_FLOAT; \ 3001 X; \ 3002 } \ 3003 } \ 3004 while (deGetFalse()) 3005 #define FOR_ALL_ENABLE_TYPES(X) \ 3006 do \ 3007 { \ 3008 { \ 3009 const char* const postfix = "_isenabled"; \ 3010 const QueryType queryType = QUERY_ISENABLED; \ 3011 X; \ 3012 } \ 3013 FOR_ALL_TYPES(X); \ 3014 } \ 3015 while (deGetFalse()) 3016 3017 for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(limits); ++ndx) 3018 { 3019 FOR_ALL_TYPES(queries->addChild(new LimitQueryCase(m_context, 3020 (std::string(limits[ndx].name) + postfix).c_str(), 3021 (std::string("Test ") + limits[ndx].targetName).c_str(), 3022 limits[ndx].target, limits[ndx].limit, queryType))); 3023 } 3024 3025 FOR_ALL_ENABLE_TYPES(queries->addChild(new IsEnabledCase (m_context, (std::string("debug_output") + postfix).c_str(), "Test DEBUG_OUTPUT", GL_DEBUG_OUTPUT, IsEnabledCase::INITIAL_CTX_IS_DEBUG, queryType))); 3026 FOR_ALL_ENABLE_TYPES(queries->addChild(new IsEnabledCase (m_context, (std::string("debug_output_synchronous") + postfix).c_str(), "Test DEBUG_OUTPUT_SYNCHRONOUS", GL_DEBUG_OUTPUT_SYNCHRONOUS, IsEnabledCase::INITIAL_FALSE, queryType))); 3027 3028 FOR_ALL_TYPES(queries->addChild(new PositiveIntegerCase (m_context, (std::string("debug_logged_messages") + postfix).c_str(), "Test DEBUG_LOGGED_MESSAGES", GL_DEBUG_LOGGED_MESSAGES, queryType))); 3029 FOR_ALL_TYPES(queries->addChild(new PositiveIntegerCase (m_context, (std::string("debug_next_logged_message_length") + postfix).c_str(), "Test DEBUG_NEXT_LOGGED_MESSAGE_LENGTH", GL_DEBUG_NEXT_LOGGED_MESSAGE_LENGTH, queryType))); 3030 FOR_ALL_TYPES(queries->addChild(new GroupStackDepthQueryCase(m_context, (std::string("debug_group_stack_depth") + postfix).c_str(), "Test DEBUG_GROUP_STACK_DEPTH", queryType))); 3031 3032 queries->addChild(new DebugCallbackFunctionCase (m_context, "debug_callback_function_getpointer", "Test DEBUG_CALLBACK_FUNCTION")); 3033 queries->addChild(new DebugCallbackUserParamCase(m_context, "debug_callback_user_param_getpointer", "Test DEBUG_CALLBACK_USER_PARAM")); 3034 3035 #undef FOR_ALL_TYPES 3036 #undef FOR_ALL_ENABLE_TYPES 3037 } 3038 3039 { 3040 tcu::TestCaseGroup* const negative = new tcu::TestCaseGroup(m_testCtx, "negative_coverage", "API error coverage with various reporting methods"); 3041 3042 addChild(negative); 3043 { 3044 tcu::TestCaseGroup* const host = new tcu::TestCaseGroup(m_testCtx, "callbacks", "Reporting of standard API errors via callback"); 3045 3046 negative->addChild(host); 3047 host->addChild(createChildCases(CASETYPE_CALLBACK, m_context, "buffer", "Negative Buffer API Cases", bufferFuncs)); 3048 host->addChild(createChildCases(CASETYPE_CALLBACK, m_context, "texture", "Negative Texture API Cases", textureFuncs)); 3049 host->addChild(createChildCases(CASETYPE_CALLBACK, m_context, "shader", "Negative Shader API Cases", shaderFuncs)); 3050 host->addChild(createChildCases(CASETYPE_CALLBACK, m_context, "fragment", "Negative Fragment API Cases", fragmentFuncs)); 3051 host->addChild(createChildCases(CASETYPE_CALLBACK, m_context, "vertex_array", "Negative Vertex Array API Cases", vaFuncs)); 3052 host->addChild(createChildCases(CASETYPE_CALLBACK, m_context, "state", "Negative GL State API Cases", stateFuncs)); 3053 host->addChild(createChildCases(CASETYPE_CALLBACK, m_context, "atomic_counter", "Negative Atomic Counter API Cases", atomicCounterFuncs)); 3054 host->addChild(createChildCases(CASETYPE_CALLBACK, m_context, "shader_image_load", "Negative Shader Image Load API Cases", imageLoadFuncs)); 3055 host->addChild(createChildCases(CASETYPE_CALLBACK, m_context, "shader_image_store", "Negative Shader Image Store API Cases", imageStoreFuncs)); 3056 host->addChild(createChildCases(CASETYPE_CALLBACK, m_context, "shader_image_atomic", "Negative Shader Image Atomic API Cases", imageAtomicFuncs)); 3057 host->addChild(createChildCases(CASETYPE_CALLBACK, m_context, "shader_image_exchange", "Negative Shader Image Atomic Exchange API Cases", imageAtomicExchangeFuncs)); 3058 host->addChild(createChildCases(CASETYPE_CALLBACK, m_context, "shader_function", "Negative Shader Function Cases", shaderFunctionFuncs)); 3059 host->addChild(createChildCases(CASETYPE_CALLBACK, m_context, "shader_directive", "Negative Shader Directive Cases", shaderDirectiveFuncs)); 3060 host->addChild(createChildCases(CASETYPE_CALLBACK, m_context, "precise", "Negative Precise Cases", preciseFuncs)); 3061 host->addChild(createChildCases(CASETYPE_CALLBACK, m_context, "advanced_blend", "Negative Advanced Blend Equation Cases", advancedBlendFuncs)); 3062 } 3063 3064 { 3065 tcu::TestCaseGroup* const host = new tcu::TestCaseGroup(m_testCtx, "log", "Reporting of standard API errors via log"); 3066 3067 negative->addChild(host); 3068 3069 host->addChild(createChildCases(CASETYPE_LOG, m_context, "buffer", "Negative Buffer API Cases", bufferFuncs)); 3070 host->addChild(createChildCases(CASETYPE_LOG, m_context, "texture", "Negative Texture API Cases", textureFuncs)); 3071 host->addChild(createChildCases(CASETYPE_LOG, m_context, "shader", "Negative Shader API Cases", shaderFuncs)); 3072 host->addChild(createChildCases(CASETYPE_LOG, m_context, "fragment", "Negative Fragment API Cases", fragmentFuncs)); 3073 host->addChild(createChildCases(CASETYPE_LOG, m_context, "vertex_array", "Negative Vertex Array API Cases", vaFuncs)); 3074 host->addChild(createChildCases(CASETYPE_LOG, m_context, "state", "Negative GL State API Cases", stateFuncs)); 3075 host->addChild(createChildCases(CASETYPE_LOG, m_context, "atomic_counter", "Negative Atomic Counter API Cases", atomicCounterFuncs)); 3076 host->addChild(createChildCases(CASETYPE_LOG, m_context, "shader_image_load", "Negative Shader Image Load API Cases", imageLoadFuncs)); 3077 host->addChild(createChildCases(CASETYPE_LOG, m_context, "shader_image_store", "Negative Shader Image Store API Cases", imageStoreFuncs)); 3078 host->addChild(createChildCases(CASETYPE_LOG, m_context, "shader_image_atomic", "Negative Shader Image Atomic API Cases", imageAtomicFuncs)); 3079 host->addChild(createChildCases(CASETYPE_LOG, m_context, "shader_image_exchange", "Negative Shader Image Atomic Exchange API Cases", imageAtomicExchangeFuncs)); 3080 host->addChild(createChildCases(CASETYPE_LOG, m_context, "shader_function", "Negative Shader Function Cases", shaderFunctionFuncs)); 3081 host->addChild(createChildCases(CASETYPE_LOG, m_context, "shader_directive", "Negative Shader Directive Cases", shaderDirectiveFuncs)); 3082 host->addChild(createChildCases(CASETYPE_LOG, m_context, "precise", "Negative Precise Cases", preciseFuncs)); 3083 host->addChild(createChildCases(CASETYPE_LOG, m_context, "advanced_blend", "Negative Advanced Blend Equation Cases", advancedBlendFuncs)); 3084 } 3085 3086 { 3087 tcu::TestCaseGroup* const host = new tcu::TestCaseGroup(m_testCtx, "get_error", "Reporting of standard API errors via glGetError"); 3088 3089 negative->addChild(host); 3090 3091 host->addChild(createChildCases(CASETYPE_GETERROR, m_context, "buffer", "Negative Buffer API Cases", bufferFuncs)); 3092 host->addChild(createChildCases(CASETYPE_GETERROR, m_context, "texture", "Negative Texture API Cases", textureFuncs)); 3093 host->addChild(createChildCases(CASETYPE_GETERROR, m_context, "shader", "Negative Shader API Cases", shaderFuncs)); 3094 host->addChild(createChildCases(CASETYPE_GETERROR, m_context, "fragment", "Negative Fragment API Cases", fragmentFuncs)); 3095 host->addChild(createChildCases(CASETYPE_GETERROR, m_context, "vertex_array", "Negative Vertex Array API Cases", vaFuncs)); 3096 host->addChild(createChildCases(CASETYPE_GETERROR, m_context, "state", "Negative GL State API Cases", stateFuncs)); 3097 host->addChild(createChildCases(CASETYPE_GETERROR, m_context, "atomic_counter", "Negative Atomic Counter API Cases", atomicCounterFuncs)); 3098 host->addChild(createChildCases(CASETYPE_GETERROR, m_context, "shader_image_load", "Negative Shader Image Load API Cases", imageLoadFuncs)); 3099 host->addChild(createChildCases(CASETYPE_GETERROR, m_context, "shader_image_store", "Negative Shader Image Store API Cases", imageStoreFuncs)); 3100 host->addChild(createChildCases(CASETYPE_GETERROR, m_context, "shader_image_atomic", "Negative Shader Image Atomic API Cases", imageAtomicFuncs)); 3101 host->addChild(createChildCases(CASETYPE_GETERROR, m_context, "shader_image_exchange", "Negative Shader Image Atomic Exchange API Cases", imageAtomicExchangeFuncs)); 3102 host->addChild(createChildCases(CASETYPE_GETERROR, m_context, "shader_function", "Negative Shader Function Cases", shaderFunctionFuncs)); 3103 host->addChild(createChildCases(CASETYPE_GETERROR, m_context, "shader_directive", "Negative Shader Directive Cases", shaderDirectiveFuncs)); 3104 host->addChild(createChildCases(CASETYPE_GETERROR, m_context, "precise", "Negative Precise Cases", preciseFuncs)); 3105 host->addChild(createChildCases(CASETYPE_GETERROR, m_context, "advanced_blend", "Negative Advanced Blend Equation Cases", advancedBlendFuncs)); 3106 } 3107 } 3108 3109 { 3110 tcu::TestCaseGroup* const host = createChildCases(CASETYPE_CALLBACK, m_context, "externally_generated", "Externally Generated Messages", externalFuncs); 3111 3112 host->addChild(new GroupCase(m_context, "push_pop_consistency", "Push/pop message generation with full message output checking")); 3113 3114 addChild(host); 3115 } 3116 3117 { 3118 vector<FunctionContainer> containers; 3119 vector<TestFunctionWrapper> allFuncs; 3120 3121 de::Random rng (0x53941903 ^ m_context.getTestContext().getCommandLine().getBaseSeed()); 3122 3123 containers.insert(containers.end(), bufferFuncs.begin(), bufferFuncs.end()); 3124 containers.insert(containers.end(), textureFuncs.begin(), textureFuncs.end()); 3125 containers.insert(containers.end(), externalFuncs.begin(), externalFuncs.end()); 3126 3127 for (size_t ndx = 0; ndx < containers.size(); ndx++) 3128 allFuncs.push_back(containers[ndx].function); 3129 3130 rng.shuffle(allFuncs.begin(), allFuncs.end()); 3131 3132 { 3133 tcu::TestCaseGroup* const filtering = new tcu::TestCaseGroup(m_testCtx, "error_filters", "Filtering of reported errors"); 3134 const int errorFuncsPerCase = 4; 3135 const int maxFilteringCaseCount = 32; 3136 const int caseCount = (int(allFuncs.size()) + errorFuncsPerCase-1) / errorFuncsPerCase; 3137 3138 addChild(filtering); 3139 3140 for (int caseNdx = 0; caseNdx < de::min(caseCount, maxFilteringCaseCount); caseNdx++) 3141 { 3142 const int start = caseNdx*errorFuncsPerCase; 3143 const int end = de::min((caseNdx+1)*errorFuncsPerCase, int(allFuncs.size())); 3144 const string name = "case_" + de::toString(caseNdx); 3145 vector<TestFunctionWrapper> funcs (allFuncs.begin()+start, allFuncs.begin()+end); 3146 3147 // These produce lots of different message types, thus always include at least one when testing filtering 3148 funcs.insert(funcs.end(), externalFuncs[caseNdx%externalFuncs.size()].function); 3149 3150 filtering->addChild(new FilterCase(m_context, name.c_str(), "DebugMessageControl usage", funcs)); 3151 } 3152 } 3153 3154 { 3155 tcu::TestCaseGroup* const groups = new tcu::TestCaseGroup(m_testCtx, "error_groups", "Filtering of reported errors with use of Error Groups"); 3156 const int errorFuncsPerCase = 4; 3157 const int maxFilteringCaseCount = 16; 3158 const int caseCount = (int(allFuncs.size()) + errorFuncsPerCase-1) / errorFuncsPerCase; 3159 3160 addChild(groups); 3161 3162 for (int caseNdx = 0; caseNdx < caseCount && caseNdx < maxFilteringCaseCount; caseNdx++) 3163 { 3164 const int start = caseNdx*errorFuncsPerCase; 3165 const int end = de::min((caseNdx+1)*errorFuncsPerCase, int(allFuncs.size())); 3166 const string name = ("case_" + de::toString(caseNdx)).c_str(); 3167 vector<TestFunctionWrapper> funcs (&allFuncs[0]+start, &allFuncs[0]+end); 3168 3169 // These produce lots of different message types, thus always include at least one when testing filtering 3170 funcs.insert(funcs.end(), externalFuncs[caseNdx%externalFuncs.size()].function); 3171 3172 groups->addChild(new GroupFilterCase(m_context, name.c_str(), "Debug Group usage", funcs)); 3173 } 3174 } 3175 3176 { 3177 tcu::TestCaseGroup* const async = new tcu::TestCaseGroup(m_testCtx, "async", "Asynchronous message generation"); 3178 const int errorFuncsPerCase = 2; 3179 const int maxAsyncCaseCount = 16; 3180 const int caseCount = (int(allFuncs.size()) + errorFuncsPerCase-1) / errorFuncsPerCase; 3181 3182 addChild(async); 3183 3184 for (int caseNdx = 0; caseNdx < caseCount && caseNdx < maxAsyncCaseCount; caseNdx++) 3185 { 3186 const int start = caseNdx*errorFuncsPerCase; 3187 const int end = de::min((caseNdx+1)*errorFuncsPerCase, int(allFuncs.size())); 3188 const string name = ("case_" + de::toString(caseNdx)).c_str(); 3189 vector<TestFunctionWrapper> funcs (&allFuncs[0]+start, &allFuncs[0]+end); 3190 3191 if (caseNdx&0x1) 3192 async->addChild(new AsyncCase(m_context, (name+"_callback").c_str(), "Async message generation", funcs, true)); 3193 else 3194 async->addChild(new AsyncCase(m_context, (name+"_log").c_str(), "Async message generation", funcs, false)); 3195 } 3196 } 3197 } 3198 3199 { 3200 tcu::TestCaseGroup* const labels = new tcu::TestCaseGroup(m_testCtx, "object_labels", "Labeling objects"); 3201 3202 const struct 3203 { 3204 GLenum identifier; 3205 const char* name; 3206 const char* desc; 3207 } cases[] = 3208 { 3209 { GL_BUFFER, "buffer", "Debug label on a buffer object" }, 3210 { GL_SHADER, "shader", "Debug label on a shader object" }, 3211 { GL_PROGRAM, "program", "Debug label on a program object" }, 3212 { GL_QUERY, "query", "Debug label on a query object" }, 3213 { GL_PROGRAM_PIPELINE, "program_pipeline", "Debug label on a program pipeline object" }, 3214 { GL_TRANSFORM_FEEDBACK, "transform_feedback", "Debug label on a transform feedback object" }, 3215 { GL_SAMPLER, "sampler", "Debug label on a sampler object" }, 3216 { GL_TEXTURE, "texture", "Debug label on a texture object" }, 3217 { GL_RENDERBUFFER, "renderbuffer", "Debug label on a renderbuffer object" }, 3218 { GL_FRAMEBUFFER, "framebuffer", "Debug label on a framebuffer object" }, 3219 }; 3220 3221 addChild(labels); 3222 3223 labels->addChild(new InitialLabelCase (m_context, "initial", "Debug label initial value")); 3224 labels->addChild(new ClearLabelCase (m_context, "clearing", "Debug label clearing")); 3225 labels->addChild(new SpecifyWithLengthCase (m_context, "specify_with_length", "Debug label specified with length")); 3226 labels->addChild(new BufferLimitedLabelCase (m_context, "buffer_limited_query", "Debug label query to too short buffer")); 3227 labels->addChild(new LabelMaxSizeCase (m_context, "max_label_length", "Max sized debug label")); 3228 labels->addChild(new LabelLengthCase (m_context, "query_length_only", "Query debug label length")); 3229 3230 for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(cases); ndx++) 3231 labels->addChild(new LabelCase(m_context, cases[ndx].name, cases[ndx].desc, cases[ndx].identifier)); 3232 labels->addChild(new SyncLabelCase(m_context, "sync", "Debug label on a sync object")); 3233 } 3234 } 3235 3236 } // Functional 3237 } // gles31 3238 } // deqp 3239