es31fDebugTests.cpp revision 3c827367444ee418f129b2c238299f49d3264554
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(), 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
604void CallbackErrorCase::callback (GLenum source, GLenum type, GLuint id, GLenum severity, const string& message)
605{
606	m_lastMessage = MessageData(MessageID(source, type, id), severity, message);
607}
608
609// Generate errors, verify that each error results in a log entry
610class LogErrorCase : public BaseCase
611{
612public:
613							LogErrorCase	(Context&				context,
614											 const char*			name,
615											 const char*			desc,
616											 TestFunc				errorFunc);
617	virtual 				~LogErrorCase	(void) {}
618
619	virtual IterateResult	iterate			(void);
620
621	virtual void			expectMessage	(GLenum source, GLenum type);
622
623private:
624	const TestFunc			m_errorFunc;
625	MessageData				m_lastMessage;
626};
627
628LogErrorCase::LogErrorCase (Context&	ctx,
629							const char*	name,
630							const char*	desc,
631							TestFunc	errorFunc)
632	: BaseCase		(ctx, name, desc)
633	, m_errorFunc	(errorFunc)
634{
635}
636
637LogErrorCase::IterateResult LogErrorCase::iterate (void)
638{
639	TCU_CHECK_AND_THROW(NotSupportedError, m_context.getContextInfo().isExtensionSupported("GL_KHR_debug"), "GL_KHR_debug is not supported");
640
641	const glw::Functions&	gl		= m_context.getRenderContext().getFunctions();
642	tcu::TestLog&			log		= m_testCtx.getLog();
643	NegativeTestContext		context	= NegativeTestContext(*this, m_context.getRenderContext(), log, m_results, true);
644	GLint					numMsg	= 0;
645
646	gl.enable(GL_DEBUG_OUTPUT);
647	gl.enable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
648	gl.debugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, DE_NULL, false); // disable all
649	gl.debugMessageControl(GL_DEBUG_SOURCE_API, GL_DEBUG_TYPE_ERROR, GL_DONT_CARE, 0, DE_NULL, true); // enable API errors
650	gl.debugMessageCallback(DE_NULL, DE_NULL); // enable logging
651	gl.getIntegerv(GL_DEBUG_LOGGED_MESSAGES, &numMsg);
652	gl.getDebugMessageLog(numMsg, 0, DE_NULL, DE_NULL, DE_NULL, DE_NULL, DE_NULL, DE_NULL); // clear log
653
654	m_errorFunc(context);
655
656	gl.disable(GL_DEBUG_OUTPUT);
657	m_results.setTestContextResult(m_testCtx);
658
659	return STOP;
660}
661
662void LogErrorCase::expectMessage (GLenum source, GLenum type)
663{
664	const glw::Functions&	gl			= m_context.getRenderContext().getFunctions();
665	int						numMsg		= 0;
666	TestLog&				log			= m_testCtx.getLog();
667	MessageData				lastMsg;
668
669	if (source == GL_DONT_CARE || type == GL_DONT_CARE)
670		return;
671
672	gl.getIntegerv(GL_DEBUG_LOGGED_MESSAGES, &numMsg);
673
674	if (numMsg == 0)
675	{
676		if (isDebugContext())
677		{
678			m_results.addResult(QP_TEST_RESULT_FAIL, "Error was not reported as expected");
679			log << TestLog::Message << "A message was expected but none was reported (empty message log)" << TestLog::EndMessage;
680		}
681		else
682		{
683			m_results.addResult(QP_TEST_RESULT_QUALITY_WARNING, "Verification accuracy is lacking without a debug context");
684			log << TestLog::Message << "A message was expected but none was reported (empty message log). Running without a debug context" << TestLog::EndMessage;
685		}
686		return;
687	}
688
689	// There may be messages other than the error we are looking for in the log.
690	// Strictly nothing prevents the implementation from producing more than the
691	// required error from an API call with a defined error. however we assume that
692	// since calls that produce an error should not change GL state the implementation
693	// should have nothing else to report.
694	if (numMsg > 1)
695		gl.getDebugMessageLog(numMsg-1, 0, DE_NULL, DE_NULL, DE_NULL, DE_NULL, DE_NULL, DE_NULL); // Clear all but last
696
697	{
698		int  msgLen = 0;
699		gl.getIntegerv(GL_DEBUG_NEXT_LOGGED_MESSAGE_LENGTH, &msgLen);
700
701		TCU_CHECK_MSG(msgLen >= 0, "Negative message length");
702		TCU_CHECK_MSG(msgLen < 100000, "Excessively long message");
703
704		lastMsg.message.resize(msgLen);
705		gl.getDebugMessageLog(1, msgLen, &lastMsg.id.source, &lastMsg.id.type, &lastMsg.id.id, &lastMsg.severity, &msgLen, &lastMsg.message[0]);
706	}
707
708	log << TestLog::Message << "Driver says: \"" << lastMsg.message << "\"" << TestLog::EndMessage;
709
710	verifyMessage(lastMsg, source, type);
711}
712
713// Generate errors, verify that calling glGetError afterwards produces desired result
714class GetErrorCase : public BaseCase
715{
716public:
717							GetErrorCase	(Context&				ctx,
718											 const char*			name,
719											 const char*			desc,
720											 TestFunc				errorFunc);
721	virtual 				~GetErrorCase	(void) {}
722
723	virtual IterateResult	iterate			(void);
724
725	virtual void			expectMessage	(GLenum source, GLenum type);
726	virtual void			expectError		(glw::GLenum error0, glw::GLenum error1);
727
728private:
729	const TestFunc			m_errorFunc;
730};
731
732GetErrorCase::GetErrorCase (Context&	ctx,
733							const char*	name,
734							const char*	desc,
735							TestFunc	errorFunc)
736	: BaseCase		(ctx, name, desc)
737	, m_errorFunc	(errorFunc)
738{
739}
740
741GetErrorCase::IterateResult GetErrorCase::iterate (void)
742{
743	tcu::TestLog&			log		= m_testCtx.getLog();
744	NegativeTestContext		context	= NegativeTestContext(*this, m_context.getRenderContext(), log, m_results, true);
745
746	m_errorFunc(context);
747
748	m_results.setTestContextResult(m_testCtx);
749
750	return STOP;
751}
752
753void GetErrorCase::expectMessage (GLenum source, GLenum type)
754{
755	DE_UNREF(source);
756	DE_UNREF(type);
757	DE_ASSERT(!"GetErrorCase cannot handle anything other than error codes");
758}
759
760void GetErrorCase::expectError (glw::GLenum error0, glw::GLenum error1)
761{
762	const glw::Functions&	gl		= m_context.getRenderContext().getFunctions();
763	TestLog&				log		= m_testCtx.getLog();
764
765	const GLenum			result	= gl.getError();
766
767	if (result != error0 && result != error1)
768	{
769		m_results.addResult(QP_TEST_RESULT_FAIL, "Incorrect error was reported");
770		if (error0 == error1)
771			log << TestLog::Message
772				<< glu::getErrorStr(error0) << " was expected but got "
773				<< glu::getErrorStr(result)
774				<< TestLog::EndMessage;
775		else
776			log << TestLog::Message
777				<< glu::getErrorStr(error0) << " or "
778				<< glu::getErrorStr(error1) << " was expected but got "
779				<< glu::getErrorStr(result)
780				<< TestLog::EndMessage;
781		return;
782	}
783}
784
785// Generate errors, log the types, disable some, regenerate errors, verify correct errors (not)reported
786class FilterCase : public BaseCase
787{
788public:
789								FilterCase		(Context&				ctx,
790												 const char*			name,
791												 const char*			desc,
792												 const vector<TestFunc>	errorFuncs);
793	virtual 					~FilterCase		(void) {}
794
795	virtual IterateResult		iterate			(void);
796
797	virtual void				expectMessage	(GLenum source, GLenum type);
798
799protected:
800	struct MessageFilter
801	{
802		MessageFilter() : source(GL_DONT_CARE), type(GL_DONT_CARE), severity(GL_DONT_CARE), enabled(true) {} // Default to enable all
803		MessageFilter(GLenum source_, GLenum type_, GLenum severity_, const vector<GLuint>& ids_, bool enabled_) : source(source_), type(type_), severity(severity_), ids(ids_), enabled(enabled_) {}
804
805		GLenum			source;
806		GLenum			type;
807		GLenum			severity;
808		vector<GLuint>	ids;
809		bool			enabled;
810	};
811
812	virtual void				callback			(GLenum source, GLenum type, GLuint id, GLenum severity, const string& message);
813
814	vector<MessageData>			genMessages			(bool uselog, const string& desc);
815
816	vector<MessageFilter>		genFilters			(const vector<MessageData>& messages, const vector<MessageFilter>& initial, deUint32 seed, int iterations) const;
817	void						applyFilters		(const vector<MessageFilter>& filters) const;
818	bool						isEnabled			(const vector<MessageFilter>& filters, const MessageData& message) const;
819
820	void						verify				(const vector<MessageData>&		refMessages,
821													 const vector<MessageData>&		filteredMessages,
822													 const vector<MessageFilter>&	filters);
823
824	const vector<TestFunc>		m_errorFuncs;
825
826	vector<MessageData>*		m_currentErrors;
827};
828
829FilterCase::FilterCase (Context&				ctx,
830						const char*				name,
831						const char*				desc,
832						const vector<TestFunc>	errorFuncs)
833	: BaseCase			(ctx, name, desc)
834	, m_errorFuncs		(errorFuncs)
835	, m_currentErrors	(DE_NULL)
836{
837}
838
839FilterCase::IterateResult FilterCase::iterate (void)
840{
841	TCU_CHECK_AND_THROW(NotSupportedError, m_context.getContextInfo().isExtensionSupported("GL_KHR_debug"), "GL_KHR_debug is not supported");
842
843	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
844
845	gl.enable(GL_DEBUG_OUTPUT);
846	gl.enable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
847	gl.debugMessageCallback(callbackHandle, this);
848	gl.debugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, DE_NULL, true);
849
850	{
851		const vector<MessageData>	refMessages		= genMessages(true, "Reference run");
852		const MessageFilter			baseFilter		(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, vector<GLuint>(), true);
853		const deUint32				baseSeed		= deStringHash(getName()) ^ m_testCtx.getCommandLine().getBaseSeed();
854		const vector<MessageFilter>	filters			= genFilters(refMessages, vector<MessageFilter>(1, baseFilter), baseSeed, 4);
855		vector<MessageData>			filteredMessages;
856
857		applyFilters(filters);
858
859		// Generate errors
860		filteredMessages = genMessages(false, "Filtered run");
861
862		// Verify
863		verify(refMessages, filteredMessages, filters);
864
865		if (!isDebugContext() && refMessages.empty())
866			m_results.addResult(QP_TEST_RESULT_QUALITY_WARNING, "Verification accuracy is lacking without a debug context");
867	}
868
869	gl.disable(GL_DEBUG_OUTPUT);
870	m_results.setTestContextResult(m_testCtx);
871
872	return STOP;
873}
874
875void FilterCase::expectMessage (GLenum source, GLenum type)
876{
877	DE_UNREF(source);
878	DE_UNREF(type);
879}
880
881void FilterCase::callback (GLenum source, GLenum type, GLuint id, GLenum severity, const string& message)
882{
883	if (m_currentErrors)
884		m_currentErrors->push_back(MessageData(MessageID(source, type, id), severity, message));
885}
886
887vector<MessageData> FilterCase::genMessages (bool uselog, const string& desc)
888{
889	tcu::TestLog&			log			= m_testCtx.getLog();
890	NegativeTestContext		context		= NegativeTestContext(*this, m_context.getRenderContext(), log, m_results, uselog);
891	tcu::ScopedLogSection	section		(log, "message gen", desc);
892	vector<MessageData>		messages;
893
894	m_currentErrors = &messages;
895
896	for (int ndx = 0; ndx < int(m_errorFuncs.size()); ndx++)
897		m_errorFuncs[ndx](context);
898
899	m_currentErrors = DE_NULL;
900
901	return messages;
902}
903
904vector<FilterCase::MessageFilter> FilterCase::genFilters (const vector<MessageData>& messages, const vector<MessageFilter>& initial, deUint32 seed, int iterations) const
905{
906	de::Random				rng				(seed ^ deInt32Hash(deStringHash(getName())));
907
908	set<MessageID>			tempMessageIds;
909	set<GLenum>				tempSources;
910	set<GLenum>				tempTypes;
911	set<GLenum>				tempSeverities;
912
913	if (messages.empty())
914		return initial;
915
916	for (int ndx = 0; ndx < int(messages.size()); ndx++)
917	{
918		const MessageData& msg = messages[ndx];
919
920		tempMessageIds.insert(msg.id);
921		tempSources.insert(msg.id.source);
922		tempTypes.insert(msg.id.type);
923		tempSeverities.insert(msg.severity);
924	}
925
926	{
927		// Fetchable by index
928		const vector<MessageID> messageIds	(tempMessageIds.begin(), tempMessageIds.end());
929		const vector<GLenum>	sources		(tempSources.begin(), tempSources.end());
930		const vector<GLenum>	types		(tempTypes.begin(), tempTypes.end());
931		const vector<GLenum>	severities	(tempSeverities.begin(), tempSeverities.end());
932
933		vector<MessageFilter>	filters		= initial;
934
935		for (int iteration = 0; iteration < iterations; iteration++)
936		{
937			switch(rng.getInt(0, 8)) // Distribute so that per-message randomization (the default branch) is prevalent
938			{
939				case 0:
940				{
941					const GLenum	source	= sources[rng.getInt(0, int(sources.size()-1))];
942					const bool		enabled	= rng.getBool();
943
944					filters.push_back(MessageFilter(source, GL_DONT_CARE, GL_DONT_CARE, vector<GLuint>(), enabled));
945					break;
946				}
947
948				case 1:
949				{
950					const GLenum	type	= types[rng.getUint32()%types.size()];
951					const bool		enabled	= rng.getBool();
952
953					filters.push_back(MessageFilter(GL_DONT_CARE, type, GL_DONT_CARE, vector<GLuint>(), enabled));
954					break;
955				}
956
957				case 2:
958				{
959					const GLenum	severity	= severities[rng.getUint32()%severities.size()];
960					const bool		enabled		= rng.getBool();
961
962					filters.push_back(MessageFilter(GL_DONT_CARE, GL_DONT_CARE, severity, vector<GLuint>(), enabled));
963					break;
964				}
965
966				default:
967				{
968					const int start = rng.getInt(0, int(messageIds.size()));
969
970					for (int itr = 0; itr < 4; itr++)
971					{
972						const MessageID&	id		= messageIds[(start+itr)%messageIds.size()];
973						const bool			enabled = rng.getBool();
974
975						filters.push_back(MessageFilter(id.source, id.type, GL_DONT_CARE, vector<GLuint>(1, id.id), enabled));
976					}
977				}
978			}
979		}
980
981		return filters;
982	}
983}
984
985void FilterCase::applyFilters (const vector<MessageFilter>& filters) const
986{
987	TestLog&					log		= m_testCtx.getLog();
988	const tcu::ScopedLogSection	section	(log, "", "Setting message filters");
989	const glw::Functions&		gl		= m_context.getRenderContext().getFunctions();
990
991	for (size_t filterNdx = 0; filterNdx < filters.size(); filterNdx++)
992	{
993		const MessageFilter& filter = filters[filterNdx];
994
995		if (filter.ids.empty())
996			log << TestLog::Message << "Setting messages with"
997				<< " source " << glu::getDebugMessageSourceStr(filter.source)
998				<< ", type " << glu::getDebugMessageTypeStr(filter.type)
999				<< " and severity " << glu::getDebugMessageSeverityStr(filter.severity)
1000				<< (filter.enabled ? " to enabled" : " to disabled")
1001				<< TestLog::EndMessage;
1002		else
1003		{
1004			for (size_t ndx = 0; ndx < filter.ids.size(); ndx++)
1005				log << TestLog::Message << "Setting message (" << MessageID(filter.source, filter.type, filter.ids[ndx]) << ") to " << (filter.enabled ? "enabled" : "disabled") << TestLog::EndMessage;
1006		}
1007
1008		gl.debugMessageControl(filter.source, filter.type, filter.severity, GLsizei(filter.ids.size()), filter.ids.empty() ? DE_NULL : &filter.ids[0], filter.enabled);
1009	}
1010}
1011
1012bool FilterCase::isEnabled (const vector<MessageFilter>& filters, const MessageData& message) const
1013{
1014	bool retval = true;
1015
1016	for (size_t filterNdx = 0; filterNdx < filters.size(); filterNdx++)
1017	{
1018		const MessageFilter&	filter	= filters[filterNdx];
1019
1020		if (filter.ids.empty())
1021		{
1022			if (filter.source != GL_DONT_CARE && filter.source != message.id.source)
1023				continue;
1024
1025			if (filter.type != GL_DONT_CARE && filter.type != message.id.type)
1026				continue;
1027
1028			if (filter.severity != GL_DONT_CARE && filter.severity != message.severity)
1029				continue;
1030		}
1031		else
1032		{
1033			DE_ASSERT(filter.source != GL_DONT_CARE);
1034			DE_ASSERT(filter.type != GL_DONT_CARE);
1035			DE_ASSERT(filter.severity == GL_DONT_CARE);
1036
1037			if (filter.source != message.id.source || filter.type != message.id.type)
1038				continue;
1039
1040			if (!de::contains(filter.ids.begin(), filter.ids.end(), message.id.id))
1041				continue;
1042		}
1043
1044		retval = filter.enabled;
1045	}
1046
1047	return retval;
1048}
1049
1050struct MessageMeta
1051{
1052	int		refCount;
1053	int		resCount;
1054	GLenum	severity;
1055
1056	MessageMeta (void) : refCount(0), resCount(0), severity(GL_NONE) {}
1057};
1058
1059void FilterCase::verify (const vector<MessageData>& refMessages, const vector<MessageData>& resMessages, const vector<MessageFilter>& filters)
1060{
1061	TestLog&						log		= m_testCtx.getLog();
1062	map<MessageID, MessageMeta>		counts;
1063
1064	log << TestLog::Section("verification", "Verifying");
1065
1066	// Gather message counts & severities, report severity mismatches if found
1067	for (size_t refNdx = 0; refNdx < refMessages.size(); refNdx++)
1068	{
1069		const MessageData&	msg  = refMessages[refNdx];
1070		MessageMeta&		meta = counts[msg.id];
1071
1072		if (meta.severity != GL_NONE && meta.severity != msg.severity)
1073		{
1074			log << TestLog::Message << "A message has variable severity between instances: (" << msg.id << ") with severity "
1075				<< glu::getDebugMessageSeverityStr(meta.severity) << " and " << glu::getDebugMessageSeverityStr(msg.severity) << TestLog::EndMessage;
1076			m_results.addResult(QP_TEST_RESULT_FAIL, "Message severity changed between instances of the same message");
1077		}
1078
1079		meta.refCount++;
1080		meta.severity = msg.severity;
1081	}
1082
1083	for (size_t resNdx = 0; resNdx < resMessages.size(); resNdx++)
1084	{
1085		const MessageData&	msg  = resMessages[resNdx];
1086		MessageMeta&		meta = counts[msg.id];
1087
1088		if (meta.severity != GL_NONE && meta.severity != msg.severity)
1089		{
1090			log << TestLog::Message << "A message has variable severity between instances: (" << msg.id << ") with severity "
1091				<< glu::getDebugMessageSeverityStr(meta.severity) << " and " << glu::getDebugMessageSeverityStr(msg.severity) << TestLog::EndMessage;
1092			m_results.addResult(QP_TEST_RESULT_FAIL, "Message severity changed between instances of the same message");
1093		}
1094
1095		meta.resCount++;
1096		meta.severity = msg.severity;
1097	}
1098
1099	for (map<MessageID, MessageMeta>::const_iterator itr = counts.begin(); itr != counts.end(); itr++)
1100	{
1101		const MessageID&	id			= itr->first;
1102		const GLenum		severity	= itr->second.severity;
1103
1104		const int			refCount	= itr->second.refCount;
1105		const int			resCount	= itr->second.resCount;
1106		const bool			enabled		= isEnabled(filters, MessageData(id, severity, ""));
1107
1108		VerificationResult	result		= verifyMessageCount(id, severity, refCount, resCount, enabled);
1109
1110		log << TestLog::Message << result.logMessage << TestLog::EndMessage;
1111
1112		if (result.result != QP_TEST_RESULT_PASS)
1113			m_results.addResult(result.result, result.resultMessage);
1114	}
1115
1116	log << TestLog::EndSection;
1117}
1118
1119// Filter case that uses debug groups
1120class GroupFilterCase : public FilterCase
1121{
1122public:
1123							GroupFilterCase		(Context&				ctx,
1124												 const char*			name,
1125												 const char*			desc,
1126												 const vector<TestFunc>	errorFuncs);
1127	virtual 				~GroupFilterCase	(void) {}
1128
1129	virtual IterateResult	iterate				(void);
1130};
1131
1132GroupFilterCase::GroupFilterCase (Context&					ctx,
1133								  const char*				name,
1134								  const char*				desc,
1135								  const vector<TestFunc>	errorFuncs)
1136	: FilterCase(ctx, name, desc, errorFuncs)
1137{
1138}
1139
1140template<typename T>
1141vector<T> join(const vector<T>& a, const vector<T>&b)
1142{
1143	vector<T> retval;
1144
1145	retval.reserve(a.size()+b.size());
1146	retval.insert(retval.end(), a.begin(), a.end());
1147	retval.insert(retval.end(), b.begin(), b.end());
1148	return retval;
1149}
1150
1151GroupFilterCase::IterateResult GroupFilterCase::iterate (void)
1152{
1153	TCU_CHECK_AND_THROW(NotSupportedError, m_context.getContextInfo().isExtensionSupported("GL_KHR_debug"), "GL_KHR_debug is not supported");
1154
1155	const glw::Functions&	gl			= m_context.getRenderContext().getFunctions();
1156	tcu::TestLog&			log			= m_testCtx.getLog();
1157
1158	gl.enable(GL_DEBUG_OUTPUT);
1159	gl.enable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
1160	gl.debugMessageCallback(callbackHandle, this);
1161	gl.debugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, DE_NULL, true);
1162
1163	{
1164
1165		// Generate reference (all errors)
1166		const vector<MessageData>	refMessages	 = genMessages(true, "Reference run");
1167		const deUint32				baseSeed	 = deStringHash(getName()) ^ m_testCtx.getCommandLine().getBaseSeed();
1168		const MessageFilter			baseFilter	 (GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, vector<GLuint>(), true);
1169		const vector<MessageFilter>	filter0		 = genFilters(refMessages, vector<MessageFilter>(1, baseFilter), baseSeed, 4);
1170		vector<MessageData>			resMessages0;
1171
1172		applyFilters(filter0);
1173
1174		resMessages0 = genMessages(false, "Filtered run, default debug group");
1175
1176		// Initial verification
1177		verify(refMessages, resMessages0, filter0);
1178
1179		{
1180			// Generate reference (filters inherited from parent)
1181			const vector<MessageFilter> filter1base		= genFilters(refMessages, vector<MessageFilter>(), baseSeed ^ 0xDEADBEEF, 4);
1182			const vector<MessageFilter>	filter1full		= join(filter0, filter1base);
1183			tcu::ScopedLogSection		section1		(log, "", "Pushing Debug Group");
1184			vector<MessageData>			resMessages1;
1185
1186			gl.pushDebugGroup(GL_DEBUG_SOURCE_APPLICATION, 1, -1, "Test Group");
1187			applyFilters(filter1base);
1188
1189			// First nested verification
1190			resMessages1 = genMessages(false, "Filtered run, pushed one debug group");
1191			verify(refMessages, resMessages1, filter1full);
1192
1193			{
1194				// Generate reference (filters iherited again)
1195				const vector<MessageFilter>	filter2base		= genFilters(refMessages, vector<MessageFilter>(), baseSeed ^ 0x43211234, 4);
1196				const vector<MessageFilter>	filter2full		= join(filter1full, filter2base);
1197				tcu::ScopedLogSection		section2		(log, "", "Pushing Debug Group");
1198				vector<MessageData>			resMessages2;
1199
1200				gl.pushDebugGroup(GL_DEBUG_SOURCE_APPLICATION, 1, -1, "Nested Test Group");
1201				applyFilters(filter2base);
1202
1203				// Second nested verification
1204				resMessages2 = genMessages(false, "Filtered run, pushed two debug groups");
1205				verify(refMessages, resMessages2, filter2full);
1206
1207				gl.popDebugGroup();
1208			}
1209
1210			// First restore verification
1211			resMessages1 = genMessages(false, "Filtered run, popped second debug group");
1212			verify(refMessages, resMessages1, filter1full);
1213
1214			gl.popDebugGroup();
1215		}
1216
1217		// restore verification
1218		resMessages0 = genMessages(false, "Filtered run, popped first debug group");
1219		verify(refMessages, resMessages0, filter0);
1220
1221		if (!isDebugContext() && refMessages.empty())
1222			m_results.addResult(QP_TEST_RESULT_QUALITY_WARNING, "Verification accuracy is lacking without a debug context");
1223	}
1224
1225	gl.disable(GL_DEBUG_OUTPUT);
1226	m_results.setTestContextResult(m_testCtx);
1227	return STOP;
1228}
1229
1230// Basic grouping functionality
1231class GroupCase : public BaseCase
1232{
1233public:
1234							GroupCase	(Context&				ctx,
1235										 const char*			name,
1236										 const char*			desc);
1237	virtual					~GroupCase	() {}
1238
1239	virtual IterateResult	iterate		(void);
1240
1241private:
1242	virtual void			callback	(GLenum source, GLenum type, GLuint id, GLenum severity, const string& message);
1243
1244	MessageData				m_lastMessage;
1245};
1246
1247GroupCase::GroupCase (Context&				ctx,
1248					  const char*			name,
1249					  const char*			desc)
1250	: BaseCase(ctx, name, desc)
1251{
1252}
1253
1254GroupCase::IterateResult GroupCase::iterate (void)
1255{
1256	TCU_CHECK_AND_THROW(NotSupportedError, m_context.getContextInfo().isExtensionSupported("GL_KHR_debug"), "GL_KHR_debug is not supported");
1257
1258	const glw::Functions&	gl		= m_context.getRenderContext().getFunctions();
1259	tcu::TestLog&			log		= m_testCtx.getLog();
1260	glu::CallLogWrapper		wrapper	(gl, log);
1261
1262	gl.enable(GL_DEBUG_OUTPUT);
1263	gl.enable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
1264	gl.debugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, DE_NULL, false); // disable all
1265	gl.debugMessageControl(GL_DEBUG_SOURCE_API, GL_DEBUG_TYPE_ERROR, GL_DONT_CARE, 0, DE_NULL, true); // enable API errors
1266	gl.debugMessageControl(GL_DEBUG_SOURCE_APPLICATION, GL_DONT_CARE, GL_DONT_CARE, 0, DE_NULL, true); // enable application messages
1267	gl.debugMessageControl(GL_DEBUG_SOURCE_THIRD_PARTY, GL_DONT_CARE, GL_DONT_CARE, 0, DE_NULL, true); // enable third party messages
1268	gl.debugMessageCallback(callbackHandle, this);
1269
1270	wrapper.enableLogging(true);
1271	wrapper.glPushDebugGroup(GL_DEBUG_SOURCE_APPLICATION, 1234, -1, "Pushed debug stack");
1272	verifyMessage(m_lastMessage, GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_PUSH_GROUP, 1234, GL_DEBUG_SEVERITY_NOTIFICATION);
1273	wrapper.glPopDebugGroup();
1274	verifyMessage(m_lastMessage, GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_POP_GROUP, 1234, GL_DEBUG_SEVERITY_NOTIFICATION);
1275
1276	wrapper.glPushDebugGroup(GL_DEBUG_SOURCE_THIRD_PARTY, 4231, -1, "Pushed debug stack");
1277	verifyMessage(m_lastMessage, GL_DEBUG_SOURCE_THIRD_PARTY, GL_DEBUG_TYPE_PUSH_GROUP, 4231, GL_DEBUG_SEVERITY_NOTIFICATION);
1278	wrapper.glPopDebugGroup();
1279	verifyMessage(m_lastMessage, GL_DEBUG_SOURCE_THIRD_PARTY, GL_DEBUG_TYPE_POP_GROUP, 4231, GL_DEBUG_SEVERITY_NOTIFICATION);
1280
1281	gl.debugMessageCallback(DE_NULL, DE_NULL);
1282	gl.disable(GL_DEBUG_OUTPUT);
1283
1284	m_results.setTestContextResult(m_testCtx);
1285
1286	return STOP;
1287}
1288
1289void GroupCase::callback (GLenum source, GLenum type, GLuint id, GLenum severity, const string& message)
1290{
1291	m_lastMessage = MessageData(MessageID(source, type, id), severity, message);
1292}
1293
1294// Asynchronous debug output
1295class AsyncCase : public BaseCase
1296{
1297public:
1298							AsyncCase			(Context&				ctx,
1299												 const char*			name,
1300												 const char*			desc,
1301												 const vector<TestFunc>	errorFuncs,
1302												 bool					useCallbacks);
1303	virtual					~AsyncCase			() {}
1304
1305	virtual IterateResult	iterate				(void);
1306
1307	virtual void			expectMessage		(glw::GLenum source, glw::GLenum type);
1308
1309private:
1310	struct MessageCount
1311	{
1312		int received;
1313		int expected;
1314
1315		MessageCount(void) : received(0), expected(0) {}
1316	};
1317	typedef map<MessageID, MessageCount> MessageCounter;
1318
1319	enum VerifyState
1320	{
1321		VERIFY_PASS = 0,
1322		VERIFY_MINIMUM,
1323		VERIFY_FAIL,
1324
1325		VERIFY_LAST
1326	};
1327
1328	virtual void			callback			(glw::GLenum source, glw::GLenum type, glw::GLuint id, glw::GLenum severity, const std::string& message);
1329	VerifyState				verify				(bool uselog);
1330	void					fetchLogMessages	(void);
1331
1332	const vector<TestFunc>	m_errorFuncs;
1333	const bool				m_useCallbacks;
1334
1335	MessageCounter			m_counts;
1336
1337	de::Mutex				m_mutex;
1338};
1339
1340AsyncCase::AsyncCase (Context&					ctx,
1341					  const char*				name,
1342					  const char*				desc,
1343					  const vector<TestFunc>	errorFuncs,
1344					  bool						useCallbacks)
1345	: BaseCase			(ctx, name, desc)
1346	, m_errorFuncs		(errorFuncs)
1347	, m_useCallbacks	(useCallbacks)
1348{
1349}
1350
1351AsyncCase::IterateResult AsyncCase::iterate (void)
1352{
1353	TCU_CHECK_AND_THROW(NotSupportedError, m_context.getContextInfo().isExtensionSupported("GL_KHR_debug"), "GL_KHR_debug is not supported");
1354
1355	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
1356	tcu::TestLog&		log			= m_testCtx.getLog();
1357	NegativeTestContext	context		= NegativeTestContext(*this, m_context.getRenderContext(), log, m_results, true);
1358	const int			maxWait		= 10000; // ms
1359	const int			warnWait	= 100;
1360
1361	gl.enable(GL_DEBUG_OUTPUT);
1362	gl.enable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
1363	gl.debugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, DE_NULL, false);
1364
1365	// Some messages could be dependent on the value of DEBUG_OUTPUT_SYNCHRONOUS so only use API errors which should be generated in all cases
1366	gl.debugMessageControl(GL_DEBUG_SOURCE_API, GL_DEBUG_TYPE_ERROR, GL_DONT_CARE, 0, DE_NULL, true);
1367
1368	if (m_useCallbacks) // will use log otherwise
1369		gl.debugMessageCallback(callbackHandle, this);
1370	else
1371		gl.debugMessageCallback(DE_NULL, DE_NULL);
1372
1373	// Reference run (synchoronous)
1374	{
1375		tcu::ScopedLogSection section(log, "reference run", "Reference run (synchronous)");
1376
1377		for (int ndx = 0; ndx < int(m_errorFuncs.size()); ndx++)
1378			m_errorFuncs[ndx](context);
1379	}
1380
1381	if (m_counts.empty())
1382	{
1383		if (!isDebugContext())
1384			m_results.addResult(QP_TEST_RESULT_QUALITY_WARNING, "Need debug context to guarantee implementation behaviour (see command line options)");
1385
1386		log << TestLog::Message << "Reference run produced no messages, nothing to verify" << TestLog::EndMessage;
1387
1388		gl.debugMessageCallback(DE_NULL, DE_NULL);
1389		gl.disable(GL_DEBUG_OUTPUT);
1390
1391		m_results.setTestContextResult(m_testCtx);
1392		return STOP;
1393	}
1394
1395	for (MessageCounter::iterator itr = m_counts.begin(); itr != m_counts.end(); itr++)
1396	{
1397		itr->second.expected = itr->second.received;
1398		itr->second.received = 0;
1399	}
1400
1401	gl.disable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
1402
1403	// Result run (async)
1404	for (int ndx = 0; ndx < int(m_errorFuncs.size()); ndx++)
1405		m_errorFuncs[ndx](context);
1406
1407	// Repatedly try verification, new results may be added to m_receivedMessages at any time
1408	{
1409		tcu::ScopedLogSection	section			(log, "result run", "Result run (asynchronous)");
1410		VerifyState				lastTimelyState = VERIFY_FAIL;
1411
1412		for (int waited = 0;;)
1413		{
1414			const VerifyState	pass = verify(false);
1415			const int			wait = de::max(50, waited>>2);
1416
1417			// Pass (possibly due to time limit)
1418			if (pass == VERIFY_PASS || (pass == VERIFY_MINIMUM && waited >= maxWait))
1419			{
1420				verify(true); // log
1421
1422				// State changed late
1423				if (waited >= warnWait && lastTimelyState != pass)
1424					m_results.addResult(QP_TEST_RESULT_QUALITY_WARNING, "Async messages were returned to application somewhat slowly");
1425
1426				log << TestLog::Message << "Passed after ~" << waited << "ms of waiting" << TestLog::EndMessage;
1427				break;
1428			}
1429			// fail
1430			else if (waited >= maxWait)
1431			{
1432				verify(true); // log
1433
1434				log << TestLog::Message << "Waited for ~" << waited << "ms without getting all expected messages" << TestLog::EndMessage;
1435				m_results.addResult(QP_TEST_RESULT_FAIL, "Async messages were not returned to application within a reasonable timeframe");
1436				break;
1437			}
1438
1439			if (waited < warnWait)
1440				lastTimelyState = pass;
1441
1442			deSleep(wait);
1443			waited += wait;
1444
1445			if (!m_useCallbacks)
1446				fetchLogMessages();
1447		}
1448	}
1449
1450	gl.debugMessageCallback(DE_NULL, DE_NULL);
1451
1452	gl.disable(GL_DEBUG_OUTPUT);
1453	m_results.setTestContextResult(m_testCtx);
1454
1455	return STOP;
1456}
1457
1458void AsyncCase::expectMessage (GLenum source, GLenum type)
1459{
1460	// Good time to clean up the queue as this should be called after most messages are generated
1461	if (!m_useCallbacks)
1462		fetchLogMessages();
1463
1464	DE_UNREF(source);
1465	DE_UNREF(type);
1466}
1467
1468void AsyncCase::callback (GLenum source, GLenum type, GLuint id, GLenum severity, const string& message)
1469{
1470	DE_ASSERT(m_useCallbacks);
1471	DE_UNREF(severity);
1472	DE_UNREF(message);
1473
1474	de::ScopedLock lock(m_mutex);
1475
1476	m_counts[MessageID(source, type, id)].received++;
1477}
1478
1479// 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
1480void AsyncCase::fetchLogMessages (void)
1481{
1482	const glw::Functions&	gl		= m_context.getRenderContext().getFunctions();
1483	GLint					numMsg	= 0;
1484
1485	gl.getIntegerv(GL_DEBUG_LOGGED_MESSAGES, &numMsg);
1486
1487	for(int msgNdx = 0; msgNdx < numMsg; msgNdx++)
1488	{
1489		int			msgLen = 0;
1490		MessageData msg;
1491
1492		gl.getIntegerv(GL_DEBUG_NEXT_LOGGED_MESSAGE_LENGTH, &msgLen);
1493
1494		TCU_CHECK_MSG(msgLen >= 0, "Negative message length");
1495		TCU_CHECK_MSG(msgLen < 100000, "Excessively long message");
1496
1497		msg.message.resize(msgLen);
1498		gl.getDebugMessageLog(1, msgLen, &msg.id.source, &msg.id.type, &msg.id.id, &msg.severity, &msgLen, &msg.message[0]);
1499
1500		{
1501			const de::ScopedLock lock(m_mutex); // Don't block during API call
1502
1503			m_counts[MessageID(msg.id)].received++;
1504		}
1505	}
1506}
1507
1508AsyncCase::VerifyState AsyncCase::verify (bool uselog)
1509{
1510	using std::map;
1511
1512	VerifyState			retval		= VERIFY_PASS;
1513	TestLog&			log			= m_testCtx.getLog();
1514
1515	const de::ScopedLock lock(m_mutex);
1516
1517	for (map<MessageID, MessageCount>::const_iterator itr = m_counts.begin(); itr != m_counts.end(); itr++)
1518	{
1519		const MessageID&	id			= itr->first;
1520
1521		const int			refCount	= itr->second.expected;
1522		const int			resCount	= itr->second.received;
1523		const bool			enabled		= true;
1524
1525		VerificationResult	result		= verifyMessageCount(id, GL_DONT_CARE, refCount, resCount, enabled);
1526
1527		if (uselog)
1528			log << TestLog::Message << result.logMessage << TestLog::EndMessage;
1529
1530		if (result.result == QP_TEST_RESULT_FAIL)
1531			retval = VERIFY_FAIL;
1532		else if (result.result != QP_TEST_RESULT_PASS && retval == VERIFY_PASS)
1533			retval = VERIFY_MINIMUM;
1534	}
1535
1536	return retval;
1537}
1538
1539// Tests debug labels
1540class LabelCase : public TestCase
1541{
1542public:
1543							LabelCase	(Context&				ctx,
1544										 const char*			name,
1545										 const char*			desc,
1546										 GLenum					identifier);
1547	virtual					~LabelCase	(void) {}
1548
1549	virtual IterateResult	iterate		(void);
1550
1551private:
1552	GLenum					m_identifier;
1553};
1554
1555LabelCase::LabelCase (Context&		ctx,
1556					  const char*			name,
1557					  const char*			desc,
1558					  GLenum				identifier)
1559	: TestCase		(ctx, name, desc)
1560	, m_identifier	(identifier)
1561{
1562}
1563
1564LabelCase::IterateResult LabelCase::iterate (void)
1565{
1566	TCU_CHECK_AND_THROW(NotSupportedError, m_context.getContextInfo().isExtensionSupported("GL_KHR_debug"), "GL_KHR_debug is not supported");
1567
1568	const glw::Functions&	gl			= m_context.getRenderContext().getFunctions();
1569	const char*	const		msg			= "This is a debug label";
1570	GLuint					object		= 0;
1571	char					buffer[64];
1572	int						outlen		= 0;
1573
1574	switch(m_identifier)
1575	{
1576		case GL_BUFFER:
1577			gl.genBuffers(1, &object);
1578			gl.bindBuffer(GL_ARRAY_BUFFER, object);
1579			gl.bindBuffer(GL_ARRAY_BUFFER, 0);
1580			break;
1581
1582		case GL_SHADER:
1583			object = gl.createShader(GL_FRAGMENT_SHADER);
1584			break;
1585
1586		case GL_PROGRAM:
1587			object = gl.createProgram();
1588			break;
1589
1590		case GL_QUERY:
1591			gl.genQueries(1, &object);
1592			gl.beginQuery(GL_ANY_SAMPLES_PASSED, object); // Create
1593			gl.endQuery(GL_ANY_SAMPLES_PASSED); // Cleanup
1594			break;
1595
1596		case GL_PROGRAM_PIPELINE:
1597			gl.genProgramPipelines(1, &object);
1598			gl.bindProgramPipeline(object); // Create
1599			gl.bindProgramPipeline(0); // Cleanup
1600			break;
1601
1602		case GL_TRANSFORM_FEEDBACK:
1603			gl.genTransformFeedbacks(1, &object);
1604			gl.bindTransformFeedback(GL_TRANSFORM_FEEDBACK, object);
1605			gl.bindTransformFeedback(GL_TRANSFORM_FEEDBACK, 0);
1606			break;
1607
1608		case GL_SAMPLER:
1609			gl.genSamplers(1, &object);
1610			gl.bindSampler(0, object);
1611			gl.bindSampler(0, 0);
1612			break;
1613
1614		case GL_TEXTURE:
1615			gl.genTextures(1, &object);
1616			gl.bindTexture(GL_TEXTURE_2D, object);
1617			gl.bindTexture(GL_TEXTURE_2D, 0);
1618			break;
1619
1620		case GL_RENDERBUFFER:
1621			gl.genRenderbuffers(1, &object);
1622			gl.bindRenderbuffer(GL_RENDERBUFFER, object);
1623			gl.bindRenderbuffer(GL_RENDERBUFFER, 0);
1624			break;
1625
1626		case GL_FRAMEBUFFER:
1627			gl.genFramebuffers(1, &object);
1628			gl.bindFramebuffer(GL_DRAW_FRAMEBUFFER, object);
1629			gl.bindFramebuffer(GL_DRAW_FRAMEBUFFER, m_context.getRenderContext().getDefaultFramebuffer());
1630			break;
1631
1632		default:
1633			DE_ASSERT(!"Invalid identifier");
1634	}
1635
1636	gl.objectLabel(m_identifier, object, -1, msg);
1637
1638	gl.getObjectLabel(m_identifier, object, sizeof(buffer), &outlen, buffer);
1639
1640	if (outlen == 0)
1641		m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Failed to query debug label from object");
1642	else if (deStringEqual(msg, buffer))
1643	{
1644		m_testCtx.getLog() << TestLog::Message << "Query returned string: \"" << buffer << "\"" << TestLog::EndMessage;
1645		m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
1646	}
1647	else
1648	{
1649		m_testCtx.getLog() << TestLog::Message << "Query returned wrong string: expected \"" << msg << "\" but got \"" << buffer << "\"" << TestLog::EndMessage;
1650		m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Query returned wrong label");
1651	}
1652
1653	switch(m_identifier)
1654	{
1655		case GL_BUFFER:				gl.deleteBuffers(1, &object);				break;
1656		case GL_SHADER:				gl.deleteShader(object);					break;
1657		case GL_PROGRAM:			gl.deleteProgram(object);					break;
1658		case GL_QUERY:				gl.deleteQueries(1, &object);				break;
1659		case GL_PROGRAM_PIPELINE:	gl.deleteProgramPipelines(1, &object);		break;
1660		case GL_TRANSFORM_FEEDBACK:	gl.deleteTransformFeedbacks(1, &object);	break;
1661		case GL_SAMPLER:			gl.deleteSamplers(1, &object);				break;
1662		case GL_TEXTURE:			gl.deleteTextures(1, &object);				break;
1663		case GL_RENDERBUFFER:		gl.deleteRenderbuffers(1, &object);			break;
1664		case GL_FRAMEBUFFER:		gl.deleteFramebuffers(1, &object);			break;
1665
1666		default:
1667			DE_ASSERT(!"Invalid identifier");
1668	}
1669
1670	return STOP;
1671}
1672
1673} // Anonymous
1674
1675DebugTests::DebugTests (Context& context)
1676	: TestCaseGroup(context, "debug", "Debug tests")
1677{
1678}
1679
1680enum CaseType
1681{
1682	CASETYPE_CALLBACK = 0,
1683	CASETYPE_LOG,
1684	CASETYPE_GETERROR,
1685
1686	CASETYPE_LAST
1687};
1688
1689tcu::TestNode* createCase (CaseType type, Context& ctx, const char* name, const char* desc, TestFunc function)
1690{
1691	switch(type)
1692	{
1693		case CASETYPE_CALLBACK: return new CallbackErrorCase(ctx, name, desc, function);
1694		case CASETYPE_LOG:		return new LogErrorCase(ctx, name, desc, function);
1695		case CASETYPE_GETERROR: return new GetErrorCase(ctx, name, desc, function);
1696
1697		default:
1698			DE_ASSERT(!"Invalid type");
1699	}
1700
1701	return DE_NULL;
1702}
1703
1704tcu::TestCaseGroup* createChildCases (CaseType type, Context& ctx, const char* name, const char* desc, const vector<FunctionContainer>& funcs)
1705{
1706	tcu::TestCaseGroup* host = new tcu::TestCaseGroup(ctx.getTestContext(), name, desc);
1707
1708	for (size_t ndx = 0; ndx < funcs.size(); ndx++)
1709			host->addChild(createCase(type, ctx, funcs[ndx].name, funcs[ndx].desc, funcs[ndx].function));
1710
1711	return host;
1712}
1713
1714void DebugTests::init (void)
1715{
1716	const vector<FunctionContainer> bufferFuncs		= NegativeTestShared::getNegativeBufferApiTestFunctions();
1717	const vector<FunctionContainer> textureFuncs	= NegativeTestShared::getNegativeTextureApiTestFunctions();
1718	const vector<FunctionContainer> shaderFuncs		= NegativeTestShared::getNegativeShaderApiTestFunctions();
1719	const vector<FunctionContainer> fragmentFuncs	= NegativeTestShared::getNegativeFragmentApiTestFunctions();
1720	const vector<FunctionContainer> vaFuncs			= NegativeTestShared::getNegativeVertexArrayApiTestFunctions();
1721	const vector<FunctionContainer> stateFuncs		= NegativeTestShared::getNegativeStateApiTestFunctions();
1722	const vector<FunctionContainer> externalFuncs	= getUserMessageFuncs();
1723
1724	{
1725		tcu::TestCaseGroup* const	negative	= new tcu::TestCaseGroup(m_testCtx, "negative_coverage", "API error coverage with various reporting methods");
1726
1727		addChild(negative);
1728
1729		{
1730			tcu::TestCaseGroup* const	host	= new tcu::TestCaseGroup(m_testCtx, "callbacks", "Reporting of standard API errors via callback");
1731
1732			negative->addChild(host);
1733			host->addChild(createChildCases(CASETYPE_CALLBACK, m_context, "buffer",			"Negative Buffer API Cases",		bufferFuncs));
1734			host->addChild(createChildCases(CASETYPE_CALLBACK, m_context, "texture",		"Negative Texture API Cases",		textureFuncs));
1735			host->addChild(createChildCases(CASETYPE_CALLBACK, m_context, "shader",			"Negative Shader API Cases",		shaderFuncs));
1736			host->addChild(createChildCases(CASETYPE_CALLBACK, m_context, "fragment",		"Negative Fragment API Cases",		fragmentFuncs));
1737			host->addChild(createChildCases(CASETYPE_CALLBACK, m_context, "vertex_array",	"Negative Vertex Array API Cases",	vaFuncs));
1738			host->addChild(createChildCases(CASETYPE_CALLBACK, m_context, "state",			"Negative GL State API Cases",		stateFuncs));
1739		}
1740
1741		{
1742			tcu::TestCaseGroup* const	host	= new tcu::TestCaseGroup(m_testCtx, "log", "Reporting of standard API errors via log");
1743
1744			negative->addChild(host);
1745
1746			host->addChild(createChildCases(CASETYPE_LOG, m_context, "buffer",				"Negative Buffer API Cases",		bufferFuncs));
1747			host->addChild(createChildCases(CASETYPE_LOG, m_context, "texture",				"Negative Texture API Cases",		textureFuncs));
1748			host->addChild(createChildCases(CASETYPE_LOG, m_context, "shader",				"Negative Shader API Cases",		shaderFuncs));
1749			host->addChild(createChildCases(CASETYPE_LOG, m_context, "fragment",			"Negative Fragment API Cases",		fragmentFuncs));
1750			host->addChild(createChildCases(CASETYPE_LOG, m_context, "vertex_array",		"Negative Vertex Array API Cases",	vaFuncs));
1751			host->addChild(createChildCases(CASETYPE_LOG, m_context, "state",				"Negative GL State API Cases",		stateFuncs));
1752		}
1753
1754		{
1755			tcu::TestCaseGroup* const	host	= new tcu::TestCaseGroup(m_testCtx, "get_error", "Reporting of standard API errors via glGetError");
1756
1757			negative->addChild(host);
1758
1759			host->addChild(createChildCases(CASETYPE_GETERROR, m_context, "buffer",			"Negative Buffer API Cases",		bufferFuncs));
1760			host->addChild(createChildCases(CASETYPE_GETERROR, m_context, "texture",		"Negative Texture API Cases",		textureFuncs));
1761			host->addChild(createChildCases(CASETYPE_GETERROR, m_context, "shader",			"Negative Shader API Cases",		shaderFuncs));
1762			host->addChild(createChildCases(CASETYPE_GETERROR, m_context, "fragment",		"Negative Fragment API Cases",		fragmentFuncs));
1763			host->addChild(createChildCases(CASETYPE_GETERROR, m_context, "vertex_array",	"Negative Vertex Array API Cases",	vaFuncs));
1764			host->addChild(createChildCases(CASETYPE_GETERROR, m_context, "state",			"Negative GL State API Cases",		stateFuncs));
1765		}
1766	}
1767
1768	{
1769		tcu::TestCaseGroup*			host	= createChildCases(CASETYPE_CALLBACK, m_context, "externally_generated", "Externally Generated Messages", externalFuncs);
1770
1771		host->addChild(new GroupCase(m_context, "push_pop_consistency", "Push/pop message generation with full message output checking"));
1772
1773		addChild(host);
1774	}
1775
1776	{
1777		vector<FunctionContainer>	containers;
1778		vector<TestFunc>			allFuncs;
1779
1780		de::Random					rng			(0x53941903 ^ m_context.getTestContext().getCommandLine().getBaseSeed());
1781
1782		containers.insert(containers.end(), bufferFuncs.begin(), bufferFuncs.end());
1783		containers.insert(containers.end(), textureFuncs.begin(), textureFuncs.end());
1784		containers.insert(containers.end(), externalFuncs.begin(), externalFuncs.end());
1785
1786		for (size_t ndx = 0; ndx < containers.size(); ndx++)
1787			allFuncs.push_back(containers[ndx].function);
1788
1789		rng.shuffle(allFuncs.begin(), allFuncs.end());
1790
1791		{
1792			tcu::TestCaseGroup* const	filtering				= new tcu::TestCaseGroup(m_testCtx, "error_filters", "Filtering of reported errors");
1793			const int					errorFuncsPerCase		= 4;
1794			const int					maxFilteringCaseCount	= 32;
1795			const int					caseCount				= (int(allFuncs.size()) + errorFuncsPerCase-1) / errorFuncsPerCase;
1796
1797			addChild(filtering);
1798
1799			for (int caseNdx = 0; caseNdx < de::min(caseCount, maxFilteringCaseCount); caseNdx++)
1800			{
1801				const int			start		= caseNdx*errorFuncsPerCase;
1802				const int			end			= de::min((caseNdx+1)*errorFuncsPerCase, int(allFuncs.size()));
1803				const string		name		= "case_" + de::toString(caseNdx);
1804				vector<TestFunc>	funcs		(allFuncs.begin()+start, allFuncs.begin()+end);
1805
1806				// These produce lots of different message types, thus always include at least one when testing filtering
1807				funcs.insert(funcs.end(), externalFuncs[caseNdx%externalFuncs.size()].function);
1808
1809				filtering->addChild(new FilterCase(m_context, name.c_str(), "DebugMessageControl usage", funcs));
1810			}
1811		}
1812
1813		{
1814			tcu::TestCaseGroup* const	groups					= new tcu::TestCaseGroup(m_testCtx, "error_groups", "Filtering of reported errors with use of Error Groups");
1815			const int					errorFuncsPerCase		= 4;
1816			const int					maxFilteringCaseCount	= 16;
1817			const int					caseCount				= (int(allFuncs.size()) + errorFuncsPerCase-1) / errorFuncsPerCase;
1818
1819			addChild(groups);
1820
1821			for (int caseNdx = 0; caseNdx < caseCount && caseNdx < maxFilteringCaseCount; caseNdx++)
1822			{
1823				const int			start		= caseNdx*errorFuncsPerCase;
1824				const int			end			= de::min((caseNdx+1)*errorFuncsPerCase, int(allFuncs.size()));
1825				const string		name		= ("case_" + de::toString(caseNdx)).c_str();
1826				vector<TestFunc>	funcs		(&allFuncs[0]+start, &allFuncs[0]+end);
1827
1828				// These produce lots of different message types, thus always include at least one when testing filtering
1829				funcs.insert(funcs.end(), externalFuncs[caseNdx%externalFuncs.size()].function);
1830
1831				groups->addChild(new GroupFilterCase(m_context, name.c_str(), "Debug Group usage", funcs));
1832			}
1833		}
1834
1835		{
1836			tcu::TestCaseGroup* const	async				= new tcu::TestCaseGroup(m_testCtx, "async", "Asynchronous message generation");
1837			const int					errorFuncsPerCase	= 2;
1838			const int					maxAsyncCaseCount	= 16;
1839			const int					caseCount			= (int(allFuncs.size()) + errorFuncsPerCase-1) / errorFuncsPerCase;
1840
1841			addChild(async);
1842
1843			for (int caseNdx = 0; caseNdx < caseCount && caseNdx < maxAsyncCaseCount; caseNdx++)
1844			{
1845				const int			start		= caseNdx*errorFuncsPerCase;
1846				const int			end			= de::min((caseNdx+1)*errorFuncsPerCase, int(allFuncs.size()));
1847				const string		name		= ("case_" + de::toString(caseNdx)).c_str();
1848				vector<TestFunc>	funcs		(&allFuncs[0]+start, &allFuncs[0]+end);
1849
1850				if (caseNdx&0x1)
1851					async->addChild(new AsyncCase(m_context, (name+"_callback").c_str(), "Async message generation", funcs, true));
1852				else
1853					async->addChild(new AsyncCase(m_context, (name+"_log").c_str(), "Async message generation", funcs, false));
1854			}
1855		}
1856	}
1857
1858	{
1859		tcu::TestCaseGroup* const labels = new tcu::TestCaseGroup(m_testCtx, "object_labels", "Labeling objects");
1860
1861		const struct
1862		{
1863			GLenum		identifier;
1864			const char*	name;
1865			const char* desc;
1866		} cases[] =
1867		{
1868			{ GL_BUFFER,				"buffer",				"Debug label on a buffer object"				},
1869			{ GL_SHADER,				"shader",				"Debug label on a shader object"				},
1870			{ GL_PROGRAM,				"program",				"Debug label on a program object"				},
1871			{ GL_QUERY,					"query",				"Debug label on a query object"					},
1872			{ GL_PROGRAM_PIPELINE,		"program_pipeline",		"Debug label on a program pipeline object"		},
1873			{ GL_TRANSFORM_FEEDBACK,	"transform_feedback",	"Debug label on a transform feedback object"	},
1874			{ GL_SAMPLER,				"sampler",				"Debug label on a sampler object"				},
1875			{ GL_TEXTURE,				"texture",				"Debug label on a texture object"				},
1876			{ GL_RENDERBUFFER,			"renderbuffer",			"Debug label on a renderbuffer object"			},
1877			{ GL_FRAMEBUFFER,			"framebuffer",			"Debug label on a framebuffer object"			},
1878		};
1879
1880		addChild(labels);
1881
1882		for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(cases); ndx++)
1883			labels->addChild(new LabelCase(m_context, cases[ndx].name, cases[ndx].desc, cases[ndx].identifier));
1884	}
1885}
1886
1887} // Functional
1888} // gles31
1889} // deqp
1890