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