xref: /aosp_15_r20/external/angle/src/tests/egl_tests/EGLSyncTestMetalSharedEvent.mm (revision 8975f5c5ed3d1c378011245431ada316dfb6f244)
1//
2// Copyright 2022 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// EGLSyncTestMetalSharedEvent:
7//   Tests pertaining to EGL_ANGLE_sync_mtl_shared_event extension.
8//
9
10#include <gtest/gtest.h>
11
12#include "test_utils/ANGLETest.h"
13#include "util/EGLWindow.h"
14
15#include <Metal/Metal.h>
16
17using namespace angle;
18
19static inline EGLAttrib Uint64HighPart(uint64_t value)
20{
21    return value >> 32;
22}
23
24static inline EGLAttrib Uint64LowPart(uint64_t value)
25{
26    return value & 0xFFFFFFFF;
27}
28
29class EGLSyncTestMetalSharedEvent : public ANGLETest<>
30{
31  protected:
32    id<MTLSharedEvent> createMetalSharedEvent() const
33    {
34        id<MTLDevice> device           = getMetalDevice();
35        id<MTLSharedEvent> sharedEvent = [device newSharedEvent];
36        sharedEvent.label              = @"TestSharedEvent";
37        return sharedEvent;
38    }
39
40    id<MTLDevice> getMetalDevice() const
41    {
42        EGLAttrib angleDevice = 0;
43        EXPECT_EGL_TRUE(
44            eglQueryDisplayAttribEXT(getEGLWindow()->getDisplay(), EGL_DEVICE_EXT, &angleDevice));
45
46        EGLAttrib device = 0;
47        EXPECT_EGL_TRUE(eglQueryDeviceAttribEXT(reinterpret_cast<EGLDeviceEXT>(angleDevice),
48                                                EGL_METAL_DEVICE_ANGLE, &device));
49
50        return (__bridge id<MTLDevice>)reinterpret_cast<void *>(device);
51    }
52
53    bool hasEGLDisplayExtension(const char *extname) const
54    {
55        return IsEGLDisplayExtensionEnabled(getEGLWindow()->getDisplay(), extname);
56    }
57
58    bool hasSyncMetalSharedEventExtension() const
59    {
60        return hasEGLDisplayExtension("EGL_ANGLE_metal_shared_event_sync");
61    }
62
63    EGLAttrib sharedEventAsAttrib(id<MTLSharedEvent> sharedEvent) const
64    {
65        return reinterpret_cast<EGLAttrib>(sharedEvent);
66    }
67
68    id<MTLSharedEvent> sharedEventFromVoidPtr(void *ptr) const
69    {
70        return (__bridge id<MTLSharedEvent>)ptr;
71    }
72};
73
74// Test existing fence is created unsignaled
75TEST_P(EGLSyncTestMetalSharedEvent, BasicEGLSync)
76{
77    ANGLE_SKIP_TEST_IF(!hasSyncMetalSharedEventExtension());
78
79    EGLDisplay display = getEGLWindow()->getDisplay();
80
81    EGLSyncKHR sync = eglCreateSyncKHR(display, EGL_SYNC_FENCE_KHR, nullptr);
82    EXPECT_NE(sync, EGL_NO_SYNC_KHR);
83
84    constexpr EGLint kSentinelAttribValue = 123456789;
85    EGLint signaledValue                  = kSentinelAttribValue;
86    EXPECT_EGL_TRUE(eglGetSyncAttribKHR(display, sync, EGL_SYNC_STATUS_KHR, &signaledValue));
87    EXPECT_EQ(signaledValue, EGL_UNSIGNALED_KHR);
88
89    glClearColor(1.0f, 0.0f, 1.0f, 1.0f);
90
91    glClear(GL_COLOR_BUFFER_BIT);
92    EXPECT_EGL_TRUE(eglWaitSyncKHR(display, sync, 0));
93
94    glFinish();
95
96    // Don't wait forever to make sure the test terminates
97    constexpr GLuint64 kTimeout = 1000'000'000ul;  // 1 second
98    EXPECT_EQ(EGL_CONDITION_SATISFIED_KHR,
99              eglClientWaitSyncKHR(display, sync, EGL_SYNC_FLUSH_COMMANDS_BIT_KHR, kTimeout));
100
101    signaledValue = kSentinelAttribValue;
102    EXPECT_EGL_TRUE(eglGetSyncAttribKHR(display, sync, EGL_SYNC_STATUS_KHR, &signaledValue));
103    EXPECT_EQ(signaledValue, EGL_SIGNALED_KHR);
104
105    EXPECT_EGL_TRUE(eglDestroySyncKHR(display, sync));
106}
107
108// Test usage of eglGetSyncAttrib
109TEST_P(EGLSyncTestMetalSharedEvent, GetSyncAttrib)
110{
111    ANGLE_SKIP_TEST_IF(!hasSyncMetalSharedEventExtension());
112
113    id<MTLSharedEvent> sharedEvent = createMetalSharedEvent();
114    EXPECT_EQ([sharedEvent retainCount], 1ul);
115    uint64_t initialSignalValue = sharedEvent.signaledValue;
116    EXPECT_EQ(initialSignalValue, 0u);
117
118    EGLDisplay display      = getEGLWindow()->getDisplay();
119    EGLAttrib syncAttribs[] = {EGL_SYNC_METAL_SHARED_EVENT_OBJECT_ANGLE,
120                               sharedEventAsAttrib(sharedEvent), EGL_NONE};
121    EXPECT_EQ([sharedEvent retainCount], 1ul);
122
123    EGLSync sync = eglCreateSync(display, EGL_SYNC_METAL_SHARED_EVENT_ANGLE, syncAttribs);
124    EXPECT_NE(sync, EGL_NO_SYNC);
125    // sharedEvent, sync, mtlCommandBuffer
126    EXPECT_GT([sharedEvent retainCount], 1ul);
127
128    // Fence sync attributes are:
129    //
130    // EGL_SYNC_TYPE: EGL_SYNC_METAL_SHARED_EVENT_ANGLE
131    // EGL_SYNC_STATUS: EGL_UNSIGNALED or EGL_SIGNALED
132    // EGL_SYNC_CONDITION: EGL_SYNC_PRIOR_COMMANDS_COMPLETE
133
134    constexpr EGLAttrib kSentinelAttribValue = 123456789;
135    EGLAttrib attribValue                    = kSentinelAttribValue;
136    EXPECT_EGL_TRUE(eglGetSyncAttrib(display, sync, EGL_SYNC_TYPE, &attribValue));
137    EXPECT_EQ(attribValue, EGL_SYNC_METAL_SHARED_EVENT_ANGLE);
138
139    attribValue = kSentinelAttribValue;
140    EXPECT_EGL_TRUE(eglGetSyncAttrib(display, sync, EGL_SYNC_CONDITION, &attribValue));
141    EXPECT_EQ(attribValue, EGL_SYNC_PRIOR_COMMANDS_COMPLETE);
142
143    attribValue = kSentinelAttribValue;
144    EXPECT_EGL_TRUE(eglGetSyncAttrib(display, sync, EGL_SYNC_STATUS, &attribValue));
145    EXPECT_EQ(attribValue, EGL_UNSIGNALED);
146    EXPECT_GT([sharedEvent retainCount], 1ul);
147
148    glFinish();
149
150    attribValue = kSentinelAttribValue;
151    EXPECT_EGL_TRUE(eglGetSyncAttrib(display, sync, EGL_SYNC_STATUS, &attribValue));
152    EXPECT_EQ(attribValue, EGL_SIGNALED);
153    EXPECT_EQ(sharedEvent.signaledValue, initialSignalValue + 1);
154    EXPECT_GT([sharedEvent retainCount], 1ul);
155
156    EXPECT_EGL_TRUE(eglDestroySync(display, sync));
157    EXPECT_EQ([sharedEvent retainCount], 1ul);
158
159    sharedEvent = nil;
160}
161
162// Test usage of eglGetSyncAttrib with explicit sync condition
163TEST_P(EGLSyncTestMetalSharedEvent, GetSyncAttrib_ExplicitSyncCondition)
164{
165    ANGLE_SKIP_TEST_IF(!hasSyncMetalSharedEventExtension());
166
167    id<MTLSharedEvent> sharedEvent = createMetalSharedEvent();
168    EXPECT_EQ(sharedEvent.signaledValue, 0u);
169
170    EGLDisplay display          = getEGLWindow()->getDisplay();
171    EGLAttrib syncAttribs[3][5] = {
172        {EGL_SYNC_METAL_SHARED_EVENT_OBJECT_ANGLE, sharedEventAsAttrib(sharedEvent), EGL_NONE},
173        {EGL_SYNC_METAL_SHARED_EVENT_OBJECT_ANGLE, sharedEventAsAttrib(sharedEvent),
174         EGL_SYNC_CONDITION, EGL_SYNC_PRIOR_COMMANDS_COMPLETE, EGL_NONE},
175        {EGL_SYNC_METAL_SHARED_EVENT_OBJECT_ANGLE, sharedEventAsAttrib(sharedEvent),
176         EGL_SYNC_CONDITION, EGL_SYNC_METAL_SHARED_EVENT_SIGNALED_ANGLE, EGL_NONE}};
177
178    EGLAttrib expectedSyncCondition[3] = {EGL_SYNC_PRIOR_COMMANDS_COMPLETE,
179                                          EGL_SYNC_PRIOR_COMMANDS_COMPLETE,
180                                          EGL_SYNC_METAL_SHARED_EVENT_SIGNALED_ANGLE};
181
182    for (int i = 0; i < 3; ++i)
183    {
184        uint64_t initialSignalValue = sharedEvent.signaledValue;
185
186        EGLSync sync = eglCreateSync(display, EGL_SYNC_METAL_SHARED_EVENT_ANGLE, syncAttribs[i]);
187        EXPECT_NE(sync, EGL_NO_SYNC);
188
189        constexpr EGLAttrib kSentinelAttribValue = 123456789;
190        EGLAttrib attribValue                    = kSentinelAttribValue;
191        EXPECT_EGL_TRUE(eglGetSyncAttrib(display, sync, EGL_SYNC_TYPE, &attribValue));
192        EXPECT_EQ(attribValue, EGL_SYNC_METAL_SHARED_EVENT_ANGLE);
193
194        attribValue = kSentinelAttribValue;
195        EXPECT_EGL_TRUE(eglGetSyncAttrib(display, sync, EGL_SYNC_CONDITION, &attribValue));
196        EXPECT_EQ(attribValue, expectedSyncCondition[i]);
197
198        attribValue = kSentinelAttribValue;
199        EXPECT_EGL_TRUE(eglGetSyncAttrib(display, sync, EGL_SYNC_STATUS, &attribValue));
200        EXPECT_EQ(attribValue, EGL_UNSIGNALED);
201
202        glFinish();
203
204        if (i == 2)
205        {
206            sharedEvent.signaledValue += 1;
207        }
208
209        attribValue = kSentinelAttribValue;
210        EXPECT_EGL_TRUE(eglGetSyncAttrib(display, sync, EGL_SYNC_STATUS, &attribValue));
211        EXPECT_EQ(attribValue, EGL_SIGNALED);
212        EXPECT_EQ(sharedEvent.signaledValue, initialSignalValue + 1);
213
214        EXPECT_EGL_TRUE(eglDestroySync(display, sync));
215    }
216
217    sharedEvent = nil;
218}
219
220// Verify CreateSync and ClientWait for EGL_ANGLE_metal_shared_event_sync
221TEST_P(EGLSyncTestMetalSharedEvent, AngleMetalSharedEventSync_ClientWait)
222{
223    ANGLE_SKIP_TEST_IF(!hasSyncMetalSharedEventExtension());
224
225    id<MTLSharedEvent> sharedEvent = createMetalSharedEvent();
226
227    EGLDisplay display      = getEGLWindow()->getDisplay();
228    EGLAttrib syncAttribs[] = {EGL_SYNC_METAL_SHARED_EVENT_OBJECT_ANGLE,
229                               sharedEventAsAttrib(sharedEvent), EGL_NONE};
230
231    // We can ClientWait on this
232    EGLSync syncWithSharedEvent =
233        eglCreateSync(display, EGL_SYNC_METAL_SHARED_EVENT_ANGLE, syncAttribs);
234    EXPECT_NE(syncWithSharedEvent, EGL_NO_SYNC);
235
236    // Create work to do
237    glClearColor(0.0f, 1.0f, 1.0f, 1.0f);
238    glClear(GL_COLOR_BUFFER_BIT);
239    glFlush();
240
241    // Wait for the draw to complete
242    glClear(GL_COLOR_BUFFER_BIT);
243
244    // Don't wait forever to make sure the test terminates
245    constexpr GLuint64 kTimeout = 1000000000;  // 1 second
246    EGLAttrib value             = 0;
247    EXPECT_EQ(EGL_CONDITION_SATISFIED, eglClientWaitSync(display, syncWithSharedEvent,
248                                                         EGL_SYNC_FLUSH_COMMANDS_BIT, kTimeout));
249    EXPECT_EGL_TRUE(eglGetSyncAttrib(display, syncWithSharedEvent, EGL_SYNC_STATUS, &value));
250    EXPECT_EQ(value, EGL_SIGNALED);
251
252    // Clean up created objects.
253    EXPECT_EGL_TRUE(eglDestroySync(display, syncWithSharedEvent));
254    sharedEvent = nil;
255}
256
257// Verify CreateSync and ClientWait for EGL_ANGLE_metal_shared_event_sync
258TEST_P(EGLSyncTestMetalSharedEvent, AngleMetalSharedEventSync_ClientWait_WithSignalValue)
259{
260    ANGLE_SKIP_TEST_IF(!hasSyncMetalSharedEventExtension());
261
262    id<MTLSharedEvent> sharedEvent = createMetalSharedEvent();
263
264    constexpr uint64_t kSignalValue = 0xDEADBEEFCAFE;
265    EGLDisplay display              = getEGLWindow()->getDisplay();
266    EGLAttrib syncAttribs[]         = {EGL_SYNC_METAL_SHARED_EVENT_OBJECT_ANGLE,
267                                       sharedEventAsAttrib(sharedEvent),
268                                       EGL_SYNC_METAL_SHARED_EVENT_SIGNAL_VALUE_HI_ANGLE,
269                                       Uint64HighPart(kSignalValue),
270                                       EGL_SYNC_METAL_SHARED_EVENT_SIGNAL_VALUE_LO_ANGLE,
271                                       Uint64LowPart(kSignalValue),
272                                       EGL_NONE};
273
274    // We can ClientWait on this
275    EGLSync syncWithSharedEvent =
276        eglCreateSync(display, EGL_SYNC_METAL_SHARED_EVENT_ANGLE, syncAttribs);
277    EXPECT_NE(syncWithSharedEvent, EGL_NO_SYNC);
278
279    // Create work to do
280    glClearColor(0.0f, 1.0f, 1.0f, 1.0f);
281    glClear(GL_COLOR_BUFFER_BIT);
282    glFlush();
283
284    // Wait for the draw to complete
285    glClear(GL_COLOR_BUFFER_BIT);
286
287    // Don't wait forever to make sure the test terminates
288    constexpr GLuint64 kTimeout = 1000000000;  // 1 second
289    EGLAttrib value             = 0;
290    EXPECT_EQ(EGL_CONDITION_SATISFIED, eglClientWaitSync(display, syncWithSharedEvent,
291                                                         EGL_SYNC_FLUSH_COMMANDS_BIT, kTimeout));
292    EXPECT_EGL_TRUE(eglGetSyncAttrib(display, syncWithSharedEvent, EGL_SYNC_STATUS, &value));
293    EXPECT_EQ(value, EGL_SIGNALED);
294    EXPECT_EQ(sharedEvent.signaledValue, kSignalValue);
295
296    // Clean up created objects.
297    EXPECT_EGL_TRUE(eglDestroySync(display, syncWithSharedEvent));
298    sharedEvent = nil;
299}
300
301// Verify eglCopyMetalSharedEventANGLE for EGL_ANGLE_metal_shared_event_sync
302TEST_P(EGLSyncTestMetalSharedEvent, AngleMetalSharedEventSync_CopyMetalSharedEventANGLE)
303{
304    ANGLE_SKIP_TEST_IF(!hasSyncMetalSharedEventExtension());
305
306    EGLDisplay display = getEGLWindow()->getDisplay();
307
308    // We can ClientWait on this
309    EGLSync syncWithGeneratedEvent =
310        eglCreateSyncKHR(display, EGL_SYNC_METAL_SHARED_EVENT_ANGLE, nullptr);
311    EXPECT_NE(syncWithGeneratedEvent, EGL_NO_SYNC_KHR);
312
313    id<MTLSharedEvent> sharedEvent =
314        sharedEventFromVoidPtr(eglCopyMetalSharedEventANGLE(display, syncWithGeneratedEvent));
315    EXPECT_EGL_SUCCESS();
316    EXPECT_GT([sharedEvent retainCount], 1ul);
317
318    glFinish();
319    EXPECT_EGL_TRUE(eglDestroySync(display, syncWithGeneratedEvent));
320
321    // Clean up created objects.
322    EXPECT_EQ([sharedEvent retainCount], 1ul);
323    [sharedEvent release];
324}
325
326// Verify WaitSync with EGL_ANGLE_metal_shared_event_sync
327// Simulate passing shared events across processes by passing across Contexts.
328TEST_P(EGLSyncTestMetalSharedEvent, AngleMetalSharedEventSync_WaitSync)
329{
330    ANGLE_SKIP_TEST_IF(!hasSyncMetalSharedEventExtension());
331
332    id<MTLSharedEvent> sharedEvent = createMetalSharedEvent();
333
334    EGLAttrib value    = 0;
335    EGLDisplay display = getEGLWindow()->getDisplay();
336    EGLSurface surface = getEGLWindow()->getSurface();
337
338    /*- First Context ------------------------*/
339
340    EGLAttrib syncAttribs[] = {EGL_SYNC_METAL_SHARED_EVENT_OBJECT_ANGLE,
341                               sharedEventAsAttrib(sharedEvent), EGL_NONE};
342    // We can ClientWait on this
343
344    EGLSync syncWithSharedEvent1 =
345        eglCreateSync(display, EGL_SYNC_METAL_SHARED_EVENT_ANGLE, syncAttribs);
346    EXPECT_NE(syncWithSharedEvent1, EGL_NO_SYNC);
347    if (syncWithSharedEvent1 == EGL_NO_SYNC)
348    {
349        // Unable to continue with test.
350        return;
351    }
352
353    // Create work to do
354    glClearColor(0.0f, 1.0f, 0.0f, 1.0f);
355    glClear(GL_COLOR_BUFFER_BIT);
356    glFlush();
357
358    /*- Second Context ------------------------*/
359    EXPECT_EGL_TRUE(eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT));
360
361    EGLContext context2 = getEGLWindow()->createContext(EGL_NO_CONTEXT, nullptr);
362    EXPECT_EGL_TRUE(eglMakeCurrent(display, surface, surface, context2));
363
364    EGLSync syncWithSharedEvent2 =
365        eglCreateSync(display, EGL_SYNC_METAL_SHARED_EVENT_ANGLE, syncAttribs);
366    EXPECT_NE(syncWithSharedEvent2, EGL_NO_SYNC);
367    if (syncWithSharedEvent2 == EGL_NO_SYNC)
368    {
369        // Unable to continue with test.
370        return;
371    }
372
373    // Second draw waits for first to complete. May already be signaled - ignore error.
374    if (eglWaitSync(display, syncWithSharedEvent2, 0) == EGL_TRUE)
375    {
376        // Create work to do
377        glClearColor(1.0f, 0.0f, 0.0f, 1.0f);
378        glClear(GL_COLOR_BUFFER_BIT);
379        glFlush();
380    }
381
382    // Wait for second draw to complete
383    EXPECT_EQ(EGL_CONDITION_SATISFIED, eglClientWaitSync(display, syncWithSharedEvent2,
384                                                         EGL_SYNC_FLUSH_COMMANDS_BIT, 1000000000));
385    EXPECT_EGL_TRUE(eglGetSyncAttrib(display, syncWithSharedEvent2, EGL_SYNC_STATUS, &value));
386    EXPECT_EQ(value, EGL_SIGNALED);
387
388    // Reset to default context and surface.
389    EXPECT_EGL_TRUE(eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT));
390    EXPECT_EGL_TRUE(eglMakeCurrent(display, surface, surface, getEGLWindow()->getContext()));
391
392    // Clean up created objects.
393    EXPECT_EGL_TRUE(eglDestroySync(display, syncWithSharedEvent2));
394    EXPECT_EGL_TRUE(eglDestroyContext(display, context2));
395
396    // Wait for first draw to complete
397    EXPECT_EQ(EGL_CONDITION_SATISFIED, eglClientWaitSync(display, syncWithSharedEvent1,
398                                                         EGL_SYNC_FLUSH_COMMANDS_BIT, 1000000000));
399    EXPECT_EGL_TRUE(eglGetSyncAttrib(display, syncWithSharedEvent1, EGL_SYNC_STATUS, &value));
400    EXPECT_EQ(value, EGL_SIGNALED);
401
402    // Clean up created objects.
403    EXPECT_EGL_TRUE(eglDestroySync(display, syncWithSharedEvent1));
404    sharedEvent = nil;
405}
406
407// Verify WaitSync with EGL_ANGLE_metal_shared_event_sync
408// Simulate passing shared events across processes by passing across Contexts.
409TEST_P(EGLSyncTestMetalSharedEvent, AngleMetalSharedEventSync_WaitSync_ExternallySignaled)
410{
411    ANGLE_SKIP_TEST_IF(!hasSyncMetalSharedEventExtension());
412
413    id<MTLSharedEvent> sharedEvent = createMetalSharedEvent();
414
415    EGLAttrib value    = 0;
416    EGLDisplay display = getEGLWindow()->getDisplay();
417
418    EGLAttrib syncAttribs[] = {EGL_SYNC_METAL_SHARED_EVENT_OBJECT_ANGLE,
419                               sharedEventAsAttrib(sharedEvent), EGL_SYNC_CONDITION,
420                               EGL_SYNC_METAL_SHARED_EVENT_SIGNALED_ANGLE, EGL_NONE};
421
422    // We can ClientWait on this
423    EGLSync syncWithSharedEvent =
424        eglCreateSync(display, EGL_SYNC_METAL_SHARED_EVENT_ANGLE, syncAttribs);
425    EXPECT_NE(syncWithSharedEvent, EGL_NO_SYNC);
426    if (syncWithSharedEvent == EGL_NO_SYNC)
427    {
428        // Unable to continue with test.
429        return;
430    }
431
432    constexpr EGLAttrib kSentinelAttribValue = 123456789;
433    value                                    = kSentinelAttribValue;
434    EXPECT_EGL_TRUE(eglGetSyncAttrib(display, syncWithSharedEvent, EGL_SYNC_CONDITION, &value));
435    EXPECT_EQ(value, EGL_SYNC_METAL_SHARED_EVENT_SIGNALED_ANGLE);
436
437    EXPECT_EQ(EGL_TIMEOUT_EXPIRED,
438              eglClientWaitSync(display, syncWithSharedEvent, EGL_SYNC_FLUSH_COMMANDS_BIT, 0));
439
440    value = kSentinelAttribValue;
441    EXPECT_EGL_TRUE(eglGetSyncAttrib(display, syncWithSharedEvent, EGL_SYNC_STATUS, &value));
442    EXPECT_EQ(value, EGL_UNSIGNALED);
443
444    // Wait for previous work to complete before drawing
445    EXPECT_EGL_TRUE(eglWaitSync(display, syncWithSharedEvent, 0));
446
447    // Create work to do
448    glClearColor(0.0f, 1.0f, 0.0f, 1.0f);
449    glClear(GL_COLOR_BUFFER_BIT);
450    glFlush();
451
452    // After explicit flush, should still time out
453    // TODO(djg): flushing here causes a 5s stall in `CommandBuffer::wait`
454    // (mtl_command_buffer.mm:765) EXPECT_EQ(EGL_TIMEOUT_EXPIRED,
455    //           eglClientWaitSync(display, syncWithSharedEvent, EGL_SYNC_FLUSH_COMMANDS_BIT, 0));
456    EXPECT_EQ(EGL_TIMEOUT_EXPIRED, eglClientWaitSync(display, syncWithSharedEvent, 0, 0));
457
458    value = kSentinelAttribValue;
459    EXPECT_EGL_TRUE(eglGetSyncAttrib(display, syncWithSharedEvent, EGL_SYNC_STATUS, &value));
460    EXPECT_EQ(value, EGL_UNSIGNALED);
461
462    // Signal the MTLSharedEvent
463    sharedEvent.signaledValue += 1;
464
465    // Wait for draw to complete. This will be satisfied since the signalValue
466    // was incremented on sharedEvent.
467    EXPECT_EQ(EGL_CONDITION_SATISFIED,
468              eglClientWaitSync(display, syncWithSharedEvent, EGL_SYNC_FLUSH_COMMANDS_BIT, 0));
469    EXPECT_EGL_TRUE(eglGetSyncAttrib(display, syncWithSharedEvent, EGL_SYNC_STATUS, &value));
470    EXPECT_EQ(value, EGL_SIGNALED);
471
472    // Clean up created objects.
473    EXPECT_EGL_TRUE(eglDestroySync(display, syncWithSharedEvent));
474    sharedEvent = nil;
475}
476
477ANGLE_INSTANTIATE_TEST(EGLSyncTestMetalSharedEvent, ES2_METAL(), ES3_METAL());
478// This test suite is not instantiated on non-Metal backends and OSes.
479GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(EGLSyncTestMetalSharedEvent);
480