xref: /aosp_15_r20/external/angle/src/libANGLE/renderer/metal/SyncMtl.mm (revision 8975f5c5ed3d1c378011245431ada316dfb6f244)
1*8975f5c5SAndroid Build Coastguard Worker//
2*8975f5c5SAndroid Build Coastguard Worker// Copyright (c) 2020 The ANGLE Project Authors. All rights reserved.
3*8975f5c5SAndroid Build Coastguard Worker// Use of this source code is governed by a BSD-style license that can be
4*8975f5c5SAndroid Build Coastguard Worker// found in the LICENSE file.
5*8975f5c5SAndroid Build Coastguard Worker//
6*8975f5c5SAndroid Build Coastguard Worker// SyncMtl:
7*8975f5c5SAndroid Build Coastguard Worker//    Defines the class interface for SyncMtl, implementing SyncImpl.
8*8975f5c5SAndroid Build Coastguard Worker//
9*8975f5c5SAndroid Build Coastguard Worker
10*8975f5c5SAndroid Build Coastguard Worker#include "libANGLE/renderer/metal/SyncMtl.h"
11*8975f5c5SAndroid Build Coastguard Worker
12*8975f5c5SAndroid Build Coastguard Worker#include <chrono>
13*8975f5c5SAndroid Build Coastguard Worker#include <condition_variable>
14*8975f5c5SAndroid Build Coastguard Worker#include <mutex>
15*8975f5c5SAndroid Build Coastguard Worker
16*8975f5c5SAndroid Build Coastguard Worker#include "common/debug.h"
17*8975f5c5SAndroid Build Coastguard Worker#include "libANGLE/Context.h"
18*8975f5c5SAndroid Build Coastguard Worker#include "libANGLE/Display.h"
19*8975f5c5SAndroid Build Coastguard Worker#include "libANGLE/renderer/metal/ContextMtl.h"
20*8975f5c5SAndroid Build Coastguard Worker#include "libANGLE/renderer/metal/DisplayMtl.h"
21*8975f5c5SAndroid Build Coastguard Worker
22*8975f5c5SAndroid Build Coastguard Workernamespace rx
23*8975f5c5SAndroid Build Coastguard Worker{
24*8975f5c5SAndroid Build Coastguard Workernamespace mtl
25*8975f5c5SAndroid Build Coastguard Worker{
26*8975f5c5SAndroid Build Coastguard Worker
27*8975f5c5SAndroid Build Coastguard Workerstatic uint64_t UnpackSignalValue(EGLAttrib highPart, EGLAttrib lowPart)
28*8975f5c5SAndroid Build Coastguard Worker{
29*8975f5c5SAndroid Build Coastguard Worker    return (static_cast<uint64_t>(highPart & 0xFFFFFFFF) << 32) |
30*8975f5c5SAndroid Build Coastguard Worker           (static_cast<uint64_t>(lowPart & 0xFFFFFFFF));
31*8975f5c5SAndroid Build Coastguard Worker}
32*8975f5c5SAndroid Build Coastguard Worker
33*8975f5c5SAndroid Build Coastguard Workerstatic constexpr uint64_t kNanosecondsPerDay = 86400000000000;
34*8975f5c5SAndroid Build Coastguard Workerstatic uint64_t SanitizeTimeout(uint64_t timeout)
35*8975f5c5SAndroid Build Coastguard Worker{
36*8975f5c5SAndroid Build Coastguard Worker    // Passing EGL_FOREVER_KHR overflows std::chrono::nanoseconds.
37*8975f5c5SAndroid Build Coastguard Worker    return std::min(timeout, kNanosecondsPerDay);
38*8975f5c5SAndroid Build Coastguard Worker}
39*8975f5c5SAndroid Build Coastguard Worker
40*8975f5c5SAndroid Build Coastguard Workerclass SyncImpl
41*8975f5c5SAndroid Build Coastguard Worker{
42*8975f5c5SAndroid Build Coastguard Worker  public:
43*8975f5c5SAndroid Build Coastguard Worker    virtual ~SyncImpl() {}
44*8975f5c5SAndroid Build Coastguard Worker
45*8975f5c5SAndroid Build Coastguard Worker    virtual angle::Result clientWait(ContextMtl *contextMtl,
46*8975f5c5SAndroid Build Coastguard Worker                                     bool flushCommands,
47*8975f5c5SAndroid Build Coastguard Worker                                     uint64_t timeout,
48*8975f5c5SAndroid Build Coastguard Worker                                     GLenum *outResult)                     = 0;
49*8975f5c5SAndroid Build Coastguard Worker    virtual angle::Result serverWait(ContextMtl *contextMtl)                = 0;
50*8975f5c5SAndroid Build Coastguard Worker    virtual angle::Result getStatus(DisplayMtl *displayMtl, bool *signaled) = 0;
51*8975f5c5SAndroid Build Coastguard Worker};
52*8975f5c5SAndroid Build Coastguard Worker
53*8975f5c5SAndroid Build Coastguard Worker// SharedEvent is only available on iOS 12.0+ or mac 10.14+
54*8975f5c5SAndroid Build Coastguard Workerclass SharedEventSyncImpl : public SyncImpl
55*8975f5c5SAndroid Build Coastguard Worker{
56*8975f5c5SAndroid Build Coastguard Worker  public:
57*8975f5c5SAndroid Build Coastguard Worker    SharedEventSyncImpl() : mCv(new std::condition_variable()), mLock(new std::mutex()) {}
58*8975f5c5SAndroid Build Coastguard Worker
59*8975f5c5SAndroid Build Coastguard Worker    ~SharedEventSyncImpl() override {}
60*8975f5c5SAndroid Build Coastguard Worker
61*8975f5c5SAndroid Build Coastguard Worker    angle::Result set(ContextMtl *contextMtl,
62*8975f5c5SAndroid Build Coastguard Worker                      id<MTLSharedEvent> sharedEvent,
63*8975f5c5SAndroid Build Coastguard Worker                      uint64_t signalValue,
64*8975f5c5SAndroid Build Coastguard Worker                      bool enqueueEvent)
65*8975f5c5SAndroid Build Coastguard Worker    {
66*8975f5c5SAndroid Build Coastguard Worker        mMetalSharedEvent.retainAssign(sharedEvent);
67*8975f5c5SAndroid Build Coastguard Worker        mSignalValue = signalValue;
68*8975f5c5SAndroid Build Coastguard Worker
69*8975f5c5SAndroid Build Coastguard Worker        if (enqueueEvent)
70*8975f5c5SAndroid Build Coastguard Worker        {
71*8975f5c5SAndroid Build Coastguard Worker            contextMtl->queueEventSignal(mMetalSharedEvent, mSignalValue);
72*8975f5c5SAndroid Build Coastguard Worker        }
73*8975f5c5SAndroid Build Coastguard Worker
74*8975f5c5SAndroid Build Coastguard Worker        return angle::Result::Continue;
75*8975f5c5SAndroid Build Coastguard Worker    }
76*8975f5c5SAndroid Build Coastguard Worker
77*8975f5c5SAndroid Build Coastguard Worker    angle::Result clientWait(ContextMtl *contextMtl,
78*8975f5c5SAndroid Build Coastguard Worker                             bool flushCommands,
79*8975f5c5SAndroid Build Coastguard Worker                             uint64_t timeout,
80*8975f5c5SAndroid Build Coastguard Worker                             GLenum *outResult) override
81*8975f5c5SAndroid Build Coastguard Worker    {
82*8975f5c5SAndroid Build Coastguard Worker        std::unique_lock<std::mutex> lg(*mLock);
83*8975f5c5SAndroid Build Coastguard Worker        if (mMetalSharedEvent.get().signaledValue >= mSignalValue)
84*8975f5c5SAndroid Build Coastguard Worker        {
85*8975f5c5SAndroid Build Coastguard Worker            *outResult = GL_ALREADY_SIGNALED;
86*8975f5c5SAndroid Build Coastguard Worker            return angle::Result::Continue;
87*8975f5c5SAndroid Build Coastguard Worker        }
88*8975f5c5SAndroid Build Coastguard Worker        if (flushCommands)
89*8975f5c5SAndroid Build Coastguard Worker        {
90*8975f5c5SAndroid Build Coastguard Worker            contextMtl->flushCommandBuffer(mtl::WaitUntilScheduled);
91*8975f5c5SAndroid Build Coastguard Worker        }
92*8975f5c5SAndroid Build Coastguard Worker
93*8975f5c5SAndroid Build Coastguard Worker        if (timeout == 0)
94*8975f5c5SAndroid Build Coastguard Worker        {
95*8975f5c5SAndroid Build Coastguard Worker            *outResult = GL_TIMEOUT_EXPIRED;
96*8975f5c5SAndroid Build Coastguard Worker            return angle::Result::Continue;
97*8975f5c5SAndroid Build Coastguard Worker        }
98*8975f5c5SAndroid Build Coastguard Worker
99*8975f5c5SAndroid Build Coastguard Worker        // Create references to mutex and condition variable since they might be released in
100*8975f5c5SAndroid Build Coastguard Worker        // onDestroy(), but the callback might still not be fired yet.
101*8975f5c5SAndroid Build Coastguard Worker        std::shared_ptr<std::condition_variable> cvRef = mCv;
102*8975f5c5SAndroid Build Coastguard Worker        std::shared_ptr<std::mutex> lockRef            = mLock;
103*8975f5c5SAndroid Build Coastguard Worker        AutoObjCObj<MTLSharedEventListener> eventListener =
104*8975f5c5SAndroid Build Coastguard Worker            contextMtl->getDisplay()->getOrCreateSharedEventListener();
105*8975f5c5SAndroid Build Coastguard Worker        [mMetalSharedEvent.get() notifyListener:eventListener
106*8975f5c5SAndroid Build Coastguard Worker                                        atValue:mSignalValue
107*8975f5c5SAndroid Build Coastguard Worker                                          block:^(id<MTLSharedEvent> sharedEvent, uint64_t value) {
108*8975f5c5SAndroid Build Coastguard Worker                                            std::unique_lock<std::mutex> localLock(*lockRef);
109*8975f5c5SAndroid Build Coastguard Worker                                            cvRef->notify_one();
110*8975f5c5SAndroid Build Coastguard Worker                                          }];
111*8975f5c5SAndroid Build Coastguard Worker
112*8975f5c5SAndroid Build Coastguard Worker        if (!mCv->wait_for(lg, std::chrono::nanoseconds(SanitizeTimeout(timeout)), [this] {
113*8975f5c5SAndroid Build Coastguard Worker                return mMetalSharedEvent.get().signaledValue >= mSignalValue;
114*8975f5c5SAndroid Build Coastguard Worker            }))
115*8975f5c5SAndroid Build Coastguard Worker        {
116*8975f5c5SAndroid Build Coastguard Worker            *outResult = GL_TIMEOUT_EXPIRED;
117*8975f5c5SAndroid Build Coastguard Worker            return angle::Result::Continue;
118*8975f5c5SAndroid Build Coastguard Worker        }
119*8975f5c5SAndroid Build Coastguard Worker
120*8975f5c5SAndroid Build Coastguard Worker        ASSERT(mMetalSharedEvent.get().signaledValue >= mSignalValue);
121*8975f5c5SAndroid Build Coastguard Worker        *outResult = GL_CONDITION_SATISFIED;
122*8975f5c5SAndroid Build Coastguard Worker
123*8975f5c5SAndroid Build Coastguard Worker        return angle::Result::Continue;
124*8975f5c5SAndroid Build Coastguard Worker    }
125*8975f5c5SAndroid Build Coastguard Worker
126*8975f5c5SAndroid Build Coastguard Worker    angle::Result serverWait(ContextMtl *contextMtl) override
127*8975f5c5SAndroid Build Coastguard Worker    {
128*8975f5c5SAndroid Build Coastguard Worker        contextMtl->serverWaitEvent(mMetalSharedEvent, mSignalValue);
129*8975f5c5SAndroid Build Coastguard Worker        return angle::Result::Continue;
130*8975f5c5SAndroid Build Coastguard Worker    }
131*8975f5c5SAndroid Build Coastguard Worker
132*8975f5c5SAndroid Build Coastguard Worker    angle::Result getStatus(DisplayMtl *displayMtl, bool *signaled) override
133*8975f5c5SAndroid Build Coastguard Worker    {
134*8975f5c5SAndroid Build Coastguard Worker        *signaled = mMetalSharedEvent.get().signaledValue >= mSignalValue;
135*8975f5c5SAndroid Build Coastguard Worker        return angle::Result::Continue;
136*8975f5c5SAndroid Build Coastguard Worker    }
137*8975f5c5SAndroid Build Coastguard Worker
138*8975f5c5SAndroid Build Coastguard Worker  private:
139*8975f5c5SAndroid Build Coastguard Worker    AutoObjCPtr<id<MTLSharedEvent>> mMetalSharedEvent;
140*8975f5c5SAndroid Build Coastguard Worker    uint64_t mSignalValue = 0;
141*8975f5c5SAndroid Build Coastguard Worker
142*8975f5c5SAndroid Build Coastguard Worker    std::shared_ptr<std::condition_variable> mCv;
143*8975f5c5SAndroid Build Coastguard Worker    std::shared_ptr<std::mutex> mLock;
144*8975f5c5SAndroid Build Coastguard Worker};
145*8975f5c5SAndroid Build Coastguard Worker
146*8975f5c5SAndroid Build Coastguard Workerclass EventSyncImpl : public SyncImpl
147*8975f5c5SAndroid Build Coastguard Worker{
148*8975f5c5SAndroid Build Coastguard Worker  private:
149*8975f5c5SAndroid Build Coastguard Worker    // MTLEvent starts with a value of 0, use 1 to signal it.
150*8975f5c5SAndroid Build Coastguard Worker    static constexpr uint64_t kEventSignalValue = 1;
151*8975f5c5SAndroid Build Coastguard Worker
152*8975f5c5SAndroid Build Coastguard Worker  public:
153*8975f5c5SAndroid Build Coastguard Worker    ~EventSyncImpl() override {}
154*8975f5c5SAndroid Build Coastguard Worker
155*8975f5c5SAndroid Build Coastguard Worker    angle::Result set(ContextMtl *contextMtl)
156*8975f5c5SAndroid Build Coastguard Worker    {
157*8975f5c5SAndroid Build Coastguard Worker        ANGLE_MTL_OBJC_SCOPE
158*8975f5c5SAndroid Build Coastguard Worker        {
159*8975f5c5SAndroid Build Coastguard Worker            mMetalEvent = contextMtl->getMetalDevice().newEvent();
160*8975f5c5SAndroid Build Coastguard Worker        }
161*8975f5c5SAndroid Build Coastguard Worker
162*8975f5c5SAndroid Build Coastguard Worker        mEncodedCommandBufferSerial = contextMtl->queueEventSignal(mMetalEvent, kEventSignalValue);
163*8975f5c5SAndroid Build Coastguard Worker        return angle::Result::Continue;
164*8975f5c5SAndroid Build Coastguard Worker    }
165*8975f5c5SAndroid Build Coastguard Worker
166*8975f5c5SAndroid Build Coastguard Worker    angle::Result clientWait(ContextMtl *contextMtl,
167*8975f5c5SAndroid Build Coastguard Worker                             bool flushCommands,
168*8975f5c5SAndroid Build Coastguard Worker                             uint64_t timeout,
169*8975f5c5SAndroid Build Coastguard Worker                             GLenum *outResult) override
170*8975f5c5SAndroid Build Coastguard Worker    {
171*8975f5c5SAndroid Build Coastguard Worker        DisplayMtl *display = contextMtl->getDisplay();
172*8975f5c5SAndroid Build Coastguard Worker
173*8975f5c5SAndroid Build Coastguard Worker        if (display->cmdQueue().isSerialCompleted(mEncodedCommandBufferSerial))
174*8975f5c5SAndroid Build Coastguard Worker        {
175*8975f5c5SAndroid Build Coastguard Worker            *outResult = GL_ALREADY_SIGNALED;
176*8975f5c5SAndroid Build Coastguard Worker            return angle::Result::Continue;
177*8975f5c5SAndroid Build Coastguard Worker        }
178*8975f5c5SAndroid Build Coastguard Worker
179*8975f5c5SAndroid Build Coastguard Worker        if (flushCommands)
180*8975f5c5SAndroid Build Coastguard Worker        {
181*8975f5c5SAndroid Build Coastguard Worker            contextMtl->flushCommandBuffer(mtl::WaitUntilScheduled);
182*8975f5c5SAndroid Build Coastguard Worker        }
183*8975f5c5SAndroid Build Coastguard Worker
184*8975f5c5SAndroid Build Coastguard Worker        if (timeout == 0 || !display->cmdQueue().waitUntilSerialCompleted(
185*8975f5c5SAndroid Build Coastguard Worker                                mEncodedCommandBufferSerial, SanitizeTimeout(timeout)))
186*8975f5c5SAndroid Build Coastguard Worker        {
187*8975f5c5SAndroid Build Coastguard Worker            *outResult = GL_TIMEOUT_EXPIRED;
188*8975f5c5SAndroid Build Coastguard Worker            return angle::Result::Continue;
189*8975f5c5SAndroid Build Coastguard Worker        }
190*8975f5c5SAndroid Build Coastguard Worker
191*8975f5c5SAndroid Build Coastguard Worker        *outResult = GL_CONDITION_SATISFIED;
192*8975f5c5SAndroid Build Coastguard Worker        return angle::Result::Continue;
193*8975f5c5SAndroid Build Coastguard Worker    }
194*8975f5c5SAndroid Build Coastguard Worker
195*8975f5c5SAndroid Build Coastguard Worker    angle::Result serverWait(ContextMtl *contextMtl) override
196*8975f5c5SAndroid Build Coastguard Worker    {
197*8975f5c5SAndroid Build Coastguard Worker        contextMtl->serverWaitEvent(mMetalEvent, kEventSignalValue);
198*8975f5c5SAndroid Build Coastguard Worker        return angle::Result::Continue;
199*8975f5c5SAndroid Build Coastguard Worker    }
200*8975f5c5SAndroid Build Coastguard Worker
201*8975f5c5SAndroid Build Coastguard Worker    angle::Result getStatus(DisplayMtl *displayMtl, bool *signaled) override
202*8975f5c5SAndroid Build Coastguard Worker    {
203*8975f5c5SAndroid Build Coastguard Worker        *signaled = displayMtl->cmdQueue().isSerialCompleted(mEncodedCommandBufferSerial);
204*8975f5c5SAndroid Build Coastguard Worker        return angle::Result::Continue;
205*8975f5c5SAndroid Build Coastguard Worker    }
206*8975f5c5SAndroid Build Coastguard Worker
207*8975f5c5SAndroid Build Coastguard Worker  private:
208*8975f5c5SAndroid Build Coastguard Worker    AutoObjCPtr<id<MTLEvent>> mMetalEvent;
209*8975f5c5SAndroid Build Coastguard Worker    uint64_t mEncodedCommandBufferSerial = 0;
210*8975f5c5SAndroid Build Coastguard Worker};
211*8975f5c5SAndroid Build Coastguard Worker}  // namespace mtl
212*8975f5c5SAndroid Build Coastguard Worker
213*8975f5c5SAndroid Build Coastguard Worker// FenceNVMtl implementation
214*8975f5c5SAndroid Build Coastguard WorkerFenceNVMtl::FenceNVMtl() : FenceNVImpl() {}
215*8975f5c5SAndroid Build Coastguard Worker
216*8975f5c5SAndroid Build Coastguard WorkerFenceNVMtl::~FenceNVMtl() {}
217*8975f5c5SAndroid Build Coastguard Worker
218*8975f5c5SAndroid Build Coastguard Workervoid FenceNVMtl::onDestroy(const gl::Context *context)
219*8975f5c5SAndroid Build Coastguard Worker{
220*8975f5c5SAndroid Build Coastguard Worker    mSync.reset();
221*8975f5c5SAndroid Build Coastguard Worker}
222*8975f5c5SAndroid Build Coastguard Worker
223*8975f5c5SAndroid Build Coastguard Workerangle::Result FenceNVMtl::set(const gl::Context *context, GLenum condition)
224*8975f5c5SAndroid Build Coastguard Worker{
225*8975f5c5SAndroid Build Coastguard Worker    ASSERT(condition == GL_ALL_COMPLETED_NV);
226*8975f5c5SAndroid Build Coastguard Worker    ContextMtl *contextMtl = mtl::GetImpl(context);
227*8975f5c5SAndroid Build Coastguard Worker
228*8975f5c5SAndroid Build Coastguard Worker    std::unique_ptr<mtl::EventSyncImpl> impl = std::make_unique<mtl::EventSyncImpl>();
229*8975f5c5SAndroid Build Coastguard Worker    ANGLE_TRY(impl->set(contextMtl));
230*8975f5c5SAndroid Build Coastguard Worker    mSync = std::move(impl);
231*8975f5c5SAndroid Build Coastguard Worker
232*8975f5c5SAndroid Build Coastguard Worker    return angle::Result::Continue;
233*8975f5c5SAndroid Build Coastguard Worker}
234*8975f5c5SAndroid Build Coastguard Worker
235*8975f5c5SAndroid Build Coastguard Workerangle::Result FenceNVMtl::test(const gl::Context *context, GLboolean *outFinished)
236*8975f5c5SAndroid Build Coastguard Worker{
237*8975f5c5SAndroid Build Coastguard Worker    ContextMtl *contextMtl = mtl::GetImpl(context);
238*8975f5c5SAndroid Build Coastguard Worker
239*8975f5c5SAndroid Build Coastguard Worker    bool signaled = false;
240*8975f5c5SAndroid Build Coastguard Worker    ANGLE_TRY(mSync->getStatus(contextMtl->getDisplay(), &signaled));
241*8975f5c5SAndroid Build Coastguard Worker
242*8975f5c5SAndroid Build Coastguard Worker    *outFinished = signaled ? GL_TRUE : GL_FALSE;
243*8975f5c5SAndroid Build Coastguard Worker    return angle::Result::Continue;
244*8975f5c5SAndroid Build Coastguard Worker}
245*8975f5c5SAndroid Build Coastguard Worker
246*8975f5c5SAndroid Build Coastguard Workerangle::Result FenceNVMtl::finish(const gl::Context *context)
247*8975f5c5SAndroid Build Coastguard Worker{
248*8975f5c5SAndroid Build Coastguard Worker    ContextMtl *contextMtl = mtl::GetImpl(context);
249*8975f5c5SAndroid Build Coastguard Worker    GLenum result          = GL_NONE;
250*8975f5c5SAndroid Build Coastguard Worker    ANGLE_TRY(mSync->clientWait(contextMtl, true, mtl::kNanosecondsPerDay, &result));
251*8975f5c5SAndroid Build Coastguard Worker    ASSERT(result != GL_WAIT_FAILED);
252*8975f5c5SAndroid Build Coastguard Worker    return angle::Result::Continue;
253*8975f5c5SAndroid Build Coastguard Worker}
254*8975f5c5SAndroid Build Coastguard Worker
255*8975f5c5SAndroid Build Coastguard Worker// SyncMtl implementation
256*8975f5c5SAndroid Build Coastguard WorkerSyncMtl::SyncMtl() : SyncImpl() {}
257*8975f5c5SAndroid Build Coastguard Worker
258*8975f5c5SAndroid Build Coastguard WorkerSyncMtl::~SyncMtl() {}
259*8975f5c5SAndroid Build Coastguard Worker
260*8975f5c5SAndroid Build Coastguard Workervoid SyncMtl::onDestroy(const gl::Context *context)
261*8975f5c5SAndroid Build Coastguard Worker{
262*8975f5c5SAndroid Build Coastguard Worker    mSync.reset();
263*8975f5c5SAndroid Build Coastguard Worker}
264*8975f5c5SAndroid Build Coastguard Worker
265*8975f5c5SAndroid Build Coastguard Workerangle::Result SyncMtl::set(const gl::Context *context, GLenum condition, GLbitfield flags)
266*8975f5c5SAndroid Build Coastguard Worker{
267*8975f5c5SAndroid Build Coastguard Worker    ASSERT(condition == GL_SYNC_GPU_COMMANDS_COMPLETE);
268*8975f5c5SAndroid Build Coastguard Worker    ASSERT(flags == 0);
269*8975f5c5SAndroid Build Coastguard Worker
270*8975f5c5SAndroid Build Coastguard Worker    ContextMtl *contextMtl                   = mtl::GetImpl(context);
271*8975f5c5SAndroid Build Coastguard Worker    std::unique_ptr<mtl::EventSyncImpl> impl = std::make_unique<mtl::EventSyncImpl>();
272*8975f5c5SAndroid Build Coastguard Worker    ANGLE_TRY(impl->set(contextMtl));
273*8975f5c5SAndroid Build Coastguard Worker    mSync = std::move(impl);
274*8975f5c5SAndroid Build Coastguard Worker
275*8975f5c5SAndroid Build Coastguard Worker    return angle::Result::Continue;
276*8975f5c5SAndroid Build Coastguard Worker}
277*8975f5c5SAndroid Build Coastguard Worker
278*8975f5c5SAndroid Build Coastguard Workerangle::Result SyncMtl::clientWait(const gl::Context *context,
279*8975f5c5SAndroid Build Coastguard Worker                                  GLbitfield flags,
280*8975f5c5SAndroid Build Coastguard Worker                                  GLuint64 timeout,
281*8975f5c5SAndroid Build Coastguard Worker                                  GLenum *outResult)
282*8975f5c5SAndroid Build Coastguard Worker{
283*8975f5c5SAndroid Build Coastguard Worker    ASSERT((flags & ~GL_SYNC_FLUSH_COMMANDS_BIT) == 0);
284*8975f5c5SAndroid Build Coastguard Worker
285*8975f5c5SAndroid Build Coastguard Worker    ContextMtl *contextMtl = mtl::GetImpl(context);
286*8975f5c5SAndroid Build Coastguard Worker    bool flush             = (flags & GL_SYNC_FLUSH_COMMANDS_BIT) != 0;
287*8975f5c5SAndroid Build Coastguard Worker    return mSync->clientWait(contextMtl, flush, timeout, outResult);
288*8975f5c5SAndroid Build Coastguard Worker}
289*8975f5c5SAndroid Build Coastguard Worker
290*8975f5c5SAndroid Build Coastguard Workerangle::Result SyncMtl::serverWait(const gl::Context *context, GLbitfield flags, GLuint64 timeout)
291*8975f5c5SAndroid Build Coastguard Worker{
292*8975f5c5SAndroid Build Coastguard Worker    ASSERT(flags == 0);
293*8975f5c5SAndroid Build Coastguard Worker    ASSERT(timeout == GL_TIMEOUT_IGNORED);
294*8975f5c5SAndroid Build Coastguard Worker
295*8975f5c5SAndroid Build Coastguard Worker    ContextMtl *contextMtl = mtl::GetImpl(context);
296*8975f5c5SAndroid Build Coastguard Worker    return mSync->serverWait(contextMtl);
297*8975f5c5SAndroid Build Coastguard Worker}
298*8975f5c5SAndroid Build Coastguard Worker
299*8975f5c5SAndroid Build Coastguard Workerangle::Result SyncMtl::getStatus(const gl::Context *context, GLint *outResult)
300*8975f5c5SAndroid Build Coastguard Worker{
301*8975f5c5SAndroid Build Coastguard Worker    ContextMtl *contextMtl = mtl::GetImpl(context);
302*8975f5c5SAndroid Build Coastguard Worker
303*8975f5c5SAndroid Build Coastguard Worker    bool signaled = false;
304*8975f5c5SAndroid Build Coastguard Worker    ANGLE_TRY(mSync->getStatus(contextMtl->getDisplay(), &signaled));
305*8975f5c5SAndroid Build Coastguard Worker
306*8975f5c5SAndroid Build Coastguard Worker    *outResult = signaled ? GL_SIGNALED : GL_UNSIGNALED;
307*8975f5c5SAndroid Build Coastguard Worker    return angle::Result::Continue;
308*8975f5c5SAndroid Build Coastguard Worker}
309*8975f5c5SAndroid Build Coastguard Worker
310*8975f5c5SAndroid Build Coastguard Worker// EGLSyncMtl implementation
311*8975f5c5SAndroid Build Coastguard WorkerEGLSyncMtl::EGLSyncMtl() : EGLSyncImpl() {}
312*8975f5c5SAndroid Build Coastguard Worker
313*8975f5c5SAndroid Build Coastguard WorkerEGLSyncMtl::~EGLSyncMtl() {}
314*8975f5c5SAndroid Build Coastguard Worker
315*8975f5c5SAndroid Build Coastguard Workervoid EGLSyncMtl::onDestroy(const egl::Display *display)
316*8975f5c5SAndroid Build Coastguard Worker{
317*8975f5c5SAndroid Build Coastguard Worker    mSync.reset();
318*8975f5c5SAndroid Build Coastguard Worker    mSharedEvent = nil;
319*8975f5c5SAndroid Build Coastguard Worker}
320*8975f5c5SAndroid Build Coastguard Worker
321*8975f5c5SAndroid Build Coastguard Workeregl::Error EGLSyncMtl::initialize(const egl::Display *display,
322*8975f5c5SAndroid Build Coastguard Worker                                  const gl::Context *context,
323*8975f5c5SAndroid Build Coastguard Worker                                  EGLenum type,
324*8975f5c5SAndroid Build Coastguard Worker                                  const egl::AttributeMap &attribs)
325*8975f5c5SAndroid Build Coastguard Worker{
326*8975f5c5SAndroid Build Coastguard Worker    ASSERT(context != nullptr);
327*8975f5c5SAndroid Build Coastguard Worker
328*8975f5c5SAndroid Build Coastguard Worker    ContextMtl *contextMtl = mtl::GetImpl(context);
329*8975f5c5SAndroid Build Coastguard Worker    switch (type)
330*8975f5c5SAndroid Build Coastguard Worker    {
331*8975f5c5SAndroid Build Coastguard Worker        case EGL_SYNC_FENCE_KHR:
332*8975f5c5SAndroid Build Coastguard Worker        {
333*8975f5c5SAndroid Build Coastguard Worker            std::unique_ptr<mtl::EventSyncImpl> impl = std::make_unique<mtl::EventSyncImpl>();
334*8975f5c5SAndroid Build Coastguard Worker            if (IsError(impl->set(contextMtl)))
335*8975f5c5SAndroid Build Coastguard Worker            {
336*8975f5c5SAndroid Build Coastguard Worker                return egl::Error(EGL_BAD_ALLOC, "eglCreateSyncKHR failed to create sync object");
337*8975f5c5SAndroid Build Coastguard Worker            }
338*8975f5c5SAndroid Build Coastguard Worker            mSync = std::move(impl);
339*8975f5c5SAndroid Build Coastguard Worker
340*8975f5c5SAndroid Build Coastguard Worker            break;
341*8975f5c5SAndroid Build Coastguard Worker        }
342*8975f5c5SAndroid Build Coastguard Worker
343*8975f5c5SAndroid Build Coastguard Worker        case EGL_SYNC_METAL_SHARED_EVENT_ANGLE:
344*8975f5c5SAndroid Build Coastguard Worker        {
345*8975f5c5SAndroid Build Coastguard Worker            mSharedEvent.retainAssign((__bridge id<MTLSharedEvent>)reinterpret_cast<void *>(
346*8975f5c5SAndroid Build Coastguard Worker                attribs.get(EGL_SYNC_METAL_SHARED_EVENT_OBJECT_ANGLE, 0)));
347*8975f5c5SAndroid Build Coastguard Worker            if (!mSharedEvent)
348*8975f5c5SAndroid Build Coastguard Worker            {
349*8975f5c5SAndroid Build Coastguard Worker                mSharedEvent = contextMtl->getMetalDevice().newSharedEvent();
350*8975f5c5SAndroid Build Coastguard Worker            }
351*8975f5c5SAndroid Build Coastguard Worker
352*8975f5c5SAndroid Build Coastguard Worker            uint64_t signalValue = 0;
353*8975f5c5SAndroid Build Coastguard Worker            if (attribs.contains(EGL_SYNC_METAL_SHARED_EVENT_SIGNAL_VALUE_HI_ANGLE) ||
354*8975f5c5SAndroid Build Coastguard Worker                attribs.contains(EGL_SYNC_METAL_SHARED_EVENT_SIGNAL_VALUE_LO_ANGLE))
355*8975f5c5SAndroid Build Coastguard Worker            {
356*8975f5c5SAndroid Build Coastguard Worker                signalValue = mtl::UnpackSignalValue(
357*8975f5c5SAndroid Build Coastguard Worker                    attribs.get(EGL_SYNC_METAL_SHARED_EVENT_SIGNAL_VALUE_HI_ANGLE, 0),
358*8975f5c5SAndroid Build Coastguard Worker                    attribs.get(EGL_SYNC_METAL_SHARED_EVENT_SIGNAL_VALUE_LO_ANGLE, 0));
359*8975f5c5SAndroid Build Coastguard Worker            }
360*8975f5c5SAndroid Build Coastguard Worker            else
361*8975f5c5SAndroid Build Coastguard Worker            {
362*8975f5c5SAndroid Build Coastguard Worker                signalValue = mSharedEvent.get().signaledValue + 1;
363*8975f5c5SAndroid Build Coastguard Worker            }
364*8975f5c5SAndroid Build Coastguard Worker
365*8975f5c5SAndroid Build Coastguard Worker            // If the condition is anything other than EGL_SYNC_METAL_SHARED_EVENT_SIGNALED_ANGLE,
366*8975f5c5SAndroid Build Coastguard Worker            // we enque the event created/provided.
367*8975f5c5SAndroid Build Coastguard Worker            // TODO: Could this be changed to `mSharedEvent != nullptr`? Do we ever create an event
368*8975f5c5SAndroid Build Coastguard Worker            // but not want to enqueue it?
369*8975f5c5SAndroid Build Coastguard Worker            bool enqueue = attribs.getAsInt(EGL_SYNC_CONDITION, 0) !=
370*8975f5c5SAndroid Build Coastguard Worker                           EGL_SYNC_METAL_SHARED_EVENT_SIGNALED_ANGLE;
371*8975f5c5SAndroid Build Coastguard Worker
372*8975f5c5SAndroid Build Coastguard Worker            std::unique_ptr<mtl::SharedEventSyncImpl> impl =
373*8975f5c5SAndroid Build Coastguard Worker                std::make_unique<mtl::SharedEventSyncImpl>();
374*8975f5c5SAndroid Build Coastguard Worker            if (IsError(impl->set(contextMtl, mSharedEvent, signalValue, enqueue)))
375*8975f5c5SAndroid Build Coastguard Worker            {
376*8975f5c5SAndroid Build Coastguard Worker                return egl::Error(EGL_BAD_ALLOC, "eglCreateSyncKHR failed to create sync object");
377*8975f5c5SAndroid Build Coastguard Worker            }
378*8975f5c5SAndroid Build Coastguard Worker            mSync = std::move(impl);
379*8975f5c5SAndroid Build Coastguard Worker            break;
380*8975f5c5SAndroid Build Coastguard Worker        }
381*8975f5c5SAndroid Build Coastguard Worker
382*8975f5c5SAndroid Build Coastguard Worker        default:
383*8975f5c5SAndroid Build Coastguard Worker            UNREACHABLE();
384*8975f5c5SAndroid Build Coastguard Worker            return egl::Error(EGL_BAD_ALLOC);
385*8975f5c5SAndroid Build Coastguard Worker    }
386*8975f5c5SAndroid Build Coastguard Worker
387*8975f5c5SAndroid Build Coastguard Worker    return egl::NoError();
388*8975f5c5SAndroid Build Coastguard Worker}
389*8975f5c5SAndroid Build Coastguard Worker
390*8975f5c5SAndroid Build Coastguard Workeregl::Error EGLSyncMtl::clientWait(const egl::Display *display,
391*8975f5c5SAndroid Build Coastguard Worker                                  const gl::Context *context,
392*8975f5c5SAndroid Build Coastguard Worker                                  EGLint flags,
393*8975f5c5SAndroid Build Coastguard Worker                                  EGLTime timeout,
394*8975f5c5SAndroid Build Coastguard Worker                                  EGLint *outResult)
395*8975f5c5SAndroid Build Coastguard Worker{
396*8975f5c5SAndroid Build Coastguard Worker    ASSERT((flags & ~EGL_SYNC_FLUSH_COMMANDS_BIT_KHR) == 0);
397*8975f5c5SAndroid Build Coastguard Worker
398*8975f5c5SAndroid Build Coastguard Worker    bool flush             = (flags & EGL_SYNC_FLUSH_COMMANDS_BIT_KHR) != 0;
399*8975f5c5SAndroid Build Coastguard Worker    GLenum result          = GL_NONE;
400*8975f5c5SAndroid Build Coastguard Worker    ContextMtl *contextMtl = mtl::GetImpl(context);
401*8975f5c5SAndroid Build Coastguard Worker    if (IsError(mSync->clientWait(contextMtl, flush, static_cast<uint64_t>(timeout), &result)))
402*8975f5c5SAndroid Build Coastguard Worker    {
403*8975f5c5SAndroid Build Coastguard Worker        return egl::Error(EGL_BAD_ALLOC);
404*8975f5c5SAndroid Build Coastguard Worker    }
405*8975f5c5SAndroid Build Coastguard Worker
406*8975f5c5SAndroid Build Coastguard Worker    switch (result)
407*8975f5c5SAndroid Build Coastguard Worker    {
408*8975f5c5SAndroid Build Coastguard Worker        case GL_ALREADY_SIGNALED:
409*8975f5c5SAndroid Build Coastguard Worker            // fall through.  EGL doesn't differentiate between event being already set, or set
410*8975f5c5SAndroid Build Coastguard Worker            // before timeout.
411*8975f5c5SAndroid Build Coastguard Worker        case GL_CONDITION_SATISFIED:
412*8975f5c5SAndroid Build Coastguard Worker            *outResult = EGL_CONDITION_SATISFIED_KHR;
413*8975f5c5SAndroid Build Coastguard Worker            return egl::NoError();
414*8975f5c5SAndroid Build Coastguard Worker
415*8975f5c5SAndroid Build Coastguard Worker        case GL_TIMEOUT_EXPIRED:
416*8975f5c5SAndroid Build Coastguard Worker            *outResult = EGL_TIMEOUT_EXPIRED_KHR;
417*8975f5c5SAndroid Build Coastguard Worker            return egl::NoError();
418*8975f5c5SAndroid Build Coastguard Worker
419*8975f5c5SAndroid Build Coastguard Worker        default:
420*8975f5c5SAndroid Build Coastguard Worker            UNREACHABLE();
421*8975f5c5SAndroid Build Coastguard Worker            *outResult = EGL_FALSE;
422*8975f5c5SAndroid Build Coastguard Worker            return egl::Error(EGL_BAD_ALLOC);
423*8975f5c5SAndroid Build Coastguard Worker    }
424*8975f5c5SAndroid Build Coastguard Worker}
425*8975f5c5SAndroid Build Coastguard Worker
426*8975f5c5SAndroid Build Coastguard Workeregl::Error EGLSyncMtl::serverWait(const egl::Display *display,
427*8975f5c5SAndroid Build Coastguard Worker                                  const gl::Context *context,
428*8975f5c5SAndroid Build Coastguard Worker                                  EGLint flags)
429*8975f5c5SAndroid Build Coastguard Worker{
430*8975f5c5SAndroid Build Coastguard Worker    // Server wait requires a valid bound context.
431*8975f5c5SAndroid Build Coastguard Worker    ASSERT(context);
432*8975f5c5SAndroid Build Coastguard Worker
433*8975f5c5SAndroid Build Coastguard Worker    // No flags are currently implemented.
434*8975f5c5SAndroid Build Coastguard Worker    ASSERT(flags == 0);
435*8975f5c5SAndroid Build Coastguard Worker
436*8975f5c5SAndroid Build Coastguard Worker    ContextMtl *contextMtl = mtl::GetImpl(context);
437*8975f5c5SAndroid Build Coastguard Worker    if (IsError(mSync->serverWait(contextMtl)))
438*8975f5c5SAndroid Build Coastguard Worker    {
439*8975f5c5SAndroid Build Coastguard Worker        return egl::Error(EGL_BAD_ALLOC);
440*8975f5c5SAndroid Build Coastguard Worker    }
441*8975f5c5SAndroid Build Coastguard Worker
442*8975f5c5SAndroid Build Coastguard Worker    return egl::NoError();
443*8975f5c5SAndroid Build Coastguard Worker}
444*8975f5c5SAndroid Build Coastguard Worker
445*8975f5c5SAndroid Build Coastguard Workeregl::Error EGLSyncMtl::getStatus(const egl::Display *display, EGLint *outStatus)
446*8975f5c5SAndroid Build Coastguard Worker{
447*8975f5c5SAndroid Build Coastguard Worker    DisplayMtl *displayMtl = mtl::GetImpl(display);
448*8975f5c5SAndroid Build Coastguard Worker    bool signaled          = false;
449*8975f5c5SAndroid Build Coastguard Worker    if (IsError(mSync->getStatus(displayMtl, &signaled)))
450*8975f5c5SAndroid Build Coastguard Worker    {
451*8975f5c5SAndroid Build Coastguard Worker        return egl::Error(EGL_BAD_ALLOC);
452*8975f5c5SAndroid Build Coastguard Worker    }
453*8975f5c5SAndroid Build Coastguard Worker
454*8975f5c5SAndroid Build Coastguard Worker    *outStatus = signaled ? EGL_SIGNALED_KHR : EGL_UNSIGNALED_KHR;
455*8975f5c5SAndroid Build Coastguard Worker    return egl::NoError();
456*8975f5c5SAndroid Build Coastguard Worker}
457*8975f5c5SAndroid Build Coastguard Worker
458*8975f5c5SAndroid Build Coastguard Workeregl::Error EGLSyncMtl::copyMetalSharedEventANGLE(const egl::Display *display, void **result) const
459*8975f5c5SAndroid Build Coastguard Worker{
460*8975f5c5SAndroid Build Coastguard Worker    ASSERT(mSharedEvent != nil);
461*8975f5c5SAndroid Build Coastguard Worker
462*8975f5c5SAndroid Build Coastguard Worker    mtl::AutoObjCPtr<id<MTLSharedEvent>> copySharedEvent = mSharedEvent;
463*8975f5c5SAndroid Build Coastguard Worker    *result = reinterpret_cast<void *>(copySharedEvent.leakObject());
464*8975f5c5SAndroid Build Coastguard Worker
465*8975f5c5SAndroid Build Coastguard Worker    return egl::NoError();
466*8975f5c5SAndroid Build Coastguard Worker}
467*8975f5c5SAndroid Build Coastguard Worker
468*8975f5c5SAndroid Build Coastguard Workeregl::Error EGLSyncMtl::dupNativeFenceFD(const egl::Display *display, EGLint *result) const
469*8975f5c5SAndroid Build Coastguard Worker{
470*8975f5c5SAndroid Build Coastguard Worker    UNREACHABLE();
471*8975f5c5SAndroid Build Coastguard Worker    return egl::EglBadDisplay();
472*8975f5c5SAndroid Build Coastguard Worker}
473*8975f5c5SAndroid Build Coastguard Worker
474*8975f5c5SAndroid Build Coastguard Worker}  // namespace rx
475