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