1 //
2 // Copyright 2022 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 #include <gtest/gtest.h>
8 #include <vector>
9
10 #include "test_utils/ANGLETest.h"
11
12 using namespace angle;
13
14 class EGLDisplayTest : public ANGLETest<>
15 {
16 protected:
chooseConfig(EGLDisplay display)17 EGLConfig chooseConfig(EGLDisplay display)
18 {
19 const EGLint attribs[] = {EGL_RED_SIZE,
20 8,
21 EGL_GREEN_SIZE,
22 8,
23 EGL_BLUE_SIZE,
24 8,
25 EGL_ALPHA_SIZE,
26 8,
27 EGL_RENDERABLE_TYPE,
28 EGL_OPENGL_ES2_BIT,
29 EGL_SURFACE_TYPE,
30 EGL_PBUFFER_BIT,
31 EGL_NONE};
32 EGLConfig config = EGL_NO_CONFIG_KHR;
33 EGLint count = 0;
34 EXPECT_EGL_TRUE(eglChooseConfig(display, attribs, &config, 1, &count));
35 EXPECT_EGL_TRUE(count > 0);
36 return config;
37 }
38
createContext(EGLDisplay display,EGLConfig config)39 EGLContext createContext(EGLDisplay display, EGLConfig config)
40 {
41 const EGLint attribs[] = {EGL_CONTEXT_MAJOR_VERSION, 2, EGL_NONE};
42 EGLContext context = eglCreateContext(display, config, nullptr, attribs);
43 EXPECT_NE(context, EGL_NO_CONTEXT);
44 return context;
45 }
46
createSurface(EGLDisplay display,EGLConfig config)47 EGLSurface createSurface(EGLDisplay display, EGLConfig config)
48 {
49 const EGLint attribs[] = {EGL_WIDTH, 64, EGL_HEIGHT, 64, EGL_NONE};
50 EGLSurface surface = eglCreatePbufferSurface(display, config, attribs);
51 EXPECT_NE(surface, EGL_NO_SURFACE);
52 return surface;
53 }
54 };
55
56 // Tests that an eglInitialize can be re-initialized. The spec says:
57 //
58 // > Initializing an already-initialized display is allowed, but the only effect of such a call is
59 // to return EGL_TRUE and update the EGL version numbers
TEST_P(EGLDisplayTest,InitializeMultipleTimes)60 TEST_P(EGLDisplayTest, InitializeMultipleTimes)
61 {
62 EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
63 EGLint major = 0, minor = 0;
64 EXPECT_EGL_TRUE(eglInitialize(display, &major, &minor) != EGL_FALSE);
65 for (uint32_t i = 0; i < 10; ++i)
66 {
67 EGLint retryMajor = 123456, retryMinor = -1;
68 EXPECT_EGL_TRUE(eglInitialize(display, &retryMajor, &retryMinor) != EGL_FALSE);
69 EXPECT_EQ(major, retryMajor) << i;
70 EXPECT_EQ(minor, retryMinor) << i;
71 }
72 }
73
74 // Test that call eglInitialize() in parallel in multiple threads works
75 // > Initializing an already-initialized display is allowed, but the only effect
76 // of such a call is to return EGL_TRUE and update the EGL version numbers
TEST_P(EGLDisplayTest,InitializeMultipleTimesInDifferentThreads)77 TEST_P(EGLDisplayTest, InitializeMultipleTimesInDifferentThreads)
78 {
79 std::array<std::thread, 10> threads;
80 for (std::thread &thread : threads)
81 {
82 thread = std::thread([&]() {
83 EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
84 const int INVALID_GL_MAJOR_VERSION = -1;
85 const int INVALID_GL_MINOR_VERSION = -1;
86 EGLint threadMajor = INVALID_GL_MAJOR_VERSION;
87 EGLint threadMinor = INVALID_GL_MINOR_VERSION;
88 EXPECT_EGL_TRUE(eglInitialize(display, &threadMajor, &threadMinor) != EGL_FALSE);
89 EXPECT_NE(threadMajor, INVALID_GL_MAJOR_VERSION);
90 EXPECT_NE(threadMinor, INVALID_GL_MINOR_VERSION);
91 });
92 }
93
94 for (std::thread &thread : threads)
95 {
96 thread.join();
97 }
98 }
99
100 // Tests that an EGLDisplay can be re-initialized.
TEST_P(EGLDisplayTest,InitializeTerminateInitialize)101 TEST_P(EGLDisplayTest, InitializeTerminateInitialize)
102 {
103 EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
104 EXPECT_EGL_TRUE(eglInitialize(display, nullptr, nullptr) != EGL_FALSE);
105 EXPECT_EGL_TRUE(eglTerminate(display) != EGL_FALSE);
106 EXPECT_EGL_TRUE(eglInitialize(display, nullptr, nullptr) != EGL_FALSE);
107 }
108
109 // Tests current Context leaking when call eglTerminate() while it is current.
TEST_P(EGLDisplayTest,ContextLeakAfterTerminate)110 TEST_P(EGLDisplayTest, ContextLeakAfterTerminate)
111 {
112 EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
113 EXPECT_EGL_TRUE(eglInitialize(display, nullptr, nullptr));
114
115 EGLConfig config = chooseConfig(display);
116 EGLContext context = createContext(display, config);
117 EGLSurface surface = createSurface(display, config);
118
119 // Make "context" current.
120 EXPECT_EGL_TRUE(eglMakeCurrent(display, surface, surface, context));
121
122 // Terminate display while "context" is current.
123 EXPECT_EGL_TRUE(eglTerminate(display));
124
125 // Unmake "context" from current and allow Display to actually terminate.
126 (void)eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
127
128 // Get EGLDisplay again.
129 display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
130
131 // Check if Display was actually terminated.
132 EGLint val;
133 EXPECT_EGL_FALSE(eglQueryContext(display, context, EGL_CONTEXT_CLIENT_TYPE, &val));
134 EXPECT_EQ(eglGetError(), EGL_NOT_INITIALIZED);
135 }
136
137 ANGLE_INSTANTIATE_TEST(EGLDisplayTest,
138 WithNoFixture(ES2_D3D9()),
139 WithNoFixture(ES2_D3D11()),
140 WithNoFixture(ES2_OPENGL()),
141 WithNoFixture(ES2_VULKAN()),
142 WithNoFixture(ES3_D3D11()),
143 WithNoFixture(ES3_OPENGL()),
144 WithNoFixture(ES3_VULKAN()));
145