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