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