xref: /aosp_15_r20/external/angle/src/tests/egl_tests/EGLSyncTest.cpp (revision 8975f5c5ed3d1c378011245431ada316dfb6f244)
1 //
2 // Copyright 2019 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 // EGLSyncTest.cpp:
7 //   Tests of EGL_KHR_fence_sync and EGL_KHR_wait_sync extensions.
8 
9 #include <gtest/gtest.h>
10 
11 #include "test_utils/ANGLETest.h"
12 #include "test_utils/angle_test_configs.h"
13 #include "test_utils/gl_raii.h"
14 #include "util/EGLWindow.h"
15 
16 using namespace angle;
17 
18 class EGLSyncTest : public ANGLETest<>
19 {
20   protected:
hasFenceSyncExtension() const21     bool hasFenceSyncExtension() const
22     {
23         return IsEGLDisplayExtensionEnabled(getEGLWindow()->getDisplay(), "EGL_KHR_fence_sync");
24     }
hasWaitSyncExtension() const25     bool hasWaitSyncExtension() const
26     {
27         return hasFenceSyncExtension() &&
28                IsEGLDisplayExtensionEnabled(getEGLWindow()->getDisplay(), "EGL_KHR_wait_sync");
29     }
hasGLSyncExtension() const30     bool hasGLSyncExtension() const { return IsGLExtensionEnabled("GL_OES_EGL_sync"); }
31 
hasAndroidNativeFenceSyncExtension() const32     bool hasAndroidNativeFenceSyncExtension() const
33     {
34         return IsEGLDisplayExtensionEnabled(getEGLWindow()->getDisplay(),
35                                             "EGL_ANDROID_native_fence_sync");
36     }
37 };
38 
39 // Test error cases for all EGL_KHR_fence_sync functions
TEST_P(EGLSyncTest,FenceSyncErrors)40 TEST_P(EGLSyncTest, FenceSyncErrors)
41 {
42     ANGLE_SKIP_TEST_IF(!hasFenceSyncExtension());
43 
44     EGLDisplay display = getEGLWindow()->getDisplay();
45 
46     // If the client API doesn't have the necessary extension, test that sync creation fails and
47     // ignore the rest of the tests.
48     if (!hasGLSyncExtension())
49     {
50         EXPECT_EQ(EGL_NO_SYNC_KHR, eglCreateSyncKHR(display, EGL_SYNC_FENCE_KHR, nullptr));
51         EXPECT_EGL_ERROR(EGL_BAD_MATCH);
52     }
53 
54     ANGLE_SKIP_TEST_IF(!hasGLSyncExtension());
55 
56     EGLContext context     = eglGetCurrentContext();
57     EGLSurface drawSurface = eglGetCurrentSurface(EGL_DRAW);
58     EGLSurface readSurface = eglGetCurrentSurface(EGL_READ);
59 
60     EXPECT_NE(context, EGL_NO_CONTEXT);
61     EXPECT_NE(drawSurface, EGL_NO_SURFACE);
62     EXPECT_NE(readSurface, EGL_NO_SURFACE);
63 
64     // CreateSync with no attribute shouldn't cause an error
65     EGLSyncKHR sync = eglCreateSyncKHR(display, EGL_SYNC_FENCE_KHR, nullptr);
66     EXPECT_NE(sync, EGL_NO_SYNC_KHR);
67 
68     EXPECT_EGL_TRUE(eglDestroySyncKHR(display, sync));
69 
70     // CreateSync with empty attribute shouldn't cause an error
71     const EGLint emptyAttributes[] = {EGL_NONE};
72     sync                           = eglCreateSyncKHR(display, EGL_SYNC_FENCE_KHR, emptyAttributes);
73     EXPECT_NE(sync, EGL_NO_SYNC_KHR);
74 
75     // DestroySync generates BAD_PARAMETER if the sync is not valid
76     EXPECT_EGL_FALSE(eglDestroySyncKHR(display, reinterpret_cast<EGLSyncKHR>(20)));
77     EXPECT_EGL_ERROR(EGL_BAD_PARAMETER);
78 
79     // CreateSync generates BAD_DISPLAY if display is not valid
80     EXPECT_EQ(EGL_NO_SYNC_KHR, eglCreateSyncKHR(EGL_NO_DISPLAY, EGL_SYNC_FENCE_KHR, nullptr));
81     EXPECT_EGL_ERROR(EGL_BAD_DISPLAY);
82 
83     // CreateSync generates BAD_ATTRIBUTE if attribute is neither nullptr nor empty.
84     const EGLint nonEmptyAttributes[] = {
85         EGL_CL_EVENT_HANDLE,
86         0,
87         EGL_NONE,
88     };
89     EXPECT_EQ(EGL_NO_SYNC_KHR, eglCreateSyncKHR(display, EGL_SYNC_FENCE_KHR, nonEmptyAttributes));
90     EXPECT_EGL_ERROR(EGL_BAD_ATTRIBUTE);
91 
92     // CreateSync generates BAD_ATTRIBUTE if type is not valid
93     EXPECT_EQ(EGL_NO_SYNC_KHR, eglCreateSyncKHR(display, 0, nullptr));
94     EXPECT_EGL_ERROR(EGL_BAD_ATTRIBUTE);
95 
96     // CreateSync generates BAD_MATCH if no context is current
97     eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
98     EXPECT_EQ(EGL_NO_SYNC_KHR, eglCreateSyncKHR(display, EGL_SYNC_FENCE_KHR, nullptr));
99     EXPECT_EGL_ERROR(EGL_BAD_MATCH);
100     eglMakeCurrent(display, drawSurface, readSurface, context);
101 
102     // ClientWaitSync generates EGL_BAD_PARAMETER if the sync object is not valid
103     EXPECT_EGL_FALSE(eglClientWaitSyncKHR(display, reinterpret_cast<EGLSyncKHR>(30), 0, 0));
104     EXPECT_EGL_ERROR(EGL_BAD_PARAMETER);
105 
106     // GetSyncAttrib generates EGL_BAD_PARAMETER if the sync object is not valid, and value is not
107     // modified
108     constexpr EGLint kSentinelAttribValue = 123456789;
109     EGLint attribValue                    = kSentinelAttribValue;
110     EXPECT_EGL_FALSE(eglGetSyncAttribKHR(display, reinterpret_cast<EGLSyncKHR>(40),
111                                          EGL_SYNC_TYPE_KHR, &attribValue));
112     EXPECT_EGL_ERROR(EGL_BAD_PARAMETER);
113     EXPECT_EQ(attribValue, kSentinelAttribValue);
114 
115     // GetSyncAttrib generates EGL_BAD_ATTRIBUTE if the attribute is not valid, and value is not
116     // modified
117     EXPECT_EGL_FALSE(eglGetSyncAttribKHR(display, sync, EGL_CL_EVENT_HANDLE, &attribValue));
118     EXPECT_EGL_ERROR(EGL_BAD_ATTRIBUTE);
119     EXPECT_EQ(attribValue, kSentinelAttribValue);
120 
121     // GetSyncAttrib generates EGL_BAD_MATCH if the attribute is valid for sync, but not the
122     // particular sync type. We don't have such a case at the moment.
123 
124     EXPECT_EGL_TRUE(eglDestroySyncKHR(display, sync));
125 }
126 
127 // Test error cases for all EGL_KHR_wait_sync functions
TEST_P(EGLSyncTest,WaitSyncErrors)128 TEST_P(EGLSyncTest, WaitSyncErrors)
129 {
130     // The client API that shows support for eglWaitSyncKHR is the same as the one required for
131     // eglCreateSyncKHR.  As such, there is no way to create a sync and not be able to wait on it.
132     // This would have created an EGL_BAD_MATCH error.
133     ANGLE_SKIP_TEST_IF(!hasWaitSyncExtension() || !hasGLSyncExtension());
134 
135     EGLDisplay display     = getEGLWindow()->getDisplay();
136     EGLContext context     = eglGetCurrentContext();
137     EGLSurface drawSurface = eglGetCurrentSurface(EGL_DRAW);
138     EGLSurface readSurface = eglGetCurrentSurface(EGL_READ);
139 
140     EXPECT_NE(context, EGL_NO_CONTEXT);
141     EXPECT_NE(drawSurface, EGL_NO_SURFACE);
142     EXPECT_NE(readSurface, EGL_NO_SURFACE);
143 
144     EGLSyncKHR sync = eglCreateSyncKHR(display, EGL_SYNC_FENCE_KHR, nullptr);
145     EXPECT_NE(sync, EGL_NO_SYNC_KHR);
146 
147     // WaitSync generates BAD_MATCH if no context is current
148     eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
149     EXPECT_EGL_FALSE(eglWaitSyncKHR(display, sync, 0));
150     EXPECT_EGL_ERROR(EGL_BAD_MATCH);
151     eglMakeCurrent(display, drawSurface, readSurface, context);
152 
153     // WaitSync generates BAD_PARAMETER if the sync is not valid
154     EXPECT_EGL_FALSE(eglWaitSyncKHR(display, reinterpret_cast<EGLSyncKHR>(20), 0));
155     EXPECT_EGL_ERROR(EGL_BAD_PARAMETER);
156 
157     // WaitSync generates BAD_PARAMETER if flags is non-zero
158     EXPECT_EGL_FALSE(eglWaitSyncKHR(display, sync, 1));
159     EXPECT_EGL_ERROR(EGL_BAD_PARAMETER);
160 
161     EXPECT_EGL_TRUE(eglDestroySyncKHR(display, sync));
162 }
163 
164 // Test usage of eglGetSyncAttribKHR
TEST_P(EGLSyncTest,GetSyncAttrib)165 TEST_P(EGLSyncTest, GetSyncAttrib)
166 {
167     ANGLE_SKIP_TEST_IF(!hasFenceSyncExtension() || !hasGLSyncExtension());
168 
169     EGLDisplay display = getEGLWindow()->getDisplay();
170 
171     EGLSyncKHR sync = eglCreateSyncKHR(display, EGL_SYNC_FENCE_KHR, nullptr);
172     EXPECT_NE(sync, EGL_NO_SYNC_KHR);
173 
174     // Fence sync attributes are:
175     //
176     // EGL_SYNC_TYPE_KHR: EGL_SYNC_FENCE_KHR
177     // EGL_SYNC_STATUS_KHR: EGL_UNSIGNALED_KHR or EGL_SIGNALED_KHR
178     // EGL_SYNC_CONDITION_KHR: EGL_SYNC_PRIOR_COMMANDS_COMPLETE_KHR
179 
180     constexpr EGLint kSentinelAttribValue = 123456789;
181     EGLint attribValue                    = kSentinelAttribValue;
182     EXPECT_EGL_TRUE(eglGetSyncAttribKHR(display, sync, EGL_SYNC_TYPE_KHR, &attribValue));
183     EXPECT_EQ(attribValue, EGL_SYNC_FENCE_KHR);
184 
185     attribValue = kSentinelAttribValue;
186     EXPECT_EGL_TRUE(eglGetSyncAttribKHR(display, sync, EGL_SYNC_CONDITION_KHR, &attribValue));
187     EXPECT_EQ(attribValue, EGL_SYNC_PRIOR_COMMANDS_COMPLETE_KHR);
188 
189     attribValue = kSentinelAttribValue;
190     EXPECT_EGL_TRUE(eglGetSyncAttribKHR(display, sync, EGL_SYNC_STATUS_KHR, &attribValue));
191 
192     // Hack around EXPECT_* not having an "either this or that" variant:
193     if (attribValue != EGL_SIGNALED_KHR)
194     {
195         EXPECT_EQ(attribValue, EGL_UNSIGNALED_KHR);
196     }
197 
198     EXPECT_EGL_TRUE(eglDestroySyncKHR(display, sync));
199 }
200 
201 // Test that basic usage works and doesn't generate errors or crash
TEST_P(EGLSyncTest,BasicOperations)202 TEST_P(EGLSyncTest, BasicOperations)
203 {
204     ANGLE_SKIP_TEST_IF(!hasFenceSyncExtension() || !hasGLSyncExtension());
205 
206     EGLDisplay display = getEGLWindow()->getDisplay();
207 
208     EGLSyncKHR sync = eglCreateSyncKHR(display, EGL_SYNC_FENCE_KHR, nullptr);
209     EXPECT_NE(sync, EGL_NO_SYNC_KHR);
210 
211     glClearColor(1.0f, 0.0f, 1.0f, 1.0f);
212 
213     glClear(GL_COLOR_BUFFER_BIT);
214     EXPECT_EGL_TRUE(eglWaitSyncKHR(display, sync, 0));
215 
216     glFlush();
217 
218     glClear(GL_COLOR_BUFFER_BIT);
219 
220     // Don't wait forever to make sure the test terminates
221     constexpr GLuint64 kTimeout = 1'000'000'000;  // 1 second
222     EGLint value                = 0;
223     ASSERT_EQ(EGL_CONDITION_SATISFIED_KHR,
224               eglClientWaitSyncKHR(display, sync, EGL_SYNC_FLUSH_COMMANDS_BIT_KHR, kTimeout));
225 
226     for (size_t i = 0; i < 20; i++)
227     {
228         glClear(GL_COLOR_BUFFER_BIT);
229         EXPECT_EQ(
230             EGL_CONDITION_SATISFIED_KHR,
231             eglClientWaitSyncKHR(display, sync, EGL_SYNC_FLUSH_COMMANDS_BIT_KHR, EGL_FOREVER_KHR));
232         EXPECT_EGL_TRUE(eglGetSyncAttribKHR(display, sync, EGL_SYNC_STATUS_KHR, &value));
233         EXPECT_EQ(value, EGL_SIGNALED_KHR);
234     }
235 
236     EXPECT_EGL_TRUE(eglDestroySyncKHR(display, sync));
237 }
238 
239 // Test that eglClientWaitSync* APIs work.
TEST_P(EGLSyncTest,EglClientWaitSync)240 TEST_P(EGLSyncTest, EglClientWaitSync)
241 {
242     ANGLE_SKIP_TEST_IF(!hasFenceSyncExtension());
243 
244     EGLDisplay display = getEGLWindow()->getDisplay();
245     ANGLE_GL_PROGRAM(greenProgram, essl1_shaders::vs::Simple(), essl1_shaders::fs::Green());
246 
247     // Test eglClientWaitSyncKHR
248     for (size_t i = 0; i < 5; i++)
249     {
250         glClearColor(1.0f, 0.0f, 1.0f, 1.0f);
251         glClear(GL_COLOR_BUFFER_BIT);
252         drawQuad(greenProgram, std::string(essl1_shaders::PositionAttrib()), 0.0f);
253         ASSERT_GL_NO_ERROR();
254 
255         // Don't wait forever to make sure the test terminates
256         constexpr GLuint64 kTimeout = 1'000'000'000;  // 1 second
257         EGLSyncKHR clientWaitSync   = eglCreateSyncKHR(display, EGL_SYNC_FENCE_KHR, nullptr);
258         EXPECT_NE(clientWaitSync, EGL_NO_SYNC_KHR);
259 
260         ASSERT_EQ(EGL_CONDITION_SATISFIED_KHR,
261                   eglClientWaitSyncKHR(display, clientWaitSync, EGL_SYNC_FLUSH_COMMANDS_BIT_KHR,
262                                        kTimeout));
263 
264         EXPECT_EGL_TRUE(eglDestroySyncKHR(display, clientWaitSync));
265         ASSERT_EGL_SUCCESS();
266     }
267 
268     // Test eglClientWaitSync
269     for (size_t i = 0; i < 5; i++)
270     {
271         glClearColor(1.0f, 0.0f, 1.0f, 1.0f);
272         glClear(GL_COLOR_BUFFER_BIT);
273         drawQuad(greenProgram, std::string(essl1_shaders::PositionAttrib()), 0.0f);
274         ASSERT_GL_NO_ERROR();
275 
276         // Don't wait forever to make sure the test terminates
277         constexpr GLuint64 kTimeout = 1'000'000'000;  // 1 second
278         EGLSyncKHR clientWaitSync   = eglCreateSync(display, EGL_SYNC_FENCE, nullptr);
279         EXPECT_NE(clientWaitSync, EGL_NO_SYNC);
280 
281         ASSERT_EQ(
282             EGL_CONDITION_SATISFIED,
283             eglClientWaitSync(display, clientWaitSync, EGL_SYNC_FLUSH_COMMANDS_BIT, kTimeout));
284 
285         EXPECT_EGL_TRUE(eglDestroySync(display, clientWaitSync));
286         ASSERT_EGL_SUCCESS();
287     }
288 }
289 
290 // Test eglWaitClient api
TEST_P(EGLSyncTest,WaitClient)291 TEST_P(EGLSyncTest, WaitClient)
292 {
293     // Clear to red color
294     glClearColor(1.0f, 0.0f, 0.0f, 1.0f);
295 
296     glClear(GL_COLOR_BUFFER_BIT);
297     EXPECT_EGL_TRUE(eglWaitClient());
298     EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 2, getWindowHeight() / 2, GLColor::red);
299 
300     EGLDisplay display = getEGLWindow()->getDisplay();
301     EGLContext context = getEGLWindow()->getContext();
302     EGLSurface surface = getEGLWindow()->getSurface();
303     eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
304     EXPECT_EGL_TRUE(eglWaitClient());
305     eglMakeCurrent(display, surface, surface, context);
306 }
307 
308 // Test eglWaitGL api
TEST_P(EGLSyncTest,WaitGL)309 TEST_P(EGLSyncTest, WaitGL)
310 {
311     // Clear to red color
312     glClearColor(1.0f, 0.0f, 0.0f, 1.0f);
313 
314     glClear(GL_COLOR_BUFFER_BIT);
315     EXPECT_EGL_TRUE(eglWaitGL());
316     EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 2, getWindowHeight() / 2, GLColor::red);
317 
318     EGLDisplay display = getEGLWindow()->getDisplay();
319     EGLContext context = getEGLWindow()->getContext();
320     EGLSurface surface = getEGLWindow()->getSurface();
321     eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
322     EXPECT_EGL_TRUE(eglWaitGL());
323     eglMakeCurrent(display, surface, surface, context);
324 }
325 
326 // Test eglWaitNative api
TEST_P(EGLSyncTest,WaitNative)327 TEST_P(EGLSyncTest, WaitNative)
328 {
329     // Clear to red color
330     glClearColor(1.0f, 0.0f, 0.0f, 1.0f);
331 
332     glClear(GL_COLOR_BUFFER_BIT);
333     EXPECT_EGL_TRUE(eglWaitNative(EGL_CORE_NATIVE_ENGINE));
334     EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 2, getWindowHeight() / 2, GLColor::red);
335 
336     EGLDisplay display = getEGLWindow()->getDisplay();
337     EGLContext context = getEGLWindow()->getContext();
338     EGLSurface surface = getEGLWindow()->getSurface();
339     eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
340     EXPECT_EGL_TRUE(eglWaitNative(EGL_CORE_NATIVE_ENGINE));
341     eglMakeCurrent(display, surface, surface, context);
342 }
343 
344 // Verify eglDupNativeFence for EGL_ANDROID_native_fence_sync
TEST_P(EGLSyncTest,AndroidNativeFence_DupNativeFenceFD)345 TEST_P(EGLSyncTest, AndroidNativeFence_DupNativeFenceFD)
346 {
347     ANGLE_SKIP_TEST_IF(!hasFenceSyncExtension());
348     ANGLE_SKIP_TEST_IF(!hasFenceSyncExtension() || !hasGLSyncExtension());
349     ANGLE_SKIP_TEST_IF(!hasAndroidNativeFenceSyncExtension());
350 
351     EGLDisplay display = getEGLWindow()->getDisplay();
352 
353     // We can ClientWait on this
354     EGLSyncKHR syncWithGeneratedFD =
355         eglCreateSyncKHR(display, EGL_SYNC_NATIVE_FENCE_ANDROID, nullptr);
356     EXPECT_NE(syncWithGeneratedFD, EGL_NO_SYNC_KHR);
357 
358     int fd = eglDupNativeFenceFDANDROID(display, syncWithGeneratedFD);
359     EXPECT_EGL_SUCCESS();
360 
361     // Clean up created objects.
362     if (fd != EGL_NO_NATIVE_FENCE_FD_ANDROID)
363     {
364         close(fd);
365     }
366 
367     EXPECT_EGL_TRUE(eglDestroySyncKHR(display, syncWithGeneratedFD));
368 }
369 
370 // Verify CreateSync and ClientWait for EGL_ANDROID_native_fence_sync
TEST_P(EGLSyncTest,AndroidNativeFence_ClientWait)371 TEST_P(EGLSyncTest, AndroidNativeFence_ClientWait)
372 {
373     ANGLE_SKIP_TEST_IF(!hasFenceSyncExtension());
374     ANGLE_SKIP_TEST_IF(!hasFenceSyncExtension() || !hasGLSyncExtension());
375     ANGLE_SKIP_TEST_IF(!hasAndroidNativeFenceSyncExtension());
376 
377     EGLint value       = 0;
378     EGLDisplay display = getEGLWindow()->getDisplay();
379 
380     // We can ClientWait on this
381     EGLSyncKHR syncWithGeneratedFD =
382         eglCreateSyncKHR(display, EGL_SYNC_NATIVE_FENCE_ANDROID, nullptr);
383     EXPECT_NE(syncWithGeneratedFD, EGL_NO_SYNC_KHR);
384 
385     // Create work to do
386     glClearColor(0.0f, 1.0f, 0.0f, 1.0f);
387     glClear(GL_COLOR_BUFFER_BIT);
388     glFlush();
389 
390     // Wait for draw to complete
391     EXPECT_EQ(EGL_CONDITION_SATISFIED,
392               eglClientWaitSyncKHR(display, syncWithGeneratedFD, EGL_SYNC_FLUSH_COMMANDS_BIT_KHR,
393                                    1'000'000'000));
394     EXPECT_EGL_TRUE(eglGetSyncAttribKHR(display, syncWithGeneratedFD, EGL_SYNC_STATUS_KHR, &value));
395     EXPECT_EQ(value, EGL_SIGNALED_KHR);
396 
397     // Clean up created objects.
398     EXPECT_EGL_TRUE(eglDestroySyncKHR(display, syncWithGeneratedFD));
399 }
400 
401 // Verify WaitSync with EGL_ANDROID_native_fence_sync
402 // Simulate passing FDs across processes by passing across Contexts.
TEST_P(EGLSyncTest,AndroidNativeFence_WaitSync)403 TEST_P(EGLSyncTest, AndroidNativeFence_WaitSync)
404 {
405     ANGLE_SKIP_TEST_IF(!hasFenceSyncExtension());
406     ANGLE_SKIP_TEST_IF(!hasWaitSyncExtension() || !hasGLSyncExtension());
407     ANGLE_SKIP_TEST_IF(!hasAndroidNativeFenceSyncExtension());
408 
409     EGLint value       = 0;
410     EGLDisplay display = getEGLWindow()->getDisplay();
411     EGLSurface surface = getEGLWindow()->getSurface();
412 
413     /*- First Context ------------------------*/
414 
415     // We can ClientWait on this
416     EGLSyncKHR syncWithGeneratedFD =
417         eglCreateSyncKHR(display, EGL_SYNC_NATIVE_FENCE_ANDROID, nullptr);
418     EXPECT_NE(syncWithGeneratedFD, EGL_NO_SYNC_KHR);
419 
420     int fd = eglDupNativeFenceFDANDROID(display, syncWithGeneratedFD);
421     EXPECT_EGL_SUCCESS();  // Can return -1 (when signaled) or valid FD.
422 
423     // Create work to do
424     glClearColor(0.0f, 1.0f, 0.0f, 1.0f);
425     glClear(GL_COLOR_BUFFER_BIT);
426     glFlush();
427 
428     /*- Second Context ------------------------*/
429     if (fd > EGL_NO_NATIVE_FENCE_FD_ANDROID)
430     {
431         EXPECT_EGL_TRUE(eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT));
432 
433         EGLContext context2 = getEGLWindow()->createContext(EGL_NO_CONTEXT, nullptr);
434         EXPECT_EGL_TRUE(eglMakeCurrent(display, surface, surface, context2));
435 
436         // We can eglWaitSync on this - import FD from first sync.
437         EGLint syncAttribs[] = {EGL_SYNC_NATIVE_FENCE_FD_ANDROID, (EGLint)fd, EGL_NONE};
438         EGLSyncKHR syncWithDupFD =
439             eglCreateSyncKHR(display, EGL_SYNC_NATIVE_FENCE_ANDROID, syncAttribs);
440         EXPECT_NE(syncWithDupFD, EGL_NO_SYNC_KHR);
441 
442         // Second draw waits for first to complete. May already be signaled - ignore error.
443         if (eglWaitSyncKHR(display, syncWithDupFD, 0) == EGL_TRUE)
444         {
445             // Create work to do
446             glClearColor(1.0f, 0.0f, 0.0f, 1.0f);
447             glClear(GL_COLOR_BUFFER_BIT);
448             glFlush();
449         }
450 
451         // Wait for second draw to complete
452         EXPECT_EQ(EGL_CONDITION_SATISFIED,
453                   eglClientWaitSyncKHR(display, syncWithDupFD, EGL_SYNC_FLUSH_COMMANDS_BIT_KHR,
454                                        1000000000));
455         EXPECT_EGL_TRUE(eglGetSyncAttribKHR(display, syncWithDupFD, EGL_SYNC_STATUS_KHR, &value));
456         EXPECT_EQ(value, EGL_SIGNALED_KHR);
457 
458         // Reset to default context and surface.
459         EXPECT_EGL_TRUE(eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT));
460         EXPECT_EGL_TRUE(eglMakeCurrent(display, surface, surface, getEGLWindow()->getContext()));
461 
462         // Clean up created objects.
463         EXPECT_EGL_TRUE(eglDestroySyncKHR(display, syncWithDupFD));
464         EXPECT_EGL_TRUE(eglDestroyContext(display, context2));
465     }
466 
467     // Wait for first draw to complete
468     EXPECT_EQ(EGL_CONDITION_SATISFIED,
469               eglClientWaitSyncKHR(display, syncWithGeneratedFD, EGL_SYNC_FLUSH_COMMANDS_BIT_KHR,
470                                    1000000000));
471     EXPECT_EGL_TRUE(eglGetSyncAttribKHR(display, syncWithGeneratedFD, EGL_SYNC_STATUS_KHR, &value));
472     EXPECT_EQ(value, EGL_SIGNALED_KHR);
473 
474     // Clean up created objects.
475     EXPECT_EGL_TRUE(eglDestroySyncKHR(display, syncWithGeneratedFD));
476 }
477 
478 // Verify EGL_ANDROID_native_fence_sync
479 // Simulate passing FDs across processes by passing across Contexts.
TEST_P(EGLSyncTest,AndroidNativeFence_withFences)480 TEST_P(EGLSyncTest, AndroidNativeFence_withFences)
481 {
482     ANGLE_SKIP_TEST_IF(!hasFenceSyncExtension());
483     ANGLE_SKIP_TEST_IF(!hasWaitSyncExtension() || !hasGLSyncExtension());
484     ANGLE_SKIP_TEST_IF(!hasAndroidNativeFenceSyncExtension());
485 
486     EGLint value       = 0;
487     EGLDisplay display = getEGLWindow()->getDisplay();
488     EGLSurface surface = getEGLWindow()->getSurface();
489 
490     /*- First Context ------------------------*/
491 
492     // Extra fence syncs to ensure that Fence and Android Native fences work together
493     EGLSyncKHR syncFence1 = eglCreateSyncKHR(display, EGL_SYNC_FENCE_KHR, nullptr);
494     EXPECT_NE(syncFence1, EGL_NO_SYNC_KHR);
495 
496     // We can ClientWait on this
497     EGLSyncKHR syncWithGeneratedFD =
498         eglCreateSyncKHR(display, EGL_SYNC_NATIVE_FENCE_ANDROID, nullptr);
499     EXPECT_NE(syncWithGeneratedFD, EGL_NO_SYNC_KHR);
500 
501     int fd = eglDupNativeFenceFDANDROID(display, syncWithGeneratedFD);
502     EXPECT_EGL_SUCCESS();  // Can return -1 (when signaled) or valid FD.
503 
504     EGLSyncKHR syncFence2 = eglCreateSyncKHR(display, EGL_SYNC_FENCE_KHR, nullptr);
505     EXPECT_NE(syncFence2, EGL_NO_SYNC_KHR);
506 
507     // Create work to do
508     glClearColor(0.0f, 1.0f, 0.0f, 1.0f);
509     glClear(GL_COLOR_BUFFER_BIT);
510     glFlush();
511 
512     /*- Second Context ------------------------*/
513     if (fd > EGL_NO_NATIVE_FENCE_FD_ANDROID)
514     {
515         EXPECT_EGL_TRUE(eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT));
516 
517         EGLContext context2 = getEGLWindow()->createContext(EGL_NO_CONTEXT, nullptr);
518         EXPECT_EGL_TRUE(eglMakeCurrent(display, surface, surface, context2));
519 
520         // check that Fence and Android fences work together
521         EGLSyncKHR syncFence3 = eglCreateSyncKHR(display, EGL_SYNC_FENCE_KHR, nullptr);
522         EXPECT_NE(syncFence3, EGL_NO_SYNC_KHR);
523 
524         // We can eglWaitSync on this
525         EGLint syncAttribs[] = {EGL_SYNC_NATIVE_FENCE_FD_ANDROID, (EGLint)fd, EGL_NONE};
526         EGLSyncKHR syncWithDupFD =
527             eglCreateSyncKHR(display, EGL_SYNC_NATIVE_FENCE_ANDROID, syncAttribs);
528         EXPECT_NE(syncWithDupFD, EGL_NO_SYNC_KHR);
529 
530         EGLSyncKHR syncFence4 = eglCreateSyncKHR(display, EGL_SYNC_FENCE_KHR, nullptr);
531         EXPECT_NE(syncFence4, EGL_NO_SYNC_KHR);
532 
533         // Second draw waits for first to complete. May already be signaled - ignore error.
534         if (eglWaitSyncKHR(display, syncWithDupFD, 0) == EGL_TRUE)
535         {
536             // Create work to do
537             glClearColor(1.0f, 0.0f, 0.0f, 1.0f);
538             glClear(GL_COLOR_BUFFER_BIT);
539             glFlush();
540         }
541 
542         // Wait for second draw to complete
543         EXPECT_EQ(EGL_CONDITION_SATISFIED,
544                   eglClientWaitSyncKHR(display, syncWithDupFD, EGL_SYNC_FLUSH_COMMANDS_BIT_KHR,
545                                        1000000000));
546         EXPECT_EGL_TRUE(eglGetSyncAttribKHR(display, syncWithDupFD, EGL_SYNC_STATUS_KHR, &value));
547         EXPECT_EQ(value, EGL_SIGNALED_KHR);
548 
549         // Reset to default context and surface.
550         EXPECT_EGL_TRUE(eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT));
551         EXPECT_EGL_TRUE(eglMakeCurrent(display, surface, surface, getEGLWindow()->getContext()));
552 
553         // Clean up created objects.
554         EXPECT_EGL_TRUE(eglDestroySyncKHR(display, syncFence3));
555         EXPECT_EGL_TRUE(eglDestroySyncKHR(display, syncFence4));
556         EXPECT_EGL_TRUE(eglDestroySyncKHR(display, syncWithDupFD));
557         EXPECT_EGL_TRUE(eglDestroyContext(display, context2));
558     }
559 
560     // Wait for first draw to complete
561     EXPECT_EQ(EGL_CONDITION_SATISFIED,
562               eglClientWaitSyncKHR(display, syncWithGeneratedFD, EGL_SYNC_FLUSH_COMMANDS_BIT_KHR,
563                                    1000000000));
564     EXPECT_EGL_TRUE(eglGetSyncAttribKHR(display, syncWithGeneratedFD, EGL_SYNC_STATUS_KHR, &value));
565     EXPECT_EQ(value, EGL_SIGNALED_KHR);
566 
567     // Clean up created objects.
568     EXPECT_EGL_TRUE(eglDestroySyncKHR(display, syncFence1));
569     EXPECT_EGL_TRUE(eglDestroySyncKHR(display, syncFence2));
570     EXPECT_EGL_TRUE(eglDestroySyncKHR(display, syncWithGeneratedFD));
571 }
572 
573 // Verify that VkSemaphore is not destroyed before used for waiting
TEST_P(EGLSyncTest,AndroidNativeFence_VkSemaphoreDestroyBug)574 TEST_P(EGLSyncTest, AndroidNativeFence_VkSemaphoreDestroyBug)
575 {
576     ANGLE_SKIP_TEST_IF(!IsVulkan());
577     ANGLE_SKIP_TEST_IF(!hasFenceSyncExtension());
578     ANGLE_SKIP_TEST_IF(!hasWaitSyncExtension() || !hasGLSyncExtension());
579     ANGLE_SKIP_TEST_IF(!hasAndroidNativeFenceSyncExtension());
580 
581     EGLDisplay display = getEGLWindow()->getDisplay();
582 
583     glFinish();  // Ensure no pending commands
584 
585     EGLSyncKHR syncWithGeneratedFD =
586         eglCreateSyncKHR(display, EGL_SYNC_NATIVE_FENCE_ANDROID, nullptr);
587     EXPECT_NE(syncWithGeneratedFD, EGL_NO_SYNC_KHR);
588     EXPECT_EGL_TRUE(eglWaitSyncKHR(display, syncWithGeneratedFD, 0));
589     EXPECT_EGL_TRUE(eglDestroySyncKHR(display, syncWithGeneratedFD));
590     glFinish();  // May destroy VkSemaphore if bug is present.
591 
592     // Create work to do
593     glClearColor(0.0f, 1.0f, 0.0f, 1.0f);
594     glClear(GL_COLOR_BUFFER_BIT);
595     glFinish();  // Will submit destroyed Semaphores.
596 }
597 
598 // Verify that no VVL errors are generated when External Fence Handle is used to track submissions
TEST_P(EGLSyncTest,AndroidNativeFence_ExternalFenceWaitVVLBug)599 TEST_P(EGLSyncTest, AndroidNativeFence_ExternalFenceWaitVVLBug)
600 {
601     ANGLE_SKIP_TEST_IF(!IsVulkan());
602     ANGLE_SKIP_TEST_IF(!hasFenceSyncExtension() || !hasGLSyncExtension());
603     ANGLE_SKIP_TEST_IF(!hasAndroidNativeFenceSyncExtension());
604 
605     EGLint value       = 0;
606     EGLDisplay display = getEGLWindow()->getDisplay();
607 
608     // Create work to do
609     ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Simple(), essl1_shaders::fs::Red());
610     drawQuad(program, essl1_shaders::PositionAttrib(), 0.0f);
611     ASSERT_GL_NO_ERROR();
612 
613     // We can ClientWait on this
614     EGLSyncKHR syncWithGeneratedFD =
615         eglCreateSyncKHR(display, EGL_SYNC_NATIVE_FENCE_ANDROID, nullptr);
616     EXPECT_NE(syncWithGeneratedFD, EGL_NO_SYNC_KHR);
617 
618     // Wait for draw to complete
619     EXPECT_EQ(EGL_CONDITION_SATISFIED,
620               eglClientWaitSyncKHR(display, syncWithGeneratedFD, EGL_SYNC_FLUSH_COMMANDS_BIT_KHR,
621                                    1'000'000'000));
622     EXPECT_EGL_TRUE(eglGetSyncAttribKHR(display, syncWithGeneratedFD, EGL_SYNC_STATUS_KHR, &value));
623     EXPECT_EQ(value, EGL_SIGNALED_KHR);
624 
625     // Clean up created objects.
626     EXPECT_EGL_TRUE(eglDestroySyncKHR(display, syncWithGeneratedFD));
627 
628     // Finish to cleanup internal garbage in the backend.
629     glFinish();
630 }
631 
632 // Test functionality of EGL_ANGLE_global_fence_sync.
TEST_P(EGLSyncTest,GlobalFenceSync)633 TEST_P(EGLSyncTest, GlobalFenceSync)
634 {
635     EGLDisplay display = getEGLWindow()->getDisplay();
636 
637     ANGLE_SKIP_TEST_IF(!hasFenceSyncExtension());
638     ANGLE_SKIP_TEST_IF(!IsEGLDisplayExtensionEnabled(display, "EGL_ANGLE_global_fence_sync"));
639 
640     // Create a second context
641     EGLContext context1     = eglGetCurrentContext();
642     EGLSurface drawSurface1 = eglGetCurrentSurface(EGL_DRAW);
643     EGLSurface readSurface1 = eglGetCurrentSurface(EGL_READ);
644     EGLConfig config        = getEGLWindow()->getConfig();
645 
646     const EGLint contextAttribs[] = {
647         EGL_CONTEXT_CLIENT_VERSION, getEGLWindow()->getClientMajorVersion(),
648         EGL_CONTEXT_MINOR_VERSION_KHR, getEGLWindow()->getClientMinorVersion(), EGL_NONE};
649 
650     EGLContext context2 = eglCreateContext(display, config, context1, contextAttribs);
651     ASSERT_NE(EGL_NO_CONTEXT, context2);
652 
653     const EGLint pbufferAttribs[] = {EGL_WIDTH, getWindowWidth(), EGL_HEIGHT, getWindowHeight(),
654                                      EGL_NONE};
655     EGLSurface drawSurface2       = eglCreatePbufferSurface(display, config, pbufferAttribs);
656     ASSERT_NE(EGL_NO_SURFACE, drawSurface2);
657 
658     // Do an expensive draw in context 2
659     eglMakeCurrent(display, drawSurface2, drawSurface2, context2);
660 
661     constexpr char kCostlyVS[] = R"(attribute highp vec4 position;
662 varying highp vec4 testPos;
663 void main(void)
664 {
665     testPos     = position;
666     gl_Position = position;
667 })";
668 
669     constexpr char kCostlyFS[] = R"(precision highp float;
670 varying highp vec4 testPos;
671 void main(void)
672 {
673     vec4 test = testPos;
674     for (int i = 0; i < 500; i++)
675     {
676         test = sqrt(test);
677     }
678     gl_FragColor = test;
679 })";
680 
681     ANGLE_GL_PROGRAM(expensiveProgram, kCostlyVS, kCostlyFS);
682     drawQuad(expensiveProgram, "position", 0.0f);
683 
684     // Signal a fence sync for testing
685     EGLSyncKHR sync2 = eglCreateSyncKHR(display, EGL_SYNC_FENCE_KHR, nullptr);
686 
687     // Switch to context 1, and create a global fence sync
688     eglMakeCurrent(display, drawSurface1, readSurface1, context1);
689 
690     EGLSyncKHR sync1 = eglCreateSyncKHR(display, EGL_SYNC_GLOBAL_FENCE_ANGLE, nullptr);
691 
692     // Wait for the global fence sync to finish.
693     constexpr GLuint64 kTimeout = 1'000'000'000;  // 1 second
694     ASSERT_EQ(EGL_CONDITION_SATISFIED_KHR, eglClientWaitSyncKHR(display, sync1, 0, kTimeout));
695 
696     // If the global fence sync is signaled, then the signal from context2 must also be signaled.
697     // Note that if sync1 was an EGL_SYNC_FENCE_KHR, this would not necessarily be true.
698     EGLint value = 0;
699     EXPECT_EGL_TRUE(eglGetSyncAttribKHR(display, sync2, EGL_SYNC_STATUS_KHR, &value));
700     EXPECT_EQ(value, EGL_SIGNALED_KHR);
701 
702     EXPECT_EQ(EGL_CONDITION_SATISFIED_KHR, eglClientWaitSyncKHR(display, sync2, 0, 0));
703 
704     EXPECT_EGL_TRUE(eglDestroySyncKHR(display, sync1));
705     EXPECT_EGL_TRUE(eglDestroySyncKHR(display, sync2));
706 
707     EXPECT_EGL_TRUE(eglDestroySurface(display, drawSurface2));
708     EXPECT_EGL_TRUE(eglDestroyContext(display, context2));
709 }
710 
711 // Test that leaked fences are cleaned up in a safe way. Regression test for sync objects using tail
712 // calls for destruction.
TEST_P(EGLSyncTest,DISABLED_LeakSyncToDisplayDestruction)713 TEST_P(EGLSyncTest, DISABLED_LeakSyncToDisplayDestruction)
714 {
715     ANGLE_SKIP_TEST_IF(!hasFenceSyncExtension());
716 
717     EGLDisplay display = getEGLWindow()->getDisplay();
718 
719     EGLSyncKHR sync = eglCreateSyncKHR(display, EGL_SYNC_FENCE_KHR, nullptr);
720     EXPECT_NE(sync, EGL_NO_SYNC_KHR);
721 }
722 
723 ANGLE_INSTANTIATE_TEST_ES2_AND_ES3(EGLSyncTest);
724