blob: e9a303c6760c166fc4b75953f12a58c8d59d3f03 [file] [log] [blame]
//
// Copyright 2018 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.
//
// EGLDebugTest.cpp:
// Tests of EGL_KHR_debug extension
#include <gtest/gtest.h>
#include "test_utils/ANGLETest.h"
#include "test_utils/angle_test_configs.h"
#include "util/EGLWindow.h"
namespace angle
{
class EGLDebugTest : public ANGLETest
{
protected:
void testTearDown() override { eglDebugMessageControlKHR(nullptr, nullptr); }
bool hasExtension() const { return IsEGLClientExtensionEnabled("EGL_KHR_debug"); }
static void EGLAPIENTRY StubCallback(EGLenum error,
const char *command,
EGLint messageType,
EGLLabelKHR threadLabel,
EGLLabelKHR objectLabel,
const char *message)
{}
static void EGLAPIENTRY CheckBadBindAPIError(EGLenum error,
const char *command,
EGLint messageType,
EGLLabelKHR threadLabel,
EGLLabelKHR objectLabel,
const char *message)
{
EXPECT_STREQ("eglBindAPI", command);
ASSERT_EGLENUM_EQ(EGL_BAD_PARAMETER, error);
EXPECT_STREQ("Thread", static_cast<const char *>(threadLabel));
}
static EGLDEBUGPROCKHR EGLAttribToDebugCallback(EGLAttrib attrib)
{
return reinterpret_cast<EGLDEBUGPROCKHR>(static_cast<uintptr_t>(attrib));
}
static EGLAttrib DebugCallbackToEGLAttrib(EGLDEBUGPROCKHR callback)
{
return static_cast<EGLAttrib>(reinterpret_cast<intptr_t>(callback));
}
};
// Test that the extension is always available (it is implemented in ANGLE's frontend).
TEST_P(EGLDebugTest, ExtensionAlwaysAvailable)
{
ASSERT_TRUE(hasExtension());
}
// Check that the default message filters and callbacks are correct
TEST_P(EGLDebugTest, DefaultParameters)
{
ANGLE_SKIP_TEST_IF(!hasExtension());
EXPECT_EQ(static_cast<EGLint>(EGL_SUCCESS), eglDebugMessageControlKHR(nullptr, nullptr));
EGLAttrib result = 0;
EXPECT_EGL_TRUE(eglQueryDebugKHR(EGL_DEBUG_MSG_ERROR_KHR, &result));
EXPECT_EGL_TRUE(result);
EXPECT_EGL_TRUE(eglQueryDebugKHR(EGL_DEBUG_MSG_WARN_KHR, &result));
EXPECT_EGL_FALSE(result);
EXPECT_EGL_TRUE(eglQueryDebugKHR(EGL_DEBUG_MSG_INFO_KHR, &result));
EXPECT_EGL_FALSE(result);
EXPECT_EGL_TRUE(eglQueryDebugKHR(EGL_DEBUG_CALLBACK_KHR, &result));
EXPECT_EQ(nullptr, EGLAttribToDebugCallback(result));
}
// Check that the message control and callback parameters can be set and then queried back
TEST_P(EGLDebugTest, SetMessageControl)
{
ANGLE_SKIP_TEST_IF(!hasExtension());
EGLAttrib controls[] = {
EGL_DEBUG_MSG_CRITICAL_KHR,
EGL_FALSE,
// EGL_DEBUG_MSG_ERROR_KHR left unset
EGL_DEBUG_MSG_WARN_KHR,
EGL_TRUE,
EGL_DEBUG_MSG_INFO_KHR,
EGL_FALSE,
EGL_NONE,
EGL_NONE,
};
EXPECT_EQ(static_cast<EGLint>(EGL_SUCCESS), eglDebugMessageControlKHR(&StubCallback, controls));
EGLAttrib result = 0;
EXPECT_EGL_TRUE(eglQueryDebugKHR(EGL_DEBUG_MSG_CRITICAL_KHR, &result));
EXPECT_EGL_FALSE(result);
EXPECT_EGL_TRUE(eglQueryDebugKHR(EGL_DEBUG_MSG_ERROR_KHR, &result));
EXPECT_EGL_TRUE(result);
EXPECT_EGL_TRUE(eglQueryDebugKHR(EGL_DEBUG_MSG_WARN_KHR, &result));
EXPECT_EGL_TRUE(result);
EXPECT_EGL_TRUE(eglQueryDebugKHR(EGL_DEBUG_MSG_INFO_KHR, &result));
EXPECT_EGL_FALSE(result);
EXPECT_EGL_TRUE(eglQueryDebugKHR(EGL_DEBUG_CALLBACK_KHR, &result));
EXPECT_EQ(DebugCallbackToEGLAttrib(&StubCallback), result);
}
// Set a thread label and then trigger a callback to verify the callback parameters are correct
TEST_P(EGLDebugTest, CorrectCallbackParameters)
{
ANGLE_SKIP_TEST_IF(!hasExtension());
EXPECT_EQ(static_cast<EGLint>(EGL_SUCCESS), eglDebugMessageControlKHR(nullptr, nullptr));
EXPECT_EQ(EGL_SUCCESS, eglLabelObjectKHR(EGL_NO_DISPLAY, EGL_OBJECT_THREAD_KHR, nullptr,
const_cast<char *>("Thread")));
// Enable all messages
EGLAttrib controls[] = {
EGL_DEBUG_MSG_CRITICAL_KHR,
EGL_TRUE,
EGL_DEBUG_MSG_ERROR_KHR,
EGL_TRUE,
EGL_DEBUG_MSG_WARN_KHR,
EGL_TRUE,
EGL_DEBUG_MSG_INFO_KHR,
EGL_TRUE,
EGL_NONE,
EGL_NONE,
};
EXPECT_EQ(static_cast<EGLint>(EGL_SUCCESS),
eglDebugMessageControlKHR(&CheckBadBindAPIError, controls));
// Generate an error and trigger the callback
EXPECT_EGL_FALSE(eglBindAPI(0xBADDBADD));
}
// Test that labels can be set and that errors are generated if the wrong object type is used
TEST_P(EGLDebugTest, SetLabel)
{
ANGLE_SKIP_TEST_IF(!hasExtension());
EXPECT_EQ(static_cast<EGLint>(EGL_SUCCESS), eglDebugMessageControlKHR(nullptr, nullptr));
// Display display and object must be equal when setting a display label
EXPECT_EQ(static_cast<EGLint>(EGL_SUCCESS),
eglLabelObjectKHR(getEGLWindow()->getDisplay(), EGL_OBJECT_DISPLAY_KHR,
getEGLWindow()->getDisplay(), const_cast<char *>("Display")));
EXPECT_NE(static_cast<EGLint>(EGL_SUCCESS),
eglLabelObjectKHR(nullptr, EGL_OBJECT_DISPLAY_KHR, getEGLWindow()->getDisplay(),
const_cast<char *>("Display")));
// Set a surface label
EXPECT_EQ(static_cast<EGLint>(EGL_SUCCESS),
eglLabelObjectKHR(getEGLWindow()->getDisplay(), EGL_OBJECT_SURFACE_KHR,
getEGLWindow()->getSurface(), const_cast<char *>("Surface")));
EXPECT_EGL_ERROR(EGL_SUCCESS);
// Provide a surface but use an image label type
EXPECT_EQ(static_cast<EGLint>(EGL_BAD_PARAMETER),
eglLabelObjectKHR(getEGLWindow()->getDisplay(), EGL_OBJECT_IMAGE_KHR,
getEGLWindow()->getSurface(), const_cast<char *>("Image")));
EXPECT_EGL_ERROR(EGL_BAD_PARAMETER);
}
ANGLE_INSTANTIATE_TEST(EGLDebugTest,
ES2_D3D9(),
ES2_D3D11(),
ES3_D3D11(),
ES2_OPENGL(),
ES3_OPENGL(),
ES2_VULKAN());
} // namespace angle