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