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