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 "common/debug.h"
10 #include "test_utils/ANGLETest.h"
11 #include "test_utils/gl_raii.h"
12
13 namespace angle
14 {
15 constexpr char kBufferObjLabel[] = "buffer";
16 constexpr char kShaderObjLabel[] = "shader";
17 constexpr char kProgramObjLabel[] = "program";
18 constexpr char kVertexArrayObjLabel[] = "vertexarray";
19 constexpr char kQueryObjLabel[] = "query";
20 constexpr char kProgramPipelineObjLabel[] = "programpipeline";
21 constexpr GLenum kObjectTypes[] = {GL_BUFFER_OBJECT_EXT, GL_SHADER_OBJECT_EXT,
22 GL_PROGRAM_OBJECT_EXT, GL_QUERY_OBJECT_EXT,
23 GL_PROGRAM_PIPELINE_OBJECT_EXT, GL_VERTEX_ARRAY_OBJECT_EXT};
24
25 class DebugTest : public ANGLETest<>
26 {
27 protected:
DebugTest()28 DebugTest() : mDebugExtensionAvailable(false)
29 {
30 setWindowWidth(128);
31 setWindowHeight(128);
32 setConfigRedBits(8);
33 setConfigGreenBits(8);
34 setConfigBlueBits(8);
35 setConfigAlphaBits(8);
36 setConfigDepthBits(24);
37 setDebugEnabled(true);
38 }
39
testSetUp()40 void testSetUp() override
41 {
42 mDebugExtensionAvailable = IsGLExtensionEnabled("GL_KHR_debug");
43 if (mDebugExtensionAvailable)
44 {
45 glEnable(GL_DEBUG_OUTPUT);
46 }
47 }
48
49 bool mDebugExtensionAvailable;
50 };
51
createGLObjectAndLabel(GLenum identifier,GLuint & object,const char ** label)52 void createGLObjectAndLabel(GLenum identifier, GLuint &object, const char **label)
53 {
54 switch (identifier)
55 {
56 case GL_BUFFER_OBJECT_EXT:
57 glGenBuffers(1, &object);
58 glBindBuffer(GL_ARRAY_BUFFER, object);
59 *label = kBufferObjLabel;
60 break;
61 case GL_SHADER_OBJECT_EXT:
62 object = glCreateShader(GL_VERTEX_SHADER);
63 *label = kShaderObjLabel;
64 break;
65 case GL_PROGRAM_OBJECT_EXT:
66 object = glCreateProgram();
67 *label = kProgramObjLabel;
68 break;
69 case GL_VERTEX_ARRAY_OBJECT_EXT:
70 glGenVertexArrays(1, &object);
71 glBindVertexArray(object);
72 *label = kVertexArrayObjLabel;
73 break;
74 case GL_QUERY_OBJECT_EXT:
75 glGenQueries(1, &object);
76 glBeginQuery(GL_ANY_SAMPLES_PASSED, object);
77 *label = kQueryObjLabel;
78 break;
79 case GL_PROGRAM_PIPELINE_OBJECT_EXT:
80 glGenProgramPipelines(1, &object);
81 glBindProgramPipeline(object);
82 *label = kProgramPipelineObjLabel;
83 break;
84 default:
85 UNREACHABLE();
86 break;
87 }
88 }
89
deleteGLObject(GLenum identifier,GLuint & object)90 void deleteGLObject(GLenum identifier, GLuint &object)
91 {
92 switch (identifier)
93 {
94 case GL_BUFFER_OBJECT_EXT:
95 glDeleteBuffers(1, &object);
96 break;
97 case GL_SHADER_OBJECT_EXT:
98 glDeleteShader(object);
99 break;
100 case GL_PROGRAM_OBJECT_EXT:
101 glDeleteProgram(object);
102 break;
103 case GL_VERTEX_ARRAY_OBJECT_EXT:
104 glDeleteVertexArrays(1, &object);
105 break;
106 case GL_QUERY_OBJECT_EXT:
107 glEndQuery(GL_ANY_SAMPLES_PASSED);
108 glDeleteQueries(1, &object);
109 break;
110 case GL_PROGRAM_PIPELINE_OBJECT_EXT:
111 glDeleteProgramPipelines(1, &object);
112 break;
113 default:
114 UNREACHABLE();
115 break;
116 }
117 }
118
119 // Test basic usage of setting and getting labels using GL_EXT_debug_label
TEST_P(DebugTest,ObjectLabelsEXT)120 TEST_P(DebugTest, ObjectLabelsEXT)
121 {
122 ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_debug_label"));
123
124 for (const GLenum identifier : kObjectTypes)
125 {
126 bool skip = false;
127 switch (identifier)
128 {
129 case GL_PROGRAM_PIPELINE_OBJECT_EXT:
130 if (!(getClientMajorVersion() >= 3 && getClientMinorVersion() >= 1) ||
131 !IsGLExtensionEnabled("GL_EXT_separate_shader_objects"))
132 {
133 skip = true;
134 }
135 break;
136 case GL_QUERY_OBJECT_EXT:
137 // GLES3 context is required for glGenQueries()
138 if (getClientMajorVersion() < 3 ||
139 !IsGLExtensionEnabled("GL_EXT_occlusion_query_boolean"))
140 {
141 skip = true;
142 }
143 break;
144 case GL_VERTEX_ARRAY_OBJECT_EXT:
145 if (getClientMajorVersion() < 3)
146 {
147 skip = true;
148 }
149 break;
150 default:
151 break;
152 }
153
154 // if object enum is not supported, move on to the next object type
155 if (skip)
156 {
157 continue;
158 }
159
160 GLuint object;
161 const char *label;
162 createGLObjectAndLabel(identifier, object, &label);
163
164 glLabelObjectEXT(identifier, object, 0, label);
165 ASSERT_GL_NO_ERROR();
166
167 std::vector<char> labelBuf(strlen(label) + 1);
168 GLsizei labelLengthBuf = 0;
169 glGetObjectLabelEXT(identifier, object, static_cast<GLsizei>(labelBuf.size()),
170 &labelLengthBuf, labelBuf.data());
171 ASSERT_GL_NO_ERROR();
172
173 EXPECT_EQ(static_cast<GLsizei>(strlen(label)), labelLengthBuf);
174 EXPECT_STREQ(label, labelBuf.data());
175
176 ASSERT_GL_NO_ERROR();
177
178 deleteGLObject(identifier, object);
179
180 glLabelObjectEXT(identifier, object, 0, label);
181 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
182
183 glGetObjectLabelEXT(identifier, object, static_cast<GLsizei>(labelBuf.size()),
184 &labelLengthBuf, labelBuf.data());
185 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
186 }
187 }
188
189 class DebugTestES3 : public DebugTest
190 {};
191
192 class DebugTestES32 : public DebugTestES3
193 {
testSetUp()194 void testSetUp() override { ; }
195 };
196
197 struct Message
198 {
199 GLenum source;
200 GLenum type;
201 GLuint id;
202 GLenum severity;
203 std::string message;
204 const void *userParam;
205 };
206
Callback(GLenum source,GLenum type,GLuint id,GLenum severity,GLsizei length,const GLchar * message,const void * userParam)207 static void GL_APIENTRY Callback(GLenum source,
208 GLenum type,
209 GLuint id,
210 GLenum severity,
211 GLsizei length,
212 const GLchar *message,
213 const void *userParam)
214 {
215 Message m{source, type, id, severity, std::string(message, length), userParam};
216 std::vector<Message> *messages =
217 static_cast<std::vector<Message> *>(const_cast<void *>(userParam));
218 messages->push_back(m);
219 }
220
221 // Test that all ANGLE back-ends have GL_KHR_debug enabled
TEST_P(DebugTestES3,Enabled)222 TEST_P(DebugTestES3, Enabled)
223 {
224 ASSERT_TRUE(mDebugExtensionAvailable);
225 }
226
227 // Test that when debug output is disabled, no message are outputted
TEST_P(DebugTestES3,DisabledOutput)228 TEST_P(DebugTestES3, DisabledOutput)
229 {
230 ANGLE_SKIP_TEST_IF(!mDebugExtensionAvailable);
231
232 glDisable(GL_DEBUG_OUTPUT);
233
234 glDebugMessageInsertKHR(GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_OTHER, 1,
235 GL_DEBUG_SEVERITY_NOTIFICATION, -1, "discarded");
236
237 GLint numMessages = 0;
238 glGetIntegerv(GL_DEBUG_LOGGED_MESSAGES, &numMessages);
239 ASSERT_EQ(0, numMessages);
240
241 std::vector<Message> messages;
242 glDebugMessageCallbackKHR(Callback, &messages);
243 glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
244
245 ASSERT_EQ(0u, messages.size());
246 }
247
248 // Test a basic flow of inserting a message and reading it back
TEST_P(DebugTestES3,InsertMessage)249 TEST_P(DebugTestES3, InsertMessage)
250 {
251 ANGLE_SKIP_TEST_IF(!mDebugExtensionAvailable);
252
253 const GLenum source = GL_DEBUG_SOURCE_APPLICATION;
254 const GLenum type = GL_DEBUG_TYPE_OTHER;
255 const GLuint id = 1;
256 const GLenum severity = GL_DEBUG_SEVERITY_NOTIFICATION;
257 const std::string message = "Message";
258
259 glDebugMessageInsertKHR(source, type, id, severity, -1, message.c_str());
260
261 GLint numMessages = 0;
262 glGetIntegerv(GL_DEBUG_LOGGED_MESSAGES, &numMessages);
263 ASSERT_EQ(1, numMessages);
264
265 GLint messageLength = 0;
266 glGetIntegerv(GL_DEBUG_NEXT_LOGGED_MESSAGE_LENGTH, &messageLength);
267 EXPECT_EQ(static_cast<GLint>(message.length()) + 1, messageLength);
268
269 GLenum sourceBuf = 0;
270 GLenum typeBuf = 0;
271 GLenum idBuf = 0;
272 GLenum severityBuf = 0;
273 GLsizei lengthBuf = 0;
274 std::vector<char> messageBuf(messageLength);
275 GLuint ret =
276 glGetDebugMessageLogKHR(1, static_cast<GLsizei>(messageBuf.size()), &sourceBuf, &typeBuf,
277 &idBuf, &severityBuf, &lengthBuf, messageBuf.data());
278 EXPECT_EQ(1u, ret);
279 EXPECT_EQ(source, sourceBuf);
280 EXPECT_EQ(type, typeBuf);
281 EXPECT_EQ(id, idBuf);
282 EXPECT_EQ(severity, severityBuf);
283 EXPECT_EQ(lengthBuf, messageLength);
284 EXPECT_STREQ(message.c_str(), messageBuf.data());
285
286 glGetIntegerv(GL_DEBUG_LOGGED_MESSAGES, &numMessages);
287 EXPECT_EQ(0, numMessages);
288
289 ASSERT_GL_NO_ERROR();
290 }
291
292 // Test inserting multiple messages
TEST_P(DebugTestES3,InsertMessageMultiple)293 TEST_P(DebugTestES3, InsertMessageMultiple)
294 {
295 ANGLE_SKIP_TEST_IF(!mDebugExtensionAvailable);
296
297 const GLenum source = GL_DEBUG_SOURCE_APPLICATION;
298 const GLenum type = GL_DEBUG_TYPE_OTHER;
299 const GLuint startID = 1;
300 const GLenum severity = GL_DEBUG_SEVERITY_NOTIFICATION;
301 const char messageRepeatChar = 'm';
302 const size_t messageCount = 32;
303
304 for (size_t i = 0; i < messageCount; i++)
305 {
306 std::string message(i + 1, messageRepeatChar);
307 glDebugMessageInsertKHR(source, type, startID + static_cast<GLuint>(i), severity, -1,
308 message.c_str());
309 }
310
311 GLint numMessages = 0;
312 glGetIntegerv(GL_DEBUG_LOGGED_MESSAGES, &numMessages);
313 ASSERT_EQ(static_cast<GLint>(messageCount), numMessages);
314
315 for (size_t i = 0; i < messageCount; i++)
316 {
317 glGetIntegerv(GL_DEBUG_LOGGED_MESSAGES, &numMessages);
318 EXPECT_EQ(static_cast<GLint>(messageCount - i), numMessages);
319
320 std::string expectedMessage(i + 1, messageRepeatChar);
321
322 GLint messageLength = 0;
323 glGetIntegerv(GL_DEBUG_NEXT_LOGGED_MESSAGE_LENGTH, &messageLength);
324 EXPECT_EQ(static_cast<GLint>(expectedMessage.length()) + 1, messageLength);
325
326 GLenum sourceBuf = 0;
327 GLenum typeBuf = 0;
328 GLenum idBuf = 0;
329 GLenum severityBuf = 0;
330 GLsizei lengthBuf = 0;
331 std::vector<char> messageBuf(messageLength);
332 GLuint ret =
333 glGetDebugMessageLogKHR(1, static_cast<GLsizei>(messageBuf.size()), &sourceBuf,
334 &typeBuf, &idBuf, &severityBuf, &lengthBuf, messageBuf.data());
335 EXPECT_EQ(1u, ret);
336 EXPECT_EQ(source, sourceBuf);
337 EXPECT_EQ(type, typeBuf);
338 EXPECT_EQ(startID + i, idBuf);
339 EXPECT_EQ(severity, severityBuf);
340 EXPECT_EQ(lengthBuf, messageLength);
341 EXPECT_STREQ(expectedMessage.c_str(), messageBuf.data());
342 }
343
344 glGetIntegerv(GL_DEBUG_LOGGED_MESSAGES, &numMessages);
345 EXPECT_EQ(0, numMessages);
346
347 ASSERT_GL_NO_ERROR();
348 }
349
350 // Test using a debug callback
TEST_P(DebugTestES3,DebugCallback)351 TEST_P(DebugTestES3, DebugCallback)
352 {
353 ANGLE_SKIP_TEST_IF(!mDebugExtensionAvailable);
354
355 std::vector<Message> messages;
356
357 glDebugMessageCallbackKHR(Callback, &messages);
358 glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
359
360 const GLenum source = GL_DEBUG_SOURCE_APPLICATION;
361 const GLenum type = GL_DEBUG_TYPE_OTHER;
362 const GLuint id = 1;
363 const GLenum severity = GL_DEBUG_SEVERITY_NOTIFICATION;
364 const std::string message = "Message";
365
366 glDebugMessageInsertKHR(source, type, id, severity, -1, message.c_str());
367
368 GLint numMessages = 0;
369 glGetIntegerv(GL_DEBUG_LOGGED_MESSAGES, &numMessages);
370 EXPECT_EQ(0, numMessages);
371
372 ASSERT_EQ(1u, messages.size());
373
374 const Message &m = messages.front();
375 EXPECT_EQ(source, m.source);
376 EXPECT_EQ(type, m.type);
377 EXPECT_EQ(id, m.id);
378 EXPECT_EQ(severity, m.severity);
379 EXPECT_EQ(message, m.message);
380
381 ASSERT_GL_NO_ERROR();
382 }
383
384 // Test the glGetPointervKHR entry point
TEST_P(DebugTestES3,GetPointer)385 TEST_P(DebugTestES3, GetPointer)
386 {
387 ANGLE_SKIP_TEST_IF(!mDebugExtensionAvailable);
388
389 std::vector<Message> messages;
390
391 glDebugMessageCallbackKHR(Callback, &messages);
392
393 void *callback = nullptr;
394 glGetPointervKHR(GL_DEBUG_CALLBACK_FUNCTION, &callback);
395 EXPECT_EQ(reinterpret_cast<void *>(Callback), callback);
396
397 void *userData = nullptr;
398 glGetPointervKHR(GL_DEBUG_CALLBACK_USER_PARAM, &userData);
399 EXPECT_EQ(static_cast<void *>(&messages), userData);
400 }
401
402 // Test usage of message control. Example taken from GL_KHR_debug spec.
TEST_P(DebugTestES3,MessageControl1)403 TEST_P(DebugTestES3, MessageControl1)
404 {
405 ANGLE_SKIP_TEST_IF(!mDebugExtensionAvailable);
406
407 std::vector<Message> messages;
408
409 glDebugMessageCallbackKHR(Callback, &messages);
410 glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
411
412 // Setup of the default active debug group: Filter everything in
413 glDebugMessageControlKHR(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, nullptr, GL_TRUE);
414
415 // Generate a debug marker debug output message
416 glDebugMessageInsertKHR(GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_MARKER, 100,
417 GL_DEBUG_SEVERITY_NOTIFICATION, -1, "Message 1");
418
419 // Push debug group 1
420 glPushDebugGroupKHR(GL_DEBUG_SOURCE_APPLICATION, 1, -1, "Message 2");
421
422 // Setup of the debug group 1: Filter everything out
423 glDebugMessageControlKHR(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, nullptr, GL_FALSE);
424
425 // This message won't appear in the debug output log of
426 glDebugMessageInsertKHR(GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_MARKER, 100,
427 GL_DEBUG_SEVERITY_NOTIFICATION, -1, "Message 3");
428
429 // Pop debug group 1, restore the volume control of the default debug group.
430 glPopDebugGroupKHR();
431
432 // Generate a debug marker debug output message
433 glDebugMessageInsertKHR(GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_MARKER, 100,
434 GL_DEBUG_SEVERITY_NOTIFICATION, -1, "Message 5");
435
436 // Expected debug output from the GL implementation
437 // Message 1
438 // Message 2
439 // Message 2
440 // Message 5
441 EXPECT_EQ(4u, messages.size());
442 EXPECT_STREQ(messages[0].message.c_str(), "Message 1");
443 EXPECT_STREQ(messages[1].message.c_str(), "Message 2");
444 EXPECT_STREQ(messages[2].message.c_str(), "Message 2");
445 EXPECT_STREQ(messages[3].message.c_str(), "Message 5");
446
447 ASSERT_GL_NO_ERROR();
448 }
449
450 // Test usage of message control. Example taken from GL_KHR_debug spec.
TEST_P(DebugTestES3,MessageControl2)451 TEST_P(DebugTestES3, MessageControl2)
452 {
453 ANGLE_SKIP_TEST_IF(!mDebugExtensionAvailable);
454
455 std::vector<Message> messages;
456
457 glDebugMessageCallbackKHR(Callback, &messages);
458 glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
459
460 // Setup the control of de debug output for the default debug group
461 glDebugMessageControlKHR(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, nullptr, GL_FALSE);
462 glDebugMessageControlKHR(GL_DEBUG_SOURCE_THIRD_PARTY, GL_DONT_CARE, GL_DONT_CARE, 0, nullptr,
463 GL_FALSE);
464 std::vector<GLuint> ids0 = {1234, 2345, 3456, 4567};
465 glDebugMessageControlKHR(GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_OTHER, GL_DONT_CARE,
466 static_cast<GLuint>(ids0.size()), ids0.data(), GL_FALSE);
467 glDebugMessageControlKHR(GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_PORTABILITY, GL_DONT_CARE,
468 static_cast<GLuint>(ids0.size()), ids0.data(), GL_FALSE);
469
470 // Push debug group 1
471 // Inherit of the default debug group debug output volume control
472 // Filtered out by glDebugMessageControl
473 glPushDebugGroupKHR(GL_DEBUG_SOURCE_APPLICATION, 1, -1, "Message 1");
474
475 // In this section of the code, we are interested in performances.
476 glDebugMessageControlKHR(GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_PERFORMANCE, GL_DONT_CARE,
477 0, nullptr, GL_TRUE);
478 // But we already identify that some messages are not really useful for us.
479 std::vector<GLuint> ids1 = {5678, 6789};
480 glDebugMessageControlKHR(GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_OTHER, GL_DONT_CARE,
481 static_cast<GLuint>(ids1.size()), ids1.data(), GL_FALSE);
482
483 glDebugMessageInsertKHR(GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_PERFORMANCE, 1357,
484 GL_DEBUG_SEVERITY_MEDIUM, -1, "Message 2");
485 glDebugMessageInsertKHR(GL_DEBUG_SOURCE_THIRD_PARTY, // We still filter out these messages.
486 GL_DEBUG_TYPE_OTHER, 3579, GL_DEBUG_SEVERITY_MEDIUM, -1, "Message 3");
487
488 glPopDebugGroupKHR();
489
490 // Expected debug output from the GL implementation
491 // Message 2
492 EXPECT_EQ(1u, messages.size());
493 EXPECT_STREQ(messages[0].message.c_str(), "Message 2");
494
495 ASSERT_GL_NO_ERROR();
496 }
497
498 // Test basic usage of setting and getting labels
TEST_P(DebugTestES3,ObjectLabelsKHR)499 TEST_P(DebugTestES3, ObjectLabelsKHR)
500 {
501 ANGLE_SKIP_TEST_IF(!mDebugExtensionAvailable);
502
503 GLuint renderbuffer = 0;
504 glGenRenderbuffers(1, &renderbuffer);
505 glBindRenderbuffer(GL_RENDERBUFFER, renderbuffer);
506
507 const std::string &label = "renderbuffer";
508 glObjectLabelKHR(GL_RENDERBUFFER, renderbuffer, -1, label.c_str());
509
510 std::vector<char> labelBuf(label.length() + 1);
511 GLsizei labelLengthBuf = 0;
512 glGetObjectLabelKHR(GL_RENDERBUFFER, renderbuffer, static_cast<GLsizei>(labelBuf.size()),
513 &labelLengthBuf, labelBuf.data());
514
515 EXPECT_EQ(static_cast<GLsizei>(label.length()), labelLengthBuf);
516 EXPECT_STREQ(label.c_str(), labelBuf.data());
517
518 ASSERT_GL_NO_ERROR();
519
520 glDeleteRenderbuffers(1, &renderbuffer);
521
522 glObjectLabelKHR(GL_RENDERBUFFER, renderbuffer, -1, label.c_str());
523 EXPECT_GL_ERROR(GL_INVALID_VALUE);
524
525 glGetObjectLabelKHR(GL_RENDERBUFFER, renderbuffer, static_cast<GLsizei>(labelBuf.size()),
526 &labelLengthBuf, labelBuf.data());
527 EXPECT_GL_ERROR(GL_INVALID_VALUE);
528 }
529
530 // Test basic usage of setting and getting labels
TEST_P(DebugTestES3,ObjectPtrLabelsKHR)531 TEST_P(DebugTestES3, ObjectPtrLabelsKHR)
532 {
533 ANGLE_SKIP_TEST_IF(!mDebugExtensionAvailable);
534
535 GLsync sync = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
536
537 const std::string &label = "sync";
538 glObjectPtrLabelKHR(sync, -1, label.c_str());
539
540 std::vector<char> labelBuf(label.length() + 1);
541 GLsizei labelLengthBuf = 0;
542 glGetObjectPtrLabelKHR(sync, static_cast<GLsizei>(labelBuf.size()), &labelLengthBuf,
543 labelBuf.data());
544
545 EXPECT_EQ(static_cast<GLsizei>(label.length()), labelLengthBuf);
546 EXPECT_STREQ(label.c_str(), labelBuf.data());
547
548 ASSERT_GL_NO_ERROR();
549
550 glDeleteSync(sync);
551
552 glObjectPtrLabelKHR(sync, -1, label.c_str());
553 EXPECT_GL_ERROR(GL_INVALID_VALUE);
554
555 glGetObjectPtrLabelKHR(sync, static_cast<GLsizei>(labelBuf.size()), &labelLengthBuf,
556 labelBuf.data());
557 EXPECT_GL_ERROR(GL_INVALID_VALUE);
558 }
559
560 // Test setting labels before, during and after rendering. The debug markers can be validated by
561 // capturing this test under a graphics debugger.
TEST_P(DebugTestES3,Rendering)562 TEST_P(DebugTestES3, Rendering)
563 {
564 ANGLE_SKIP_TEST_IF(!mDebugExtensionAvailable);
565
566 // The test produces the following hierarchy:
567 //
568 // Group: Before Draw
569 // Message: Before Draw Marker
570 // Message: In Group 1 Marker
571 // glDrawArrays
572 // Group: After Draw 1
573 // glDrawArrays
574 // Message: In Group 2 Marker
575 //
576 // glCopyTexImage <-- this breaks the render pass
577 //
578 // glDrawArrays
579 // End Group
580 //
581 // glCopyTexImage <-- this breaks the render pass
582 //
583 // Group: After Draw 2
584 // glDrawArrays
585 //
586 // glCopyTexImage <-- this breaks the render pass
587 //
588 // Message: In Group 3 Marker
589 // End Group
590 // Message: After Draw Marker
591 // End Group
592 const std::string beforeDrawGroup = "Before Draw";
593 const std::string drawGroup1 = "Group 1";
594 const std::string drawGroup2 = "Group 2";
595
596 const std::string beforeDrawMarker = "Before Draw Marker";
597 const std::string inGroup1Marker = "In Group 1 Marker";
598 const std::string inGroup2Marker = "In Group 2 Marker";
599 const std::string inGroup3Marker = "In Group 3 Marker";
600 const std::string afterDrawMarker = "After Draw Marker";
601
602 ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Simple(), essl1_shaders::fs::Blue());
603 glUseProgram(program);
604
605 glPushDebugGroupKHR(GL_DEBUG_SOURCE_THIRD_PARTY, 0, -1, beforeDrawGroup.c_str());
606 glDebugMessageInsertKHR(GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_PERFORMANCE, 0,
607 GL_DEBUG_SEVERITY_NOTIFICATION, -1, beforeDrawMarker.c_str());
608 {
609 glDebugMessageInsertKHR(GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_MARKER, 0,
610 GL_DEBUG_SEVERITY_LOW, -1, inGroup1Marker.c_str());
611
612 glDrawArrays(GL_TRIANGLES, 0, 6);
613
614 glPushDebugGroupKHR(GL_DEBUG_SOURCE_APPLICATION, 0, -1, drawGroup1.c_str());
615 {
616 glDrawArrays(GL_TRIANGLES, 0, 6);
617
618 glDebugMessageInsertKHR(GL_DEBUG_SOURCE_THIRD_PARTY, GL_DEBUG_TYPE_PORTABILITY, 0,
619 GL_DEBUG_SEVERITY_MEDIUM, -1, inGroup2Marker.c_str());
620
621 GLTexture texture;
622 glBindTexture(GL_TEXTURE_2D, texture);
623 glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 0, 0, 1, 1, 0);
624
625 glDrawArrays(GL_TRIANGLES, 0, 6);
626 }
627 glPopDebugGroupKHR();
628
629 glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 0, 0, 2, 2, 0);
630
631 glPushDebugGroupKHR(GL_DEBUG_SOURCE_THIRD_PARTY, 0, -1, drawGroup2.c_str());
632 {
633 glDrawArrays(GL_TRIANGLES, 0, 6);
634
635 glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 0, 0, 3, 3, 0);
636
637 glDebugMessageInsertKHR(GL_DEBUG_SOURCE_THIRD_PARTY, GL_DEBUG_TYPE_OTHER, 0,
638 GL_DEBUG_SEVERITY_HIGH, -1, inGroup3Marker.c_str());
639 }
640 glPopGroupMarkerEXT();
641
642 glDebugMessageInsertKHR(GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0,
643 GL_DEBUG_SEVERITY_HIGH, -1, afterDrawMarker.c_str());
644 }
645 glPopGroupMarkerEXT();
646
647 ASSERT_GL_NO_ERROR();
648 }
649
650 // Simple test for gl[Push, Pop]DebugGroup using ES32 core APIs
TEST_P(DebugTestES32,DebugGroup)651 TEST_P(DebugTestES32, DebugGroup)
652 {
653 const std::string testDrawGroup = "Test Draw Group";
654
655 // Pop without a push should generate GL_STACK_UNDERFLOW error
656 glPopDebugGroup();
657 EXPECT_GL_ERROR(GL_STACK_UNDERFLOW);
658
659 // Push a test debug group and expect no error
660 glPushDebugGroup(GL_DEBUG_SOURCE_THIRD_PARTY, 0, -1, testDrawGroup.c_str());
661 ASSERT_GL_NO_ERROR();
662
663 // Pop the test debug group and expect no error
664 glPopDebugGroup();
665 ASSERT_GL_NO_ERROR();
666 }
667
668 // Simple test for setting and getting labels using ES32 core APIs
TEST_P(DebugTestES32,ObjectLabels)669 TEST_P(DebugTestES32, ObjectLabels)
670 {
671 GLuint renderbuffer = 0;
672 glGenRenderbuffers(1, &renderbuffer);
673 glBindRenderbuffer(GL_RENDERBUFFER, renderbuffer);
674
675 const std::string &label = "renderbuffer";
676 glObjectLabel(GL_RENDERBUFFER, renderbuffer, -1, label.c_str());
677
678 std::vector<char> labelBuf(label.length() + 1);
679 GLsizei labelLengthBuf = 0;
680 glGetObjectLabel(GL_RENDERBUFFER, renderbuffer, static_cast<GLsizei>(labelBuf.size()),
681 &labelLengthBuf, labelBuf.data());
682
683 EXPECT_EQ(static_cast<GLsizei>(label.length()), labelLengthBuf);
684 EXPECT_STREQ(label.c_str(), labelBuf.data());
685
686 ASSERT_GL_NO_ERROR();
687
688 glDeleteRenderbuffers(1, &renderbuffer);
689
690 glObjectLabel(GL_RENDERBUFFER, renderbuffer, -1, label.c_str());
691 EXPECT_GL_ERROR(GL_INVALID_VALUE);
692
693 glGetObjectLabel(GL_RENDERBUFFER, renderbuffer, static_cast<GLsizei>(labelBuf.size()),
694 &labelLengthBuf, labelBuf.data());
695 EXPECT_GL_ERROR(GL_INVALID_VALUE);
696 }
697
698 // Simple test for setting and getting labels using ES32 core APIs
TEST_P(DebugTestES32,ObjectPtrLabels)699 TEST_P(DebugTestES32, ObjectPtrLabels)
700 {
701 GLsync sync = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
702
703 const std::string &label = "sync";
704 glObjectPtrLabel(sync, -1, label.c_str());
705
706 std::vector<char> labelBuf(label.length() + 1);
707 GLsizei labelLengthBuf = 0;
708 glGetObjectPtrLabel(sync, static_cast<GLsizei>(labelBuf.size()), &labelLengthBuf,
709 labelBuf.data());
710
711 EXPECT_EQ(static_cast<GLsizei>(label.length()), labelLengthBuf);
712 EXPECT_STREQ(label.c_str(), labelBuf.data());
713
714 ASSERT_GL_NO_ERROR();
715
716 glDeleteSync(sync);
717
718 glObjectPtrLabel(sync, -1, label.c_str());
719 EXPECT_GL_ERROR(GL_INVALID_VALUE);
720
721 glGetObjectPtrLabel(sync, static_cast<GLsizei>(labelBuf.size()), &labelLengthBuf,
722 labelBuf.data());
723 EXPECT_GL_ERROR(GL_INVALID_VALUE);
724 }
725
726 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(DebugTestES3);
727 ANGLE_INSTANTIATE_TEST_ES3(DebugTestES3);
728
729 ANGLE_INSTANTIATE_TEST(DebugTest,
730 ANGLE_ALL_TEST_PLATFORMS_ES1,
731 ANGLE_ALL_TEST_PLATFORMS_ES2,
732 ANGLE_ALL_TEST_PLATFORMS_ES3,
733 ANGLE_ALL_TEST_PLATFORMS_ES31);
734
735 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(DebugTestES32);
736 ANGLE_INSTANTIATE_TEST_ES32(DebugTestES32);
737 } // namespace angle
738