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