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