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