1 //
2 // Copyright 2015 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6 
7 // DebugTest.cpp : Tests of the GL_KHR_debug extension
8 
9 #include "test_utils/ANGLETest.h"
10 
11 namespace angle
12 {
13 
14 class DebugTest : public ANGLETest
15 {
16   protected:
DebugTest()17     DebugTest() : mDebugExtensionAvailable(false)
18     {
19         setWindowWidth(128);
20         setWindowHeight(128);
21         setConfigRedBits(8);
22         setConfigGreenBits(8);
23         setConfigBlueBits(8);
24         setConfigAlphaBits(8);
25         setConfigDepthBits(24);
26         setDebugEnabled(true);
27     }
28 
SetUp()29     void SetUp() override
30     {
31         ANGLETest::SetUp();
32 
33         mDebugExtensionAvailable = extensionEnabled("GL_KHR_debug");
34         if (mDebugExtensionAvailable)
35         {
36             glEnable(GL_DEBUG_OUTPUT);
37         }
38     }
39 
40     bool mDebugExtensionAvailable;
41 };
42 
43 struct Message
44 {
45     GLenum source;
46     GLenum type;
47     GLuint id;
48     GLenum severity;
49     std::string message;
50     const void *userParam;
51 };
52 
Callback(GLenum source,GLenum type,GLuint id,GLenum severity,GLsizei length,const GLchar * message,const void * userParam)53 static void GL_APIENTRY Callback(GLenum source,
54                                  GLenum type,
55                                  GLuint id,
56                                  GLenum severity,
57                                  GLsizei length,
58                                  const GLchar *message,
59                                  const void *userParam)
60 {
61     Message m{source, type, id, severity, std::string(message, length), userParam};
62     std::vector<Message> *messages =
63         static_cast<std::vector<Message> *>(const_cast<void *>(userParam));
64     messages->push_back(m);
65 }
66 
67 // Test that all ANGLE back-ends have GL_KHR_debug enabled
TEST_P(DebugTest,Enabled)68 TEST_P(DebugTest, Enabled)
69 {
70     ASSERT_TRUE(mDebugExtensionAvailable);
71 }
72 
73 // Test that when debug output is disabled, no message are outputted
TEST_P(DebugTest,DisabledOutput)74 TEST_P(DebugTest, DisabledOutput)
75 {
76     if (!mDebugExtensionAvailable)
77     {
78         std::cout << "Test skipped because GL_KHR_debug is not available." << std::endl;
79         return;
80     }
81 
82     glDisable(GL_DEBUG_OUTPUT);
83 
84     glDebugMessageInsertKHR(GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_OTHER, 1,
85                             GL_DEBUG_SEVERITY_NOTIFICATION, -1, "discarded");
86 
87     GLint numMessages = 0;
88     glGetIntegerv(GL_DEBUG_LOGGED_MESSAGES, &numMessages);
89     ASSERT_EQ(0, numMessages);
90 
91     std::vector<Message> messages;
92     glDebugMessageCallbackKHR(Callback, &messages);
93     glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
94 
95     ASSERT_EQ(0u, messages.size());
96 }
97 
98 // Test a basic flow of inserting a message and reading it back
TEST_P(DebugTest,InsertMessage)99 TEST_P(DebugTest, InsertMessage)
100 {
101     if (!mDebugExtensionAvailable)
102     {
103         std::cout << "Test skipped because GL_KHR_debug is not available." << std::endl;
104         return;
105     }
106 
107     const GLenum source       = GL_DEBUG_SOURCE_APPLICATION;
108     const GLenum type         = GL_DEBUG_TYPE_OTHER;
109     const GLuint id           = 1;
110     const GLenum severity     = GL_DEBUG_SEVERITY_NOTIFICATION;
111     const std::string message = "Message";
112 
113     glDebugMessageInsertKHR(source, type, id, severity, -1, message.c_str());
114 
115     GLint numMessages = 0;
116     glGetIntegerv(GL_DEBUG_LOGGED_MESSAGES, &numMessages);
117     ASSERT_EQ(1, numMessages);
118 
119     GLint messageLength = 0;
120     glGetIntegerv(GL_DEBUG_NEXT_LOGGED_MESSAGE_LENGTH, &messageLength);
121     EXPECT_EQ(static_cast<GLint>(message.length()), messageLength);
122 
123     GLenum sourceBuf   = 0;
124     GLenum typeBuf     = 0;
125     GLenum idBuf       = 0;
126     GLenum severityBuf = 0;
127     GLsizei lengthBuf = 0;
128     std::vector<char> messageBuf(messageLength + 1);
129     GLuint ret =
130         glGetDebugMessageLogKHR(1, static_cast<GLsizei>(messageBuf.size()), &sourceBuf, &typeBuf,
131                                 &idBuf, &severityBuf, &lengthBuf, messageBuf.data());
132     EXPECT_EQ(1u, ret);
133     EXPECT_EQ(source, sourceBuf);
134     EXPECT_EQ(type, typeBuf);
135     EXPECT_EQ(id, idBuf);
136     EXPECT_EQ(severity, severityBuf);
137     EXPECT_EQ(lengthBuf, messageLength);
138     EXPECT_STREQ(message.c_str(), messageBuf.data());
139 
140     glGetIntegerv(GL_DEBUG_LOGGED_MESSAGES, &numMessages);
141     EXPECT_EQ(0, numMessages);
142 
143     ASSERT_GL_NO_ERROR();
144 }
145 
146 // Test inserting multiple messages
TEST_P(DebugTest,InsertMessageMultiple)147 TEST_P(DebugTest, InsertMessageMultiple)
148 {
149     if (!mDebugExtensionAvailable)
150     {
151         std::cout << "Test skipped because GL_KHR_debug is not available." << std::endl;
152         return;
153     }
154 
155     const GLenum source          = GL_DEBUG_SOURCE_APPLICATION;
156     const GLenum type            = GL_DEBUG_TYPE_OTHER;
157     const GLuint startID         = 1;
158     const GLenum severity        = GL_DEBUG_SEVERITY_NOTIFICATION;
159     const char messageRepeatChar = 'm';
160     const size_t messageCount    = 32;
161 
162     for (size_t i = 0; i < messageCount; i++)
163     {
164         std::string message(i + 1, messageRepeatChar);
165         glDebugMessageInsertKHR(source, type, startID + static_cast<GLuint>(i), severity, -1,
166                                 message.c_str());
167     }
168 
169     GLint numMessages = 0;
170     glGetIntegerv(GL_DEBUG_LOGGED_MESSAGES, &numMessages);
171     ASSERT_EQ(static_cast<GLint>(messageCount), numMessages);
172 
173     for (size_t i = 0; i < messageCount; i++)
174     {
175         glGetIntegerv(GL_DEBUG_LOGGED_MESSAGES, &numMessages);
176         EXPECT_EQ(static_cast<GLint>(messageCount - i), numMessages);
177 
178         std::string expectedMessage(i + 1, messageRepeatChar);
179 
180         GLint messageLength = 0;
181         glGetIntegerv(GL_DEBUG_NEXT_LOGGED_MESSAGE_LENGTH, &messageLength);
182         EXPECT_EQ(static_cast<GLint>(expectedMessage.length()), messageLength);
183 
184         GLenum sourceBuf   = 0;
185         GLenum typeBuf     = 0;
186         GLenum idBuf       = 0;
187         GLenum severityBuf = 0;
188         GLsizei lengthBuf = 0;
189         std::vector<char> messageBuf(messageLength + 1);
190         GLuint ret =
191             glGetDebugMessageLogKHR(1, static_cast<GLsizei>(messageBuf.size()), &sourceBuf,
192                                     &typeBuf, &idBuf, &severityBuf, &lengthBuf, messageBuf.data());
193         EXPECT_EQ(1u, ret);
194         EXPECT_EQ(source, sourceBuf);
195         EXPECT_EQ(type, typeBuf);
196         EXPECT_EQ(startID + i, idBuf);
197         EXPECT_EQ(severity, severityBuf);
198         EXPECT_EQ(lengthBuf, messageLength);
199         EXPECT_STREQ(expectedMessage.c_str(), messageBuf.data());
200     }
201 
202     glGetIntegerv(GL_DEBUG_LOGGED_MESSAGES, &numMessages);
203     EXPECT_EQ(0, numMessages);
204 
205     ASSERT_GL_NO_ERROR();
206 }
207 
208 // Test using a debug callback
TEST_P(DebugTest,DebugCallback)209 TEST_P(DebugTest, DebugCallback)
210 {
211     if (!mDebugExtensionAvailable)
212     {
213         std::cout << "Test skipped because GL_KHR_debug is not available." << std::endl;
214         return;
215     }
216 
217     std::vector<Message> messages;
218 
219     glDebugMessageCallbackKHR(Callback, &messages);
220     glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
221 
222     const GLenum source       = GL_DEBUG_SOURCE_APPLICATION;
223     const GLenum type         = GL_DEBUG_TYPE_OTHER;
224     const GLuint id           = 1;
225     const GLenum severity     = GL_DEBUG_SEVERITY_NOTIFICATION;
226     const std::string message = "Message";
227 
228     glDebugMessageInsertKHR(source, type, id, severity, -1, message.c_str());
229 
230     GLint numMessages = 0;
231     glGetIntegerv(GL_DEBUG_LOGGED_MESSAGES, &numMessages);
232     EXPECT_EQ(0, numMessages);
233 
234     ASSERT_EQ(1u, messages.size());
235 
236     const Message &m = messages.front();
237     EXPECT_EQ(source, m.source);
238     EXPECT_EQ(type, m.type);
239     EXPECT_EQ(id, m.id);
240     EXPECT_EQ(severity, m.severity);
241     EXPECT_EQ(message, m.message);
242 
243     ASSERT_GL_NO_ERROR();
244 }
245 
246 // Test the glGetPointervKHR entry point
TEST_P(DebugTest,GetPointer)247 TEST_P(DebugTest, GetPointer)
248 {
249     if (!mDebugExtensionAvailable)
250     {
251         std::cout << "Test skipped because GL_KHR_debug is not available." << std::endl;
252         return;
253     }
254 
255     std::vector<Message> messages;
256 
257     glDebugMessageCallbackKHR(Callback, &messages);
258 
259     void *callback = nullptr;
260     glGetPointervKHR(GL_DEBUG_CALLBACK_FUNCTION, &callback);
261     EXPECT_EQ(reinterpret_cast<void *>(Callback), callback);
262 
263     void *userData = nullptr;
264     glGetPointervKHR(GL_DEBUG_CALLBACK_USER_PARAM, &userData);
265     EXPECT_EQ(static_cast<void *>(&messages), userData);
266 }
267 
268 // Test usage of message control.  Example taken from GL_KHR_debug spec.
TEST_P(DebugTest,MessageControl1)269 TEST_P(DebugTest, MessageControl1)
270 {
271     if (!mDebugExtensionAvailable)
272     {
273         std::cout << "Test skipped because GL_KHR_debug is not available." << std::endl;
274         return;
275     }
276 
277     std::vector<Message> messages;
278 
279     glDebugMessageCallbackKHR(Callback, &messages);
280     glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
281 
282     // Setup of the default active debug group: Filter everything in
283     glDebugMessageControlKHR(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, NULL, GL_TRUE);
284 
285     // Generate a debug marker debug output message
286     glDebugMessageInsertKHR(GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_MARKER, 100,
287                             GL_DEBUG_SEVERITY_NOTIFICATION, -1, "Message 1");
288 
289     // Push debug group 1
290     glPushDebugGroupKHR(GL_DEBUG_SOURCE_APPLICATION, 1, -1, "Message 2");
291 
292     // Setup of the debug group 1: Filter everything out
293     glDebugMessageControlKHR(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, NULL, GL_FALSE);
294 
295     // This message won't appear in the debug output log of
296     glDebugMessageInsertKHR(GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_MARKER, 100,
297                             GL_DEBUG_SEVERITY_NOTIFICATION, -1, "Message 3");
298 
299     // Pop debug group 1, restore the volume control of the default debug group.
300     glPopDebugGroupKHR();
301 
302     // Generate a debug marker debug output message
303     glDebugMessageInsertKHR(GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_MARKER, 100,
304                             GL_DEBUG_SEVERITY_NOTIFICATION, -1, "Message 5");
305 
306     // Expected debug output from the GL implementation
307     // Message 1
308     // Message 2
309     // Message 2
310     // Message 5
311     EXPECT_EQ(4u, messages.size());
312     EXPECT_STREQ(messages[0].message.c_str(), "Message 1");
313     EXPECT_STREQ(messages[1].message.c_str(), "Message 2");
314     EXPECT_STREQ(messages[2].message.c_str(), "Message 2");
315     EXPECT_STREQ(messages[3].message.c_str(), "Message 5");
316 
317     ASSERT_GL_NO_ERROR();
318 }
319 
320 // Test usage of message control.  Example taken from GL_KHR_debug spec.
TEST_P(DebugTest,MessageControl2)321 TEST_P(DebugTest, MessageControl2)
322 {
323     if (!mDebugExtensionAvailable)
324     {
325         std::cout << "Test skipped because GL_KHR_debug is not available." << std::endl;
326         return;
327     }
328 
329     std::vector<Message> messages;
330 
331     glDebugMessageCallbackKHR(Callback, &messages);
332     glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
333 
334     // Setup the control of de debug output for the default debug group
335     glDebugMessageControlKHR(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, NULL, GL_FALSE);
336     glDebugMessageControlKHR(GL_DEBUG_SOURCE_THIRD_PARTY, GL_DONT_CARE, GL_DONT_CARE, 0, NULL,
337                              GL_FALSE);
338     std::vector<GLuint> ids0 = {1234, 2345, 3456, 4567};
339     glDebugMessageControlKHR(GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_OTHER, GL_DONT_CARE,
340                              static_cast<GLuint>(ids0.size()), ids0.data(), GL_FALSE);
341     glDebugMessageControlKHR(GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_PORTABILITY, GL_DONT_CARE,
342                              static_cast<GLuint>(ids0.size()), ids0.data(), GL_FALSE);
343 
344     // Push debug group 1
345     // Inherit of the default debug group debug output volume control
346     // Filtered out by glDebugMessageControl
347     glPushDebugGroupKHR(GL_DEBUG_SOURCE_APPLICATION, 1, -1, "Message 1");
348 
349     // In this section of the code, we are interested in performances.
350     glDebugMessageControlKHR(GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_PERFORMANCE, GL_DONT_CARE,
351                              0, NULL, GL_TRUE);
352     // But we already identify that some messages are not really useful for us.
353     std::vector<GLuint> ids1 = {5678, 6789};
354     glDebugMessageControlKHR(GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_OTHER, GL_DONT_CARE,
355                              static_cast<GLuint>(ids1.size()), ids1.data(), GL_FALSE);
356 
357     glDebugMessageInsertKHR(GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_PERFORMANCE, 1357,
358                             GL_DEBUG_SEVERITY_MEDIUM, -1, "Message 2");
359     glDebugMessageInsertKHR(GL_DEBUG_SOURCE_THIRD_PARTY,  // We still filter out these messages.
360                             GL_DEBUG_TYPE_OTHER, 3579, GL_DEBUG_SEVERITY_MEDIUM, -1, "Message 3");
361 
362     glPopDebugGroupKHR();
363 
364     // Expected debug output from the GL implementation
365     // Message 2
366     EXPECT_EQ(1u, messages.size());
367     EXPECT_STREQ(messages[0].message.c_str(), "Message 2");
368 
369     ASSERT_GL_NO_ERROR();
370 }
371 
372 // Test basic usage of setting and getting labels
TEST_P(DebugTest,ObjectLabels)373 TEST_P(DebugTest, ObjectLabels)
374 {
375     if (!mDebugExtensionAvailable)
376     {
377         std::cout << "Test skipped because GL_KHR_debug is not available." << std::endl;
378         return;
379     }
380 
381     GLuint renderbuffer = 0;
382     glGenRenderbuffers(1, &renderbuffer);
383     glBindRenderbuffer(GL_RENDERBUFFER, renderbuffer);
384 
385     const std::string &label = "renderbuffer";
386     glObjectLabelKHR(GL_RENDERBUFFER, renderbuffer, -1, label.c_str());
387 
388     std::vector<char> labelBuf(label.length() + 1);
389     GLsizei labelLengthBuf = 0;
390     glGetObjectLabelKHR(GL_RENDERBUFFER, renderbuffer, static_cast<GLsizei>(labelBuf.size()),
391                         &labelLengthBuf, labelBuf.data());
392 
393     EXPECT_EQ(static_cast<GLsizei>(label.length()), labelLengthBuf);
394     EXPECT_STREQ(label.c_str(), labelBuf.data());
395 
396     ASSERT_GL_NO_ERROR();
397 
398     glDeleteRenderbuffers(1, &renderbuffer);
399 
400     glObjectLabelKHR(GL_RENDERBUFFER, renderbuffer, -1, label.c_str());
401     EXPECT_GL_ERROR(GL_INVALID_VALUE);
402 
403     glGetObjectLabelKHR(GL_RENDERBUFFER, renderbuffer, static_cast<GLsizei>(labelBuf.size()),
404                         &labelLengthBuf, labelBuf.data());
405     EXPECT_GL_ERROR(GL_INVALID_VALUE);
406 }
407 
408 // Test basic usage of setting and getting labels
TEST_P(DebugTest,ObjectPtrLabels)409 TEST_P(DebugTest, ObjectPtrLabels)
410 {
411     if (!mDebugExtensionAvailable || getClientMajorVersion() < 3)
412     {
413         std::cout << "Test skipped because GL_KHR_debug or ES3 is not available." << std::endl;
414         return;
415     }
416 
417     GLsync sync = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
418 
419     const std::string &label = "sync";
420     glObjectPtrLabelKHR(sync, -1, label.c_str());
421 
422     std::vector<char> labelBuf(label.length() + 1);
423     GLsizei labelLengthBuf = 0;
424     glGetObjectPtrLabelKHR(sync, static_cast<GLsizei>(labelBuf.size()), &labelLengthBuf,
425                            labelBuf.data());
426 
427     EXPECT_EQ(static_cast<GLsizei>(label.length()), labelLengthBuf);
428     EXPECT_STREQ(label.c_str(), labelBuf.data());
429 
430     ASSERT_GL_NO_ERROR();
431 
432     glDeleteSync(sync);
433 
434     glObjectPtrLabelKHR(sync, -1, label.c_str());
435     EXPECT_GL_ERROR(GL_INVALID_VALUE);
436 
437     glGetObjectPtrLabelKHR(sync, static_cast<GLsizei>(labelBuf.size()), &labelLengthBuf,
438                            labelBuf.data());
439     EXPECT_GL_ERROR(GL_INVALID_VALUE);
440 }
441 
442 // Use this to select which configurations (e.g. which renderer, which GLES major version) these
443 // tests should be run against.
444 ANGLE_INSTANTIATE_TEST(DebugTest,
445                        ES2_D3D9(),
446                        ES2_D3D11(),
447                        ES3_D3D11(),
448                        ES2_OPENGL(),
449                        ES3_OPENGL());
450 
451 }  // namespace angle
452