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