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