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