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 #include "test_utils/gl_raii.h"
12 #include "util/OSWindow.h"
13
14 using namespace angle;
15
16 class EGLDisplayTest : public ANGLETest<>
17 {
18 protected:
chooseConfig(EGLDisplay display)19 EGLConfig chooseConfig(EGLDisplay display)
20 {
21 const EGLint attribs[] = {EGL_RED_SIZE,
22 8,
23 EGL_GREEN_SIZE,
24 8,
25 EGL_BLUE_SIZE,
26 8,
27 EGL_ALPHA_SIZE,
28 8,
29 EGL_RENDERABLE_TYPE,
30 EGL_OPENGL_ES2_BIT,
31 EGL_SURFACE_TYPE,
32 EGL_PBUFFER_BIT | EGL_WINDOW_BIT,
33 EGL_NONE};
34 EGLConfig config = EGL_NO_CONFIG_KHR;
35 EGLint count = 0;
36 EXPECT_EGL_TRUE(eglChooseConfig(display, attribs, &config, 1, &count));
37 EXPECT_EGL_TRUE(count > 0);
38 return config;
39 }
40
createContext(EGLDisplay display,EGLConfig config)41 EGLContext createContext(EGLDisplay display, EGLConfig config)
42 {
43 const EGLint attribs[] = {EGL_CONTEXT_MAJOR_VERSION, 2, EGL_NONE};
44 EGLContext context = eglCreateContext(display, config, nullptr, attribs);
45 EXPECT_NE(context, EGL_NO_CONTEXT);
46 return context;
47 }
48
createSurface(EGLDisplay display,EGLConfig config)49 EGLSurface createSurface(EGLDisplay display, EGLConfig config)
50 {
51 const EGLint attribs[] = {EGL_WIDTH, 64, EGL_HEIGHT, 64, EGL_NONE};
52 EGLSurface surface = eglCreatePbufferSurface(display, config, attribs);
53 EXPECT_NE(surface, EGL_NO_SURFACE);
54 return surface;
55 }
56 };
57
58 // Tests that an eglInitialize can be re-initialized. The spec says:
59 //
60 // > Initializing an already-initialized display is allowed, but the only effect of such a call is
61 // to return EGL_TRUE and update the EGL version numbers
TEST_P(EGLDisplayTest,InitializeMultipleTimes)62 TEST_P(EGLDisplayTest, InitializeMultipleTimes)
63 {
64 EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
65 EGLint major = 0, minor = 0;
66 EXPECT_EGL_TRUE(eglInitialize(display, &major, &minor) != EGL_FALSE);
67 for (uint32_t i = 0; i < 10; ++i)
68 {
69 EGLint retryMajor = 123456, retryMinor = -1;
70 EXPECT_EGL_TRUE(eglInitialize(display, &retryMajor, &retryMinor) != EGL_FALSE);
71 EXPECT_EQ(major, retryMajor) << i;
72 EXPECT_EQ(minor, retryMinor) << i;
73 }
74 }
75
76 // Test that call eglInitialize() in parallel in multiple threads works
77 // > Initializing an already-initialized display is allowed, but the only effect
78 // of such a call is to return EGL_TRUE and update the EGL version numbers
TEST_P(EGLDisplayTest,InitializeMultipleTimesInDifferentThreads)79 TEST_P(EGLDisplayTest, InitializeMultipleTimesInDifferentThreads)
80 {
81 std::array<std::thread, 10> threads;
82 for (std::thread &thread : threads)
83 {
84 thread = std::thread([&]() {
85 EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
86 const int INVALID_GL_MAJOR_VERSION = -1;
87 const int INVALID_GL_MINOR_VERSION = -1;
88 EGLint threadMajor = INVALID_GL_MAJOR_VERSION;
89 EGLint threadMinor = INVALID_GL_MINOR_VERSION;
90 EXPECT_EGL_TRUE(eglInitialize(display, &threadMajor, &threadMinor) != EGL_FALSE);
91 EXPECT_NE(threadMajor, INVALID_GL_MAJOR_VERSION);
92 EXPECT_NE(threadMinor, INVALID_GL_MINOR_VERSION);
93 });
94 }
95
96 for (std::thread &thread : threads)
97 {
98 thread.join();
99 }
100 }
101
102 // Tests that an EGLDisplay can be re-initialized.
TEST_P(EGLDisplayTest,InitializeTerminateInitialize)103 TEST_P(EGLDisplayTest, InitializeTerminateInitialize)
104 {
105 EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
106 EXPECT_EGL_TRUE(eglInitialize(display, nullptr, nullptr) != EGL_FALSE);
107 EXPECT_EGL_TRUE(eglTerminate(display) != EGL_FALSE);
108 EXPECT_EGL_TRUE(eglInitialize(display, nullptr, nullptr) != EGL_FALSE);
109 }
110
111 // Tests that an EGLDisplay can be re-initialized after it was used to draw into a window surface.
TEST_P(EGLDisplayTest,InitializeDrawSwapTerminateLoop)112 TEST_P(EGLDisplayTest, InitializeDrawSwapTerminateLoop)
113 {
114 constexpr int kLoopCount = 2;
115 constexpr EGLint kWidth = 64;
116 constexpr EGLint kHeight = 64;
117
118 OSWindow *osWindow = OSWindow::New();
119 osWindow->initialize("LockSurfaceTest", kWidth, kHeight);
120
121 EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
122
123 for (int i = 0; i < kLoopCount; ++i)
124 {
125 EXPECT_EGL_TRUE(eglInitialize(display, nullptr, nullptr) != EGL_FALSE);
126
127 EGLConfig config = chooseConfig(display);
128 EGLContext context = createContext(display, config);
129 EGLSurface surface =
130 eglCreateWindowSurface(display, config, osWindow->getNativeWindow(), nullptr);
131 EXPECT_NE(surface, EGL_NO_SURFACE);
132
133 EXPECT_EGL_TRUE(eglMakeCurrent(display, surface, surface, context));
134
135 ANGLE_GL_PROGRAM(greenProgram, essl1_shaders::vs::Simple(), essl1_shaders::fs::Green());
136 drawQuad(greenProgram, essl1_shaders::PositionAttrib(), 0.5f);
137
138 EXPECT_EGL_TRUE(eglSwapBuffers(display, surface));
139
140 EXPECT_EGL_TRUE(eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT));
141 EXPECT_EGL_TRUE(eglTerminate(display) != EGL_FALSE);
142 }
143
144 osWindow->destroy();
145 OSWindow::Delete(&osWindow);
146 }
147
148 // Tests current Context leaking when call eglTerminate() while it is current.
TEST_P(EGLDisplayTest,ContextLeakAfterTerminate)149 TEST_P(EGLDisplayTest, ContextLeakAfterTerminate)
150 {
151 EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
152 EXPECT_EGL_TRUE(eglInitialize(display, nullptr, nullptr));
153
154 EGLConfig config = chooseConfig(display);
155 EGLContext context = createContext(display, config);
156 EGLSurface surface = createSurface(display, config);
157
158 // Make "context" current.
159 EXPECT_EGL_TRUE(eglMakeCurrent(display, surface, surface, context));
160
161 // Terminate display while "context" is current.
162 EXPECT_EGL_TRUE(eglTerminate(display));
163
164 // Unmake "context" from current and allow Display to actually terminate.
165 (void)eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
166
167 // Get EGLDisplay again.
168 display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
169
170 // Check if Display was actually terminated.
171 EGLint val;
172 EXPECT_EGL_FALSE(eglQueryContext(display, context, EGL_CONTEXT_CLIENT_TYPE, &val));
173 EXPECT_EQ(eglGetError(), EGL_NOT_INITIALIZED);
174 }
175
176 ANGLE_INSTANTIATE_TEST(EGLDisplayTest,
177 WithNoFixture(ES2_D3D9()),
178 WithNoFixture(ES2_D3D11()),
179 WithNoFixture(ES2_METAL()),
180 WithNoFixture(ES2_OPENGL()),
181 WithNoFixture(ES2_VULKAN()),
182 WithNoFixture(ES3_D3D11()),
183 WithNoFixture(ES3_METAL()),
184 WithNoFixture(ES3_OPENGL()),
185 WithNoFixture(ES3_VULKAN()));
186