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
54namespace deqp
55{
56namespace gles31
57{
58namespace Functional
59{
60namespace
61{
62using namespace glw;
63
64using NegativeTestShared::NegativeTestContext;
65using NegativeTestShared::FunctionContainer;
66using std::string;
67using std::vector;
68
69GLenum debugTypes[] =
70{
71	GL_DEBUG_TYPE_ERROR,
72	GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR,
73	GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR,
74	GL_DEBUG_TYPE_PORTABILITY,
75	GL_DEBUG_TYPE_PERFORMANCE,
76	GL_DEBUG_TYPE_OTHER,
77	GL_DEBUG_TYPE_MARKER,
78	GL_DEBUG_TYPE_PUSH_GROUP,
79	GL_DEBUG_TYPE_POP_GROUP,
80};
81
82GLenum debugSeverities[] =
83{
84	GL_DEBUG_SEVERITY_HIGH,
85    GL_DEBUG_SEVERITY_MEDIUM,
86    GL_DEBUG_SEVERITY_LOW,
87    GL_DEBUG_SEVERITY_NOTIFICATION,
88};
89
90void emitMessages(NegativeTestContext& ctx, GLenum source)
91{
92	for (int typeNdx = 0; typeNdx < DE_LENGTH_OF_ARRAY(debugTypes); typeNdx++)
93	{
94		for (int severityNdx = 0; severityNdx < DE_LENGTH_OF_ARRAY(debugSeverities); severityNdx++)
95		{
96			const GLenum type		= debugTypes[typeNdx];
97			const GLenum severity	= debugSeverities[severityNdx];
98			const string msg		= string("Application generated message with type ") + glu::getDebugMessageTypeName(type)
99									  + " and severity " + glu::getDebugMessageSeverityName(severity);
100
101			// Use severity as ID, guaranteed unique
102			ctx.glDebugMessageInsert(source, type, severity, severity, -1, msg.c_str());
103			ctx.expectMessage(source, type);
104		}
105	}
106}
107
108void application_messages (NegativeTestContext& ctx)
109{
110	ctx.beginSection("Messages with source of GL_DEBUG_SOURCE_APPLICATION");
111	emitMessages(ctx, GL_DEBUG_SOURCE_APPLICATION);
112	ctx.endSection();
113}
114
115void thirdparty_messages (NegativeTestContext& ctx)
116{
117	ctx.beginSection("Messages with source of GL_DEBUG_SOURCE_THIRD_PARTY");
118	emitMessages(ctx, GL_DEBUG_SOURCE_THIRD_PARTY);
119	ctx.endSection();
120}
121
122void push_pop_messages (NegativeTestContext& ctx)
123{
124	ctx.beginSection("Push/Pop Debug Group");
125
126	ctx.glPushDebugGroup(GL_DEBUG_SOURCE_APPLICATION, 1, -1, "Application group 1");
127	ctx.expectMessage(GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_PUSH_GROUP);
128	ctx.glPushDebugGroup(GL_DEBUG_SOURCE_APPLICATION, 2, -1, "Application group 1-1");
129	ctx.expectMessage(GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_PUSH_GROUP);
130	ctx.glPushDebugGroup(GL_DEBUG_SOURCE_APPLICATION, 3, -1, "Application group 1-1-1");
131	ctx.expectMessage(GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_PUSH_GROUP);
132	ctx.glPopDebugGroup();
133	ctx.expectMessage(GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_POP_GROUP);
134	ctx.glPopDebugGroup();
135	ctx.expectMessage(GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_POP_GROUP);
136
137	ctx.glPushDebugGroup(GL_DEBUG_SOURCE_APPLICATION, 4, -1, "Application group 1-2");
138	ctx.expectMessage(GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_PUSH_GROUP);
139	ctx.glPopDebugGroup();
140	ctx.expectMessage(GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_POP_GROUP);
141
142	ctx.glPushDebugGroup(GL_DEBUG_SOURCE_THIRD_PARTY, 4, -1, "3rd Party group 1-3");
143	ctx.expectMessage(GL_DEBUG_SOURCE_THIRD_PARTY, GL_DEBUG_TYPE_PUSH_GROUP);
144	ctx.glPopDebugGroup();
145	ctx.expectMessage(GL_DEBUG_SOURCE_THIRD_PARTY, GL_DEBUG_TYPE_POP_GROUP);
146	ctx.glPopDebugGroup();
147	ctx.expectMessage(GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_POP_GROUP);
148
149	ctx.glPushDebugGroup(GL_DEBUG_SOURCE_THIRD_PARTY, 4, -1, "3rd Party group 2");
150	ctx.expectMessage(GL_DEBUG_SOURCE_THIRD_PARTY, GL_DEBUG_TYPE_PUSH_GROUP);
151	ctx.glPopDebugGroup();
152	ctx.expectMessage(GL_DEBUG_SOURCE_THIRD_PARTY, GL_DEBUG_TYPE_POP_GROUP);
153
154	ctx.endSection();
155}
156
157vector<FunctionContainer> getUserMessageFuncs (void)
158{
159	FunctionContainer funcs[] =
160	{
161		{ application_messages,	"application_messages", "Externally generated messages from the application"	},
162		{ thirdparty_messages,	"third_party_messages",	"Externally generated messages from a third party"		},
163		{ push_pop_messages,	"push_pop_stack",		"Messages from pushing/popping debug groups"			},
164	};
165
166	return std::vector<FunctionContainer>(DE_ARRAY_BEGIN(funcs), DE_ARRAY_END(funcs));
167}
168
169} // Anonymous
170
171namespace
172{
173
174using std::string;
175using std::vector;
176using std::set;
177using std::map;
178using de::MovePtr;
179
180using glw::GLenum;
181using glw::GLuint;
182using glw::GLsizei;
183
184using tcu::ResultCollector;
185using tcu::TestLog;
186using glu::CallLogWrapper;
187
188using NegativeTestShared::TestFunc;
189using NegativeTestShared::FunctionContainer;
190using NegativeTestShared::NegativeTestContext;
191
192// Data required to uniquely identify a debug message
193struct MessageID
194{
195	GLenum source;
196	GLenum type;
197	GLuint id;
198
199	MessageID (void) : source(GL_NONE), type(GL_NONE), id(0) {}
200	MessageID (GLenum source_, GLenum type_, GLuint id_) : source(source_), type(type_), id(id_) {}
201
202	bool operator== (const MessageID& rhs) const { return source == rhs.source && type == rhs.type && id == rhs.id;}
203	bool operator!= (const MessageID& rhs) const { return source != rhs.source || type != rhs.type || id != rhs.id;}
204	bool operator<  (const MessageID& rhs) const
205	{
206		return source < rhs.source || (source == rhs.source && (type < rhs.type || (type == rhs.type && id < rhs.id)));
207	}
208};
209
210std::ostream& operator<< (std::ostream& str, const MessageID &id)
211{
212	return str << glu::getDebugMessageSourceStr(id.source) << ", "	<< glu::getDebugMessageTypeStr(id.type) << ", " << id.id;
213}
214
215// All info from a single debug message
216struct MessageData
217{
218	MessageID	id;
219	GLenum		severity;
220	string		message;
221
222	MessageData (void) : id(MessageID()), severity(GL_NONE) {}
223	MessageData (const MessageID& id_, GLenum severity_, const string& message_) : id(id_) , severity(severity_) , message(message_) {}
224};
225
226extern "C" typedef void GLW_APIENTRY DebugCallbackFunc(GLenum, GLenum, GLuint, GLenum, GLsizei, const char*, void*);
227
228// Base class
229class BaseCase : public NegativeTestShared::ErrorCase
230{
231public:
232								BaseCase			(Context&					ctx,
233													 const char*				name,
234													 const char*				desc);
235	virtual 					~BaseCase			(void) {}
236
237	virtual IterateResult		iterate				(void) = 0;
238
239	virtual void				expectMessage		(GLenum source, GLenum type);
240	virtual void				expectError			(GLenum error0, GLenum error1);
241
242protected:
243	struct VerificationResult {
244		const qpTestResult	result;
245		const string		resultMessage;
246		const string		logMessage;
247
248		VerificationResult (qpTestResult result_, const string& resultMessage_, const string& logMessage_)
249			: result(result_), resultMessage(resultMessage_), logMessage(logMessage_) {}
250	};
251
252	static DebugCallbackFunc	callbackHandle;
253	virtual void				callback			(GLenum source, GLenum type, GLuint id, GLenum severity, const std::string& message);
254
255
256	VerificationResult			verifyMessageCount	(const MessageID& id, GLenum severity, int refCount, int resCount, bool messageEnabled) const;
257
258	// Verify a single message instance against expected attributes
259	void						verifyMessage		(const MessageData& message, GLenum source, GLenum type, GLuint id, GLenum severity);
260	void						verifyMessage		(const MessageData& message, GLenum source, GLenum type);
261
262	bool						verifyMessageExists	(const MessageData& message, GLenum source, GLenum type);
263	void						verifyMessageGroup	(const MessageData& message, GLenum source, GLenum type);
264	void						verifyMessageString	(const MessageData& message);
265
266	bool						isDebugContext		(void) const;
267
268	tcu::ResultCollector		m_results;
269};
270
271void BaseCase::callbackHandle (GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const char* message, void* userParam)
272{
273	static_cast<BaseCase*>(userParam)->callback(source, type, id, severity, string(message, &message[length]));
274}
275
276BaseCase::BaseCase (Context& ctx, const char* name, const char* desc)
277	: ErrorCase(ctx, name, desc)
278{
279}
280
281void BaseCase::expectMessage (GLenum source, GLenum type)
282{
283	DE_UNREF(source);
284	DE_UNREF(type);
285}
286
287void BaseCase::expectError (GLenum error0, GLenum error1)
288{
289	if (error0 != GL_NO_ERROR || error1 != GL_NO_ERROR)
290		expectMessage(GL_DEBUG_SOURCE_API, GL_DEBUG_TYPE_ERROR);
291	else
292		expectMessage(GL_DONT_CARE, GL_DONT_CARE);
293}
294
295void BaseCase::callback (GLenum source, GLenum type, GLuint id, GLenum severity, const string& message)
296{
297	DE_UNREF(source);
298	DE_UNREF(type);
299	DE_UNREF(id);
300	DE_UNREF(severity);
301	DE_UNREF(message);
302}
303
304BaseCase::VerificationResult BaseCase::verifyMessageCount (const MessageID& id, GLenum severity, int refCount, int resCount, bool messageEnabled) const
305{
306	std::stringstream log;
307
308	// This message should not be filtered out
309	if (messageEnabled)
310	{
311		if (resCount != refCount)
312		{
313			/*
314			 * Technically nothing requires the implementation to be consistent in terms
315			 * of the messages it produces in most situations, allowing the set of messages
316			 * produced to vary between executions. This function splits messages
317			 * into deterministic and non-deterministic to facilitate handling of such messages.
318			 *
319			 * Non-deterministic messages that are present in differing quantities in filtered and
320			 * unfiltered runs will not fail the test case unless in direct violation of a filter:
321			 * the implementation may produce an arbitrary number of such messages when they are
322			 * not filtered out and none when they are filtered.
323			 *
324			 * A list of error source/type combinations with their assumed behaviour and
325			 * the rationale for expecting such behaviour follows
326			 *
327			 * For API/shader messages we assume that the following types are deterministic:
328			 *   DEBUG_TYPE_ERROR                 Errors specified by spec and should always be produced
329			 *
330			 * For API messages the following types are assumed to be non-deterministic
331			 * and treated as quality warnings since the underlying reported issue does not change between calls:
332			 *   DEBUG_TYPE_DEPRECATED_BEHAVIOR   Reasonable to only report first instance
333             *   DEBUG_TYPE_UNDEFINED_BEHAVIOR    Reasonable to only report first instance
334             *   DEBUG_TYPE_PORTABILITY           Reasonable to only report first instance
335			 *
336			 * For API messages the following types are assumed to be non-deterministic
337			 * and do not affect test results.
338			 *   DEBUG_TYPE_PERFORMANCE           May be tied to arbitrary factors, reasonable to report only first instance
339             *   DEBUG_TYPE_OTHER                 Definition allows arbitrary contents
340			 *
341			 * For 3rd party and application messages the following types are deterministic:
342             *   DEBUG_TYPE_MARKER                Only generated by test
343			 *   DEBUG_TYPE_PUSH_GROUP            Only generated by test
344			 *   DEBUG_TYPE_POP_GROUP             Only generated by test
345			 *   All others                       Only generated by test
346			 *
347			 * All messages with category of window system or other are treated as non-deterministic
348			 * and do not effect test results since they can be assumed to be outside control of
349			 * both the implementation and test case
350			 *
351			 */
352
353			const bool isDeterministic	= id.source == GL_DEBUG_SOURCE_APPLICATION ||
354										  id.source == GL_DEBUG_SOURCE_THIRD_PARTY ||
355										  ((id.source == GL_DEBUG_SOURCE_API || id.source == GL_DEBUG_SOURCE_SHADER_COMPILER) && id.type == GL_DEBUG_TYPE_ERROR);
356
357			const bool canIgnore		= id.source == GL_DEBUG_SOURCE_WINDOW_SYSTEM || id.source == GL_DEBUG_SOURCE_OTHER;
358
359			if (isDeterministic)
360			{
361				if (resCount > refCount)
362				{
363					log << "Extra instances of message were found: (" << id << ") with "
364						<< glu::getDebugMessageSeverityStr(severity)
365						<< " (got " << resCount << ", expected " << refCount << ")";
366					return VerificationResult(QP_TEST_RESULT_FAIL, "Extra instances of a deterministic message were present", log.str());
367				}
368				else
369				{
370					log << "Instances of message were missing: (" << id << ") with "
371						<< glu::getDebugMessageSeverityStr(severity)
372						<< " (got " << resCount << ", expected " << refCount << ")";
373					return VerificationResult(QP_TEST_RESULT_FAIL, "Message missing", log.str());
374				}
375			}
376			else if(!canIgnore)
377			{
378				if (resCount > refCount)
379				{
380					log << "Extra instances of message were found but the message is non-deterministic(warning): (" << id << ") with "
381						<< glu::getDebugMessageSeverityStr(severity)
382						<< " (got " << resCount << ", expected " << refCount << ")";
383					return VerificationResult(QP_TEST_RESULT_QUALITY_WARNING, "Extra instances of a message were present", log.str());
384				}
385				else
386				{
387					log << "Instances of message were missing but the message is non-deterministic(warning): (" << id << ") with "
388						<< glu::getDebugMessageSeverityStr(severity)
389						<< " (got " << resCount << ", expected " << refCount << ")";
390					return VerificationResult(QP_TEST_RESULT_QUALITY_WARNING, "Message missing", log.str());
391				}
392			}
393			else
394			{
395				if (resCount > refCount)
396				{
397					log << "Extra instances of message were found but the message is non-deterministic(ignored): (" << id << ") with "
398						<< glu::getDebugMessageSeverityStr(severity)
399						<< " (got " << resCount << ", expected " << refCount << ")";
400					return VerificationResult(QP_TEST_RESULT_PASS, "", log.str());
401				}
402				else
403				{
404					log << "Instances of message were missing but the message is non-deterministic(ignored): (" << id << ") with "
405						<< glu::getDebugMessageSeverityStr(severity)
406						<< " (got " << resCount << ", expected " << refCount << ")";
407					return VerificationResult(QP_TEST_RESULT_PASS, "", log.str());
408				}
409			}
410		}
411		else // Passed as appropriate
412		{
413			log << "Message was found when expected: ("<< id << ") with "
414				<< glu::getDebugMessageSeverityStr(severity);
415			return VerificationResult(QP_TEST_RESULT_PASS, "", log.str());
416		}
417	}
418	// Message should be filtered out
419	else
420	{
421		// Filtered out
422		if (resCount == 0)
423		{
424			log << "Message was excluded correctly:  (" << id << ") with "
425				<< glu::getDebugMessageSeverityStr(severity);
426			return VerificationResult(QP_TEST_RESULT_PASS, "", log.str());
427		}
428		// Only present in filtered run (ERROR)
429		else if (resCount > 0 && refCount == 0)
430		{
431			log << "A message was not excluded as it should have been: (" << id << ") with "
432				<< glu::getDebugMessageSeverityStr(severity)
433				<< ". This message was not present in the reference run";
434			return VerificationResult(QP_TEST_RESULT_FAIL, "A message was not filtered out", log.str());
435		}
436		// Present in both runs (ERROR)
437		else
438		{
439			log << "A message was not excluded as it should have been: (" << id << ") with "
440				<< glu::getDebugMessageSeverityStr(severity);
441			return VerificationResult(QP_TEST_RESULT_FAIL, "A message was not filtered out", log.str());
442		}
443	}
444}
445
446// Return true if message needs further verification
447bool BaseCase::verifyMessageExists (const MessageData& message, GLenum source, GLenum type)
448{
449	TestLog& log = m_testCtx.getLog();
450
451	if (source == GL_DONT_CARE || type == GL_DONT_CARE)
452		return false;
453	else if (message.id.source == GL_NONE || message.id.type == GL_NONE)
454	{
455		if (isDebugContext())
456		{
457			m_results.addResult(QP_TEST_RESULT_FAIL, "Message was not reported as expected");
458			log << TestLog::Message << "A message was expected but none was reported" << TestLog::EndMessage;
459		}
460		else
461		{
462			m_results.addResult(QP_TEST_RESULT_QUALITY_WARNING, "Verification accuracy is lacking without a debug context");
463			log << TestLog::Message << "A message was expected but none was reported. Running without a debug context" << TestLog::EndMessage;
464		}
465		return false;
466	}
467	else
468		return true;
469}
470
471void BaseCase::verifyMessageGroup (const MessageData& message, GLenum source, GLenum type)
472{
473	TestLog& log = m_testCtx.getLog();
474
475	if (message.id.source != source)
476	{
477		m_results.addResult(QP_TEST_RESULT_FAIL, "Incorrect message source");
478		log << TestLog::Message << "Message source was " << glu::getDebugMessageSourceStr(message.id.source)
479			<< " when it should have been "  << glu::getDebugMessageSourceStr(source) << TestLog::EndMessage;
480	}
481
482	if (message.id.type != type)
483	{
484		m_results.addResult(QP_TEST_RESULT_FAIL, "Incorrect message type");
485		log << TestLog::Message << "Message type was " << glu::getDebugMessageTypeStr(message.id.type)
486			<< " when it should have been " << glu::getDebugMessageTypeStr(type) << TestLog::EndMessage;
487	}
488}
489
490void BaseCase::verifyMessageString (const MessageData& message)
491{
492	TestLog& log = m_testCtx.getLog();
493
494	log << TestLog::Message << "Driver says: \"" << message.message << "\"" << TestLog::EndMessage;
495
496	if (message.message.empty())
497	{
498		m_results.addResult(QP_TEST_RESULT_QUALITY_WARNING, "Empty message");
499		log << TestLog::Message << "Message message was empty" << TestLog::EndMessage;
500	}
501}
502
503void BaseCase::verifyMessage (const MessageData& message, GLenum source, GLenum type)
504{
505	if (verifyMessageExists(message, source, type))
506	{
507		verifyMessageString(message);
508		verifyMessageGroup(message, source, type);
509	}
510}
511
512void BaseCase::verifyMessage (const MessageData& message, GLenum source, GLenum type, GLuint id, GLenum severity)
513{
514	TestLog& log = m_testCtx.getLog();
515
516	if (verifyMessageExists(message, source, type))
517	{
518		verifyMessageString(message);
519		verifyMessageGroup(message, source, type);
520
521		if (message.id.id != id)
522		{
523			m_results.addResult(QP_TEST_RESULT_FAIL, "Incorrect message id");
524			log << TestLog::Message << "Message id was " << message.id.id
525				<< " when it should have been " << id << TestLog::EndMessage;
526		}
527
528		if (message.severity != severity)
529		{
530			m_results.addResult(QP_TEST_RESULT_FAIL, "Incorrect message severity");
531			log << TestLog::Message << "Message severity was " << glu::getDebugMessageSeverityStr(message.severity)
532				<< " when it should have been " << glu::getDebugMessageSeverityStr(severity) << TestLog::EndMessage;
533		}
534	}
535}
536
537bool BaseCase::isDebugContext (void) const
538{
539	return (m_context.getRenderContext().getType().getFlags() & glu::CONTEXT_DEBUG) != 0;
540}
541
542// Generate errors, verify that each error results in a callback call
543class CallbackErrorCase : public BaseCase
544{
545public:
546							CallbackErrorCase	(Context&				ctx,
547												 const char*			name,
548												 const char*			desc,
549												 TestFunc				errorFunc);
550	virtual 				~CallbackErrorCase	(void) {}
551
552	virtual IterateResult	iterate				(void);
553
554	virtual void			expectMessage		(GLenum source, GLenum type);
555
556private:
557	virtual void			callback			(GLenum source, GLenum type, GLuint id, GLenum severity, const string& message);
558
559	const TestFunc			m_errorFunc;
560	MessageData				m_lastMessage;
561};
562
563CallbackErrorCase::CallbackErrorCase (Context&				ctx,
564									  const char*			name,
565									  const char*			desc,
566									  TestFunc				errorFunc)
567	: BaseCase		(ctx, name, desc)
568	, m_errorFunc	(errorFunc)
569{
570}
571
572CallbackErrorCase::IterateResult CallbackErrorCase::iterate (void)
573{
574	TCU_CHECK_AND_THROW(NotSupportedError, m_context.getContextInfo().isExtensionSupported("GL_KHR_debug"), "GL_KHR_debug is not supported");
575
576	const glw::Functions&	gl		= m_context.getRenderContext().getFunctions();
577	tcu::TestLog&			log		= m_testCtx.getLog();
578	NegativeTestContext		context	= NegativeTestContext(*this, m_context.getRenderContext(), m_context.getContextInfo(), log, m_results, true);
579
580	gl.enable(GL_DEBUG_OUTPUT);
581	gl.enable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
582	gl.debugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, DE_NULL, false); // disable all
583	gl.debugMessageControl(GL_DEBUG_SOURCE_API, GL_DEBUG_TYPE_ERROR, GL_DONT_CARE, 0, DE_NULL, true); // enable API errors
584	gl.debugMessageControl(GL_DEBUG_SOURCE_APPLICATION, GL_DONT_CARE, GL_DONT_CARE, 0, DE_NULL, true); // enable application messages
585	gl.debugMessageControl(GL_DEBUG_SOURCE_THIRD_PARTY, GL_DONT_CARE, GL_DONT_CARE, 0, DE_NULL, true); // enable third party messages
586	gl.debugMessageCallback(callbackHandle, this);
587
588	m_errorFunc(context);
589
590	gl.debugMessageCallback(DE_NULL, DE_NULL);
591	gl.disable(GL_DEBUG_OUTPUT);
592
593	m_results.setTestContextResult(m_testCtx);
594
595	return STOP;
596}
597
598void CallbackErrorCase::expectMessage (GLenum source, GLenum type)
599{
600	verifyMessage(m_lastMessage, source, type);
601	m_lastMessage = MessageData();
602
603	// Reset error so that code afterwards doesn't break because of lingering error state
604	m_context.getRenderContext().getFunctions().getError();
605}
606
607void CallbackErrorCase::callback (GLenum source, GLenum type, GLuint id, GLenum severity, const string& message)
608{
609	m_lastMessage = MessageData(MessageID(source, type, id), severity, message);
610}
611
612// Generate errors, verify that each error results in a log entry
613class LogErrorCase : public BaseCase
614{
615public:
616							LogErrorCase	(Context&				context,
617											 const char*			name,
618											 const char*			desc,
619											 TestFunc				errorFunc);
620	virtual 				~LogErrorCase	(void) {}
621
622	virtual IterateResult	iterate			(void);
623
624	virtual void			expectMessage	(GLenum source, GLenum type);
625
626private:
627	const TestFunc			m_errorFunc;
628	MessageData				m_lastMessage;
629};
630
631LogErrorCase::LogErrorCase (Context&	ctx,
632							const char*	name,
633							const char*	desc,
634							TestFunc	errorFunc)
635	: BaseCase		(ctx, name, desc)
636	, m_errorFunc	(errorFunc)
637{
638}
639
640LogErrorCase::IterateResult LogErrorCase::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	NegativeTestContext		context	= NegativeTestContext(*this, m_context.getRenderContext(), m_context.getContextInfo(), log, m_results, true);
647	GLint					numMsg	= 0;
648
649	gl.enable(GL_DEBUG_OUTPUT);
650	gl.enable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
651	gl.debugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, DE_NULL, false); // disable all
652	gl.debugMessageControl(GL_DEBUG_SOURCE_API, GL_DEBUG_TYPE_ERROR, GL_DONT_CARE, 0, DE_NULL, true); // enable API errors
653	gl.debugMessageCallback(DE_NULL, DE_NULL); // enable logging
654	gl.getIntegerv(GL_DEBUG_LOGGED_MESSAGES, &numMsg);
655	gl.getDebugMessageLog(numMsg, 0, DE_NULL, DE_NULL, DE_NULL, DE_NULL, DE_NULL, DE_NULL); // clear log
656
657	m_errorFunc(context);
658
659	gl.disable(GL_DEBUG_OUTPUT);
660	m_results.setTestContextResult(m_testCtx);
661
662	return STOP;
663}
664
665void LogErrorCase::expectMessage (GLenum source, GLenum type)
666{
667	const glw::Functions&	gl			= m_context.getRenderContext().getFunctions();
668	int						numMsg		= 0;
669	TestLog&				log			= m_testCtx.getLog();
670	MessageData				lastMsg;
671
672	if (source == GL_DONT_CARE || type == GL_DONT_CARE)
673		return;
674
675	gl.getIntegerv(GL_DEBUG_LOGGED_MESSAGES, &numMsg);
676
677	if (numMsg == 0)
678	{
679		if (isDebugContext())
680		{
681			m_results.addResult(QP_TEST_RESULT_FAIL, "Error was not reported as expected");
682			log << TestLog::Message << "A message was expected but none was reported (empty message log)" << TestLog::EndMessage;
683		}
684		else
685		{
686			m_results.addResult(QP_TEST_RESULT_QUALITY_WARNING, "Verification accuracy is lacking without a debug context");
687			log << TestLog::Message << "A message was expected but none was reported (empty message log). Running without a debug context" << TestLog::EndMessage;
688		}
689		return;
690	}
691
692	// There may be messages other than the error we are looking for in the log.
693	// Strictly nothing prevents the implementation from producing more than the
694	// required error from an API call with a defined error. however we assume that
695	// since calls that produce an error should not change GL state the implementation
696	// should have nothing else to report.
697	if (numMsg > 1)
698		gl.getDebugMessageLog(numMsg-1, 0, DE_NULL, DE_NULL, DE_NULL, DE_NULL, DE_NULL, DE_NULL); // Clear all but last
699
700	{
701		int  msgLen = 0;
702		gl.getIntegerv(GL_DEBUG_NEXT_LOGGED_MESSAGE_LENGTH, &msgLen);
703
704		TCU_CHECK_MSG(msgLen >= 0, "Negative message length");
705		TCU_CHECK_MSG(msgLen < 100000, "Excessively long message");
706
707		lastMsg.message.resize(msgLen);
708		gl.getDebugMessageLog(1, msgLen, &lastMsg.id.source, &lastMsg.id.type, &lastMsg.id.id, &lastMsg.severity, &msgLen, &lastMsg.message[0]);
709	}
710
711	log << TestLog::Message << "Driver says: \"" << lastMsg.message << "\"" << TestLog::EndMessage;
712
713	verifyMessage(lastMsg, source, type);
714
715	// Reset error so that code afterwards doesn't break because of lingering error state
716	m_context.getRenderContext().getFunctions().getError();
717}
718
719// Generate errors, verify that calling glGetError afterwards produces desired result
720class GetErrorCase : public BaseCase
721{
722public:
723							GetErrorCase	(Context&				ctx,
724											 const char*			name,
725											 const char*			desc,
726											 TestFunc				errorFunc);
727	virtual 				~GetErrorCase	(void) {}
728
729	virtual IterateResult	iterate			(void);
730
731	virtual void			expectMessage	(GLenum source, GLenum type);
732	virtual void			expectError		(glw::GLenum error0, glw::GLenum error1);
733
734private:
735	const TestFunc			m_errorFunc;
736};
737
738GetErrorCase::GetErrorCase (Context&	ctx,
739							const char*	name,
740							const char*	desc,
741							TestFunc	errorFunc)
742	: BaseCase		(ctx, name, desc)
743	, m_errorFunc	(errorFunc)
744{
745}
746
747GetErrorCase::IterateResult GetErrorCase::iterate (void)
748{
749	tcu::TestLog&			log		= m_testCtx.getLog();
750	NegativeTestContext		context	= NegativeTestContext(*this, m_context.getRenderContext(), m_context.getContextInfo(), log, m_results, true);
751
752	m_errorFunc(context);
753
754	m_results.setTestContextResult(m_testCtx);
755
756	return STOP;
757}
758
759void GetErrorCase::expectMessage (GLenum source, GLenum type)
760{
761	DE_UNREF(source);
762	DE_UNREF(type);
763	DE_ASSERT(!"GetErrorCase cannot handle anything other than error codes");
764}
765
766void GetErrorCase::expectError (glw::GLenum error0, glw::GLenum error1)
767{
768	const glw::Functions&	gl		= m_context.getRenderContext().getFunctions();
769	TestLog&				log		= m_testCtx.getLog();
770
771	const GLenum			result	= gl.getError();
772
773	if (result != error0 && result != error1)
774	{
775		m_results.addResult(QP_TEST_RESULT_FAIL, "Incorrect error was reported");
776		if (error0 == error1)
777			log << TestLog::Message
778				<< glu::getErrorStr(error0) << " was expected but got "
779				<< glu::getErrorStr(result)
780				<< TestLog::EndMessage;
781		else
782			log << TestLog::Message
783				<< glu::getErrorStr(error0) << " or "
784				<< glu::getErrorStr(error1) << " was expected but got "
785				<< glu::getErrorStr(result)
786				<< TestLog::EndMessage;
787		return;
788	}
789}
790
791// Generate errors, log the types, disable some, regenerate errors, verify correct errors (not)reported
792class FilterCase : public BaseCase
793{
794public:
795								FilterCase		(Context&				ctx,
796												 const char*			name,
797												 const char*			desc,
798												 const vector<TestFunc>	errorFuncs);
799	virtual 					~FilterCase		(void) {}
800
801	virtual IterateResult		iterate			(void);
802
803	virtual void				expectMessage	(GLenum source, GLenum type);
804
805protected:
806	struct MessageFilter
807	{
808		MessageFilter() : source(GL_DONT_CARE), type(GL_DONT_CARE), severity(GL_DONT_CARE), enabled(true) {} // Default to enable all
809		MessageFilter(GLenum source_, GLenum type_, GLenum severity_, const vector<GLuint>& ids_, bool enabled_) : source(source_), type(type_), severity(severity_), ids(ids_), enabled(enabled_) {}
810
811		GLenum			source;
812		GLenum			type;
813		GLenum			severity;
814		vector<GLuint>	ids;
815		bool			enabled;
816	};
817
818	virtual void				callback			(GLenum source, GLenum type, GLuint id, GLenum severity, const string& message);
819
820	vector<MessageData>			genMessages			(bool uselog, const string& desc);
821
822	vector<MessageFilter>		genFilters			(const vector<MessageData>& messages, const vector<MessageFilter>& initial, deUint32 seed, int iterations) const;
823	void						applyFilters		(const vector<MessageFilter>& filters) const;
824	bool						isEnabled			(const vector<MessageFilter>& filters, const MessageData& message) const;
825
826	void						verify				(const vector<MessageData>&		refMessages,
827													 const vector<MessageData>&		filteredMessages,
828													 const vector<MessageFilter>&	filters);
829
830	const vector<TestFunc>		m_errorFuncs;
831
832	vector<MessageData>*		m_currentErrors;
833};
834
835FilterCase::FilterCase (Context&				ctx,
836						const char*				name,
837						const char*				desc,
838						const vector<TestFunc>	errorFuncs)
839	: BaseCase			(ctx, name, desc)
840	, m_errorFuncs		(errorFuncs)
841	, m_currentErrors	(DE_NULL)
842{
843}
844
845FilterCase::IterateResult FilterCase::iterate (void)
846{
847	TCU_CHECK_AND_THROW(NotSupportedError, m_context.getContextInfo().isExtensionSupported("GL_KHR_debug"), "GL_KHR_debug is not supported");
848
849	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
850
851	gl.enable(GL_DEBUG_OUTPUT);
852	gl.enable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
853	gl.debugMessageCallback(callbackHandle, this);
854	gl.debugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, DE_NULL, true);
855
856	{
857		const vector<MessageData>	refMessages		= genMessages(true, "Reference run");
858		const MessageFilter			baseFilter		(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, vector<GLuint>(), true);
859		const deUint32				baseSeed		= deStringHash(getName()) ^ m_testCtx.getCommandLine().getBaseSeed();
860		const vector<MessageFilter>	filters			= genFilters(refMessages, vector<MessageFilter>(1, baseFilter), baseSeed, 4);
861		vector<MessageData>			filteredMessages;
862
863		applyFilters(filters);
864
865		// Generate errors
866		filteredMessages = genMessages(false, "Filtered run");
867
868		// Verify
869		verify(refMessages, filteredMessages, filters);
870
871		if (!isDebugContext() && refMessages.empty())
872			m_results.addResult(QP_TEST_RESULT_QUALITY_WARNING, "Verification accuracy is lacking without a debug context");
873	}
874
875	gl.disable(GL_DEBUG_OUTPUT);
876	m_results.setTestContextResult(m_testCtx);
877
878	return STOP;
879}
880
881void FilterCase::expectMessage (GLenum source, GLenum type)
882{
883	DE_UNREF(source);
884	DE_UNREF(type);
885}
886
887void FilterCase::callback (GLenum source, GLenum type, GLuint id, GLenum severity, const string& message)
888{
889	if (m_currentErrors)
890		m_currentErrors->push_back(MessageData(MessageID(source, type, id), severity, message));
891}
892
893vector<MessageData> FilterCase::genMessages (bool uselog, const string& desc)
894{
895	tcu::TestLog&			log			= m_testCtx.getLog();
896	NegativeTestContext		context		= NegativeTestContext(*this, m_context.getRenderContext(), m_context.getContextInfo(), log, m_results, uselog);
897	tcu::ScopedLogSection	section		(log, "message gen", desc);
898	vector<MessageData>		messages;
899
900	m_currentErrors = &messages;
901
902	for (int ndx = 0; ndx < int(m_errorFuncs.size()); ndx++)
903		m_errorFuncs[ndx](context);
904
905	m_currentErrors = DE_NULL;
906
907	return messages;
908}
909
910vector<FilterCase::MessageFilter> FilterCase::genFilters (const vector<MessageData>& messages, const vector<MessageFilter>& initial, deUint32 seed, int iterations) const
911{
912	de::Random				rng				(seed ^ deInt32Hash(deStringHash(getName())));
913
914	set<MessageID>			tempMessageIds;
915	set<GLenum>				tempSources;
916	set<GLenum>				tempTypes;
917	set<GLenum>				tempSeverities;
918
919	if (messages.empty())
920		return initial;
921
922	for (int ndx = 0; ndx < int(messages.size()); ndx++)
923	{
924		const MessageData& msg = messages[ndx];
925
926		tempMessageIds.insert(msg.id);
927		tempSources.insert(msg.id.source);
928		tempTypes.insert(msg.id.type);
929		tempSeverities.insert(msg.severity);
930	}
931
932	{
933		// Fetchable by index
934		const vector<MessageID> messageIds	(tempMessageIds.begin(), tempMessageIds.end());
935		const vector<GLenum>	sources		(tempSources.begin(), tempSources.end());
936		const vector<GLenum>	types		(tempTypes.begin(), tempTypes.end());
937		const vector<GLenum>	severities	(tempSeverities.begin(), tempSeverities.end());
938
939		vector<MessageFilter>	filters		= initial;
940
941		for (int iteration = 0; iteration < iterations; iteration++)
942		{
943			switch(rng.getInt(0, 8)) // Distribute so that per-message randomization (the default branch) is prevalent
944			{
945				case 0:
946				{
947					const GLenum	source	= sources[rng.getInt(0, int(sources.size()-1))];
948					const bool		enabled	= rng.getBool();
949
950					filters.push_back(MessageFilter(source, GL_DONT_CARE, GL_DONT_CARE, vector<GLuint>(), enabled));
951					break;
952				}
953
954				case 1:
955				{
956					const GLenum	type	= types[rng.getUint32()%types.size()];
957					const bool		enabled	= rng.getBool();
958
959					filters.push_back(MessageFilter(GL_DONT_CARE, type, GL_DONT_CARE, vector<GLuint>(), enabled));
960					break;
961				}
962
963				case 2:
964				{
965					const GLenum	severity	= severities[rng.getUint32()%severities.size()];
966					const bool		enabled		= rng.getBool();
967
968					filters.push_back(MessageFilter(GL_DONT_CARE, GL_DONT_CARE, severity, vector<GLuint>(), enabled));
969					break;
970				}
971
972				default:
973				{
974					const int start = rng.getInt(0, int(messageIds.size()));
975
976					for (int itr = 0; itr < 4; itr++)
977					{
978						const MessageID&	id		= messageIds[(start+itr)%messageIds.size()];
979						const bool			enabled = rng.getBool();
980
981						filters.push_back(MessageFilter(id.source, id.type, GL_DONT_CARE, vector<GLuint>(1, id.id), enabled));
982					}
983				}
984			}
985		}
986
987		return filters;
988	}
989}
990
991void FilterCase::applyFilters (const vector<MessageFilter>& filters) const
992{
993	TestLog&					log		= m_testCtx.getLog();
994	const tcu::ScopedLogSection	section	(log, "", "Setting message filters");
995	const glw::Functions&		gl		= m_context.getRenderContext().getFunctions();
996
997	for (size_t filterNdx = 0; filterNdx < filters.size(); filterNdx++)
998	{
999		const MessageFilter& filter = filters[filterNdx];
1000
1001		if (filter.ids.empty())
1002			log << TestLog::Message << "Setting messages with"
1003				<< " source " << glu::getDebugMessageSourceStr(filter.source)
1004				<< ", type " << glu::getDebugMessageTypeStr(filter.type)
1005				<< " and severity " << glu::getDebugMessageSeverityStr(filter.severity)
1006				<< (filter.enabled ? " to enabled" : " to disabled")
1007				<< TestLog::EndMessage;
1008		else
1009		{
1010			for (size_t ndx = 0; ndx < filter.ids.size(); ndx++)
1011				log << TestLog::Message << "Setting message (" << MessageID(filter.source, filter.type, filter.ids[ndx]) << ") to " << (filter.enabled ? "enabled" : "disabled") << TestLog::EndMessage;
1012		}
1013
1014		gl.debugMessageControl(filter.source, filter.type, filter.severity, GLsizei(filter.ids.size()), filter.ids.empty() ? DE_NULL : &filter.ids[0], filter.enabled);
1015	}
1016}
1017
1018bool FilterCase::isEnabled (const vector<MessageFilter>& filters, const MessageData& message) const
1019{
1020	bool retval = true;
1021
1022	for (size_t filterNdx = 0; filterNdx < filters.size(); filterNdx++)
1023	{
1024		const MessageFilter&	filter	= filters[filterNdx];
1025
1026		if (filter.ids.empty())
1027		{
1028			if (filter.source != GL_DONT_CARE && filter.source != message.id.source)
1029				continue;
1030
1031			if (filter.type != GL_DONT_CARE && filter.type != message.id.type)
1032				continue;
1033
1034			if (filter.severity != GL_DONT_CARE && filter.severity != message.severity)
1035				continue;
1036		}
1037		else
1038		{
1039			DE_ASSERT(filter.source != GL_DONT_CARE);
1040			DE_ASSERT(filter.type != GL_DONT_CARE);
1041			DE_ASSERT(filter.severity == GL_DONT_CARE);
1042
1043			if (filter.source != message.id.source || filter.type != message.id.type)
1044				continue;
1045
1046			if (!de::contains(filter.ids.begin(), filter.ids.end(), message.id.id))
1047				continue;
1048		}
1049
1050		retval = filter.enabled;
1051	}
1052
1053	return retval;
1054}
1055
1056struct MessageMeta
1057{
1058	int		refCount;
1059	int		resCount;
1060	GLenum	severity;
1061
1062	MessageMeta (void) : refCount(0), resCount(0), severity(GL_NONE) {}
1063};
1064
1065void FilterCase::verify (const vector<MessageData>& refMessages, const vector<MessageData>& resMessages, const vector<MessageFilter>& filters)
1066{
1067	TestLog&						log		= m_testCtx.getLog();
1068	map<MessageID, MessageMeta>		counts;
1069
1070	log << TestLog::Section("verification", "Verifying");
1071
1072	// Gather message counts & severities, report severity mismatches if found
1073	for (size_t refNdx = 0; refNdx < refMessages.size(); refNdx++)
1074	{
1075		const MessageData&	msg  = refMessages[refNdx];
1076		MessageMeta&		meta = counts[msg.id];
1077
1078		if (meta.severity != GL_NONE && meta.severity != msg.severity)
1079		{
1080			log << TestLog::Message << "A message has variable severity between instances: (" << msg.id << ") with severity "
1081				<< glu::getDebugMessageSeverityStr(meta.severity) << " and " << glu::getDebugMessageSeverityStr(msg.severity) << TestLog::EndMessage;
1082			m_results.addResult(QP_TEST_RESULT_FAIL, "Message severity changed between instances of the same message");
1083		}
1084
1085		meta.refCount++;
1086		meta.severity = msg.severity;
1087	}
1088
1089	for (size_t resNdx = 0; resNdx < resMessages.size(); resNdx++)
1090	{
1091		const MessageData&	msg  = resMessages[resNdx];
1092		MessageMeta&		meta = counts[msg.id];
1093
1094		if (meta.severity != GL_NONE && meta.severity != msg.severity)
1095		{
1096			log << TestLog::Message << "A message has variable severity between instances: (" << msg.id << ") with severity "
1097				<< glu::getDebugMessageSeverityStr(meta.severity) << " and " << glu::getDebugMessageSeverityStr(msg.severity) << TestLog::EndMessage;
1098			m_results.addResult(QP_TEST_RESULT_FAIL, "Message severity changed between instances of the same message");
1099		}
1100
1101		meta.resCount++;
1102		meta.severity = msg.severity;
1103	}
1104
1105	for (map<MessageID, MessageMeta>::const_iterator itr = counts.begin(); itr != counts.end(); itr++)
1106	{
1107		const MessageID&	id			= itr->first;
1108		const GLenum		severity	= itr->second.severity;
1109
1110		const int			refCount	= itr->second.refCount;
1111		const int			resCount	= itr->second.resCount;
1112		const bool			enabled		= isEnabled(filters, MessageData(id, severity, ""));
1113
1114		VerificationResult	result		= verifyMessageCount(id, severity, refCount, resCount, enabled);
1115
1116		log << TestLog::Message << result.logMessage << TestLog::EndMessage;
1117
1118		if (result.result != QP_TEST_RESULT_PASS)
1119			m_results.addResult(result.result, result.resultMessage);
1120	}
1121
1122	log << TestLog::EndSection;
1123}
1124
1125// Filter case that uses debug groups
1126class GroupFilterCase : public FilterCase
1127{
1128public:
1129							GroupFilterCase		(Context&				ctx,
1130												 const char*			name,
1131												 const char*			desc,
1132												 const vector<TestFunc>	errorFuncs);
1133	virtual 				~GroupFilterCase	(void) {}
1134
1135	virtual IterateResult	iterate				(void);
1136};
1137
1138GroupFilterCase::GroupFilterCase (Context&					ctx,
1139								  const char*				name,
1140								  const char*				desc,
1141								  const vector<TestFunc>	errorFuncs)
1142	: FilterCase(ctx, name, desc, errorFuncs)
1143{
1144}
1145
1146template<typename T>
1147vector<T> join(const vector<T>& a, const vector<T>&b)
1148{
1149	vector<T> retval;
1150
1151	retval.reserve(a.size()+b.size());
1152	retval.insert(retval.end(), a.begin(), a.end());
1153	retval.insert(retval.end(), b.begin(), b.end());
1154	return retval;
1155}
1156
1157GroupFilterCase::IterateResult GroupFilterCase::iterate (void)
1158{
1159	TCU_CHECK_AND_THROW(NotSupportedError, m_context.getContextInfo().isExtensionSupported("GL_KHR_debug"), "GL_KHR_debug is not supported");
1160
1161	const glw::Functions&	gl			= m_context.getRenderContext().getFunctions();
1162	tcu::TestLog&			log			= m_testCtx.getLog();
1163
1164	gl.enable(GL_DEBUG_OUTPUT);
1165	gl.enable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
1166	gl.debugMessageCallback(callbackHandle, this);
1167	gl.debugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, DE_NULL, true);
1168
1169	{
1170
1171		// Generate reference (all errors)
1172		const vector<MessageData>	refMessages	 = genMessages(true, "Reference run");
1173		const deUint32				baseSeed	 = deStringHash(getName()) ^ m_testCtx.getCommandLine().getBaseSeed();
1174		const MessageFilter			baseFilter	 (GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, vector<GLuint>(), true);
1175		const vector<MessageFilter>	filter0		 = genFilters(refMessages, vector<MessageFilter>(1, baseFilter), baseSeed, 4);
1176		vector<MessageData>			resMessages0;
1177
1178		applyFilters(filter0);
1179
1180		resMessages0 = genMessages(false, "Filtered run, default debug group");
1181
1182		// Initial verification
1183		verify(refMessages, resMessages0, filter0);
1184
1185		{
1186			// Generate reference (filters inherited from parent)
1187			const vector<MessageFilter> filter1base		= genFilters(refMessages, vector<MessageFilter>(), baseSeed ^ 0xDEADBEEF, 4);
1188			const vector<MessageFilter>	filter1full		= join(filter0, filter1base);
1189			tcu::ScopedLogSection		section1		(log, "", "Pushing Debug Group");
1190			vector<MessageData>			resMessages1;
1191
1192			gl.pushDebugGroup(GL_DEBUG_SOURCE_APPLICATION, 1, -1, "Test Group");
1193			applyFilters(filter1base);
1194
1195			// First nested verification
1196			resMessages1 = genMessages(false, "Filtered run, pushed one debug group");
1197			verify(refMessages, resMessages1, filter1full);
1198
1199			{
1200				// Generate reference (filters iherited again)
1201				const vector<MessageFilter>	filter2base		= genFilters(refMessages, vector<MessageFilter>(), baseSeed ^ 0x43211234, 4);
1202				const vector<MessageFilter>	filter2full		= join(filter1full, filter2base);
1203				tcu::ScopedLogSection		section2		(log, "", "Pushing Debug Group");
1204				vector<MessageData>			resMessages2;
1205
1206				gl.pushDebugGroup(GL_DEBUG_SOURCE_APPLICATION, 1, -1, "Nested Test Group");
1207				applyFilters(filter2base);
1208
1209				// Second nested verification
1210				resMessages2 = genMessages(false, "Filtered run, pushed two debug groups");
1211				verify(refMessages, resMessages2, filter2full);
1212
1213				gl.popDebugGroup();
1214			}
1215
1216			// First restore verification
1217			resMessages1 = genMessages(false, "Filtered run, popped second debug group");
1218			verify(refMessages, resMessages1, filter1full);
1219
1220			gl.popDebugGroup();
1221		}
1222
1223		// restore verification
1224		resMessages0 = genMessages(false, "Filtered run, popped first debug group");
1225		verify(refMessages, resMessages0, filter0);
1226
1227		if (!isDebugContext() && refMessages.empty())
1228			m_results.addResult(QP_TEST_RESULT_QUALITY_WARNING, "Verification accuracy is lacking without a debug context");
1229	}
1230
1231	gl.disable(GL_DEBUG_OUTPUT);
1232	m_results.setTestContextResult(m_testCtx);
1233	return STOP;
1234}
1235
1236// Basic grouping functionality
1237class GroupCase : public BaseCase
1238{
1239public:
1240							GroupCase	(Context&				ctx,
1241										 const char*			name,
1242										 const char*			desc);
1243	virtual					~GroupCase	() {}
1244
1245	virtual IterateResult	iterate		(void);
1246
1247private:
1248	virtual void			callback	(GLenum source, GLenum type, GLuint id, GLenum severity, const string& message);
1249
1250	MessageData				m_lastMessage;
1251};
1252
1253GroupCase::GroupCase (Context&				ctx,
1254					  const char*			name,
1255					  const char*			desc)
1256	: BaseCase(ctx, name, desc)
1257{
1258}
1259
1260GroupCase::IterateResult GroupCase::iterate (void)
1261{
1262	TCU_CHECK_AND_THROW(NotSupportedError, m_context.getContextInfo().isExtensionSupported("GL_KHR_debug"), "GL_KHR_debug is not supported");
1263
1264	const glw::Functions&	gl		= m_context.getRenderContext().getFunctions();
1265	tcu::TestLog&			log		= m_testCtx.getLog();
1266	glu::CallLogWrapper		wrapper	(gl, log);
1267
1268	gl.enable(GL_DEBUG_OUTPUT);
1269	gl.enable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
1270	gl.debugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, DE_NULL, false); // disable all
1271	gl.debugMessageControl(GL_DEBUG_SOURCE_API, GL_DEBUG_TYPE_ERROR, GL_DONT_CARE, 0, DE_NULL, true); // enable API errors
1272	gl.debugMessageControl(GL_DEBUG_SOURCE_APPLICATION, GL_DONT_CARE, GL_DONT_CARE, 0, DE_NULL, true); // enable application messages
1273	gl.debugMessageControl(GL_DEBUG_SOURCE_THIRD_PARTY, GL_DONT_CARE, GL_DONT_CARE, 0, DE_NULL, true); // enable third party messages
1274	gl.debugMessageCallback(callbackHandle, this);
1275
1276	wrapper.enableLogging(true);
1277	wrapper.glPushDebugGroup(GL_DEBUG_SOURCE_APPLICATION, 1234, -1, "Pushed debug stack");
1278	verifyMessage(m_lastMessage, GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_PUSH_GROUP, 1234, GL_DEBUG_SEVERITY_NOTIFICATION);
1279	wrapper.glPopDebugGroup();
1280	verifyMessage(m_lastMessage, GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_POP_GROUP, 1234, GL_DEBUG_SEVERITY_NOTIFICATION);
1281
1282	wrapper.glPushDebugGroup(GL_DEBUG_SOURCE_THIRD_PARTY, 4231, -1, "Pushed debug stack");
1283	verifyMessage(m_lastMessage, GL_DEBUG_SOURCE_THIRD_PARTY, GL_DEBUG_TYPE_PUSH_GROUP, 4231, GL_DEBUG_SEVERITY_NOTIFICATION);
1284	wrapper.glPopDebugGroup();
1285	verifyMessage(m_lastMessage, GL_DEBUG_SOURCE_THIRD_PARTY, GL_DEBUG_TYPE_POP_GROUP, 4231, GL_DEBUG_SEVERITY_NOTIFICATION);
1286
1287	gl.debugMessageCallback(DE_NULL, DE_NULL);
1288	gl.disable(GL_DEBUG_OUTPUT);
1289
1290	m_results.setTestContextResult(m_testCtx);
1291
1292	return STOP;
1293}
1294
1295void GroupCase::callback (GLenum source, GLenum type, GLuint id, GLenum severity, const string& message)
1296{
1297	m_lastMessage = MessageData(MessageID(source, type, id), severity, message);
1298}
1299
1300// Asynchronous debug output
1301class AsyncCase : public BaseCase
1302{
1303public:
1304							AsyncCase			(Context&				ctx,
1305												 const char*			name,
1306												 const char*			desc,
1307												 const vector<TestFunc>	errorFuncs,
1308												 bool					useCallbacks);
1309	virtual					~AsyncCase			() {}
1310
1311	virtual IterateResult	iterate				(void);
1312
1313	virtual void			expectMessage		(glw::GLenum source, glw::GLenum type);
1314
1315private:
1316	struct MessageCount
1317	{
1318		int received;
1319		int expected;
1320
1321		MessageCount(void) : received(0), expected(0) {}
1322	};
1323	typedef map<MessageID, MessageCount> MessageCounter;
1324
1325	enum VerifyState
1326	{
1327		VERIFY_PASS = 0,
1328		VERIFY_MINIMUM,
1329		VERIFY_FAIL,
1330
1331		VERIFY_LAST
1332	};
1333
1334	virtual void			callback			(glw::GLenum source, glw::GLenum type, glw::GLuint id, glw::GLenum severity, const std::string& message);
1335	VerifyState				verify				(bool uselog);
1336	void					fetchLogMessages	(void);
1337
1338	const vector<TestFunc>	m_errorFuncs;
1339	const bool				m_useCallbacks;
1340
1341	MessageCounter			m_counts;
1342
1343	de::Mutex				m_mutex;
1344};
1345
1346AsyncCase::AsyncCase (Context&					ctx,
1347					  const char*				name,
1348					  const char*				desc,
1349					  const vector<TestFunc>	errorFuncs,
1350					  bool						useCallbacks)
1351	: BaseCase			(ctx, name, desc)
1352	, m_errorFuncs		(errorFuncs)
1353	, m_useCallbacks	(useCallbacks)
1354{
1355}
1356
1357AsyncCase::IterateResult AsyncCase::iterate (void)
1358{
1359	TCU_CHECK_AND_THROW(NotSupportedError, m_context.getContextInfo().isExtensionSupported("GL_KHR_debug"), "GL_KHR_debug is not supported");
1360
1361	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
1362	tcu::TestLog&		log			= m_testCtx.getLog();
1363	NegativeTestContext	context		= NegativeTestContext(*this, m_context.getRenderContext(), m_context.getContextInfo(), log, m_results, true);
1364	const int			maxWait		= 10000; // ms
1365	const int			warnWait	= 100;
1366
1367	gl.enable(GL_DEBUG_OUTPUT);
1368	gl.enable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
1369	gl.debugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, DE_NULL, false);
1370
1371	// Some messages could be dependent on the value of DEBUG_OUTPUT_SYNCHRONOUS so only use API errors which should be generated in all cases
1372	gl.debugMessageControl(GL_DEBUG_SOURCE_API, GL_DEBUG_TYPE_ERROR, GL_DONT_CARE, 0, DE_NULL, true);
1373
1374	if (m_useCallbacks) // will use log otherwise
1375		gl.debugMessageCallback(callbackHandle, this);
1376	else
1377		gl.debugMessageCallback(DE_NULL, DE_NULL);
1378
1379	// Reference run (synchoronous)
1380	{
1381		tcu::ScopedLogSection section(log, "reference run", "Reference run (synchronous)");
1382
1383		for (int ndx = 0; ndx < int(m_errorFuncs.size()); ndx++)
1384			m_errorFuncs[ndx](context);
1385	}
1386
1387	if (m_counts.empty())
1388	{
1389		if (!isDebugContext())
1390			m_results.addResult(QP_TEST_RESULT_QUALITY_WARNING, "Need debug context to guarantee implementation behaviour (see command line options)");
1391
1392		log << TestLog::Message << "Reference run produced no messages, nothing to verify" << TestLog::EndMessage;
1393
1394		gl.debugMessageCallback(DE_NULL, DE_NULL);
1395		gl.disable(GL_DEBUG_OUTPUT);
1396
1397		m_results.setTestContextResult(m_testCtx);
1398		return STOP;
1399	}
1400
1401	for (MessageCounter::iterator itr = m_counts.begin(); itr != m_counts.end(); itr++)
1402	{
1403		itr->second.expected = itr->second.received;
1404		itr->second.received = 0;
1405	}
1406
1407	gl.disable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
1408
1409	// Result run (async)
1410	for (int ndx = 0; ndx < int(m_errorFuncs.size()); ndx++)
1411		m_errorFuncs[ndx](context);
1412
1413	// Repatedly try verification, new results may be added to m_receivedMessages at any time
1414	{
1415		tcu::ScopedLogSection	section			(log, "result run", "Result run (asynchronous)");
1416		VerifyState				lastTimelyState = VERIFY_FAIL;
1417
1418		for (int waited = 0;;)
1419		{
1420			const VerifyState	pass = verify(false);
1421			const int			wait = de::max(50, waited>>2);
1422
1423			// Pass (possibly due to time limit)
1424			if (pass == VERIFY_PASS || (pass == VERIFY_MINIMUM && waited >= maxWait))
1425			{
1426				verify(true); // log
1427
1428				// State changed late
1429				if (waited >= warnWait && lastTimelyState != pass)
1430					m_results.addResult(QP_TEST_RESULT_QUALITY_WARNING, "Async messages were returned to application somewhat slowly");
1431
1432				log << TestLog::Message << "Passed after ~" << waited << "ms of waiting" << TestLog::EndMessage;
1433				break;
1434			}
1435			// fail
1436			else if (waited >= maxWait)
1437			{
1438				verify(true); // log
1439
1440				log << TestLog::Message << "Waited for ~" << waited << "ms without getting all expected messages" << TestLog::EndMessage;
1441				m_results.addResult(QP_TEST_RESULT_FAIL, "Async messages were not returned to application within a reasonable timeframe");
1442				break;
1443			}
1444
1445			if (waited < warnWait)
1446				lastTimelyState = pass;
1447
1448			deSleep(wait);
1449			waited += wait;
1450
1451			if (!m_useCallbacks)
1452				fetchLogMessages();
1453		}
1454	}
1455
1456	gl.debugMessageCallback(DE_NULL, DE_NULL);
1457
1458	gl.disable(GL_DEBUG_OUTPUT);
1459	m_results.setTestContextResult(m_testCtx);
1460
1461	return STOP;
1462}
1463
1464void AsyncCase::expectMessage (GLenum source, GLenum type)
1465{
1466	// Good time to clean up the queue as this should be called after most messages are generated
1467	if (!m_useCallbacks)
1468		fetchLogMessages();
1469
1470	DE_UNREF(source);
1471	DE_UNREF(type);
1472}
1473
1474void AsyncCase::callback (GLenum source, GLenum type, GLuint id, GLenum severity, const string& message)
1475{
1476	DE_ASSERT(m_useCallbacks);
1477	DE_UNREF(severity);
1478	DE_UNREF(message);
1479
1480	de::ScopedLock lock(m_mutex);
1481
1482	m_counts[MessageID(source, type, id)].received++;
1483}
1484
1485// 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
1486void AsyncCase::fetchLogMessages (void)
1487{
1488	const glw::Functions&	gl		= m_context.getRenderContext().getFunctions();
1489	GLint					numMsg	= 0;
1490
1491	gl.getIntegerv(GL_DEBUG_LOGGED_MESSAGES, &numMsg);
1492
1493	for(int msgNdx = 0; msgNdx < numMsg; msgNdx++)
1494	{
1495		int			msgLen = 0;
1496		MessageData msg;
1497
1498		gl.getIntegerv(GL_DEBUG_NEXT_LOGGED_MESSAGE_LENGTH, &msgLen);
1499
1500		TCU_CHECK_MSG(msgLen >= 0, "Negative message length");
1501		TCU_CHECK_MSG(msgLen < 100000, "Excessively long message");
1502
1503		msg.message.resize(msgLen);
1504		gl.getDebugMessageLog(1, msgLen, &msg.id.source, &msg.id.type, &msg.id.id, &msg.severity, &msgLen, &msg.message[0]);
1505
1506		{
1507			const de::ScopedLock lock(m_mutex); // Don't block during API call
1508
1509			m_counts[MessageID(msg.id)].received++;
1510		}
1511	}
1512}
1513
1514AsyncCase::VerifyState AsyncCase::verify (bool uselog)
1515{
1516	using std::map;
1517
1518	VerifyState			retval		= VERIFY_PASS;
1519	TestLog&			log			= m_testCtx.getLog();
1520
1521	const de::ScopedLock lock(m_mutex);
1522
1523	for (map<MessageID, MessageCount>::const_iterator itr = m_counts.begin(); itr != m_counts.end(); itr++)
1524	{
1525		const MessageID&	id			= itr->first;
1526
1527		const int			refCount	= itr->second.expected;
1528		const int			resCount	= itr->second.received;
1529		const bool			enabled		= true;
1530
1531		VerificationResult	result		= verifyMessageCount(id, GL_DONT_CARE, refCount, resCount, enabled);
1532
1533		if (uselog)
1534			log << TestLog::Message << result.logMessage << TestLog::EndMessage;
1535
1536		if (result.result == QP_TEST_RESULT_FAIL)
1537			retval = VERIFY_FAIL;
1538		else if (result.result != QP_TEST_RESULT_PASS && retval == VERIFY_PASS)
1539			retval = VERIFY_MINIMUM;
1540	}
1541
1542	return retval;
1543}
1544
1545// Tests debug labels
1546class LabelCase : public TestCase
1547{
1548public:
1549							LabelCase	(Context&				ctx,
1550										 const char*			name,
1551										 const char*			desc,
1552										 GLenum					identifier);
1553	virtual					~LabelCase	(void) {}
1554
1555	virtual IterateResult	iterate		(void);
1556
1557private:
1558	GLenum					m_identifier;
1559};
1560
1561LabelCase::LabelCase (Context&		ctx,
1562					  const char*			name,
1563					  const char*			desc,
1564					  GLenum				identifier)
1565	: TestCase		(ctx, name, desc)
1566	, m_identifier	(identifier)
1567{
1568}
1569
1570LabelCase::IterateResult LabelCase::iterate (void)
1571{
1572	TCU_CHECK_AND_THROW(NotSupportedError, m_context.getContextInfo().isExtensionSupported("GL_KHR_debug"), "GL_KHR_debug is not supported");
1573
1574	const glw::Functions&	gl			= m_context.getRenderContext().getFunctions();
1575	const char*	const		msg			= "This is a debug label";
1576	GLuint					object		= 0;
1577	char					buffer[64];
1578	int						outlen		= 0;
1579
1580	switch(m_identifier)
1581	{
1582		case GL_BUFFER:
1583			gl.genBuffers(1, &object);
1584			gl.bindBuffer(GL_ARRAY_BUFFER, object);
1585			gl.bindBuffer(GL_ARRAY_BUFFER, 0);
1586			break;
1587
1588		case GL_SHADER:
1589			object = gl.createShader(GL_FRAGMENT_SHADER);
1590			break;
1591
1592		case GL_PROGRAM:
1593			object = gl.createProgram();
1594			break;
1595
1596		case GL_QUERY:
1597			gl.genQueries(1, &object);
1598			gl.beginQuery(GL_ANY_SAMPLES_PASSED, object); // Create
1599			gl.endQuery(GL_ANY_SAMPLES_PASSED); // Cleanup
1600			break;
1601
1602		case GL_PROGRAM_PIPELINE:
1603			gl.genProgramPipelines(1, &object);
1604			gl.bindProgramPipeline(object); // Create
1605			gl.bindProgramPipeline(0); // Cleanup
1606			break;
1607
1608		case GL_TRANSFORM_FEEDBACK:
1609			gl.genTransformFeedbacks(1, &object);
1610			gl.bindTransformFeedback(GL_TRANSFORM_FEEDBACK, object);
1611			gl.bindTransformFeedback(GL_TRANSFORM_FEEDBACK, 0);
1612			break;
1613
1614		case GL_SAMPLER:
1615			gl.genSamplers(1, &object);
1616			gl.bindSampler(0, object);
1617			gl.bindSampler(0, 0);
1618			break;
1619
1620		case GL_TEXTURE:
1621			gl.genTextures(1, &object);
1622			gl.bindTexture(GL_TEXTURE_2D, object);
1623			gl.bindTexture(GL_TEXTURE_2D, 0);
1624			break;
1625
1626		case GL_RENDERBUFFER:
1627			gl.genRenderbuffers(1, &object);
1628			gl.bindRenderbuffer(GL_RENDERBUFFER, object);
1629			gl.bindRenderbuffer(GL_RENDERBUFFER, 0);
1630			break;
1631
1632		case GL_FRAMEBUFFER:
1633			gl.genFramebuffers(1, &object);
1634			gl.bindFramebuffer(GL_DRAW_FRAMEBUFFER, object);
1635			gl.bindFramebuffer(GL_DRAW_FRAMEBUFFER, m_context.getRenderContext().getDefaultFramebuffer());
1636			break;
1637
1638		default:
1639			DE_ASSERT(!"Invalid identifier");
1640	}
1641
1642	gl.objectLabel(m_identifier, object, -1, msg);
1643
1644	gl.getObjectLabel(m_identifier, object, sizeof(buffer), &outlen, buffer);
1645
1646	if (outlen == 0)
1647		m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Failed to query debug label from object");
1648	else if (deStringEqual(msg, buffer))
1649	{
1650		m_testCtx.getLog() << TestLog::Message << "Query returned string: \"" << buffer << "\"" << TestLog::EndMessage;
1651		m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
1652	}
1653	else
1654	{
1655		m_testCtx.getLog() << TestLog::Message << "Query returned wrong string: expected \"" << msg << "\" but got \"" << buffer << "\"" << TestLog::EndMessage;
1656		m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Query returned wrong label");
1657	}
1658
1659	switch(m_identifier)
1660	{
1661		case GL_BUFFER:				gl.deleteBuffers(1, &object);				break;
1662		case GL_SHADER:				gl.deleteShader(object);					break;
1663		case GL_PROGRAM:			gl.deleteProgram(object);					break;
1664		case GL_QUERY:				gl.deleteQueries(1, &object);				break;
1665		case GL_PROGRAM_PIPELINE:	gl.deleteProgramPipelines(1, &object);		break;
1666		case GL_TRANSFORM_FEEDBACK:	gl.deleteTransformFeedbacks(1, &object);	break;
1667		case GL_SAMPLER:			gl.deleteSamplers(1, &object);				break;
1668		case GL_TEXTURE:			gl.deleteTextures(1, &object);				break;
1669		case GL_RENDERBUFFER:		gl.deleteRenderbuffers(1, &object);			break;
1670		case GL_FRAMEBUFFER:		gl.deleteFramebuffers(1, &object);			break;
1671
1672		default:
1673			DE_ASSERT(!"Invalid identifier");
1674	}
1675
1676	return STOP;
1677}
1678
1679} // Anonymous
1680
1681DebugTests::DebugTests (Context& context)
1682	: TestCaseGroup(context, "debug", "Debug tests")
1683{
1684}
1685
1686enum CaseType
1687{
1688	CASETYPE_CALLBACK = 0,
1689	CASETYPE_LOG,
1690	CASETYPE_GETERROR,
1691
1692	CASETYPE_LAST
1693};
1694
1695tcu::TestNode* createCase (CaseType type, Context& ctx, const char* name, const char* desc, TestFunc function)
1696{
1697	switch(type)
1698	{
1699		case CASETYPE_CALLBACK: return new CallbackErrorCase(ctx, name, desc, function);
1700		case CASETYPE_LOG:		return new LogErrorCase(ctx, name, desc, function);
1701		case CASETYPE_GETERROR: return new GetErrorCase(ctx, name, desc, function);
1702
1703		default:
1704			DE_ASSERT(!"Invalid type");
1705	}
1706
1707	return DE_NULL;
1708}
1709
1710tcu::TestCaseGroup* createChildCases (CaseType type, Context& ctx, const char* name, const char* desc, const vector<FunctionContainer>& funcs)
1711{
1712	tcu::TestCaseGroup* host = new tcu::TestCaseGroup(ctx.getTestContext(), name, desc);
1713
1714	for (size_t ndx = 0; ndx < funcs.size(); ndx++)
1715			host->addChild(createCase(type, ctx, funcs[ndx].name, funcs[ndx].desc, funcs[ndx].function));
1716
1717	return host;
1718}
1719
1720void DebugTests::init (void)
1721{
1722	const vector<FunctionContainer> bufferFuncs		= NegativeTestShared::getNegativeBufferApiTestFunctions();
1723	const vector<FunctionContainer> textureFuncs	= NegativeTestShared::getNegativeTextureApiTestFunctions();
1724	const vector<FunctionContainer> shaderFuncs		= NegativeTestShared::getNegativeShaderApiTestFunctions();
1725	const vector<FunctionContainer> fragmentFuncs	= NegativeTestShared::getNegativeFragmentApiTestFunctions();
1726	const vector<FunctionContainer> vaFuncs			= NegativeTestShared::getNegativeVertexArrayApiTestFunctions();
1727	const vector<FunctionContainer> stateFuncs		= NegativeTestShared::getNegativeStateApiTestFunctions();
1728	const vector<FunctionContainer> externalFuncs	= getUserMessageFuncs();
1729
1730	{
1731		tcu::TestCaseGroup* const	negative	= new tcu::TestCaseGroup(m_testCtx, "negative_coverage", "API error coverage with various reporting methods");
1732
1733		addChild(negative);
1734
1735		{
1736			tcu::TestCaseGroup* const	host	= new tcu::TestCaseGroup(m_testCtx, "callbacks", "Reporting of standard API errors via callback");
1737
1738			negative->addChild(host);
1739			host->addChild(createChildCases(CASETYPE_CALLBACK, m_context, "buffer",			"Negative Buffer API Cases",		bufferFuncs));
1740			host->addChild(createChildCases(CASETYPE_CALLBACK, m_context, "texture",		"Negative Texture API Cases",		textureFuncs));
1741			host->addChild(createChildCases(CASETYPE_CALLBACK, m_context, "shader",			"Negative Shader API Cases",		shaderFuncs));
1742			host->addChild(createChildCases(CASETYPE_CALLBACK, m_context, "fragment",		"Negative Fragment API Cases",		fragmentFuncs));
1743			host->addChild(createChildCases(CASETYPE_CALLBACK, m_context, "vertex_array",	"Negative Vertex Array API Cases",	vaFuncs));
1744			host->addChild(createChildCases(CASETYPE_CALLBACK, m_context, "state",			"Negative GL State API Cases",		stateFuncs));
1745		}
1746
1747		{
1748			tcu::TestCaseGroup* const	host	= new tcu::TestCaseGroup(m_testCtx, "log", "Reporting of standard API errors via log");
1749
1750			negative->addChild(host);
1751
1752			host->addChild(createChildCases(CASETYPE_LOG, m_context, "buffer",				"Negative Buffer API Cases",		bufferFuncs));
1753			host->addChild(createChildCases(CASETYPE_LOG, m_context, "texture",				"Negative Texture API Cases",		textureFuncs));
1754			host->addChild(createChildCases(CASETYPE_LOG, m_context, "shader",				"Negative Shader API Cases",		shaderFuncs));
1755			host->addChild(createChildCases(CASETYPE_LOG, m_context, "fragment",			"Negative Fragment API Cases",		fragmentFuncs));
1756			host->addChild(createChildCases(CASETYPE_LOG, m_context, "vertex_array",		"Negative Vertex Array API Cases",	vaFuncs));
1757			host->addChild(createChildCases(CASETYPE_LOG, m_context, "state",				"Negative GL State API Cases",		stateFuncs));
1758		}
1759
1760		{
1761			tcu::TestCaseGroup* const	host	= new tcu::TestCaseGroup(m_testCtx, "get_error", "Reporting of standard API errors via glGetError");
1762
1763			negative->addChild(host);
1764
1765			host->addChild(createChildCases(CASETYPE_GETERROR, m_context, "buffer",			"Negative Buffer API Cases",		bufferFuncs));
1766			host->addChild(createChildCases(CASETYPE_GETERROR, m_context, "texture",		"Negative Texture API Cases",		textureFuncs));
1767			host->addChild(createChildCases(CASETYPE_GETERROR, m_context, "shader",			"Negative Shader API Cases",		shaderFuncs));
1768			host->addChild(createChildCases(CASETYPE_GETERROR, m_context, "fragment",		"Negative Fragment API Cases",		fragmentFuncs));
1769			host->addChild(createChildCases(CASETYPE_GETERROR, m_context, "vertex_array",	"Negative Vertex Array API Cases",	vaFuncs));
1770			host->addChild(createChildCases(CASETYPE_GETERROR, m_context, "state",			"Negative GL State API Cases",		stateFuncs));
1771		}
1772	}
1773
1774	{
1775		tcu::TestCaseGroup*			host	= createChildCases(CASETYPE_CALLBACK, m_context, "externally_generated", "Externally Generated Messages", externalFuncs);
1776
1777		host->addChild(new GroupCase(m_context, "push_pop_consistency", "Push/pop message generation with full message output checking"));
1778
1779		addChild(host);
1780	}
1781
1782	{
1783		vector<FunctionContainer>	containers;
1784		vector<TestFunc>			allFuncs;
1785
1786		de::Random					rng			(0x53941903 ^ m_context.getTestContext().getCommandLine().getBaseSeed());
1787
1788		containers.insert(containers.end(), bufferFuncs.begin(), bufferFuncs.end());
1789		containers.insert(containers.end(), textureFuncs.begin(), textureFuncs.end());
1790		containers.insert(containers.end(), externalFuncs.begin(), externalFuncs.end());
1791
1792		for (size_t ndx = 0; ndx < containers.size(); ndx++)
1793			allFuncs.push_back(containers[ndx].function);
1794
1795		rng.shuffle(allFuncs.begin(), allFuncs.end());
1796
1797		{
1798			tcu::TestCaseGroup* const	filtering				= new tcu::TestCaseGroup(m_testCtx, "error_filters", "Filtering of reported errors");
1799			const int					errorFuncsPerCase		= 4;
1800			const int					maxFilteringCaseCount	= 32;
1801			const int					caseCount				= (int(allFuncs.size()) + errorFuncsPerCase-1) / errorFuncsPerCase;
1802
1803			addChild(filtering);
1804
1805			for (int caseNdx = 0; caseNdx < de::min(caseCount, maxFilteringCaseCount); caseNdx++)
1806			{
1807				const int			start		= caseNdx*errorFuncsPerCase;
1808				const int			end			= de::min((caseNdx+1)*errorFuncsPerCase, int(allFuncs.size()));
1809				const string		name		= "case_" + de::toString(caseNdx);
1810				vector<TestFunc>	funcs		(allFuncs.begin()+start, allFuncs.begin()+end);
1811
1812				// These produce lots of different message types, thus always include at least one when testing filtering
1813				funcs.insert(funcs.end(), externalFuncs[caseNdx%externalFuncs.size()].function);
1814
1815				filtering->addChild(new FilterCase(m_context, name.c_str(), "DebugMessageControl usage", funcs));
1816			}
1817		}
1818
1819		{
1820			tcu::TestCaseGroup* const	groups					= new tcu::TestCaseGroup(m_testCtx, "error_groups", "Filtering of reported errors with use of Error Groups");
1821			const int					errorFuncsPerCase		= 4;
1822			const int					maxFilteringCaseCount	= 16;
1823			const int					caseCount				= (int(allFuncs.size()) + errorFuncsPerCase-1) / errorFuncsPerCase;
1824
1825			addChild(groups);
1826
1827			for (int caseNdx = 0; caseNdx < caseCount && caseNdx < maxFilteringCaseCount; caseNdx++)
1828			{
1829				const int			start		= caseNdx*errorFuncsPerCase;
1830				const int			end			= de::min((caseNdx+1)*errorFuncsPerCase, int(allFuncs.size()));
1831				const string		name		= ("case_" + de::toString(caseNdx)).c_str();
1832				vector<TestFunc>	funcs		(&allFuncs[0]+start, &allFuncs[0]+end);
1833
1834				// These produce lots of different message types, thus always include at least one when testing filtering
1835				funcs.insert(funcs.end(), externalFuncs[caseNdx%externalFuncs.size()].function);
1836
1837				groups->addChild(new GroupFilterCase(m_context, name.c_str(), "Debug Group usage", funcs));
1838			}
1839		}
1840
1841		{
1842			tcu::TestCaseGroup* const	async				= new tcu::TestCaseGroup(m_testCtx, "async", "Asynchronous message generation");
1843			const int					errorFuncsPerCase	= 2;
1844			const int					maxAsyncCaseCount	= 16;
1845			const int					caseCount			= (int(allFuncs.size()) + errorFuncsPerCase-1) / errorFuncsPerCase;
1846
1847			addChild(async);
1848
1849			for (int caseNdx = 0; caseNdx < caseCount && caseNdx < maxAsyncCaseCount; caseNdx++)
1850			{
1851				const int			start		= caseNdx*errorFuncsPerCase;
1852				const int			end			= de::min((caseNdx+1)*errorFuncsPerCase, int(allFuncs.size()));
1853				const string		name		= ("case_" + de::toString(caseNdx)).c_str();
1854				vector<TestFunc>	funcs		(&allFuncs[0]+start, &allFuncs[0]+end);
1855
1856				if (caseNdx&0x1)
1857					async->addChild(new AsyncCase(m_context, (name+"_callback").c_str(), "Async message generation", funcs, true));
1858				else
1859					async->addChild(new AsyncCase(m_context, (name+"_log").c_str(), "Async message generation", funcs, false));
1860			}
1861		}
1862	}
1863
1864	{
1865		tcu::TestCaseGroup* const labels = new tcu::TestCaseGroup(m_testCtx, "object_labels", "Labeling objects");
1866
1867		const struct
1868		{
1869			GLenum		identifier;
1870			const char*	name;
1871			const char* desc;
1872		} cases[] =
1873		{
1874			{ GL_BUFFER,				"buffer",				"Debug label on a buffer object"				},
1875			{ GL_SHADER,				"shader",				"Debug label on a shader object"				},
1876			{ GL_PROGRAM,				"program",				"Debug label on a program object"				},
1877			{ GL_QUERY,					"query",				"Debug label on a query object"					},
1878			{ GL_PROGRAM_PIPELINE,		"program_pipeline",		"Debug label on a program pipeline object"		},
1879			{ GL_TRANSFORM_FEEDBACK,	"transform_feedback",	"Debug label on a transform feedback object"	},
1880			{ GL_SAMPLER,				"sampler",				"Debug label on a sampler object"				},
1881			{ GL_TEXTURE,				"texture",				"Debug label on a texture object"				},
1882			{ GL_RENDERBUFFER,			"renderbuffer",			"Debug label on a renderbuffer object"			},
1883			{ GL_FRAMEBUFFER,			"framebuffer",			"Debug label on a framebuffer object"			},
1884		};
1885
1886		addChild(labels);
1887
1888		for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(cases); ndx++)
1889			labels->addChild(new LabelCase(m_context, cases[ndx].name, cases[ndx].desc, cases[ndx].identifier));
1890	}
1891}
1892
1893} // Functional
1894} // gles31
1895} // deqp
1896