// // Copyright (c) 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. // // EGLX11VisualTest.cpp: tests for EGL_ANGLE_x11_visual extension #include #include #include #include #include "OSWindow.h" #include "test_utils/ANGLETest.h" #include "x11/X11Window.h" using namespace angle; namespace { const EGLint contextAttribs[] = {EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE}; } class EGLX11VisualHintTest : public ::testing::TestWithParam { public: void SetUp() override { mEglGetPlatformDisplayEXT = reinterpret_cast( eglGetProcAddress("eglGetPlatformDisplayEXT")); mDisplay = XOpenDisplay(NULL); } std::vector getDisplayAttributes(int visualId) const { std::vector attribs; attribs.push_back(EGL_PLATFORM_ANGLE_TYPE_ANGLE); attribs.push_back(GetParam().getRenderer()); attribs.push_back(EGL_X11_VISUAL_ID_ANGLE); attribs.push_back(visualId); attribs.push_back(EGL_NONE); return attribs; } unsigned int chooseDifferentVisual(unsigned int visualId) { int numVisuals; XVisualInfo visualTemplate; visualTemplate.screen = DefaultScreen(mDisplay); XVisualInfo *visuals = XGetVisualInfo(mDisplay, VisualScreenMask, &visualTemplate, &numVisuals); EXPECT_TRUE(numVisuals >= 2); for (int i = 0; i < numVisuals; ++i) { if (visuals[i].visualid != visualId) { int result = visuals[i].visualid; XFree(visuals); return result; } } UNREACHABLE(); return -1; } protected: PFNEGLGETPLATFORMDISPLAYEXTPROC mEglGetPlatformDisplayEXT; Display *mDisplay; }; // Test that display creation fails if the visual ID passed in invalid. TEST_P(EGLX11VisualHintTest, InvalidVisualID) { // The test platform will log an error in this negative test. IgnoreANGLEPlatformMessages(); static const int gInvalidVisualId = -1; auto attributes = getDisplayAttributes(gInvalidVisualId); EGLDisplay display = mEglGetPlatformDisplayEXT(EGL_PLATFORM_ANGLE_ANGLE, EGL_DEFAULT_DISPLAY, attributes.data()); ASSERT_TRUE(display != EGL_NO_DISPLAY); ASSERT_TRUE(EGL_FALSE == eglInitialize(display, nullptr, nullptr)); ASSERT_EGL_ERROR(EGL_NOT_INITIALIZED); } // Test that context creation with a visual ID succeeds, that the context exposes // only one config, and that a clear on a surface with this config works. TEST_P(EGLX11VisualHintTest, ValidVisualIDAndClear) { // We'll test the extension with one visual ID but we don't care which one. This means we // can use OSWindow to create a window and just grab its visual. OSWindow *osWindow = CreateOSWindow(); osWindow->initialize("EGLX11VisualHintTest", 500, 500); osWindow->setVisible(true); Window xWindow = osWindow->getNativeWindow(); XWindowAttributes windowAttributes; ASSERT_NE(0, XGetWindowAttributes(mDisplay, xWindow, &windowAttributes)); int visualId = windowAttributes.visual->visualid; auto attributes = getDisplayAttributes(visualId); EGLDisplay display = mEglGetPlatformDisplayEXT(EGL_PLATFORM_ANGLE_ANGLE, EGL_DEFAULT_DISPLAY, attributes.data()); ASSERT_NE(EGL_NO_DISPLAY, display); ASSERT_TRUE(EGL_TRUE == eglInitialize(display, nullptr, nullptr)); // While this is not required by the extension, test that our implementation returns only one // config, with the same native visual Id that we provided. int nConfigs = 0; ASSERT_TRUE(EGL_TRUE == eglGetConfigs(display, nullptr, 0, &nConfigs)); ASSERT_EQ(1, nConfigs); int nReturnedConfigs = 0; EGLConfig config; ASSERT_TRUE(EGL_TRUE == eglGetConfigs(display, &config, 1, &nReturnedConfigs)); ASSERT_EQ(nConfigs, nReturnedConfigs); EGLint eglNativeId; ASSERT_TRUE(EGL_TRUE == eglGetConfigAttrib(display, config, EGL_NATIVE_VISUAL_ID, &eglNativeId)); ASSERT_EQ(visualId, eglNativeId); // Finally, try to do a clear on the window. EGLContext context = eglCreateContext(display, config, EGL_NO_CONTEXT, contextAttribs); ASSERT_NE(EGL_NO_CONTEXT, context); EGLSurface window = eglCreateWindowSurface(display, config, xWindow, nullptr); ASSERT_EGL_SUCCESS(); eglMakeCurrent(display, window, window, context); ASSERT_EGL_SUCCESS(); glViewport(0, 0, 500, 500); glClearColor(0.0f, 0.0f, 1.0f, 1.0f); glClear(GL_COLOR_BUFFER_BIT); ASSERT_GL_NO_ERROR(); EXPECT_PIXEL_EQ(250, 250, 0, 0, 255, 255); // Teardown eglDestroySurface(display, window); ASSERT_EGL_SUCCESS(); eglDestroyContext(display, context); ASSERT_EGL_SUCCESS(); SafeDelete(osWindow); eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); eglTerminate(display); } // Test that EGL_BAD_MATCH is generated when trying to create an EGL window from // an X11 window whose visual ID doesn't match the visual ID passed at display creation. TEST_P(EGLX11VisualHintTest, InvalidWindowVisualID) { // Get the default visual ID, as a good guess of a visual id for which display // creation will succeed. int visualId; { OSWindow *osWindow = CreateOSWindow(); osWindow->initialize("EGLX11VisualHintTest", 500, 500); osWindow->setVisible(true); Window xWindow = osWindow->getNativeWindow(); XWindowAttributes windowAttributes; ASSERT_NE(0, XGetWindowAttributes(mDisplay, xWindow, &windowAttributes)); visualId = windowAttributes.visual->visualid; SafeDelete(osWindow); } auto attributes = getDisplayAttributes(visualId); EGLDisplay display = mEglGetPlatformDisplayEXT(EGL_PLATFORM_ANGLE_ANGLE, EGL_DEFAULT_DISPLAY, attributes.data()); ASSERT_NE(EGL_NO_DISPLAY, display); ASSERT_TRUE(EGL_TRUE == eglInitialize(display, nullptr, nullptr)); // Initialize the window with a visual id different from the display's visual id int otherVisualId = chooseDifferentVisual(visualId); ASSERT_NE(visualId, otherVisualId); OSWindow *osWindow = new X11Window(otherVisualId); osWindow->initialize("EGLX11VisualHintTest", 500, 500); osWindow->setVisible(true); Window xWindow = osWindow->getNativeWindow(); // Creating the EGL window should fail with EGL_BAD_MATCH int nReturnedConfigs = 0; EGLConfig config; ASSERT_TRUE(EGL_TRUE == eglGetConfigs(display, &config, 1, &nReturnedConfigs)); ASSERT_EQ(1, nReturnedConfigs); EGLSurface window = eglCreateWindowSurface(display, config, xWindow, nullptr); ASSERT_EQ(EGL_NO_SURFACE, window); ASSERT_EGL_ERROR(EGL_BAD_MATCH); SafeDelete(osWindow); } ANGLE_INSTANTIATE_TEST(EGLX11VisualHintTest, ES2_OPENGL());