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