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