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