• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "util/EGLWindow.h"
14 
15 using namespace angle;
16 
17 class EGLSyncTest : public ANGLETest
18 {
19   protected:
hasFenceSyncExtension() const20     bool hasFenceSyncExtension() const
21     {
22         return IsEGLDisplayExtensionEnabled(getEGLWindow()->getDisplay(), "EGL_KHR_fence_sync");
23     }
hasWaitSyncExtension() const24     bool hasWaitSyncExtension() const
25     {
26         return hasFenceSyncExtension() &&
27                IsEGLDisplayExtensionEnabled(getEGLWindow()->getDisplay(), "EGL_KHR_wait_sync");
28     }
hasGLSyncExtension() const29     bool hasGLSyncExtension() const { return IsGLExtensionEnabled("GL_OES_EGL_sync"); }
30 
hasAndroidNativeFenceSyncExtension() const31     bool hasAndroidNativeFenceSyncExtension() const
32     {
33         return IsEGLDisplayExtensionEnabled(getEGLWindow()->getDisplay(),
34                                             "EGL_ANDROID_native_fence_sync");
35     }
36 };
37 
38 // Test error cases for all EGL_KHR_fence_sync functions
TEST_P(EGLSyncTest,FenceSyncErrors)39 TEST_P(EGLSyncTest, FenceSyncErrors)
40 {
41     ANGLE_SKIP_TEST_IF(!hasFenceSyncExtension());
42 
43     EGLDisplay display = getEGLWindow()->getDisplay();
44 
45     // If the client API doesn't have the necessary extension, test that sync creation fails and
46     // ignore the rest of the tests.
47     if (!hasGLSyncExtension())
48     {
49         EXPECT_EQ(EGL_NO_SYNC_KHR, eglCreateSyncKHR(display, EGL_SYNC_FENCE_KHR, nullptr));
50         EXPECT_EGL_ERROR(EGL_BAD_MATCH);
51     }
52 
53     ANGLE_SKIP_TEST_IF(!hasGLSyncExtension());
54 
55     EGLContext context     = eglGetCurrentContext();
56     EGLSurface drawSurface = eglGetCurrentSurface(EGL_DRAW);
57     EGLSurface readSurface = eglGetCurrentSurface(EGL_READ);
58 
59     EXPECT_NE(context, EGL_NO_CONTEXT);
60     EXPECT_NE(drawSurface, EGL_NO_SURFACE);
61     EXPECT_NE(readSurface, EGL_NO_SURFACE);
62 
63     // CreateSync with no attribute shouldn't cause an error
64     EGLSyncKHR sync = eglCreateSyncKHR(display, EGL_SYNC_FENCE_KHR, nullptr);
65     EXPECT_NE(sync, EGL_NO_SYNC_KHR);
66 
67     EXPECT_EGL_TRUE(eglDestroySyncKHR(display, sync));
68 
69     // CreateSync with empty attribute shouldn't cause an error
70     const EGLint emptyAttributes[] = {EGL_NONE};
71     sync                           = eglCreateSyncKHR(display, EGL_SYNC_FENCE_KHR, emptyAttributes);
72     EXPECT_NE(sync, EGL_NO_SYNC_KHR);
73 
74     // DestroySync generates BAD_PARAMETER if the sync is not valid
75     EXPECT_EGL_FALSE(eglDestroySyncKHR(display, reinterpret_cast<EGLSyncKHR>(20)));
76     EXPECT_EGL_ERROR(EGL_BAD_PARAMETER);
77 
78     // CreateSync generates BAD_DISPLAY if display is not valid
79     EXPECT_EQ(EGL_NO_SYNC_KHR, eglCreateSyncKHR(EGL_NO_DISPLAY, EGL_SYNC_FENCE_KHR, nullptr));
80     EXPECT_EGL_ERROR(EGL_BAD_DISPLAY);
81 
82     // CreateSync generates BAD_ATTRIBUTE if attribute is neither nullptr nor empty.
83     const EGLint nonEmptyAttributes[] = {
84         EGL_CL_EVENT_HANDLE,
85         0,
86         EGL_NONE,
87     };
88     EXPECT_EQ(EGL_NO_SYNC_KHR, eglCreateSyncKHR(display, EGL_SYNC_FENCE_KHR, nonEmptyAttributes));
89     EXPECT_EGL_ERROR(EGL_BAD_ATTRIBUTE);
90 
91     // CreateSync generates BAD_ATTRIBUTE if type is not valid
92     EXPECT_EQ(EGL_NO_SYNC_KHR, eglCreateSyncKHR(display, 0, nullptr));
93     EXPECT_EGL_ERROR(EGL_BAD_ATTRIBUTE);
94 
95     // CreateSync generates BAD_MATCH if no context is current
96     eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
97     EXPECT_EQ(EGL_NO_SYNC_KHR, eglCreateSyncKHR(display, EGL_SYNC_FENCE_KHR, nullptr));
98     EXPECT_EGL_ERROR(EGL_BAD_MATCH);
99     eglMakeCurrent(display, drawSurface, readSurface, context);
100 
101     // ClientWaitSync generates EGL_BAD_PARAMETER if the sync object is not valid
102     EXPECT_EGL_FALSE(eglClientWaitSyncKHR(display, reinterpret_cast<EGLSyncKHR>(30), 0, 0));
103     EXPECT_EGL_ERROR(EGL_BAD_PARAMETER);
104 
105     // GetSyncAttrib generates EGL_BAD_PARAMETER if the sync object is not valid, and value is not
106     // modified
107     constexpr EGLint kSentinelAttribValue = 123456789;
108     EGLint attribValue                    = kSentinelAttribValue;
109     EXPECT_EGL_FALSE(eglGetSyncAttribKHR(display, reinterpret_cast<EGLSyncKHR>(40),
110                                          EGL_SYNC_TYPE_KHR, &attribValue));
111     EXPECT_EGL_ERROR(EGL_BAD_PARAMETER);
112     EXPECT_EQ(attribValue, kSentinelAttribValue);
113 
114     // GetSyncAttrib generates EGL_BAD_ATTRIBUTE if the attribute is not valid, and value is not
115     // modified
116     EXPECT_EGL_FALSE(eglGetSyncAttribKHR(display, sync, EGL_CL_EVENT_HANDLE, &attribValue));
117     EXPECT_EGL_ERROR(EGL_BAD_ATTRIBUTE);
118     EXPECT_EQ(attribValue, kSentinelAttribValue);
119 
120     // GetSyncAttrib generates EGL_BAD_MATCH if the attribute is valid for sync, but not the
121     // particular sync type. We don't have such a case at the moment.
122 
123     EXPECT_EGL_TRUE(eglDestroySyncKHR(display, sync));
124 }
125 
126 // Test error cases for all EGL_KHR_wait_sync functions
TEST_P(EGLSyncTest,WaitSyncErrors)127 TEST_P(EGLSyncTest, WaitSyncErrors)
128 {
129     // The client API that shows support for eglWaitSyncKHR is the same as the one required for
130     // eglCreateSyncKHR.  As such, there is no way to create a sync and not be able to wait on it.
131     // This would have created an EGL_BAD_MATCH error.
132     ANGLE_SKIP_TEST_IF(!hasWaitSyncExtension() || !hasGLSyncExtension());
133 
134     EGLDisplay display     = getEGLWindow()->getDisplay();
135     EGLContext context     = eglGetCurrentContext();
136     EGLSurface drawSurface = eglGetCurrentSurface(EGL_DRAW);
137     EGLSurface readSurface = eglGetCurrentSurface(EGL_READ);
138 
139     EXPECT_NE(context, EGL_NO_CONTEXT);
140     EXPECT_NE(drawSurface, EGL_NO_SURFACE);
141     EXPECT_NE(readSurface, EGL_NO_SURFACE);
142 
143     EGLSyncKHR sync = eglCreateSyncKHR(display, EGL_SYNC_FENCE_KHR, nullptr);
144     EXPECT_NE(sync, EGL_NO_SYNC_KHR);
145 
146     // WaitSync generates BAD_MATCH if no context is current
147     eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
148     EXPECT_EGL_FALSE(eglWaitSyncKHR(display, sync, 0));
149     EXPECT_EGL_ERROR(EGL_BAD_MATCH);
150     eglMakeCurrent(display, drawSurface, readSurface, context);
151 
152     // WaitSync generates BAD_PARAMETER if the sync is not valid
153     EXPECT_EGL_FALSE(eglWaitSyncKHR(display, reinterpret_cast<EGLSyncKHR>(20), 0));
154     EXPECT_EGL_ERROR(EGL_BAD_PARAMETER);
155 
156     // WaitSync generates BAD_PARAMETER if flags is non-zero
157     EXPECT_EGL_FALSE(eglWaitSyncKHR(display, sync, 1));
158     EXPECT_EGL_ERROR(EGL_BAD_PARAMETER);
159 
160     EXPECT_EGL_TRUE(eglDestroySyncKHR(display, sync));
161 }
162 
163 // Test usage of eglGetSyncAttribKHR
TEST_P(EGLSyncTest,GetSyncAttrib)164 TEST_P(EGLSyncTest, GetSyncAttrib)
165 {
166     ANGLE_SKIP_TEST_IF(!hasFenceSyncExtension() || !hasGLSyncExtension());
167 
168     EGLDisplay display = getEGLWindow()->getDisplay();
169 
170     EGLSyncKHR sync = eglCreateSyncKHR(display, EGL_SYNC_FENCE_KHR, nullptr);
171     EXPECT_NE(sync, EGL_NO_SYNC_KHR);
172 
173     // Fence sync attributes are:
174     //
175     // EGL_SYNC_TYPE_KHR: EGL_SYNC_FENCE_KHR
176     // EGL_SYNC_STATUS_KHR: EGL_UNSIGNALED_KHR or EGL_SIGNALED_KHR
177     // EGL_SYNC_CONDITION_KHR: EGL_SYNC_PRIOR_COMMANDS_COMPLETE_KHR
178 
179     constexpr EGLint kSentinelAttribValue = 123456789;
180     EGLint attribValue                    = kSentinelAttribValue;
181     EXPECT_EGL_TRUE(eglGetSyncAttribKHR(display, sync, EGL_SYNC_TYPE_KHR, &attribValue));
182     EXPECT_EQ(attribValue, EGL_SYNC_FENCE_KHR);
183 
184     attribValue = kSentinelAttribValue;
185     EXPECT_EGL_TRUE(eglGetSyncAttribKHR(display, sync, EGL_SYNC_CONDITION_KHR, &attribValue));
186     EXPECT_EQ(attribValue, EGL_SYNC_PRIOR_COMMANDS_COMPLETE_KHR);
187 
188     attribValue = kSentinelAttribValue;
189     EXPECT_EGL_TRUE(eglGetSyncAttribKHR(display, sync, EGL_SYNC_STATUS_KHR, &attribValue));
190 
191     // Hack around EXPECT_* not having an "either this or that" variant:
192     if (attribValue != EGL_SIGNALED_KHR)
193     {
194         EXPECT_EQ(attribValue, EGL_UNSIGNALED_KHR);
195     }
196 
197     EXPECT_EGL_TRUE(eglDestroySyncKHR(display, sync));
198 }
199 
200 // Test that basic usage works and doesn't generate errors or crash
TEST_P(EGLSyncTest,BasicOperations)201 TEST_P(EGLSyncTest, BasicOperations)
202 {
203     ANGLE_SKIP_TEST_IF(!hasFenceSyncExtension() || !hasGLSyncExtension());
204 
205     EGLDisplay display = getEGLWindow()->getDisplay();
206 
207     EGLSyncKHR sync = eglCreateSyncKHR(display, EGL_SYNC_FENCE_KHR, nullptr);
208     EXPECT_NE(sync, EGL_NO_SYNC_KHR);
209 
210     glClearColor(1.0f, 0.0f, 1.0f, 1.0f);
211 
212     glClear(GL_COLOR_BUFFER_BIT);
213     EXPECT_EGL_TRUE(eglWaitSyncKHR(display, sync, 0));
214 
215     glFlush();
216 
217     EGLint value           = 0;
218     unsigned int loopCount = 0;
219 
220     // Use 'loopCount' to make sure the test doesn't get stuck in an infinite loop
221     while (value != EGL_SIGNALED_KHR && loopCount <= 1000000)
222     {
223         loopCount++;
224         EXPECT_EGL_TRUE(eglGetSyncAttribKHR(display, sync, EGL_SYNC_STATUS_KHR, &value));
225     }
226 
227     ASSERT_EQ(value, EGL_SIGNALED_KHR);
228 
229     for (size_t i = 0; i < 20; i++)
230     {
231         glClear(GL_COLOR_BUFFER_BIT);
232         EXPECT_EQ(
233             EGL_CONDITION_SATISFIED_KHR,
234             eglClientWaitSyncKHR(display, sync, EGL_SYNC_FLUSH_COMMANDS_BIT_KHR, EGL_FOREVER_KHR));
235         EXPECT_EGL_TRUE(eglGetSyncAttribKHR(display, sync, EGL_SYNC_STATUS_KHR, &value));
236         EXPECT_EQ(value, EGL_SIGNALED_KHR);
237     }
238 
239     EXPECT_EGL_TRUE(eglDestroySyncKHR(display, sync));
240 }
241 
242 // Test eglWaitNative api
TEST_P(EGLSyncTest,WaitNative)243 TEST_P(EGLSyncTest, WaitNative)
244 {
245     // Clear to red color
246     glClearColor(1.0f, 0.0f, 0.0f, 1.0f);
247 
248     glClear(GL_COLOR_BUFFER_BIT);
249     EXPECT_EGL_TRUE(eglWaitNative(EGL_CORE_NATIVE_ENGINE));
250     EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 2, getWindowHeight() / 2, GLColor::red);
251 }
252 
253 // Verify eglDupNativeFence for EGL_ANDROID_native_fence_sync
TEST_P(EGLSyncTest,AndroidNativeFence_DupNativeFenceFD)254 TEST_P(EGLSyncTest, AndroidNativeFence_DupNativeFenceFD)
255 {
256     ANGLE_SKIP_TEST_IF(!hasFenceSyncExtension());
257     ANGLE_SKIP_TEST_IF(!hasFenceSyncExtension() || !hasGLSyncExtension());
258     ANGLE_SKIP_TEST_IF(!hasAndroidNativeFenceSyncExtension());
259 
260     EGLDisplay display = getEGLWindow()->getDisplay();
261 
262     // We can ClientWait on this
263     EGLSyncKHR syncWithGeneratedFD =
264         eglCreateSyncKHR(display, EGL_SYNC_NATIVE_FENCE_ANDROID, nullptr);
265     EXPECT_NE(syncWithGeneratedFD, EGL_NO_SYNC_KHR);
266 
267     int fd = eglDupNativeFenceFDANDROID(display, syncWithGeneratedFD);
268     EXPECT_EGL_SUCCESS();
269 
270     // Clean up created objects.
271     if (fd != EGL_NO_NATIVE_FENCE_FD_ANDROID)
272     {
273         close(fd);
274     }
275 
276     EXPECT_EGL_TRUE(eglDestroySyncKHR(display, syncWithGeneratedFD));
277 }
278 
279 // Verify CreateSync and ClientWait for EGL_ANDROID_native_fence_sync
TEST_P(EGLSyncTest,AndroidNativeFence_ClientWait)280 TEST_P(EGLSyncTest, AndroidNativeFence_ClientWait)
281 {
282     ANGLE_SKIP_TEST_IF(!hasFenceSyncExtension());
283     ANGLE_SKIP_TEST_IF(!hasFenceSyncExtension() || !hasGLSyncExtension());
284     ANGLE_SKIP_TEST_IF(!hasAndroidNativeFenceSyncExtension());
285 
286     EGLint value       = 0;
287     EGLDisplay display = getEGLWindow()->getDisplay();
288 
289     // We can ClientWait on this
290     EGLSyncKHR syncWithGeneratedFD =
291         eglCreateSyncKHR(display, EGL_SYNC_NATIVE_FENCE_ANDROID, nullptr);
292     EXPECT_NE(syncWithGeneratedFD, EGL_NO_SYNC_KHR);
293 
294     // Create work to do
295     glClearColor(0.0f, 1.0f, 0.0f, 1.0f);
296     glClear(GL_COLOR_BUFFER_BIT);
297     glFinish();
298 
299     // Wait for draw to complete
300     EXPECT_EQ(EGL_CONDITION_SATISFIED,
301               eglClientWaitSyncKHR(display, syncWithGeneratedFD, EGL_SYNC_FLUSH_COMMANDS_BIT_KHR,
302                                    1000000000));
303     EXPECT_EGL_TRUE(eglGetSyncAttribKHR(display, syncWithGeneratedFD, EGL_SYNC_STATUS_KHR, &value));
304     EXPECT_EQ(value, EGL_SIGNALED_KHR);
305 
306     // Clean up created objects.
307     EXPECT_EGL_TRUE(eglDestroySyncKHR(display, syncWithGeneratedFD));
308 }
309 
310 // Verify WaitSync with EGL_ANDROID_native_fence_sync
311 // Simulate passing FDs across processes by passing across Contexts.
TEST_P(EGLSyncTest,AndroidNativeFence_WaitSync)312 TEST_P(EGLSyncTest, AndroidNativeFence_WaitSync)
313 {
314     ANGLE_SKIP_TEST_IF(!hasFenceSyncExtension());
315     ANGLE_SKIP_TEST_IF(!hasFenceSyncExtension() || !hasGLSyncExtension());
316     ANGLE_SKIP_TEST_IF(!hasAndroidNativeFenceSyncExtension());
317 
318     EGLint value       = 0;
319     EGLDisplay display = getEGLWindow()->getDisplay();
320     EGLSurface surface = getEGLWindow()->getSurface();
321 
322     /*- First Context ------------------------*/
323 
324     // We can ClientWait on this
325     EGLSyncKHR syncWithGeneratedFD =
326         eglCreateSyncKHR(display, EGL_SYNC_NATIVE_FENCE_ANDROID, nullptr);
327     EXPECT_NE(syncWithGeneratedFD, EGL_NO_SYNC_KHR);
328 
329     int fd = eglDupNativeFenceFDANDROID(display, syncWithGeneratedFD);
330     EXPECT_EGL_SUCCESS();  // Can return -1 (when signaled) or valid FD.
331 
332     // Create work to do
333     glClearColor(0.0f, 1.0f, 0.0f, 1.0f);
334     glClear(GL_COLOR_BUFFER_BIT);
335     glFinish();
336 
337     /*- Second Context ------------------------*/
338     if (fd > EGL_NO_NATIVE_FENCE_FD_ANDROID)
339     {
340         EXPECT_EGL_TRUE(eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT));
341 
342         EGLContext context2 = getEGLWindow()->createContext(EGL_NO_CONTEXT);
343         EXPECT_EGL_TRUE(eglMakeCurrent(display, surface, surface, context2));
344 
345         // We can eglWaitSync on this - import FD from first sync.
346         EGLint syncAttribs[] = {EGL_SYNC_NATIVE_FENCE_FD_ANDROID, (EGLint)fd, EGL_NONE};
347         EGLSyncKHR syncWithDupFD =
348             eglCreateSyncKHR(display, EGL_SYNC_NATIVE_FENCE_ANDROID, syncAttribs);
349         EXPECT_NE(syncWithDupFD, EGL_NO_SYNC_KHR);
350 
351         // Second draw waits for first to complete. May already be signaled - ignore error.
352         if (eglWaitSyncKHR(display, syncWithDupFD, 0) == EGL_TRUE)
353         {
354             // Create work to do
355             glClearColor(1.0f, 0.0f, 0.0f, 1.0f);
356             glClear(GL_COLOR_BUFFER_BIT);
357             glFinish();
358         }
359 
360         // Wait for second draw to complete
361         EXPECT_EQ(EGL_CONDITION_SATISFIED,
362                   eglClientWaitSyncKHR(display, syncWithDupFD, EGL_SYNC_FLUSH_COMMANDS_BIT_KHR,
363                                        1000000000));
364         EXPECT_EGL_TRUE(eglGetSyncAttribKHR(display, syncWithDupFD, EGL_SYNC_STATUS_KHR, &value));
365         EXPECT_EQ(value, EGL_SIGNALED_KHR);
366 
367         // Reset to default context and surface.
368         EXPECT_EGL_TRUE(eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT));
369         EXPECT_EGL_TRUE(eglMakeCurrent(display, surface, surface, getEGLWindow()->getContext()));
370 
371         // Clean up created objects.
372         EXPECT_EGL_TRUE(eglDestroySyncKHR(display, syncWithDupFD));
373         EXPECT_EGL_TRUE(eglDestroyContext(display, context2));
374     }
375 
376     // Wait for first draw to complete
377     EXPECT_EQ(EGL_CONDITION_SATISFIED,
378               eglClientWaitSyncKHR(display, syncWithGeneratedFD, EGL_SYNC_FLUSH_COMMANDS_BIT_KHR,
379                                    1000000000));
380     EXPECT_EGL_TRUE(eglGetSyncAttribKHR(display, syncWithGeneratedFD, EGL_SYNC_STATUS_KHR, &value));
381     EXPECT_EQ(value, EGL_SIGNALED_KHR);
382 
383     // Clean up created objects.
384     EXPECT_EGL_TRUE(eglDestroySyncKHR(display, syncWithGeneratedFD));
385 }
386 
387 // Verify EGL_ANDROID_native_fence_sync
388 // Simulate passing FDs across processes by passing across Contexts.
TEST_P(EGLSyncTest,AndroidNativeFence_withFences)389 TEST_P(EGLSyncTest, AndroidNativeFence_withFences)
390 {
391     ANGLE_SKIP_TEST_IF(!hasFenceSyncExtension());
392     ANGLE_SKIP_TEST_IF(!hasFenceSyncExtension() || !hasGLSyncExtension());
393     ANGLE_SKIP_TEST_IF(!hasAndroidNativeFenceSyncExtension());
394 
395     EGLint value       = 0;
396     EGLDisplay display = getEGLWindow()->getDisplay();
397     EGLSurface surface = getEGLWindow()->getSurface();
398 
399     /*- First Context ------------------------*/
400 
401     // Extra fence syncs to ensure that Fence and Android Native fences work together
402     EGLSyncKHR syncFence1 = eglCreateSyncKHR(display, EGL_SYNC_FENCE_KHR, nullptr);
403     EXPECT_NE(syncFence1, EGL_NO_SYNC_KHR);
404 
405     // We can ClientWait on this
406     EGLSyncKHR syncWithGeneratedFD =
407         eglCreateSyncKHR(display, EGL_SYNC_NATIVE_FENCE_ANDROID, nullptr);
408     EXPECT_NE(syncWithGeneratedFD, EGL_NO_SYNC_KHR);
409 
410     int fd = eglDupNativeFenceFDANDROID(display, syncWithGeneratedFD);
411     EXPECT_EGL_SUCCESS();  // Can return -1 (when signaled) or valid FD.
412 
413     EGLSyncKHR syncFence2 = eglCreateSyncKHR(display, EGL_SYNC_FENCE_KHR, nullptr);
414     EXPECT_NE(syncFence2, EGL_NO_SYNC_KHR);
415 
416     // Create work to do
417     glClearColor(0.0f, 1.0f, 0.0f, 1.0f);
418     glClear(GL_COLOR_BUFFER_BIT);
419     glFlush();
420 
421     /*- Second Context ------------------------*/
422     if (fd > EGL_NO_NATIVE_FENCE_FD_ANDROID)
423     {
424         EXPECT_EGL_TRUE(eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT));
425 
426         EGLContext context2 = getEGLWindow()->createContext(EGL_NO_CONTEXT);
427         EXPECT_EGL_TRUE(eglMakeCurrent(display, surface, surface, context2));
428 
429         // check that Fence and Android fences work together
430         EGLSyncKHR syncFence3 = eglCreateSyncKHR(display, EGL_SYNC_FENCE_KHR, nullptr);
431         EXPECT_NE(syncFence3, EGL_NO_SYNC_KHR);
432 
433         // We can eglWaitSync on this
434         EGLint syncAttribs[] = {EGL_SYNC_NATIVE_FENCE_FD_ANDROID, (EGLint)fd, EGL_NONE};
435         EGLSyncKHR syncWithDupFD =
436             eglCreateSyncKHR(display, EGL_SYNC_NATIVE_FENCE_ANDROID, syncAttribs);
437         EXPECT_NE(syncWithDupFD, EGL_NO_SYNC_KHR);
438 
439         EGLSyncKHR syncFence4 = eglCreateSyncKHR(display, EGL_SYNC_FENCE_KHR, nullptr);
440         EXPECT_NE(syncFence4, 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, syncFence3));
464         EXPECT_EGL_TRUE(eglDestroySyncKHR(display, syncFence4));
465         EXPECT_EGL_TRUE(eglDestroySyncKHR(display, syncWithDupFD));
466         EXPECT_EGL_TRUE(eglDestroyContext(display, context2));
467     }
468 
469     // Wait for first draw to complete
470     EXPECT_EQ(EGL_CONDITION_SATISFIED,
471               eglClientWaitSyncKHR(display, syncWithGeneratedFD, EGL_SYNC_FLUSH_COMMANDS_BIT_KHR,
472                                    1000000000));
473     EXPECT_EGL_TRUE(eglGetSyncAttribKHR(display, syncWithGeneratedFD, EGL_SYNC_STATUS_KHR, &value));
474     EXPECT_EQ(value, EGL_SIGNALED_KHR);
475 
476     // Clean up created objects.
477     EXPECT_EGL_TRUE(eglDestroySyncKHR(display, syncFence1));
478     EXPECT_EGL_TRUE(eglDestroySyncKHR(display, syncFence2));
479     EXPECT_EGL_TRUE(eglDestroySyncKHR(display, syncWithGeneratedFD));
480 }
481 
482 ANGLE_INSTANTIATE_TEST(EGLSyncTest,
483                        ES2_D3D9(),
484                        ES2_D3D11(),
485                        ES3_D3D11(),
486                        ES2_OPENGL(),
487                        ES3_OPENGL(),
488                        ES2_OPENGLES(),
489                        ES3_OPENGLES(),
490                        ES2_VULKAN(),
491                        ES3_VULKAN());
492