• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // Copyright 2021 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 // EGLBufferAgeTest.cpp:
7 //   EGL extension EGL_EXT_buffer_age
8 //
9 
10 #include <gtest/gtest.h>
11 
12 #include "test_utils/ANGLETest.h"
13 #include "util/EGLWindow.h"
14 #include "util/OSWindow.h"
15 
16 using namespace angle;
17 
18 class EGLBufferAgeTest : public ANGLETest
19 {
20   public:
EGLBufferAgeTest()21     EGLBufferAgeTest() : mDisplay(EGL_NO_DISPLAY) {}
22 
testSetUp()23     void testSetUp() override
24     {
25         EGLint dispattrs[] = {EGL_PLATFORM_ANGLE_TYPE_ANGLE, GetParam().getRenderer(), EGL_NONE};
26         mDisplay           = eglGetPlatformDisplayEXT(
27             EGL_PLATFORM_ANGLE_ANGLE, reinterpret_cast<void *>(EGL_DEFAULT_DISPLAY), dispattrs);
28         EXPECT_TRUE(mDisplay != EGL_NO_DISPLAY);
29         EXPECT_EGL_TRUE(eglInitialize(mDisplay, nullptr, nullptr));
30         mMajorVersion       = GetParam().majorVersion;
31         mExtensionSupported = IsEGLDisplayExtensionEnabled(mDisplay, "EGL_EXT_buffer_age");
32     }
33 
testTearDown()34     void testTearDown() override
35     {
36         if (mDisplay != EGL_NO_DISPLAY)
37         {
38             eglTerminate(mDisplay);
39             eglReleaseThread();
40             mDisplay = EGL_NO_DISPLAY;
41         }
42         ASSERT_EGL_SUCCESS() << "Error during test TearDown";
43     }
44 
chooseConfig(EGLConfig * config)45     bool chooseConfig(EGLConfig *config)
46     {
47         bool result          = false;
48         EGLint count         = 0;
49         EGLint clientVersion = mMajorVersion == 3 ? EGL_OPENGL_ES3_BIT : EGL_OPENGL_ES2_BIT;
50         EGLint attribs[]     = {EGL_RED_SIZE,
51                             8,
52                             EGL_GREEN_SIZE,
53                             8,
54                             EGL_BLUE_SIZE,
55                             8,
56                             EGL_ALPHA_SIZE,
57                             0,
58                             EGL_RENDERABLE_TYPE,
59                             clientVersion,
60                             EGL_SURFACE_TYPE,
61                             EGL_WINDOW_BIT,
62                             EGL_NONE};
63 
64         result = eglChooseConfig(mDisplay, attribs, config, 1, &count);
65         EXPECT_EGL_TRUE(result && (count > 0));
66         return result;
67     }
68 
createContext(EGLConfig config,EGLContext * context)69     bool createContext(EGLConfig config, EGLContext *context)
70     {
71         bool result      = false;
72         EGLint attribs[] = {EGL_CONTEXT_MAJOR_VERSION, mMajorVersion, EGL_NONE};
73 
74         *context = eglCreateContext(mDisplay, config, nullptr, attribs);
75         result   = (*context != EGL_NO_CONTEXT);
76         EXPECT_TRUE(result);
77         return result;
78     }
79 
createWindowSurface(EGLConfig config,EGLNativeWindowType win,EGLSurface * surface)80     bool createWindowSurface(EGLConfig config, EGLNativeWindowType win, EGLSurface *surface)
81     {
82         bool result      = false;
83         EGLint attribs[] = {EGL_NONE};
84 
85         *surface = eglCreateWindowSurface(mDisplay, config, win, attribs);
86         result   = (*surface != EGL_NO_SURFACE);
87         EXPECT_TRUE(result);
88         return result;
89     }
90 
queryAge(EGLSurface surface)91     EGLint queryAge(EGLSurface surface)
92     {
93         EGLint value = 0;
94         bool result  = eglQuerySurface(mDisplay, surface, EGL_BUFFER_AGE_EXT, &value);
95         EXPECT_TRUE(result);
96         return value;
97     }
98 
99     EGLDisplay mDisplay      = EGL_NO_DISPLAY;
100     EGLint mMajorVersion     = 0;
101     const EGLint kWidth      = 64;
102     const EGLint kHeight     = 64;
103     bool mExtensionSupported = false;
104 };
105 
106 // Query for buffer age
TEST_P(EGLBufferAgeTest,QueryBufferAge)107 TEST_P(EGLBufferAgeTest, QueryBufferAge)
108 {
109     ANGLE_SKIP_TEST_IF(!mExtensionSupported);
110 
111     EGLConfig config = EGL_NO_CONFIG_KHR;
112     EXPECT_TRUE(chooseConfig(&config));
113 
114     EGLContext context = EGL_NO_CONTEXT;
115     EXPECT_TRUE(createContext(config, &context));
116     ASSERT_EGL_SUCCESS() << "eglCreateContext failed.";
117 
118     EGLSurface surface = EGL_NO_SURFACE;
119 
120     OSWindow *osWindow = OSWindow::New();
121     osWindow->initialize("EGLBufferAgeTest", kWidth, kHeight);
122     EXPECT_TRUE(createWindowSurface(config, osWindow->getNativeWindow(), &surface));
123     ASSERT_EGL_SUCCESS() << "eglCreateWindowSurface failed.";
124 
125     EXPECT_TRUE(eglMakeCurrent(mDisplay, surface, surface, context));
126     ASSERT_EGL_SUCCESS() << "eglMakeCurrent failed.";
127 
128     glClearColor(1.0, 0.0, 0.0, 1.0);
129 
130     const uint32_t loopcount = 15;
131     EGLint expectedAge       = 0;
132     for (uint32_t i = 0; i < loopcount; i++)
133     {
134         EGLint age = queryAge(surface);
135         // Should start with zero age and then flip to buffer count - which we don't know.
136         if ((expectedAge == 0) && (age > 0))
137         {
138             expectedAge = age;
139         }
140         EXPECT_EQ(age, expectedAge);
141 
142         glClear(GL_COLOR_BUFFER_BIT);
143         ASSERT_GL_NO_ERROR() << "glClear failed";
144         eglSwapBuffers(mDisplay, surface);
145         ASSERT_EGL_SUCCESS() << "eglSwapBuffers failed.";
146     }
147     EXPECT_GT(expectedAge, 0);
148 
149     EXPECT_TRUE(eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, context));
150     ASSERT_EGL_SUCCESS() << "eglMakeCurrent - uncurrent failed.";
151 
152     eglDestroySurface(mDisplay, surface);
153     surface = EGL_NO_SURFACE;
154     osWindow->destroy();
155     OSWindow::Delete(&osWindow);
156 
157     eglDestroyContext(mDisplay, context);
158     context = EGL_NO_CONTEXT;
159 }
160 
161 // Verify contents of buffer are as expected
TEST_P(EGLBufferAgeTest,VerifyContents)162 TEST_P(EGLBufferAgeTest, VerifyContents)
163 {
164     ANGLE_SKIP_TEST_IF(!mExtensionSupported);
165 
166     EGLConfig config = EGL_NO_CONFIG_KHR;
167     EXPECT_TRUE(chooseConfig(&config));
168 
169     EGLContext context = EGL_NO_CONTEXT;
170     EXPECT_TRUE(createContext(config, &context));
171     ASSERT_EGL_SUCCESS() << "eglCreateContext failed.";
172 
173     EGLSurface surface = EGL_NO_SURFACE;
174 
175     OSWindow *osWindow = OSWindow::New();
176     osWindow->initialize("EGLBufferAgeTest", kWidth, kHeight);
177     EXPECT_TRUE(createWindowSurface(config, osWindow->getNativeWindow(), &surface));
178     ASSERT_EGL_SUCCESS() << "eglCreateWindowSurface failed.";
179 
180     EXPECT_TRUE(eglMakeCurrent(mDisplay, surface, surface, context));
181     ASSERT_EGL_SUCCESS() << "eglMakeCurrent failed.";
182 
183     const angle::GLColor kLightGray(191, 191, 191, 255);  // 0.75
184     const angle::GLColor kDarkGray(64, 64, 64, 255);      // 0.25
185     const angle::GLColor kColorSet[] = {
186         GLColor::blue,  GLColor::cyan,   kDarkGray,      GLColor::green,   GLColor::red,
187         GLColor::white, GLColor::yellow, GLColor::black, GLColor::magenta, kLightGray,
188         GLColor::black,  // Extra loops until color cycled through
189         GLColor::black, GLColor::black,  GLColor::black, GLColor::black};
190 
191     EGLint age                   = 0;
192     angle::GLColor expectedColor = GLColor::black;
193     int loopCount                = (sizeof(kColorSet) / sizeof(kColorSet[0]));
194     for (int i = 0; i < loopCount; i++)
195     {
196         age = queryAge(surface);
197         if (age > 0)
198         {
199             // Check that color/content is what we expect
200             expectedColor = kColorSet[i - age];
201             EXPECT_PIXEL_COLOR_EQ(1, 1, expectedColor);
202         }
203 
204         float red   = kColorSet[i].R / 255.0;
205         float green = kColorSet[i].G / 255.0;
206         float blue  = kColorSet[i].B / 255.0;
207         float alpha = kColorSet[i].A / 255.0;
208 
209         glClearColor(red, green, blue, alpha);
210         glClear(GL_COLOR_BUFFER_BIT);
211         ASSERT_GL_NO_ERROR() << "glClear failed";
212         eglSwapBuffers(mDisplay, surface);
213         ASSERT_EGL_SUCCESS() << "eglSwapBuffers failed.";
214     }
215     EXPECT_GT(age, 0);
216 
217     EXPECT_TRUE(eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, context));
218     ASSERT_EGL_SUCCESS() << "eglMakeCurrent - uncurrent failed.";
219 
220     eglDestroySurface(mDisplay, surface);
221     surface = EGL_NO_SURFACE;
222     osWindow->destroy();
223     OSWindow::Delete(&osWindow);
224 
225     eglDestroyContext(mDisplay, context);
226     context = EGL_NO_CONTEXT;
227 }
228 
229 // Verify EGL_BAD_SURFACE when not current
TEST_P(EGLBufferAgeTest,UncurrentContextBadSurface)230 TEST_P(EGLBufferAgeTest, UncurrentContextBadSurface)
231 {
232     ANGLE_SKIP_TEST_IF(!mExtensionSupported);
233 
234     EGLConfig config = EGL_NO_CONFIG_KHR;
235     EXPECT_TRUE(chooseConfig(&config));
236 
237     EGLContext context = EGL_NO_CONTEXT;
238     EXPECT_TRUE(createContext(config, &context));
239     ASSERT_EGL_SUCCESS() << "eglCreateContext failed.";
240 
241     EGLSurface surface = EGL_NO_SURFACE;
242 
243     OSWindow *osWindow = OSWindow::New();
244     osWindow->initialize("EGLBufferAgeTest", kWidth, kHeight);
245     EXPECT_TRUE(createWindowSurface(config, osWindow->getNativeWindow(), &surface));
246     ASSERT_EGL_SUCCESS() << "eglCreateWindowSurface failed.";
247 
248     // No current context
249 
250     EGLint value = 0;
251     EXPECT_EGL_FALSE(eglQuerySurface(mDisplay, surface, EGL_BUFFER_AGE_EXT, &value));
252     EXPECT_EGL_ERROR(EGL_BAD_SURFACE);
253 
254     EGLContext otherContext = EGL_NO_CONTEXT;
255     EXPECT_TRUE(createContext(config, &otherContext));
256     ASSERT_EGL_SUCCESS() << "eglCreateContext failed.";
257 
258     // Surface current to another context
259     EXPECT_TRUE(eglMakeCurrent(mDisplay, surface, surface, otherContext));
260     // Make context the active context
261     EXPECT_TRUE(eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, context));
262 
263     value = 0;
264     EXPECT_EGL_FALSE(eglQuerySurface(mDisplay, surface, EGL_BUFFER_AGE_EXT, &value));
265     EXPECT_EGL_ERROR(EGL_BAD_SURFACE);
266 
267     eglDestroySurface(mDisplay, surface);
268     surface = EGL_NO_SURFACE;
269     osWindow->destroy();
270     OSWindow::Delete(&osWindow);
271 
272     eglDestroyContext(mDisplay, otherContext);
273     otherContext = EGL_NO_CONTEXT;
274 
275     eglDestroyContext(mDisplay, context);
276     context = EGL_NO_CONTEXT;
277 }
278 
279 // Expect age always == 1 when EGL_BUFFER_PRESERVED is chosen
TEST_P(EGLBufferAgeTest,BufferPreserved)280 TEST_P(EGLBufferAgeTest, BufferPreserved)
281 {
282     ANGLE_SKIP_TEST_IF(!mExtensionSupported);
283 
284     EGLConfig config     = EGL_NO_CONFIG_KHR;
285     EGLint count         = 0;
286     EGLint clientVersion = mMajorVersion == 3 ? EGL_OPENGL_ES3_BIT : EGL_OPENGL_ES2_BIT;
287     EGLint attribs[]     = {EGL_RED_SIZE,
288                         8,
289                         EGL_GREEN_SIZE,
290                         8,
291                         EGL_BLUE_SIZE,
292                         8,
293                         EGL_ALPHA_SIZE,
294                         0,
295                         EGL_RENDERABLE_TYPE,
296                         clientVersion,
297                         EGL_SURFACE_TYPE,
298                         EGL_WINDOW_BIT | EGL_SWAP_BEHAVIOR_PRESERVED_BIT,
299                         EGL_NONE};
300 
301     EXPECT_EGL_TRUE(eglChooseConfig(mDisplay, attribs, &config, 1, &count));
302     // Skip if no configs, this indicates EGL_BUFFER_PRESERVED is not supported.
303     ANGLE_SKIP_TEST_IF(count == 0);
304 
305     EGLContext context = EGL_NO_CONTEXT;
306     EXPECT_TRUE(createContext(config, &context));
307     ASSERT_EGL_SUCCESS() << "eglCreateContext failed.";
308 
309     EGLSurface surface = EGL_NO_SURFACE;
310 
311     OSWindow *osWindow = OSWindow::New();
312     osWindow->initialize("EGLBufferAgeTest", kWidth, kHeight);
313     EXPECT_TRUE(createWindowSurface(config, osWindow->getNativeWindow(), &surface));
314     ASSERT_EGL_SUCCESS() << "eglCreateWindowSurface failed.";
315 
316     EXPECT_TRUE(eglMakeCurrent(mDisplay, surface, surface, context));
317     ASSERT_EGL_SUCCESS() << "eglMakeCurrent failed.";
318 
319     glClearColor(1.0, 0.0, 0.0, 1.0);
320 
321     const uint32_t loopcount = 10;
322     EGLint expectedAge       = 1;
323     for (uint32_t i = 0; i < loopcount; i++)
324     {
325         EGLint age = queryAge(surface);
326         EXPECT_EQ(age, expectedAge);
327 
328         glClear(GL_COLOR_BUFFER_BIT);
329         ASSERT_GL_NO_ERROR() << "glClear failed";
330         eglSwapBuffers(mDisplay, surface);
331         ASSERT_EGL_SUCCESS() << "eglSwapBuffers failed.";
332     }
333 
334     EXPECT_TRUE(eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, context));
335     ASSERT_EGL_SUCCESS() << "eglMakeCurrent - uncurrent failed.";
336 
337     eglDestroySurface(mDisplay, surface);
338     surface = EGL_NO_SURFACE;
339     osWindow->destroy();
340     OSWindow::Delete(&osWindow);
341 
342     eglDestroyContext(mDisplay, context);
343     context = EGL_NO_CONTEXT;
344 }
345 
346 ANGLE_INSTANTIATE_TEST(EGLBufferAgeTest,
347                        WithNoFixture(ES2_OPENGLES()),
348                        WithNoFixture(ES3_OPENGLES()),
349                        WithNoFixture(ES2_OPENGL()),
350                        WithNoFixture(ES3_OPENGL()),
351                        WithNoFixture(ES2_VULKAN()),
352                        WithNoFixture(ES3_VULKAN()));