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