xref: /aosp_15_r20/external/angle/src/tests/egl_tests/EGLDisplayTest.cpp (revision 8975f5c5ed3d1c378011245431ada316dfb6f244)
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