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