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