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