diff options
Diffstat (limited to 'gfx/angle/src/tests/gl_tests/DebugTest.cpp')
-rwxr-xr-x | gfx/angle/src/tests/gl_tests/DebugTest.cpp | 451 |
1 files changed, 451 insertions, 0 deletions
diff --git a/gfx/angle/src/tests/gl_tests/DebugTest.cpp b/gfx/angle/src/tests/gl_tests/DebugTest.cpp new file mode 100755 index 000000000..fc79c5f64 --- /dev/null +++ b/gfx/angle/src/tests/gl_tests/DebugTest.cpp @@ -0,0 +1,451 @@ +// +// Copyright 2015 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// DebugTest.cpp : Tests of the GL_KHR_debug extension + +#include "test_utils/ANGLETest.h" + +namespace angle +{ + +class DebugTest : public ANGLETest +{ + protected: + DebugTest() : mDebugExtensionAvailable(false) + { + setWindowWidth(128); + setWindowHeight(128); + setConfigRedBits(8); + setConfigGreenBits(8); + setConfigBlueBits(8); + setConfigAlphaBits(8); + setConfigDepthBits(24); + setDebugEnabled(true); + } + + void SetUp() override + { + ANGLETest::SetUp(); + + mDebugExtensionAvailable = extensionEnabled("GL_KHR_debug"); + if (mDebugExtensionAvailable) + { + glEnable(GL_DEBUG_OUTPUT); + } + } + + bool mDebugExtensionAvailable; +}; + +struct Message +{ + GLenum source; + GLenum type; + GLuint id; + GLenum severity; + std::string message; + const void *userParam; +}; + +static void GL_APIENTRY Callback(GLenum source, + GLenum type, + GLuint id, + GLenum severity, + GLsizei length, + const GLchar *message, + const void *userParam) +{ + Message m{source, type, id, severity, std::string(message, length), userParam}; + std::vector<Message> *messages = + static_cast<std::vector<Message> *>(const_cast<void *>(userParam)); + messages->push_back(m); +} + +// Test that all ANGLE back-ends have GL_KHR_debug enabled +TEST_P(DebugTest, Enabled) +{ + ASSERT_TRUE(mDebugExtensionAvailable); +} + +// Test that when debug output is disabled, no message are outputted +TEST_P(DebugTest, DisabledOutput) +{ + if (!mDebugExtensionAvailable) + { + std::cout << "Test skipped because GL_KHR_debug is not available." << std::endl; + return; + } + + glDisable(GL_DEBUG_OUTPUT); + + glDebugMessageInsertKHR(GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_OTHER, 1, + GL_DEBUG_SEVERITY_NOTIFICATION, -1, "discarded"); + + GLint numMessages = 0; + glGetIntegerv(GL_DEBUG_LOGGED_MESSAGES, &numMessages); + ASSERT_EQ(0, numMessages); + + std::vector<Message> messages; + glDebugMessageCallbackKHR(Callback, &messages); + glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS); + + ASSERT_EQ(0u, messages.size()); +} + +// Test a basic flow of inserting a message and reading it back +TEST_P(DebugTest, InsertMessage) +{ + if (!mDebugExtensionAvailable) + { + std::cout << "Test skipped because GL_KHR_debug is not available." << std::endl; + return; + } + + const GLenum source = GL_DEBUG_SOURCE_APPLICATION; + const GLenum type = GL_DEBUG_TYPE_OTHER; + const GLuint id = 1; + const GLenum severity = GL_DEBUG_SEVERITY_NOTIFICATION; + const std::string message = "Message"; + + glDebugMessageInsertKHR(source, type, id, severity, -1, message.c_str()); + + GLint numMessages = 0; + glGetIntegerv(GL_DEBUG_LOGGED_MESSAGES, &numMessages); + ASSERT_EQ(1, numMessages); + + GLint messageLength = 0; + glGetIntegerv(GL_DEBUG_NEXT_LOGGED_MESSAGE_LENGTH, &messageLength); + EXPECT_EQ(static_cast<GLint>(message.length()), messageLength); + + GLenum sourceBuf = 0; + GLenum typeBuf = 0; + GLenum idBuf = 0; + GLenum severityBuf = 0; + GLsizei lengthBuf = 0; + std::vector<char> messageBuf(messageLength + 1); + GLuint ret = + glGetDebugMessageLogKHR(1, static_cast<GLsizei>(messageBuf.size()), &sourceBuf, &typeBuf, + &idBuf, &severityBuf, &lengthBuf, messageBuf.data()); + EXPECT_EQ(1u, ret); + EXPECT_EQ(source, sourceBuf); + EXPECT_EQ(type, typeBuf); + EXPECT_EQ(id, idBuf); + EXPECT_EQ(severity, severityBuf); + EXPECT_EQ(lengthBuf, messageLength); + EXPECT_STREQ(message.c_str(), messageBuf.data()); + + glGetIntegerv(GL_DEBUG_LOGGED_MESSAGES, &numMessages); + EXPECT_EQ(0, numMessages); + + ASSERT_GL_NO_ERROR(); +} + +// Test inserting multiple messages +TEST_P(DebugTest, InsertMessageMultiple) +{ + if (!mDebugExtensionAvailable) + { + std::cout << "Test skipped because GL_KHR_debug is not available." << std::endl; + return; + } + + const GLenum source = GL_DEBUG_SOURCE_APPLICATION; + const GLenum type = GL_DEBUG_TYPE_OTHER; + const GLuint startID = 1; + const GLenum severity = GL_DEBUG_SEVERITY_NOTIFICATION; + const char messageRepeatChar = 'm'; + const size_t messageCount = 32; + + for (size_t i = 0; i < messageCount; i++) + { + std::string message(i + 1, messageRepeatChar); + glDebugMessageInsertKHR(source, type, startID + static_cast<GLuint>(i), severity, -1, + message.c_str()); + } + + GLint numMessages = 0; + glGetIntegerv(GL_DEBUG_LOGGED_MESSAGES, &numMessages); + ASSERT_EQ(static_cast<GLint>(messageCount), numMessages); + + for (size_t i = 0; i < messageCount; i++) + { + glGetIntegerv(GL_DEBUG_LOGGED_MESSAGES, &numMessages); + EXPECT_EQ(static_cast<GLint>(messageCount - i), numMessages); + + std::string expectedMessage(i + 1, messageRepeatChar); + + GLint messageLength = 0; + glGetIntegerv(GL_DEBUG_NEXT_LOGGED_MESSAGE_LENGTH, &messageLength); + EXPECT_EQ(static_cast<GLint>(expectedMessage.length()), messageLength); + + GLenum sourceBuf = 0; + GLenum typeBuf = 0; + GLenum idBuf = 0; + GLenum severityBuf = 0; + GLsizei lengthBuf = 0; + std::vector<char> messageBuf(messageLength + 1); + GLuint ret = + glGetDebugMessageLogKHR(1, static_cast<GLsizei>(messageBuf.size()), &sourceBuf, + &typeBuf, &idBuf, &severityBuf, &lengthBuf, messageBuf.data()); + EXPECT_EQ(1u, ret); + EXPECT_EQ(source, sourceBuf); + EXPECT_EQ(type, typeBuf); + EXPECT_EQ(startID + i, idBuf); + EXPECT_EQ(severity, severityBuf); + EXPECT_EQ(lengthBuf, messageLength); + EXPECT_STREQ(expectedMessage.c_str(), messageBuf.data()); + } + + glGetIntegerv(GL_DEBUG_LOGGED_MESSAGES, &numMessages); + EXPECT_EQ(0, numMessages); + + ASSERT_GL_NO_ERROR(); +} + +// Test using a debug callback +TEST_P(DebugTest, DebugCallback) +{ + if (!mDebugExtensionAvailable) + { + std::cout << "Test skipped because GL_KHR_debug is not available." << std::endl; + return; + } + + std::vector<Message> messages; + + glDebugMessageCallbackKHR(Callback, &messages); + glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS); + + const GLenum source = GL_DEBUG_SOURCE_APPLICATION; + const GLenum type = GL_DEBUG_TYPE_OTHER; + const GLuint id = 1; + const GLenum severity = GL_DEBUG_SEVERITY_NOTIFICATION; + const std::string message = "Message"; + + glDebugMessageInsertKHR(source, type, id, severity, -1, message.c_str()); + + GLint numMessages = 0; + glGetIntegerv(GL_DEBUG_LOGGED_MESSAGES, &numMessages); + EXPECT_EQ(0, numMessages); + + ASSERT_EQ(1u, messages.size()); + + const Message &m = messages.front(); + EXPECT_EQ(source, m.source); + EXPECT_EQ(type, m.type); + EXPECT_EQ(id, m.id); + EXPECT_EQ(severity, m.severity); + EXPECT_EQ(message, m.message); + + ASSERT_GL_NO_ERROR(); +} + +// Test the glGetPointervKHR entry point +TEST_P(DebugTest, GetPointer) +{ + if (!mDebugExtensionAvailable) + { + std::cout << "Test skipped because GL_KHR_debug is not available." << std::endl; + return; + } + + std::vector<Message> messages; + + glDebugMessageCallbackKHR(Callback, &messages); + + void *callback = nullptr; + glGetPointervKHR(GL_DEBUG_CALLBACK_FUNCTION, &callback); + EXPECT_EQ(reinterpret_cast<void *>(Callback), callback); + + void *userData = nullptr; + glGetPointervKHR(GL_DEBUG_CALLBACK_USER_PARAM, &userData); + EXPECT_EQ(static_cast<void *>(&messages), userData); +} + +// Test usage of message control. Example taken from GL_KHR_debug spec. +TEST_P(DebugTest, MessageControl1) +{ + if (!mDebugExtensionAvailable) + { + std::cout << "Test skipped because GL_KHR_debug is not available." << std::endl; + return; + } + + std::vector<Message> messages; + + glDebugMessageCallbackKHR(Callback, &messages); + glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS); + + // Setup of the default active debug group: Filter everything in + glDebugMessageControlKHR(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, NULL, GL_TRUE); + + // Generate a debug marker debug output message + glDebugMessageInsertKHR(GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_MARKER, 100, + GL_DEBUG_SEVERITY_NOTIFICATION, -1, "Message 1"); + + // Push debug group 1 + glPushDebugGroupKHR(GL_DEBUG_SOURCE_APPLICATION, 1, -1, "Message 2"); + + // Setup of the debug group 1: Filter everything out + glDebugMessageControlKHR(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, NULL, GL_FALSE); + + // This message won't appear in the debug output log of + glDebugMessageInsertKHR(GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_MARKER, 100, + GL_DEBUG_SEVERITY_NOTIFICATION, -1, "Message 3"); + + // Pop debug group 1, restore the volume control of the default debug group. + glPopDebugGroupKHR(); + + // Generate a debug marker debug output message + glDebugMessageInsertKHR(GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_MARKER, 100, + GL_DEBUG_SEVERITY_NOTIFICATION, -1, "Message 5"); + + // Expected debug output from the GL implementation + // Message 1 + // Message 2 + // Message 2 + // Message 5 + EXPECT_EQ(4u, messages.size()); + EXPECT_STREQ(messages[0].message.c_str(), "Message 1"); + EXPECT_STREQ(messages[1].message.c_str(), "Message 2"); + EXPECT_STREQ(messages[2].message.c_str(), "Message 2"); + EXPECT_STREQ(messages[3].message.c_str(), "Message 5"); + + ASSERT_GL_NO_ERROR(); +} + +// Test usage of message control. Example taken from GL_KHR_debug spec. +TEST_P(DebugTest, MessageControl2) +{ + if (!mDebugExtensionAvailable) + { + std::cout << "Test skipped because GL_KHR_debug is not available." << std::endl; + return; + } + + std::vector<Message> messages; + + glDebugMessageCallbackKHR(Callback, &messages); + glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS); + + // Setup the control of de debug output for the default debug group + glDebugMessageControlKHR(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, NULL, GL_FALSE); + glDebugMessageControlKHR(GL_DEBUG_SOURCE_THIRD_PARTY, GL_DONT_CARE, GL_DONT_CARE, 0, NULL, + GL_FALSE); + std::vector<GLuint> ids0 = {1234, 2345, 3456, 4567}; + glDebugMessageControlKHR(GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_OTHER, GL_DONT_CARE, + static_cast<GLuint>(ids0.size()), ids0.data(), GL_FALSE); + glDebugMessageControlKHR(GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_PORTABILITY, GL_DONT_CARE, + static_cast<GLuint>(ids0.size()), ids0.data(), GL_FALSE); + + // Push debug group 1 + // Inherit of the default debug group debug output volume control + // Filtered out by glDebugMessageControl + glPushDebugGroupKHR(GL_DEBUG_SOURCE_APPLICATION, 1, -1, "Message 1"); + + // In this section of the code, we are interested in performances. + glDebugMessageControlKHR(GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_PERFORMANCE, GL_DONT_CARE, + 0, NULL, GL_TRUE); + // But we already identify that some messages are not really useful for us. + std::vector<GLuint> ids1 = {5678, 6789}; + glDebugMessageControlKHR(GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_OTHER, GL_DONT_CARE, + static_cast<GLuint>(ids1.size()), ids1.data(), GL_FALSE); + + glDebugMessageInsertKHR(GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_PERFORMANCE, 1357, + GL_DEBUG_SEVERITY_MEDIUM, -1, "Message 2"); + glDebugMessageInsertKHR(GL_DEBUG_SOURCE_THIRD_PARTY, // We still filter out these messages. + GL_DEBUG_TYPE_OTHER, 3579, GL_DEBUG_SEVERITY_MEDIUM, -1, "Message 3"); + + glPopDebugGroupKHR(); + + // Expected debug output from the GL implementation + // Message 2 + EXPECT_EQ(1u, messages.size()); + EXPECT_STREQ(messages[0].message.c_str(), "Message 2"); + + ASSERT_GL_NO_ERROR(); +} + +// Test basic usage of setting and getting labels +TEST_P(DebugTest, ObjectLabels) +{ + if (!mDebugExtensionAvailable) + { + std::cout << "Test skipped because GL_KHR_debug is not available." << std::endl; + return; + } + + GLuint renderbuffer = 0; + glGenRenderbuffers(1, &renderbuffer); + glBindRenderbuffer(GL_RENDERBUFFER, renderbuffer); + + const std::string &label = "renderbuffer"; + glObjectLabelKHR(GL_RENDERBUFFER, renderbuffer, -1, label.c_str()); + + std::vector<char> labelBuf(label.length() + 1); + GLsizei labelLengthBuf = 0; + glGetObjectLabelKHR(GL_RENDERBUFFER, renderbuffer, static_cast<GLsizei>(labelBuf.size()), + &labelLengthBuf, labelBuf.data()); + + EXPECT_EQ(static_cast<GLsizei>(label.length()), labelLengthBuf); + EXPECT_STREQ(label.c_str(), labelBuf.data()); + + ASSERT_GL_NO_ERROR(); + + glDeleteRenderbuffers(1, &renderbuffer); + + glObjectLabelKHR(GL_RENDERBUFFER, renderbuffer, -1, label.c_str()); + EXPECT_GL_ERROR(GL_INVALID_VALUE); + + glGetObjectLabelKHR(GL_RENDERBUFFER, renderbuffer, static_cast<GLsizei>(labelBuf.size()), + &labelLengthBuf, labelBuf.data()); + EXPECT_GL_ERROR(GL_INVALID_VALUE); +} + +// Test basic usage of setting and getting labels +TEST_P(DebugTest, ObjectPtrLabels) +{ + if (!mDebugExtensionAvailable || getClientMajorVersion() < 3) + { + std::cout << "Test skipped because GL_KHR_debug or ES3 is not available." << std::endl; + return; + } + + GLsync sync = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0); + + const std::string &label = "sync"; + glObjectPtrLabelKHR(sync, -1, label.c_str()); + + std::vector<char> labelBuf(label.length() + 1); + GLsizei labelLengthBuf = 0; + glGetObjectPtrLabelKHR(sync, static_cast<GLsizei>(labelBuf.size()), &labelLengthBuf, + labelBuf.data()); + + EXPECT_EQ(static_cast<GLsizei>(label.length()), labelLengthBuf); + EXPECT_STREQ(label.c_str(), labelBuf.data()); + + ASSERT_GL_NO_ERROR(); + + glDeleteSync(sync); + + glObjectPtrLabelKHR(sync, -1, label.c_str()); + EXPECT_GL_ERROR(GL_INVALID_VALUE); + + glGetObjectPtrLabelKHR(sync, static_cast<GLsizei>(labelBuf.size()), &labelLengthBuf, + labelBuf.data()); + EXPECT_GL_ERROR(GL_INVALID_VALUE); +} + +// Use this to select which configurations (e.g. which renderer, which GLES major version) these +// tests should be run against. +ANGLE_INSTANTIATE_TEST(DebugTest, + ES2_D3D9(), + ES2_D3D11(), + ES3_D3D11(), + ES2_OPENGL(), + ES3_OPENGL()); + +} // namespace angle |