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