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