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