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