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 34 #include "deUniquePtr.hpp" 35 #include "deRandom.hpp" 36 #include "deStringUtil.hpp" 37 #include "deSTLUtil.hpp" 38 #include "deMutex.hpp" 39 #include "deThread.h" 40 41 #include "gluRenderContext.hpp" 42 #include "gluContextInfo.hpp" 43 #include "gluCallLogWrapper.hpp" 44 #include "gluStrUtil.hpp" 45 46 #include "glwDefs.hpp" 47 #include "glwEnums.hpp" 48 #include "glwFunctions.hpp" 49 50 #include "tes31Context.hpp" 51 #include "tcuTestContext.hpp" 52 #include "tcuCommandLine.hpp" 53 54 namespace deqp 55 { 56 namespace gles31 57 { 58 namespace Functional 59 { 60 namespace 61 { 62 using namespace glw; 63 64 using NegativeTestShared::NegativeTestContext; 65 using NegativeTestShared::FunctionContainer; 66 using std::string; 67 using std::vector; 68 69 GLenum debugTypes[] = 70 { 71 GL_DEBUG_TYPE_ERROR, 72 GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR, 73 GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR, 74 GL_DEBUG_TYPE_PORTABILITY, 75 GL_DEBUG_TYPE_PERFORMANCE, 76 GL_DEBUG_TYPE_OTHER, 77 GL_DEBUG_TYPE_MARKER, 78 GL_DEBUG_TYPE_PUSH_GROUP, 79 GL_DEBUG_TYPE_POP_GROUP, 80 }; 81 82 GLenum debugSeverities[] = 83 { 84 GL_DEBUG_SEVERITY_HIGH, 85 GL_DEBUG_SEVERITY_MEDIUM, 86 GL_DEBUG_SEVERITY_LOW, 87 GL_DEBUG_SEVERITY_NOTIFICATION, 88 }; 89 90 void emitMessages(NegativeTestContext& ctx, GLenum source) 91 { 92 for (int typeNdx = 0; typeNdx < DE_LENGTH_OF_ARRAY(debugTypes); typeNdx++) 93 { 94 for (int severityNdx = 0; severityNdx < DE_LENGTH_OF_ARRAY(debugSeverities); severityNdx++) 95 { 96 const GLenum type = debugTypes[typeNdx]; 97 const GLenum severity = debugSeverities[severityNdx]; 98 const string msg = string("Application generated message with type ") + glu::getDebugMessageTypeName(type) 99 + " and severity " + glu::getDebugMessageSeverityName(severity); 100 101 // Use severity as ID, guaranteed unique 102 ctx.glDebugMessageInsert(source, type, severity, severity, -1, msg.c_str()); 103 ctx.expectMessage(source, type); 104 } 105 } 106 } 107 108 void application_messages (NegativeTestContext& ctx) 109 { 110 ctx.beginSection("Messages with source of GL_DEBUG_SOURCE_APPLICATION"); 111 emitMessages(ctx, GL_DEBUG_SOURCE_APPLICATION); 112 ctx.endSection(); 113 } 114 115 void thirdparty_messages (NegativeTestContext& ctx) 116 { 117 ctx.beginSection("Messages with source of GL_DEBUG_SOURCE_THIRD_PARTY"); 118 emitMessages(ctx, GL_DEBUG_SOURCE_THIRD_PARTY); 119 ctx.endSection(); 120 } 121 122 void push_pop_messages (NegativeTestContext& ctx) 123 { 124 ctx.beginSection("Push/Pop Debug Group"); 125 126 ctx.glPushDebugGroup(GL_DEBUG_SOURCE_APPLICATION, 1, -1, "Application group 1"); 127 ctx.expectMessage(GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_PUSH_GROUP); 128 ctx.glPushDebugGroup(GL_DEBUG_SOURCE_APPLICATION, 2, -1, "Application group 1-1"); 129 ctx.expectMessage(GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_PUSH_GROUP); 130 ctx.glPushDebugGroup(GL_DEBUG_SOURCE_APPLICATION, 3, -1, "Application group 1-1-1"); 131 ctx.expectMessage(GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_PUSH_GROUP); 132 ctx.glPopDebugGroup(); 133 ctx.expectMessage(GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_POP_GROUP); 134 ctx.glPopDebugGroup(); 135 ctx.expectMessage(GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_POP_GROUP); 136 137 ctx.glPushDebugGroup(GL_DEBUG_SOURCE_APPLICATION, 4, -1, "Application group 1-2"); 138 ctx.expectMessage(GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_PUSH_GROUP); 139 ctx.glPopDebugGroup(); 140 ctx.expectMessage(GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_POP_GROUP); 141 142 ctx.glPushDebugGroup(GL_DEBUG_SOURCE_THIRD_PARTY, 4, -1, "3rd Party group 1-3"); 143 ctx.expectMessage(GL_DEBUG_SOURCE_THIRD_PARTY, GL_DEBUG_TYPE_PUSH_GROUP); 144 ctx.glPopDebugGroup(); 145 ctx.expectMessage(GL_DEBUG_SOURCE_THIRD_PARTY, GL_DEBUG_TYPE_POP_GROUP); 146 ctx.glPopDebugGroup(); 147 ctx.expectMessage(GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_POP_GROUP); 148 149 ctx.glPushDebugGroup(GL_DEBUG_SOURCE_THIRD_PARTY, 4, -1, "3rd Party group 2"); 150 ctx.expectMessage(GL_DEBUG_SOURCE_THIRD_PARTY, GL_DEBUG_TYPE_PUSH_GROUP); 151 ctx.glPopDebugGroup(); 152 ctx.expectMessage(GL_DEBUG_SOURCE_THIRD_PARTY, GL_DEBUG_TYPE_POP_GROUP); 153 154 ctx.endSection(); 155 } 156 157 vector<FunctionContainer> getUserMessageFuncs (void) 158 { 159 FunctionContainer funcs[] = 160 { 161 { application_messages, "application_messages", "Externally generated messages from the application" }, 162 { thirdparty_messages, "third_party_messages", "Externally generated messages from a third party" }, 163 { push_pop_messages, "push_pop_stack", "Messages from pushing/popping debug groups" }, 164 }; 165 166 return std::vector<FunctionContainer>(DE_ARRAY_BEGIN(funcs), DE_ARRAY_END(funcs)); 167 } 168 169 } // Anonymous 170 171 namespace 172 { 173 174 using std::string; 175 using std::vector; 176 using std::set; 177 using std::map; 178 using de::MovePtr; 179 180 using glw::GLenum; 181 using glw::GLuint; 182 using glw::GLsizei; 183 184 using tcu::ResultCollector; 185 using tcu::TestLog; 186 using glu::CallLogWrapper; 187 188 using NegativeTestShared::TestFunc; 189 using NegativeTestShared::FunctionContainer; 190 using NegativeTestShared::NegativeTestContext; 191 192 // Data required to uniquely identify a debug message 193 struct MessageID 194 { 195 GLenum source; 196 GLenum type; 197 GLuint id; 198 199 MessageID (void) : source(GL_NONE), type(GL_NONE), id(0) {} 200 MessageID (GLenum source_, GLenum type_, GLuint id_) : source(source_), type(type_), id(id_) {} 201 202 bool operator== (const MessageID& rhs) const { return source == rhs.source && type == rhs.type && id == rhs.id;} 203 bool operator!= (const MessageID& rhs) const { return source != rhs.source || type != rhs.type || id != rhs.id;} 204 bool operator< (const MessageID& rhs) const 205 { 206 return source < rhs.source || (source == rhs.source && (type < rhs.type || (type == rhs.type && id < rhs.id))); 207 } 208 }; 209 210 std::ostream& operator<< (std::ostream& str, const MessageID &id) 211 { 212 return str << glu::getDebugMessageSourceStr(id.source) << ", " << glu::getDebugMessageTypeStr(id.type) << ", " << id.id; 213 } 214 215 // All info from a single debug message 216 struct MessageData 217 { 218 MessageID id; 219 GLenum severity; 220 string message; 221 222 MessageData (void) : id(MessageID()), severity(GL_NONE) {} 223 MessageData (const MessageID& id_, GLenum severity_, const string& message_) : id(id_) , severity(severity_) , message(message_) {} 224 }; 225 226 extern "C" typedef void GLW_APIENTRY DebugCallbackFunc(GLenum, GLenum, GLuint, GLenum, GLsizei, const char*, void*); 227 228 // Base class 229 class BaseCase : public NegativeTestShared::ErrorCase 230 { 231 public: 232 BaseCase (Context& ctx, 233 const char* name, 234 const char* desc); 235 virtual ~BaseCase (void) {} 236 237 virtual IterateResult iterate (void) = 0; 238 239 virtual void expectMessage (GLenum source, GLenum type); 240 virtual void expectError (GLenum error0, GLenum error1); 241 242 protected: 243 struct VerificationResult { 244 const qpTestResult result; 245 const string resultMessage; 246 const string logMessage; 247 248 VerificationResult (qpTestResult result_, const string& resultMessage_, const string& logMessage_) 249 : result(result_), resultMessage(resultMessage_), logMessage(logMessage_) {} 250 }; 251 252 static DebugCallbackFunc callbackHandle; 253 virtual void callback (GLenum source, GLenum type, GLuint id, GLenum severity, const std::string& message); 254 255 256 VerificationResult verifyMessageCount (const MessageID& id, GLenum severity, int refCount, int resCount, bool messageEnabled) const; 257 258 // Verify a single message instance against expected attributes 259 void verifyMessage (const MessageData& message, GLenum source, GLenum type, GLuint id, GLenum severity); 260 void verifyMessage (const MessageData& message, GLenum source, GLenum type); 261 262 bool verifyMessageExists (const MessageData& message, GLenum source, GLenum type); 263 void verifyMessageGroup (const MessageData& message, GLenum source, GLenum type); 264 void verifyMessageString (const MessageData& message); 265 266 bool isDebugContext (void) const; 267 268 tcu::ResultCollector m_results; 269 }; 270 271 void BaseCase::callbackHandle (GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const char* message, void* userParam) 272 { 273 static_cast<BaseCase*>(userParam)->callback(source, type, id, severity, string(message, &message[length])); 274 } 275 276 BaseCase::BaseCase (Context& ctx, const char* name, const char* desc) 277 : ErrorCase(ctx, name, desc) 278 { 279 } 280 281 void BaseCase::expectMessage (GLenum source, GLenum type) 282 { 283 DE_UNREF(source); 284 DE_UNREF(type); 285 } 286 287 void BaseCase::expectError (GLenum error0, GLenum error1) 288 { 289 if (error0 != GL_NO_ERROR || error1 != GL_NO_ERROR) 290 expectMessage(GL_DEBUG_SOURCE_API, GL_DEBUG_TYPE_ERROR); 291 else 292 expectMessage(GL_DONT_CARE, GL_DONT_CARE); 293 } 294 295 void BaseCase::callback (GLenum source, GLenum type, GLuint id, GLenum severity, const string& message) 296 { 297 DE_UNREF(source); 298 DE_UNREF(type); 299 DE_UNREF(id); 300 DE_UNREF(severity); 301 DE_UNREF(message); 302 } 303 304 BaseCase::VerificationResult BaseCase::verifyMessageCount (const MessageID& id, GLenum severity, int refCount, int resCount, bool messageEnabled) const 305 { 306 std::stringstream log; 307 308 // This message should not be filtered out 309 if (messageEnabled) 310 { 311 if (resCount != refCount) 312 { 313 /* 314 * Technically nothing requires the implementation to be consistent in terms 315 * of the messages it produces in most situations, allowing the set of messages 316 * produced to vary between executions. This function splits messages 317 * into deterministic and non-deterministic to facilitate handling of such messages. 318 * 319 * Non-deterministic messages that are present in differing quantities in filtered and 320 * unfiltered runs will not fail the test case unless in direct violation of a filter: 321 * the implementation may produce an arbitrary number of such messages when they are 322 * not filtered out and none when they are filtered. 323 * 324 * A list of error source/type combinations with their assumed behaviour and 325 * the rationale for expecting such behaviour follows 326 * 327 * For API/shader messages we assume that the following types are deterministic: 328 * DEBUG_TYPE_ERROR Errors specified by spec and should always be produced 329 * 330 * For API messages the following types are assumed to be non-deterministic 331 * and treated as quality warnings since the underlying reported issue does not change between calls: 332 * DEBUG_TYPE_DEPRECATED_BEHAVIOR Reasonable to only report first instance 333 * DEBUG_TYPE_UNDEFINED_BEHAVIOR Reasonable to only report first instance 334 * DEBUG_TYPE_PORTABILITY Reasonable to only report first instance 335 * 336 * For API messages the following types are assumed to be non-deterministic 337 * and do not affect test results. 338 * DEBUG_TYPE_PERFORMANCE May be tied to arbitrary factors, reasonable to report only first instance 339 * DEBUG_TYPE_OTHER Definition allows arbitrary contents 340 * 341 * For 3rd party and application messages the following types are deterministic: 342 * DEBUG_TYPE_MARKER Only generated by test 343 * DEBUG_TYPE_PUSH_GROUP Only generated by test 344 * DEBUG_TYPE_POP_GROUP Only generated by test 345 * All others Only generated by test 346 * 347 * All messages with category of window system or other are treated as non-deterministic 348 * and do not effect test results since they can be assumed to be outside control of 349 * both the implementation and test case 350 * 351 */ 352 353 const bool isDeterministic = id.source == GL_DEBUG_SOURCE_APPLICATION || 354 id.source == GL_DEBUG_SOURCE_THIRD_PARTY || 355 ((id.source == GL_DEBUG_SOURCE_API || id.source == GL_DEBUG_SOURCE_SHADER_COMPILER) && id.type == GL_DEBUG_TYPE_ERROR); 356 357 const bool canIgnore = id.source == GL_DEBUG_SOURCE_WINDOW_SYSTEM || id.source == GL_DEBUG_SOURCE_OTHER; 358 359 if (isDeterministic) 360 { 361 if (resCount > refCount) 362 { 363 log << "Extra instances of message were found: (" << id << ") with " 364 << glu::getDebugMessageSeverityStr(severity) 365 << " (got " << resCount << ", expected " << refCount << ")"; 366 return VerificationResult(QP_TEST_RESULT_FAIL, "Extra instances of a deterministic message were present", log.str()); 367 } 368 else 369 { 370 log << "Instances of message were missing: (" << id << ") with " 371 << glu::getDebugMessageSeverityStr(severity) 372 << " (got " << resCount << ", expected " << refCount << ")"; 373 return VerificationResult(QP_TEST_RESULT_FAIL, "Message missing", log.str()); 374 } 375 } 376 else if(!canIgnore) 377 { 378 if (resCount > refCount) 379 { 380 log << "Extra instances of message were found but the message is non-deterministic(warning): (" << id << ") with " 381 << glu::getDebugMessageSeverityStr(severity) 382 << " (got " << resCount << ", expected " << refCount << ")"; 383 return VerificationResult(QP_TEST_RESULT_QUALITY_WARNING, "Extra instances of a message were present", log.str()); 384 } 385 else 386 { 387 log << "Instances of message were missing but the message is non-deterministic(warning): (" << id << ") with " 388 << glu::getDebugMessageSeverityStr(severity) 389 << " (got " << resCount << ", expected " << refCount << ")"; 390 return VerificationResult(QP_TEST_RESULT_QUALITY_WARNING, "Message missing", log.str()); 391 } 392 } 393 else 394 { 395 if (resCount > refCount) 396 { 397 log << "Extra instances of message were found but the message is non-deterministic(ignored): (" << id << ") with " 398 << glu::getDebugMessageSeverityStr(severity) 399 << " (got " << resCount << ", expected " << refCount << ")"; 400 return VerificationResult(QP_TEST_RESULT_PASS, "", log.str()); 401 } 402 else 403 { 404 log << "Instances of message were missing but the message is non-deterministic(ignored): (" << id << ") with " 405 << glu::getDebugMessageSeverityStr(severity) 406 << " (got " << resCount << ", expected " << refCount << ")"; 407 return VerificationResult(QP_TEST_RESULT_PASS, "", log.str()); 408 } 409 } 410 } 411 else // Passed as appropriate 412 { 413 log << "Message was found when expected: ("<< id << ") with " 414 << glu::getDebugMessageSeverityStr(severity); 415 return VerificationResult(QP_TEST_RESULT_PASS, "", log.str()); 416 } 417 } 418 // Message should be filtered out 419 else 420 { 421 // Filtered out 422 if (resCount == 0) 423 { 424 log << "Message was excluded correctly: (" << id << ") with " 425 << glu::getDebugMessageSeverityStr(severity); 426 return VerificationResult(QP_TEST_RESULT_PASS, "", log.str()); 427 } 428 // Only present in filtered run (ERROR) 429 else if (resCount > 0 && refCount == 0) 430 { 431 log << "A message was not excluded as it should have been: (" << id << ") with " 432 << glu::getDebugMessageSeverityStr(severity) 433 << ". This message was not present in the reference run"; 434 return VerificationResult(QP_TEST_RESULT_FAIL, "A message was not filtered out", log.str()); 435 } 436 // Present in both runs (ERROR) 437 else 438 { 439 log << "A message was not excluded as it should have been: (" << id << ") with " 440 << glu::getDebugMessageSeverityStr(severity); 441 return VerificationResult(QP_TEST_RESULT_FAIL, "A message was not filtered out", log.str()); 442 } 443 } 444 } 445 446 // Return true if message needs further verification 447 bool BaseCase::verifyMessageExists (const MessageData& message, GLenum source, GLenum type) 448 { 449 TestLog& log = m_testCtx.getLog(); 450 451 if (source == GL_DONT_CARE || type == GL_DONT_CARE) 452 return false; 453 else if (message.id.source == GL_NONE || message.id.type == GL_NONE) 454 { 455 if (isDebugContext()) 456 { 457 m_results.addResult(QP_TEST_RESULT_FAIL, "Message was not reported as expected"); 458 log << TestLog::Message << "A message was expected but none was reported" << TestLog::EndMessage; 459 } 460 else 461 { 462 m_results.addResult(QP_TEST_RESULT_QUALITY_WARNING, "Verification accuracy is lacking without a debug context"); 463 log << TestLog::Message << "A message was expected but none was reported. Running without a debug context" << TestLog::EndMessage; 464 } 465 return false; 466 } 467 else 468 return true; 469 } 470 471 void BaseCase::verifyMessageGroup (const MessageData& message, GLenum source, GLenum type) 472 { 473 TestLog& log = m_testCtx.getLog(); 474 475 if (message.id.source != source) 476 { 477 m_results.addResult(QP_TEST_RESULT_FAIL, "Incorrect message source"); 478 log << TestLog::Message << "Message source was " << glu::getDebugMessageSourceStr(message.id.source) 479 << " when it should have been " << glu::getDebugMessageSourceStr(source) << TestLog::EndMessage; 480 } 481 482 if (message.id.type != type) 483 { 484 m_results.addResult(QP_TEST_RESULT_FAIL, "Incorrect message type"); 485 log << TestLog::Message << "Message type was " << glu::getDebugMessageTypeStr(message.id.type) 486 << " when it should have been " << glu::getDebugMessageTypeStr(type) << TestLog::EndMessage; 487 } 488 } 489 490 void BaseCase::verifyMessageString (const MessageData& message) 491 { 492 TestLog& log = m_testCtx.getLog(); 493 494 log << TestLog::Message << "Driver says: \"" << message.message << "\"" << TestLog::EndMessage; 495 496 if (message.message.empty()) 497 { 498 m_results.addResult(QP_TEST_RESULT_QUALITY_WARNING, "Empty message"); 499 log << TestLog::Message << "Message message was empty" << TestLog::EndMessage; 500 } 501 } 502 503 void BaseCase::verifyMessage (const MessageData& message, GLenum source, GLenum type) 504 { 505 if (verifyMessageExists(message, source, type)) 506 { 507 verifyMessageString(message); 508 verifyMessageGroup(message, source, type); 509 } 510 } 511 512 void BaseCase::verifyMessage (const MessageData& message, GLenum source, GLenum type, GLuint id, GLenum severity) 513 { 514 TestLog& log = m_testCtx.getLog(); 515 516 if (verifyMessageExists(message, source, type)) 517 { 518 verifyMessageString(message); 519 verifyMessageGroup(message, source, type); 520 521 if (message.id.id != id) 522 { 523 m_results.addResult(QP_TEST_RESULT_FAIL, "Incorrect message id"); 524 log << TestLog::Message << "Message id was " << message.id.id 525 << " when it should have been " << id << TestLog::EndMessage; 526 } 527 528 if (message.severity != severity) 529 { 530 m_results.addResult(QP_TEST_RESULT_FAIL, "Incorrect message severity"); 531 log << TestLog::Message << "Message severity was " << glu::getDebugMessageSeverityStr(message.severity) 532 << " when it should have been " << glu::getDebugMessageSeverityStr(severity) << TestLog::EndMessage; 533 } 534 } 535 } 536 537 bool BaseCase::isDebugContext (void) const 538 { 539 return (m_context.getRenderContext().getType().getFlags() & glu::CONTEXT_DEBUG) != 0; 540 } 541 542 // Generate errors, verify that each error results in a callback call 543 class CallbackErrorCase : public BaseCase 544 { 545 public: 546 CallbackErrorCase (Context& ctx, 547 const char* name, 548 const char* desc, 549 TestFunc errorFunc); 550 virtual ~CallbackErrorCase (void) {} 551 552 virtual IterateResult iterate (void); 553 554 virtual void expectMessage (GLenum source, GLenum type); 555 556 private: 557 virtual void callback (GLenum source, GLenum type, GLuint id, GLenum severity, const string& message); 558 559 const TestFunc m_errorFunc; 560 MessageData m_lastMessage; 561 }; 562 563 CallbackErrorCase::CallbackErrorCase (Context& ctx, 564 const char* name, 565 const char* desc, 566 TestFunc errorFunc) 567 : BaseCase (ctx, name, desc) 568 , m_errorFunc (errorFunc) 569 { 570 } 571 572 CallbackErrorCase::IterateResult CallbackErrorCase::iterate (void) 573 { 574 TCU_CHECK_AND_THROW(NotSupportedError, m_context.getContextInfo().isExtensionSupported("GL_KHR_debug"), "GL_KHR_debug is not supported"); 575 576 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 577 tcu::TestLog& log = m_testCtx.getLog(); 578 NegativeTestContext context = NegativeTestContext(*this, m_context.getRenderContext(), m_context.getContextInfo(), log, m_results, true); 579 580 gl.enable(GL_DEBUG_OUTPUT); 581 gl.enable(GL_DEBUG_OUTPUT_SYNCHRONOUS); 582 gl.debugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, DE_NULL, false); // disable all 583 gl.debugMessageControl(GL_DEBUG_SOURCE_API, GL_DEBUG_TYPE_ERROR, GL_DONT_CARE, 0, DE_NULL, true); // enable API errors 584 gl.debugMessageControl(GL_DEBUG_SOURCE_APPLICATION, GL_DONT_CARE, GL_DONT_CARE, 0, DE_NULL, true); // enable application messages 585 gl.debugMessageControl(GL_DEBUG_SOURCE_THIRD_PARTY, GL_DONT_CARE, GL_DONT_CARE, 0, DE_NULL, true); // enable third party messages 586 gl.debugMessageCallback(callbackHandle, this); 587 588 m_errorFunc(context); 589 590 gl.debugMessageCallback(DE_NULL, DE_NULL); 591 gl.disable(GL_DEBUG_OUTPUT); 592 593 m_results.setTestContextResult(m_testCtx); 594 595 return STOP; 596 } 597 598 void CallbackErrorCase::expectMessage (GLenum source, GLenum type) 599 { 600 verifyMessage(m_lastMessage, source, type); 601 m_lastMessage = MessageData(); 602 603 // Reset error so that code afterwards doesn't break because of lingering error state 604 m_context.getRenderContext().getFunctions().getError(); 605 } 606 607 void CallbackErrorCase::callback (GLenum source, GLenum type, GLuint id, GLenum severity, const string& message) 608 { 609 m_lastMessage = MessageData(MessageID(source, type, id), severity, message); 610 } 611 612 // Generate errors, verify that each error results in a log entry 613 class LogErrorCase : public BaseCase 614 { 615 public: 616 LogErrorCase (Context& context, 617 const char* name, 618 const char* desc, 619 TestFunc errorFunc); 620 virtual ~LogErrorCase (void) {} 621 622 virtual IterateResult iterate (void); 623 624 virtual void expectMessage (GLenum source, GLenum type); 625 626 private: 627 const TestFunc m_errorFunc; 628 MessageData m_lastMessage; 629 }; 630 631 LogErrorCase::LogErrorCase (Context& ctx, 632 const char* name, 633 const char* desc, 634 TestFunc errorFunc) 635 : BaseCase (ctx, name, desc) 636 , m_errorFunc (errorFunc) 637 { 638 } 639 640 LogErrorCase::IterateResult LogErrorCase::iterate (void) 641 { 642 TCU_CHECK_AND_THROW(NotSupportedError, m_context.getContextInfo().isExtensionSupported("GL_KHR_debug"), "GL_KHR_debug is not supported"); 643 644 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 645 tcu::TestLog& log = m_testCtx.getLog(); 646 NegativeTestContext context = NegativeTestContext(*this, m_context.getRenderContext(), m_context.getContextInfo(), log, m_results, true); 647 GLint numMsg = 0; 648 649 gl.enable(GL_DEBUG_OUTPUT); 650 gl.enable(GL_DEBUG_OUTPUT_SYNCHRONOUS); 651 gl.debugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, DE_NULL, false); // disable all 652 gl.debugMessageControl(GL_DEBUG_SOURCE_API, GL_DEBUG_TYPE_ERROR, GL_DONT_CARE, 0, DE_NULL, true); // enable API errors 653 gl.debugMessageCallback(DE_NULL, DE_NULL); // enable logging 654 gl.getIntegerv(GL_DEBUG_LOGGED_MESSAGES, &numMsg); 655 gl.getDebugMessageLog(numMsg, 0, DE_NULL, DE_NULL, DE_NULL, DE_NULL, DE_NULL, DE_NULL); // clear log 656 657 m_errorFunc(context); 658 659 gl.disable(GL_DEBUG_OUTPUT); 660 m_results.setTestContextResult(m_testCtx); 661 662 return STOP; 663 } 664 665 void LogErrorCase::expectMessage (GLenum source, GLenum type) 666 { 667 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 668 int numMsg = 0; 669 TestLog& log = m_testCtx.getLog(); 670 MessageData lastMsg; 671 672 if (source == GL_DONT_CARE || type == GL_DONT_CARE) 673 return; 674 675 gl.getIntegerv(GL_DEBUG_LOGGED_MESSAGES, &numMsg); 676 677 if (numMsg == 0) 678 { 679 if (isDebugContext()) 680 { 681 m_results.addResult(QP_TEST_RESULT_FAIL, "Error was not reported as expected"); 682 log << TestLog::Message << "A message was expected but none was reported (empty message log)" << TestLog::EndMessage; 683 } 684 else 685 { 686 m_results.addResult(QP_TEST_RESULT_QUALITY_WARNING, "Verification accuracy is lacking without a debug context"); 687 log << TestLog::Message << "A message was expected but none was reported (empty message log). Running without a debug context" << TestLog::EndMessage; 688 } 689 return; 690 } 691 692 // There may be messages other than the error we are looking for in the log. 693 // Strictly nothing prevents the implementation from producing more than the 694 // required error from an API call with a defined error. however we assume that 695 // since calls that produce an error should not change GL state the implementation 696 // should have nothing else to report. 697 if (numMsg > 1) 698 gl.getDebugMessageLog(numMsg-1, 0, DE_NULL, DE_NULL, DE_NULL, DE_NULL, DE_NULL, DE_NULL); // Clear all but last 699 700 { 701 int msgLen = 0; 702 gl.getIntegerv(GL_DEBUG_NEXT_LOGGED_MESSAGE_LENGTH, &msgLen); 703 704 TCU_CHECK_MSG(msgLen >= 0, "Negative message length"); 705 TCU_CHECK_MSG(msgLen < 100000, "Excessively long message"); 706 707 lastMsg.message.resize(msgLen); 708 gl.getDebugMessageLog(1, msgLen, &lastMsg.id.source, &lastMsg.id.type, &lastMsg.id.id, &lastMsg.severity, &msgLen, &lastMsg.message[0]); 709 } 710 711 log << TestLog::Message << "Driver says: \"" << lastMsg.message << "\"" << TestLog::EndMessage; 712 713 verifyMessage(lastMsg, source, type); 714 715 // Reset error so that code afterwards doesn't break because of lingering error state 716 m_context.getRenderContext().getFunctions().getError(); 717 } 718 719 // Generate errors, verify that calling glGetError afterwards produces desired result 720 class GetErrorCase : public BaseCase 721 { 722 public: 723 GetErrorCase (Context& ctx, 724 const char* name, 725 const char* desc, 726 TestFunc errorFunc); 727 virtual ~GetErrorCase (void) {} 728 729 virtual IterateResult iterate (void); 730 731 virtual void expectMessage (GLenum source, GLenum type); 732 virtual void expectError (glw::GLenum error0, glw::GLenum error1); 733 734 private: 735 const TestFunc m_errorFunc; 736 }; 737 738 GetErrorCase::GetErrorCase (Context& ctx, 739 const char* name, 740 const char* desc, 741 TestFunc errorFunc) 742 : BaseCase (ctx, name, desc) 743 , m_errorFunc (errorFunc) 744 { 745 } 746 747 GetErrorCase::IterateResult GetErrorCase::iterate (void) 748 { 749 tcu::TestLog& log = m_testCtx.getLog(); 750 NegativeTestContext context = NegativeTestContext(*this, m_context.getRenderContext(), m_context.getContextInfo(), log, m_results, true); 751 752 m_errorFunc(context); 753 754 m_results.setTestContextResult(m_testCtx); 755 756 return STOP; 757 } 758 759 void GetErrorCase::expectMessage (GLenum source, GLenum type) 760 { 761 DE_UNREF(source); 762 DE_UNREF(type); 763 DE_ASSERT(!"GetErrorCase cannot handle anything other than error codes"); 764 } 765 766 void GetErrorCase::expectError (glw::GLenum error0, glw::GLenum error1) 767 { 768 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 769 TestLog& log = m_testCtx.getLog(); 770 771 const GLenum result = gl.getError(); 772 773 if (result != error0 && result != error1) 774 { 775 m_results.addResult(QP_TEST_RESULT_FAIL, "Incorrect error was reported"); 776 if (error0 == error1) 777 log << TestLog::Message 778 << glu::getErrorStr(error0) << " was expected but got " 779 << glu::getErrorStr(result) 780 << TestLog::EndMessage; 781 else 782 log << TestLog::Message 783 << glu::getErrorStr(error0) << " or " 784 << glu::getErrorStr(error1) << " was expected but got " 785 << glu::getErrorStr(result) 786 << TestLog::EndMessage; 787 return; 788 } 789 } 790 791 // Generate errors, log the types, disable some, regenerate errors, verify correct errors (not)reported 792 class FilterCase : public BaseCase 793 { 794 public: 795 FilterCase (Context& ctx, 796 const char* name, 797 const char* desc, 798 const vector<TestFunc> errorFuncs); 799 virtual ~FilterCase (void) {} 800 801 virtual IterateResult iterate (void); 802 803 virtual void expectMessage (GLenum source, GLenum type); 804 805 protected: 806 struct MessageFilter 807 { 808 MessageFilter() : source(GL_DONT_CARE), type(GL_DONT_CARE), severity(GL_DONT_CARE), enabled(true) {} // Default to enable all 809 MessageFilter(GLenum source_, GLenum type_, GLenum severity_, const vector<GLuint>& ids_, bool enabled_) : source(source_), type(type_), severity(severity_), ids(ids_), enabled(enabled_) {} 810 811 GLenum source; 812 GLenum type; 813 GLenum severity; 814 vector<GLuint> ids; 815 bool enabled; 816 }; 817 818 virtual void callback (GLenum source, GLenum type, GLuint id, GLenum severity, const string& message); 819 820 vector<MessageData> genMessages (bool uselog, const string& desc); 821 822 vector<MessageFilter> genFilters (const vector<MessageData>& messages, const vector<MessageFilter>& initial, deUint32 seed, int iterations) const; 823 void applyFilters (const vector<MessageFilter>& filters) const; 824 bool isEnabled (const vector<MessageFilter>& filters, const MessageData& message) const; 825 826 void verify (const vector<MessageData>& refMessages, 827 const vector<MessageData>& filteredMessages, 828 const vector<MessageFilter>& filters); 829 830 const vector<TestFunc> m_errorFuncs; 831 832 vector<MessageData>* m_currentErrors; 833 }; 834 835 FilterCase::FilterCase (Context& ctx, 836 const char* name, 837 const char* desc, 838 const vector<TestFunc> errorFuncs) 839 : BaseCase (ctx, name, desc) 840 , m_errorFuncs (errorFuncs) 841 , m_currentErrors (DE_NULL) 842 { 843 } 844 845 FilterCase::IterateResult FilterCase::iterate (void) 846 { 847 TCU_CHECK_AND_THROW(NotSupportedError, m_context.getContextInfo().isExtensionSupported("GL_KHR_debug"), "GL_KHR_debug is not supported"); 848 849 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 850 851 gl.enable(GL_DEBUG_OUTPUT); 852 gl.enable(GL_DEBUG_OUTPUT_SYNCHRONOUS); 853 gl.debugMessageCallback(callbackHandle, this); 854 gl.debugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, DE_NULL, true); 855 856 { 857 const vector<MessageData> refMessages = genMessages(true, "Reference run"); 858 const MessageFilter baseFilter (GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, vector<GLuint>(), true); 859 const deUint32 baseSeed = deStringHash(getName()) ^ m_testCtx.getCommandLine().getBaseSeed(); 860 const vector<MessageFilter> filters = genFilters(refMessages, vector<MessageFilter>(1, baseFilter), baseSeed, 4); 861 vector<MessageData> filteredMessages; 862 863 applyFilters(filters); 864 865 // Generate errors 866 filteredMessages = genMessages(false, "Filtered run"); 867 868 // Verify 869 verify(refMessages, filteredMessages, filters); 870 871 if (!isDebugContext() && refMessages.empty()) 872 m_results.addResult(QP_TEST_RESULT_QUALITY_WARNING, "Verification accuracy is lacking without a debug context"); 873 } 874 875 gl.disable(GL_DEBUG_OUTPUT); 876 m_results.setTestContextResult(m_testCtx); 877 878 return STOP; 879 } 880 881 void FilterCase::expectMessage (GLenum source, GLenum type) 882 { 883 DE_UNREF(source); 884 DE_UNREF(type); 885 } 886 887 void FilterCase::callback (GLenum source, GLenum type, GLuint id, GLenum severity, const string& message) 888 { 889 if (m_currentErrors) 890 m_currentErrors->push_back(MessageData(MessageID(source, type, id), severity, message)); 891 } 892 893 vector<MessageData> FilterCase::genMessages (bool uselog, const string& desc) 894 { 895 tcu::TestLog& log = m_testCtx.getLog(); 896 NegativeTestContext context = NegativeTestContext(*this, m_context.getRenderContext(), m_context.getContextInfo(), log, m_results, uselog); 897 tcu::ScopedLogSection section (log, "message gen", desc); 898 vector<MessageData> messages; 899 900 m_currentErrors = &messages; 901 902 for (int ndx = 0; ndx < int(m_errorFuncs.size()); ndx++) 903 m_errorFuncs[ndx](context); 904 905 m_currentErrors = DE_NULL; 906 907 return messages; 908 } 909 910 vector<FilterCase::MessageFilter> FilterCase::genFilters (const vector<MessageData>& messages, const vector<MessageFilter>& initial, deUint32 seed, int iterations) const 911 { 912 de::Random rng (seed ^ deInt32Hash(deStringHash(getName()))); 913 914 set<MessageID> tempMessageIds; 915 set<GLenum> tempSources; 916 set<GLenum> tempTypes; 917 set<GLenum> tempSeverities; 918 919 if (messages.empty()) 920 return initial; 921 922 for (int ndx = 0; ndx < int(messages.size()); ndx++) 923 { 924 const MessageData& msg = messages[ndx]; 925 926 tempMessageIds.insert(msg.id); 927 tempSources.insert(msg.id.source); 928 tempTypes.insert(msg.id.type); 929 tempSeverities.insert(msg.severity); 930 } 931 932 { 933 // Fetchable by index 934 const vector<MessageID> messageIds (tempMessageIds.begin(), tempMessageIds.end()); 935 const vector<GLenum> sources (tempSources.begin(), tempSources.end()); 936 const vector<GLenum> types (tempTypes.begin(), tempTypes.end()); 937 const vector<GLenum> severities (tempSeverities.begin(), tempSeverities.end()); 938 939 vector<MessageFilter> filters = initial; 940 941 for (int iteration = 0; iteration < iterations; iteration++) 942 { 943 switch(rng.getInt(0, 8)) // Distribute so that per-message randomization (the default branch) is prevalent 944 { 945 case 0: 946 { 947 const GLenum source = sources[rng.getInt(0, int(sources.size()-1))]; 948 const bool enabled = rng.getBool(); 949 950 filters.push_back(MessageFilter(source, GL_DONT_CARE, GL_DONT_CARE, vector<GLuint>(), enabled)); 951 break; 952 } 953 954 case 1: 955 { 956 const GLenum type = types[rng.getUint32()%types.size()]; 957 const bool enabled = rng.getBool(); 958 959 filters.push_back(MessageFilter(GL_DONT_CARE, type, GL_DONT_CARE, vector<GLuint>(), enabled)); 960 break; 961 } 962 963 case 2: 964 { 965 const GLenum severity = severities[rng.getUint32()%severities.size()]; 966 const bool enabled = rng.getBool(); 967 968 filters.push_back(MessageFilter(GL_DONT_CARE, GL_DONT_CARE, severity, vector<GLuint>(), enabled)); 969 break; 970 } 971 972 default: 973 { 974 const int start = rng.getInt(0, int(messageIds.size())); 975 976 for (int itr = 0; itr < 4; itr++) 977 { 978 const MessageID& id = messageIds[(start+itr)%messageIds.size()]; 979 const bool enabled = rng.getBool(); 980 981 filters.push_back(MessageFilter(id.source, id.type, GL_DONT_CARE, vector<GLuint>(1, id.id), enabled)); 982 } 983 } 984 } 985 } 986 987 return filters; 988 } 989 } 990 991 void FilterCase::applyFilters (const vector<MessageFilter>& filters) const 992 { 993 TestLog& log = m_testCtx.getLog(); 994 const tcu::ScopedLogSection section (log, "", "Setting message filters"); 995 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 996 997 for (size_t filterNdx = 0; filterNdx < filters.size(); filterNdx++) 998 { 999 const MessageFilter& filter = filters[filterNdx]; 1000 1001 if (filter.ids.empty()) 1002 log << TestLog::Message << "Setting messages with" 1003 << " source " << glu::getDebugMessageSourceStr(filter.source) 1004 << ", type " << glu::getDebugMessageTypeStr(filter.type) 1005 << " and severity " << glu::getDebugMessageSeverityStr(filter.severity) 1006 << (filter.enabled ? " to enabled" : " to disabled") 1007 << TestLog::EndMessage; 1008 else 1009 { 1010 for (size_t ndx = 0; ndx < filter.ids.size(); ndx++) 1011 log << TestLog::Message << "Setting message (" << MessageID(filter.source, filter.type, filter.ids[ndx]) << ") to " << (filter.enabled ? "enabled" : "disabled") << TestLog::EndMessage; 1012 } 1013 1014 gl.debugMessageControl(filter.source, filter.type, filter.severity, GLsizei(filter.ids.size()), filter.ids.empty() ? DE_NULL : &filter.ids[0], filter.enabled); 1015 } 1016 } 1017 1018 bool FilterCase::isEnabled (const vector<MessageFilter>& filters, const MessageData& message) const 1019 { 1020 bool retval = true; 1021 1022 for (size_t filterNdx = 0; filterNdx < filters.size(); filterNdx++) 1023 { 1024 const MessageFilter& filter = filters[filterNdx]; 1025 1026 if (filter.ids.empty()) 1027 { 1028 if (filter.source != GL_DONT_CARE && filter.source != message.id.source) 1029 continue; 1030 1031 if (filter.type != GL_DONT_CARE && filter.type != message.id.type) 1032 continue; 1033 1034 if (filter.severity != GL_DONT_CARE && filter.severity != message.severity) 1035 continue; 1036 } 1037 else 1038 { 1039 DE_ASSERT(filter.source != GL_DONT_CARE); 1040 DE_ASSERT(filter.type != GL_DONT_CARE); 1041 DE_ASSERT(filter.severity == GL_DONT_CARE); 1042 1043 if (filter.source != message.id.source || filter.type != message.id.type) 1044 continue; 1045 1046 if (!de::contains(filter.ids.begin(), filter.ids.end(), message.id.id)) 1047 continue; 1048 } 1049 1050 retval = filter.enabled; 1051 } 1052 1053 return retval; 1054 } 1055 1056 struct MessageMeta 1057 { 1058 int refCount; 1059 int resCount; 1060 GLenum severity; 1061 1062 MessageMeta (void) : refCount(0), resCount(0), severity(GL_NONE) {} 1063 }; 1064 1065 void FilterCase::verify (const vector<MessageData>& refMessages, const vector<MessageData>& resMessages, const vector<MessageFilter>& filters) 1066 { 1067 TestLog& log = m_testCtx.getLog(); 1068 map<MessageID, MessageMeta> counts; 1069 1070 log << TestLog::Section("verification", "Verifying"); 1071 1072 // Gather message counts & severities, report severity mismatches if found 1073 for (size_t refNdx = 0; refNdx < refMessages.size(); refNdx++) 1074 { 1075 const MessageData& msg = refMessages[refNdx]; 1076 MessageMeta& meta = counts[msg.id]; 1077 1078 if (meta.severity != GL_NONE && meta.severity != msg.severity) 1079 { 1080 log << TestLog::Message << "A message has variable severity between instances: (" << msg.id << ") with severity " 1081 << glu::getDebugMessageSeverityStr(meta.severity) << " and " << glu::getDebugMessageSeverityStr(msg.severity) << TestLog::EndMessage; 1082 m_results.addResult(QP_TEST_RESULT_FAIL, "Message severity changed between instances of the same message"); 1083 } 1084 1085 meta.refCount++; 1086 meta.severity = msg.severity; 1087 } 1088 1089 for (size_t resNdx = 0; resNdx < resMessages.size(); resNdx++) 1090 { 1091 const MessageData& msg = resMessages[resNdx]; 1092 MessageMeta& meta = counts[msg.id]; 1093 1094 if (meta.severity != GL_NONE && meta.severity != msg.severity) 1095 { 1096 log << TestLog::Message << "A message has variable severity between instances: (" << msg.id << ") with severity " 1097 << glu::getDebugMessageSeverityStr(meta.severity) << " and " << glu::getDebugMessageSeverityStr(msg.severity) << TestLog::EndMessage; 1098 m_results.addResult(QP_TEST_RESULT_FAIL, "Message severity changed between instances of the same message"); 1099 } 1100 1101 meta.resCount++; 1102 meta.severity = msg.severity; 1103 } 1104 1105 for (map<MessageID, MessageMeta>::const_iterator itr = counts.begin(); itr != counts.end(); itr++) 1106 { 1107 const MessageID& id = itr->first; 1108 const GLenum severity = itr->second.severity; 1109 1110 const int refCount = itr->second.refCount; 1111 const int resCount = itr->second.resCount; 1112 const bool enabled = isEnabled(filters, MessageData(id, severity, "")); 1113 1114 VerificationResult result = verifyMessageCount(id, severity, refCount, resCount, enabled); 1115 1116 log << TestLog::Message << result.logMessage << TestLog::EndMessage; 1117 1118 if (result.result != QP_TEST_RESULT_PASS) 1119 m_results.addResult(result.result, result.resultMessage); 1120 } 1121 1122 log << TestLog::EndSection; 1123 } 1124 1125 // Filter case that uses debug groups 1126 class GroupFilterCase : public FilterCase 1127 { 1128 public: 1129 GroupFilterCase (Context& ctx, 1130 const char* name, 1131 const char* desc, 1132 const vector<TestFunc> errorFuncs); 1133 virtual ~GroupFilterCase (void) {} 1134 1135 virtual IterateResult iterate (void); 1136 }; 1137 1138 GroupFilterCase::GroupFilterCase (Context& ctx, 1139 const char* name, 1140 const char* desc, 1141 const vector<TestFunc> errorFuncs) 1142 : FilterCase(ctx, name, desc, errorFuncs) 1143 { 1144 } 1145 1146 template<typename T> 1147 vector<T> join(const vector<T>& a, const vector<T>&b) 1148 { 1149 vector<T> retval; 1150 1151 retval.reserve(a.size()+b.size()); 1152 retval.insert(retval.end(), a.begin(), a.end()); 1153 retval.insert(retval.end(), b.begin(), b.end()); 1154 return retval; 1155 } 1156 1157 GroupFilterCase::IterateResult GroupFilterCase::iterate (void) 1158 { 1159 TCU_CHECK_AND_THROW(NotSupportedError, m_context.getContextInfo().isExtensionSupported("GL_KHR_debug"), "GL_KHR_debug is not supported"); 1160 1161 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 1162 tcu::TestLog& log = m_testCtx.getLog(); 1163 1164 gl.enable(GL_DEBUG_OUTPUT); 1165 gl.enable(GL_DEBUG_OUTPUT_SYNCHRONOUS); 1166 gl.debugMessageCallback(callbackHandle, this); 1167 gl.debugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, DE_NULL, true); 1168 1169 { 1170 1171 // Generate reference (all errors) 1172 const vector<MessageData> refMessages = genMessages(true, "Reference run"); 1173 const deUint32 baseSeed = deStringHash(getName()) ^ m_testCtx.getCommandLine().getBaseSeed(); 1174 const MessageFilter baseFilter (GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, vector<GLuint>(), true); 1175 const vector<MessageFilter> filter0 = genFilters(refMessages, vector<MessageFilter>(1, baseFilter), baseSeed, 4); 1176 vector<MessageData> resMessages0; 1177 1178 applyFilters(filter0); 1179 1180 resMessages0 = genMessages(false, "Filtered run, default debug group"); 1181 1182 // Initial verification 1183 verify(refMessages, resMessages0, filter0); 1184 1185 { 1186 // Generate reference (filters inherited from parent) 1187 const vector<MessageFilter> filter1base = genFilters(refMessages, vector<MessageFilter>(), baseSeed ^ 0xDEADBEEF, 4); 1188 const vector<MessageFilter> filter1full = join(filter0, filter1base); 1189 tcu::ScopedLogSection section1 (log, "", "Pushing Debug Group"); 1190 vector<MessageData> resMessages1; 1191 1192 gl.pushDebugGroup(GL_DEBUG_SOURCE_APPLICATION, 1, -1, "Test Group"); 1193 applyFilters(filter1base); 1194 1195 // First nested verification 1196 resMessages1 = genMessages(false, "Filtered run, pushed one debug group"); 1197 verify(refMessages, resMessages1, filter1full); 1198 1199 { 1200 // Generate reference (filters iherited again) 1201 const vector<MessageFilter> filter2base = genFilters(refMessages, vector<MessageFilter>(), baseSeed ^ 0x43211234, 4); 1202 const vector<MessageFilter> filter2full = join(filter1full, filter2base); 1203 tcu::ScopedLogSection section2 (log, "", "Pushing Debug Group"); 1204 vector<MessageData> resMessages2; 1205 1206 gl.pushDebugGroup(GL_DEBUG_SOURCE_APPLICATION, 1, -1, "Nested Test Group"); 1207 applyFilters(filter2base); 1208 1209 // Second nested verification 1210 resMessages2 = genMessages(false, "Filtered run, pushed two debug groups"); 1211 verify(refMessages, resMessages2, filter2full); 1212 1213 gl.popDebugGroup(); 1214 } 1215 1216 // First restore verification 1217 resMessages1 = genMessages(false, "Filtered run, popped second debug group"); 1218 verify(refMessages, resMessages1, filter1full); 1219 1220 gl.popDebugGroup(); 1221 } 1222 1223 // restore verification 1224 resMessages0 = genMessages(false, "Filtered run, popped first debug group"); 1225 verify(refMessages, resMessages0, filter0); 1226 1227 if (!isDebugContext() && refMessages.empty()) 1228 m_results.addResult(QP_TEST_RESULT_QUALITY_WARNING, "Verification accuracy is lacking without a debug context"); 1229 } 1230 1231 gl.disable(GL_DEBUG_OUTPUT); 1232 m_results.setTestContextResult(m_testCtx); 1233 return STOP; 1234 } 1235 1236 // Basic grouping functionality 1237 class GroupCase : public BaseCase 1238 { 1239 public: 1240 GroupCase (Context& ctx, 1241 const char* name, 1242 const char* desc); 1243 virtual ~GroupCase () {} 1244 1245 virtual IterateResult iterate (void); 1246 1247 private: 1248 virtual void callback (GLenum source, GLenum type, GLuint id, GLenum severity, const string& message); 1249 1250 MessageData m_lastMessage; 1251 }; 1252 1253 GroupCase::GroupCase (Context& ctx, 1254 const char* name, 1255 const char* desc) 1256 : BaseCase(ctx, name, desc) 1257 { 1258 } 1259 1260 GroupCase::IterateResult GroupCase::iterate (void) 1261 { 1262 TCU_CHECK_AND_THROW(NotSupportedError, m_context.getContextInfo().isExtensionSupported("GL_KHR_debug"), "GL_KHR_debug is not supported"); 1263 1264 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 1265 tcu::TestLog& log = m_testCtx.getLog(); 1266 glu::CallLogWrapper wrapper (gl, log); 1267 1268 gl.enable(GL_DEBUG_OUTPUT); 1269 gl.enable(GL_DEBUG_OUTPUT_SYNCHRONOUS); 1270 gl.debugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, DE_NULL, false); // disable all 1271 gl.debugMessageControl(GL_DEBUG_SOURCE_API, GL_DEBUG_TYPE_ERROR, GL_DONT_CARE, 0, DE_NULL, true); // enable API errors 1272 gl.debugMessageControl(GL_DEBUG_SOURCE_APPLICATION, GL_DONT_CARE, GL_DONT_CARE, 0, DE_NULL, true); // enable application messages 1273 gl.debugMessageControl(GL_DEBUG_SOURCE_THIRD_PARTY, GL_DONT_CARE, GL_DONT_CARE, 0, DE_NULL, true); // enable third party messages 1274 gl.debugMessageCallback(callbackHandle, this); 1275 1276 wrapper.enableLogging(true); 1277 wrapper.glPushDebugGroup(GL_DEBUG_SOURCE_APPLICATION, 1234, -1, "Pushed debug stack"); 1278 verifyMessage(m_lastMessage, GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_PUSH_GROUP, 1234, GL_DEBUG_SEVERITY_NOTIFICATION); 1279 wrapper.glPopDebugGroup(); 1280 verifyMessage(m_lastMessage, GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_POP_GROUP, 1234, GL_DEBUG_SEVERITY_NOTIFICATION); 1281 1282 wrapper.glPushDebugGroup(GL_DEBUG_SOURCE_THIRD_PARTY, 4231, -1, "Pushed debug stack"); 1283 verifyMessage(m_lastMessage, GL_DEBUG_SOURCE_THIRD_PARTY, GL_DEBUG_TYPE_PUSH_GROUP, 4231, GL_DEBUG_SEVERITY_NOTIFICATION); 1284 wrapper.glPopDebugGroup(); 1285 verifyMessage(m_lastMessage, GL_DEBUG_SOURCE_THIRD_PARTY, GL_DEBUG_TYPE_POP_GROUP, 4231, GL_DEBUG_SEVERITY_NOTIFICATION); 1286 1287 gl.debugMessageCallback(DE_NULL, DE_NULL); 1288 gl.disable(GL_DEBUG_OUTPUT); 1289 1290 m_results.setTestContextResult(m_testCtx); 1291 1292 return STOP; 1293 } 1294 1295 void GroupCase::callback (GLenum source, GLenum type, GLuint id, GLenum severity, const string& message) 1296 { 1297 m_lastMessage = MessageData(MessageID(source, type, id), severity, message); 1298 } 1299 1300 // Asynchronous debug output 1301 class AsyncCase : public BaseCase 1302 { 1303 public: 1304 AsyncCase (Context& ctx, 1305 const char* name, 1306 const char* desc, 1307 const vector<TestFunc> errorFuncs, 1308 bool useCallbacks); 1309 virtual ~AsyncCase () {} 1310 1311 virtual IterateResult iterate (void); 1312 1313 virtual void expectMessage (glw::GLenum source, glw::GLenum type); 1314 1315 private: 1316 struct MessageCount 1317 { 1318 int received; 1319 int expected; 1320 1321 MessageCount(void) : received(0), expected(0) {} 1322 }; 1323 typedef map<MessageID, MessageCount> MessageCounter; 1324 1325 enum VerifyState 1326 { 1327 VERIFY_PASS = 0, 1328 VERIFY_MINIMUM, 1329 VERIFY_FAIL, 1330 1331 VERIFY_LAST 1332 }; 1333 1334 virtual void callback (glw::GLenum source, glw::GLenum type, glw::GLuint id, glw::GLenum severity, const std::string& message); 1335 VerifyState verify (bool uselog); 1336 void fetchLogMessages (void); 1337 1338 const vector<TestFunc> m_errorFuncs; 1339 const bool m_useCallbacks; 1340 1341 MessageCounter m_counts; 1342 1343 de::Mutex m_mutex; 1344 }; 1345 1346 AsyncCase::AsyncCase (Context& ctx, 1347 const char* name, 1348 const char* desc, 1349 const vector<TestFunc> errorFuncs, 1350 bool useCallbacks) 1351 : BaseCase (ctx, name, desc) 1352 , m_errorFuncs (errorFuncs) 1353 , m_useCallbacks (useCallbacks) 1354 { 1355 } 1356 1357 AsyncCase::IterateResult AsyncCase::iterate (void) 1358 { 1359 TCU_CHECK_AND_THROW(NotSupportedError, m_context.getContextInfo().isExtensionSupported("GL_KHR_debug"), "GL_KHR_debug is not supported"); 1360 1361 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 1362 tcu::TestLog& log = m_testCtx.getLog(); 1363 NegativeTestContext context = NegativeTestContext(*this, m_context.getRenderContext(), m_context.getContextInfo(), log, m_results, true); 1364 const int maxWait = 10000; // ms 1365 const int warnWait = 100; 1366 1367 gl.enable(GL_DEBUG_OUTPUT); 1368 gl.enable(GL_DEBUG_OUTPUT_SYNCHRONOUS); 1369 gl.debugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, DE_NULL, false); 1370 1371 // Some messages could be dependent on the value of DEBUG_OUTPUT_SYNCHRONOUS so only use API errors which should be generated in all cases 1372 gl.debugMessageControl(GL_DEBUG_SOURCE_API, GL_DEBUG_TYPE_ERROR, GL_DONT_CARE, 0, DE_NULL, true); 1373 1374 if (m_useCallbacks) // will use log otherwise 1375 gl.debugMessageCallback(callbackHandle, this); 1376 else 1377 gl.debugMessageCallback(DE_NULL, DE_NULL); 1378 1379 // Reference run (synchoronous) 1380 { 1381 tcu::ScopedLogSection section(log, "reference run", "Reference run (synchronous)"); 1382 1383 for (int ndx = 0; ndx < int(m_errorFuncs.size()); ndx++) 1384 m_errorFuncs[ndx](context); 1385 } 1386 1387 if (m_counts.empty()) 1388 { 1389 if (!isDebugContext()) 1390 m_results.addResult(QP_TEST_RESULT_QUALITY_WARNING, "Need debug context to guarantee implementation behaviour (see command line options)"); 1391 1392 log << TestLog::Message << "Reference run produced no messages, nothing to verify" << TestLog::EndMessage; 1393 1394 gl.debugMessageCallback(DE_NULL, DE_NULL); 1395 gl.disable(GL_DEBUG_OUTPUT); 1396 1397 m_results.setTestContextResult(m_testCtx); 1398 return STOP; 1399 } 1400 1401 for (MessageCounter::iterator itr = m_counts.begin(); itr != m_counts.end(); itr++) 1402 { 1403 itr->second.expected = itr->second.received; 1404 itr->second.received = 0; 1405 } 1406 1407 gl.disable(GL_DEBUG_OUTPUT_SYNCHRONOUS); 1408 1409 // Result run (async) 1410 for (int ndx = 0; ndx < int(m_errorFuncs.size()); ndx++) 1411 m_errorFuncs[ndx](context); 1412 1413 // Repatedly try verification, new results may be added to m_receivedMessages at any time 1414 { 1415 tcu::ScopedLogSection section (log, "result run", "Result run (asynchronous)"); 1416 VerifyState lastTimelyState = VERIFY_FAIL; 1417 1418 for (int waited = 0;;) 1419 { 1420 const VerifyState pass = verify(false); 1421 const int wait = de::max(50, waited>>2); 1422 1423 // Pass (possibly due to time limit) 1424 if (pass == VERIFY_PASS || (pass == VERIFY_MINIMUM && waited >= maxWait)) 1425 { 1426 verify(true); // log 1427 1428 // State changed late 1429 if (waited >= warnWait && lastTimelyState != pass) 1430 m_results.addResult(QP_TEST_RESULT_QUALITY_WARNING, "Async messages were returned to application somewhat slowly"); 1431 1432 log << TestLog::Message << "Passed after ~" << waited << "ms of waiting" << TestLog::EndMessage; 1433 break; 1434 } 1435 // fail 1436 else if (waited >= maxWait) 1437 { 1438 verify(true); // log 1439 1440 log << TestLog::Message << "Waited for ~" << waited << "ms without getting all expected messages" << TestLog::EndMessage; 1441 m_results.addResult(QP_TEST_RESULT_FAIL, "Async messages were not returned to application within a reasonable timeframe"); 1442 break; 1443 } 1444 1445 if (waited < warnWait) 1446 lastTimelyState = pass; 1447 1448 deSleep(wait); 1449 waited += wait; 1450 1451 if (!m_useCallbacks) 1452 fetchLogMessages(); 1453 } 1454 } 1455 1456 gl.debugMessageCallback(DE_NULL, DE_NULL); 1457 1458 gl.disable(GL_DEBUG_OUTPUT); 1459 m_results.setTestContextResult(m_testCtx); 1460 1461 return STOP; 1462 } 1463 1464 void AsyncCase::expectMessage (GLenum source, GLenum type) 1465 { 1466 // Good time to clean up the queue as this should be called after most messages are generated 1467 if (!m_useCallbacks) 1468 fetchLogMessages(); 1469 1470 DE_UNREF(source); 1471 DE_UNREF(type); 1472 } 1473 1474 void AsyncCase::callback (GLenum source, GLenum type, GLuint id, GLenum severity, const string& message) 1475 { 1476 DE_ASSERT(m_useCallbacks); 1477 DE_UNREF(severity); 1478 DE_UNREF(message); 1479 1480 de::ScopedLock lock(m_mutex); 1481 1482 m_counts[MessageID(source, type, id)].received++; 1483 } 1484 1485 // 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 1486 void AsyncCase::fetchLogMessages (void) 1487 { 1488 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 1489 GLint numMsg = 0; 1490 1491 gl.getIntegerv(GL_DEBUG_LOGGED_MESSAGES, &numMsg); 1492 1493 for(int msgNdx = 0; msgNdx < numMsg; msgNdx++) 1494 { 1495 int msgLen = 0; 1496 MessageData msg; 1497 1498 gl.getIntegerv(GL_DEBUG_NEXT_LOGGED_MESSAGE_LENGTH, &msgLen); 1499 1500 TCU_CHECK_MSG(msgLen >= 0, "Negative message length"); 1501 TCU_CHECK_MSG(msgLen < 100000, "Excessively long message"); 1502 1503 msg.message.resize(msgLen); 1504 gl.getDebugMessageLog(1, msgLen, &msg.id.source, &msg.id.type, &msg.id.id, &msg.severity, &msgLen, &msg.message[0]); 1505 1506 { 1507 const de::ScopedLock lock(m_mutex); // Don't block during API call 1508 1509 m_counts[MessageID(msg.id)].received++; 1510 } 1511 } 1512 } 1513 1514 AsyncCase::VerifyState AsyncCase::verify (bool uselog) 1515 { 1516 using std::map; 1517 1518 VerifyState retval = VERIFY_PASS; 1519 TestLog& log = m_testCtx.getLog(); 1520 1521 const de::ScopedLock lock(m_mutex); 1522 1523 for (map<MessageID, MessageCount>::const_iterator itr = m_counts.begin(); itr != m_counts.end(); itr++) 1524 { 1525 const MessageID& id = itr->first; 1526 1527 const int refCount = itr->second.expected; 1528 const int resCount = itr->second.received; 1529 const bool enabled = true; 1530 1531 VerificationResult result = verifyMessageCount(id, GL_DONT_CARE, refCount, resCount, enabled); 1532 1533 if (uselog) 1534 log << TestLog::Message << result.logMessage << TestLog::EndMessage; 1535 1536 if (result.result == QP_TEST_RESULT_FAIL) 1537 retval = VERIFY_FAIL; 1538 else if (result.result != QP_TEST_RESULT_PASS && retval == VERIFY_PASS) 1539 retval = VERIFY_MINIMUM; 1540 } 1541 1542 return retval; 1543 } 1544 1545 // Tests debug labels 1546 class LabelCase : public TestCase 1547 { 1548 public: 1549 LabelCase (Context& ctx, 1550 const char* name, 1551 const char* desc, 1552 GLenum identifier); 1553 virtual ~LabelCase (void) {} 1554 1555 virtual IterateResult iterate (void); 1556 1557 private: 1558 GLenum m_identifier; 1559 }; 1560 1561 LabelCase::LabelCase (Context& ctx, 1562 const char* name, 1563 const char* desc, 1564 GLenum identifier) 1565 : TestCase (ctx, name, desc) 1566 , m_identifier (identifier) 1567 { 1568 } 1569 1570 LabelCase::IterateResult LabelCase::iterate (void) 1571 { 1572 TCU_CHECK_AND_THROW(NotSupportedError, m_context.getContextInfo().isExtensionSupported("GL_KHR_debug"), "GL_KHR_debug is not supported"); 1573 1574 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 1575 const char* const msg = "This is a debug label"; 1576 GLuint object = 0; 1577 char buffer[64]; 1578 int outlen = 0; 1579 1580 switch(m_identifier) 1581 { 1582 case GL_BUFFER: 1583 gl.genBuffers(1, &object); 1584 gl.bindBuffer(GL_ARRAY_BUFFER, object); 1585 gl.bindBuffer(GL_ARRAY_BUFFER, 0); 1586 break; 1587 1588 case GL_SHADER: 1589 object = gl.createShader(GL_FRAGMENT_SHADER); 1590 break; 1591 1592 case GL_PROGRAM: 1593 object = gl.createProgram(); 1594 break; 1595 1596 case GL_QUERY: 1597 gl.genQueries(1, &object); 1598 gl.beginQuery(GL_ANY_SAMPLES_PASSED, object); // Create 1599 gl.endQuery(GL_ANY_SAMPLES_PASSED); // Cleanup 1600 break; 1601 1602 case GL_PROGRAM_PIPELINE: 1603 gl.genProgramPipelines(1, &object); 1604 gl.bindProgramPipeline(object); // Create 1605 gl.bindProgramPipeline(0); // Cleanup 1606 break; 1607 1608 case GL_TRANSFORM_FEEDBACK: 1609 gl.genTransformFeedbacks(1, &object); 1610 gl.bindTransformFeedback(GL_TRANSFORM_FEEDBACK, object); 1611 gl.bindTransformFeedback(GL_TRANSFORM_FEEDBACK, 0); 1612 break; 1613 1614 case GL_SAMPLER: 1615 gl.genSamplers(1, &object); 1616 gl.bindSampler(0, object); 1617 gl.bindSampler(0, 0); 1618 break; 1619 1620 case GL_TEXTURE: 1621 gl.genTextures(1, &object); 1622 gl.bindTexture(GL_TEXTURE_2D, object); 1623 gl.bindTexture(GL_TEXTURE_2D, 0); 1624 break; 1625 1626 case GL_RENDERBUFFER: 1627 gl.genRenderbuffers(1, &object); 1628 gl.bindRenderbuffer(GL_RENDERBUFFER, object); 1629 gl.bindRenderbuffer(GL_RENDERBUFFER, 0); 1630 break; 1631 1632 case GL_FRAMEBUFFER: 1633 gl.genFramebuffers(1, &object); 1634 gl.bindFramebuffer(GL_DRAW_FRAMEBUFFER, object); 1635 gl.bindFramebuffer(GL_DRAW_FRAMEBUFFER, m_context.getRenderContext().getDefaultFramebuffer()); 1636 break; 1637 1638 default: 1639 DE_ASSERT(!"Invalid identifier"); 1640 } 1641 1642 gl.objectLabel(m_identifier, object, -1, msg); 1643 1644 gl.getObjectLabel(m_identifier, object, sizeof(buffer), &outlen, buffer); 1645 1646 if (outlen == 0) 1647 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Failed to query debug label from object"); 1648 else if (deStringEqual(msg, buffer)) 1649 { 1650 m_testCtx.getLog() << TestLog::Message << "Query returned string: \"" << buffer << "\"" << TestLog::EndMessage; 1651 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); 1652 } 1653 else 1654 { 1655 m_testCtx.getLog() << TestLog::Message << "Query returned wrong string: expected \"" << msg << "\" but got \"" << buffer << "\"" << TestLog::EndMessage; 1656 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Query returned wrong label"); 1657 } 1658 1659 switch(m_identifier) 1660 { 1661 case GL_BUFFER: gl.deleteBuffers(1, &object); break; 1662 case GL_SHADER: gl.deleteShader(object); break; 1663 case GL_PROGRAM: gl.deleteProgram(object); break; 1664 case GL_QUERY: gl.deleteQueries(1, &object); break; 1665 case GL_PROGRAM_PIPELINE: gl.deleteProgramPipelines(1, &object); break; 1666 case GL_TRANSFORM_FEEDBACK: gl.deleteTransformFeedbacks(1, &object); break; 1667 case GL_SAMPLER: gl.deleteSamplers(1, &object); break; 1668 case GL_TEXTURE: gl.deleteTextures(1, &object); break; 1669 case GL_RENDERBUFFER: gl.deleteRenderbuffers(1, &object); break; 1670 case GL_FRAMEBUFFER: gl.deleteFramebuffers(1, &object); break; 1671 1672 default: 1673 DE_ASSERT(!"Invalid identifier"); 1674 } 1675 1676 return STOP; 1677 } 1678 1679 } // Anonymous 1680 1681 DebugTests::DebugTests (Context& context) 1682 : TestCaseGroup(context, "debug", "Debug tests") 1683 { 1684 } 1685 1686 enum CaseType 1687 { 1688 CASETYPE_CALLBACK = 0, 1689 CASETYPE_LOG, 1690 CASETYPE_GETERROR, 1691 1692 CASETYPE_LAST 1693 }; 1694 1695 tcu::TestNode* createCase (CaseType type, Context& ctx, const char* name, const char* desc, TestFunc function) 1696 { 1697 switch(type) 1698 { 1699 case CASETYPE_CALLBACK: return new CallbackErrorCase(ctx, name, desc, function); 1700 case CASETYPE_LOG: return new LogErrorCase(ctx, name, desc, function); 1701 case CASETYPE_GETERROR: return new GetErrorCase(ctx, name, desc, function); 1702 1703 default: 1704 DE_ASSERT(!"Invalid type"); 1705 } 1706 1707 return DE_NULL; 1708 } 1709 1710 tcu::TestCaseGroup* createChildCases (CaseType type, Context& ctx, const char* name, const char* desc, const vector<FunctionContainer>& funcs) 1711 { 1712 tcu::TestCaseGroup* host = new tcu::TestCaseGroup(ctx.getTestContext(), name, desc); 1713 1714 for (size_t ndx = 0; ndx < funcs.size(); ndx++) 1715 host->addChild(createCase(type, ctx, funcs[ndx].name, funcs[ndx].desc, funcs[ndx].function)); 1716 1717 return host; 1718 } 1719 1720 void DebugTests::init (void) 1721 { 1722 const vector<FunctionContainer> bufferFuncs = NegativeTestShared::getNegativeBufferApiTestFunctions(); 1723 const vector<FunctionContainer> textureFuncs = NegativeTestShared::getNegativeTextureApiTestFunctions(); 1724 const vector<FunctionContainer> shaderFuncs = NegativeTestShared::getNegativeShaderApiTestFunctions(); 1725 const vector<FunctionContainer> fragmentFuncs = NegativeTestShared::getNegativeFragmentApiTestFunctions(); 1726 const vector<FunctionContainer> vaFuncs = NegativeTestShared::getNegativeVertexArrayApiTestFunctions(); 1727 const vector<FunctionContainer> stateFuncs = NegativeTestShared::getNegativeStateApiTestFunctions(); 1728 const vector<FunctionContainer> externalFuncs = getUserMessageFuncs(); 1729 1730 { 1731 tcu::TestCaseGroup* const negative = new tcu::TestCaseGroup(m_testCtx, "negative_coverage", "API error coverage with various reporting methods"); 1732 1733 addChild(negative); 1734 1735 { 1736 tcu::TestCaseGroup* const host = new tcu::TestCaseGroup(m_testCtx, "callbacks", "Reporting of standard API errors via callback"); 1737 1738 negative->addChild(host); 1739 host->addChild(createChildCases(CASETYPE_CALLBACK, m_context, "buffer", "Negative Buffer API Cases", bufferFuncs)); 1740 host->addChild(createChildCases(CASETYPE_CALLBACK, m_context, "texture", "Negative Texture API Cases", textureFuncs)); 1741 host->addChild(createChildCases(CASETYPE_CALLBACK, m_context, "shader", "Negative Shader API Cases", shaderFuncs)); 1742 host->addChild(createChildCases(CASETYPE_CALLBACK, m_context, "fragment", "Negative Fragment API Cases", fragmentFuncs)); 1743 host->addChild(createChildCases(CASETYPE_CALLBACK, m_context, "vertex_array", "Negative Vertex Array API Cases", vaFuncs)); 1744 host->addChild(createChildCases(CASETYPE_CALLBACK, m_context, "state", "Negative GL State API Cases", stateFuncs)); 1745 } 1746 1747 { 1748 tcu::TestCaseGroup* const host = new tcu::TestCaseGroup(m_testCtx, "log", "Reporting of standard API errors via log"); 1749 1750 negative->addChild(host); 1751 1752 host->addChild(createChildCases(CASETYPE_LOG, m_context, "buffer", "Negative Buffer API Cases", bufferFuncs)); 1753 host->addChild(createChildCases(CASETYPE_LOG, m_context, "texture", "Negative Texture API Cases", textureFuncs)); 1754 host->addChild(createChildCases(CASETYPE_LOG, m_context, "shader", "Negative Shader API Cases", shaderFuncs)); 1755 host->addChild(createChildCases(CASETYPE_LOG, m_context, "fragment", "Negative Fragment API Cases", fragmentFuncs)); 1756 host->addChild(createChildCases(CASETYPE_LOG, m_context, "vertex_array", "Negative Vertex Array API Cases", vaFuncs)); 1757 host->addChild(createChildCases(CASETYPE_LOG, m_context, "state", "Negative GL State API Cases", stateFuncs)); 1758 } 1759 1760 { 1761 tcu::TestCaseGroup* const host = new tcu::TestCaseGroup(m_testCtx, "get_error", "Reporting of standard API errors via glGetError"); 1762 1763 negative->addChild(host); 1764 1765 host->addChild(createChildCases(CASETYPE_GETERROR, m_context, "buffer", "Negative Buffer API Cases", bufferFuncs)); 1766 host->addChild(createChildCases(CASETYPE_GETERROR, m_context, "texture", "Negative Texture API Cases", textureFuncs)); 1767 host->addChild(createChildCases(CASETYPE_GETERROR, m_context, "shader", "Negative Shader API Cases", shaderFuncs)); 1768 host->addChild(createChildCases(CASETYPE_GETERROR, m_context, "fragment", "Negative Fragment API Cases", fragmentFuncs)); 1769 host->addChild(createChildCases(CASETYPE_GETERROR, m_context, "vertex_array", "Negative Vertex Array API Cases", vaFuncs)); 1770 host->addChild(createChildCases(CASETYPE_GETERROR, m_context, "state", "Negative GL State API Cases", stateFuncs)); 1771 } 1772 } 1773 1774 { 1775 tcu::TestCaseGroup* host = createChildCases(CASETYPE_CALLBACK, m_context, "externally_generated", "Externally Generated Messages", externalFuncs); 1776 1777 host->addChild(new GroupCase(m_context, "push_pop_consistency", "Push/pop message generation with full message output checking")); 1778 1779 addChild(host); 1780 } 1781 1782 { 1783 vector<FunctionContainer> containers; 1784 vector<TestFunc> allFuncs; 1785 1786 de::Random rng (0x53941903 ^ m_context.getTestContext().getCommandLine().getBaseSeed()); 1787 1788 containers.insert(containers.end(), bufferFuncs.begin(), bufferFuncs.end()); 1789 containers.insert(containers.end(), textureFuncs.begin(), textureFuncs.end()); 1790 containers.insert(containers.end(), externalFuncs.begin(), externalFuncs.end()); 1791 1792 for (size_t ndx = 0; ndx < containers.size(); ndx++) 1793 allFuncs.push_back(containers[ndx].function); 1794 1795 rng.shuffle(allFuncs.begin(), allFuncs.end()); 1796 1797 { 1798 tcu::TestCaseGroup* const filtering = new tcu::TestCaseGroup(m_testCtx, "error_filters", "Filtering of reported errors"); 1799 const int errorFuncsPerCase = 4; 1800 const int maxFilteringCaseCount = 32; 1801 const int caseCount = (int(allFuncs.size()) + errorFuncsPerCase-1) / errorFuncsPerCase; 1802 1803 addChild(filtering); 1804 1805 for (int caseNdx = 0; caseNdx < de::min(caseCount, maxFilteringCaseCount); caseNdx++) 1806 { 1807 const int start = caseNdx*errorFuncsPerCase; 1808 const int end = de::min((caseNdx+1)*errorFuncsPerCase, int(allFuncs.size())); 1809 const string name = "case_" + de::toString(caseNdx); 1810 vector<TestFunc> funcs (allFuncs.begin()+start, allFuncs.begin()+end); 1811 1812 // These produce lots of different message types, thus always include at least one when testing filtering 1813 funcs.insert(funcs.end(), externalFuncs[caseNdx%externalFuncs.size()].function); 1814 1815 filtering->addChild(new FilterCase(m_context, name.c_str(), "DebugMessageControl usage", funcs)); 1816 } 1817 } 1818 1819 { 1820 tcu::TestCaseGroup* const groups = new tcu::TestCaseGroup(m_testCtx, "error_groups", "Filtering of reported errors with use of Error Groups"); 1821 const int errorFuncsPerCase = 4; 1822 const int maxFilteringCaseCount = 16; 1823 const int caseCount = (int(allFuncs.size()) + errorFuncsPerCase-1) / errorFuncsPerCase; 1824 1825 addChild(groups); 1826 1827 for (int caseNdx = 0; caseNdx < caseCount && caseNdx < maxFilteringCaseCount; caseNdx++) 1828 { 1829 const int start = caseNdx*errorFuncsPerCase; 1830 const int end = de::min((caseNdx+1)*errorFuncsPerCase, int(allFuncs.size())); 1831 const string name = ("case_" + de::toString(caseNdx)).c_str(); 1832 vector<TestFunc> funcs (&allFuncs[0]+start, &allFuncs[0]+end); 1833 1834 // These produce lots of different message types, thus always include at least one when testing filtering 1835 funcs.insert(funcs.end(), externalFuncs[caseNdx%externalFuncs.size()].function); 1836 1837 groups->addChild(new GroupFilterCase(m_context, name.c_str(), "Debug Group usage", funcs)); 1838 } 1839 } 1840 1841 { 1842 tcu::TestCaseGroup* const async = new tcu::TestCaseGroup(m_testCtx, "async", "Asynchronous message generation"); 1843 const int errorFuncsPerCase = 2; 1844 const int maxAsyncCaseCount = 16; 1845 const int caseCount = (int(allFuncs.size()) + errorFuncsPerCase-1) / errorFuncsPerCase; 1846 1847 addChild(async); 1848 1849 for (int caseNdx = 0; caseNdx < caseCount && caseNdx < maxAsyncCaseCount; caseNdx++) 1850 { 1851 const int start = caseNdx*errorFuncsPerCase; 1852 const int end = de::min((caseNdx+1)*errorFuncsPerCase, int(allFuncs.size())); 1853 const string name = ("case_" + de::toString(caseNdx)).c_str(); 1854 vector<TestFunc> funcs (&allFuncs[0]+start, &allFuncs[0]+end); 1855 1856 if (caseNdx&0x1) 1857 async->addChild(new AsyncCase(m_context, (name+"_callback").c_str(), "Async message generation", funcs, true)); 1858 else 1859 async->addChild(new AsyncCase(m_context, (name+"_log").c_str(), "Async message generation", funcs, false)); 1860 } 1861 } 1862 } 1863 1864 { 1865 tcu::TestCaseGroup* const labels = new tcu::TestCaseGroup(m_testCtx, "object_labels", "Labeling objects"); 1866 1867 const struct 1868 { 1869 GLenum identifier; 1870 const char* name; 1871 const char* desc; 1872 } cases[] = 1873 { 1874 { GL_BUFFER, "buffer", "Debug label on a buffer object" }, 1875 { GL_SHADER, "shader", "Debug label on a shader object" }, 1876 { GL_PROGRAM, "program", "Debug label on a program object" }, 1877 { GL_QUERY, "query", "Debug label on a query object" }, 1878 { GL_PROGRAM_PIPELINE, "program_pipeline", "Debug label on a program pipeline object" }, 1879 { GL_TRANSFORM_FEEDBACK, "transform_feedback", "Debug label on a transform feedback object" }, 1880 { GL_SAMPLER, "sampler", "Debug label on a sampler object" }, 1881 { GL_TEXTURE, "texture", "Debug label on a texture object" }, 1882 { GL_RENDERBUFFER, "renderbuffer", "Debug label on a renderbuffer object" }, 1883 { GL_FRAMEBUFFER, "framebuffer", "Debug label on a framebuffer object" }, 1884 }; 1885 1886 addChild(labels); 1887 1888 for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(cases); ndx++) 1889 labels->addChild(new LabelCase(m_context, cases[ndx].name, cases[ndx].desc, cases[ndx].identifier)); 1890 } 1891 } 1892 1893 } // Functional 1894 } // gles31 1895 } // deqp 1896