Bug: angleproject:2634
Change-Id: If1f7bb12c0e661c8e4b5677798a92440995819e4
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2433325
Commit-Queue: Le Hoang Quyen <le.hoang.q@gmail.com>
Reviewed-by: Geoff Lang <geofflang@chromium.org>
Reviewed-by: Jamie Madill <jmadill@chromium.org>
This commit is contained in:
Le Hoang Quyen 2020-03-25 03:02:08 +08:00 коммит произвёл Commit Bot
Родитель 0c046affc5
Коммит 6dfd855a10
13 изменённых файлов: 653 добавлений и 13 удалений

Просмотреть файл

@ -48,6 +48,9 @@ struct FeaturesMtl : FeatureSetBase
"has_msaa_stencil_auto_resolve", FeatureCategory::MetalFeatures,
"The renderer supports MSAA stencil auto resolve at the end of render pass", &members};
Feature hasEvents = {"has_mtl_events", FeatureCategory::MetalFeatures,
"The renderer supports MTL(Shared)Event", &members};
// On macos, separate depth & stencil buffers are not supproted. However, on iOS devices,
// they are supproted:
Feature allowSeparatedDepthStencilBuffers = {

Просмотреть файл

@ -33,6 +33,8 @@ _metal_backend_sources = [
"ShaderMtl.mm",
"SurfaceMtl.h",
"SurfaceMtl.mm",
"SyncMtl.h",
"SyncMtl.mm",
"TextureMtl.h",
"TextureMtl.mm",
"TransformFeedbackMtl.h",

Просмотреть файл

@ -289,12 +289,15 @@ class ContextMtl : public ContextImpl, public mtl::Context
// NOTE: the old query's result will be retained and combined with the new result.
angle::Result restartActiveOcclusionQueryInRenderPass();
const MTLClearColor &getClearColorValue() const;
// Invoke by TransformFeedbackMtl
void onTransformFeedbackActive(const gl::Context *context, TransformFeedbackMtl *xfb);
void onTransformFeedbackInactive(const gl::Context *context, TransformFeedbackMtl *xfb);
// Invoke by mtl::Sync
void queueEventSignal(const mtl::SharedEventRef &event, uint64_t value);
void serverWaitEvent(const mtl::SharedEventRef &event, uint64_t value);
const MTLClearColor &getClearColorValue() const;
MTLColorWriteMask getColorMask() const;
float getClearDepthValue() const;
uint32_t getClearStencilValue() const;

Просмотреть файл

@ -22,6 +22,7 @@
#include "libANGLE/renderer/metal/RenderBufferMtl.h"
#include "libANGLE/renderer/metal/RenderTargetMtl.h"
#include "libANGLE/renderer/metal/ShaderMtl.h"
#include "libANGLE/renderer/metal/SyncMtl.h"
#include "libANGLE/renderer/metal/TextureMtl.h"
#include "libANGLE/renderer/metal/TransformFeedbackMtl.h"
#include "libANGLE/renderer/metal/VertexArrayMtl.h"
@ -978,13 +979,11 @@ QueryImpl *ContextMtl::createQuery(gl::QueryType type)
}
FenceNVImpl *ContextMtl::createFenceNV()
{
UNIMPLEMENTED();
return nullptr;
return new FenceNVMtl();
}
SyncImpl *ContextMtl::createSync()
{
UNIMPLEMENTED();
return nullptr;
return new SyncMtl();
}
// Transform Feedback creation
@ -1609,6 +1608,22 @@ void ContextMtl::onTransformFeedbackInactive(const gl::Context *context, Transfo
endEncoding(true);
}
void ContextMtl::queueEventSignal(const mtl::SharedEventRef &event, uint64_t value)
{
ensureCommandBufferReady();
mCmdBuffer.queueEventSignal(event, value);
}
void ContextMtl::serverWaitEvent(const mtl::SharedEventRef &event, uint64_t value)
{
ensureCommandBufferReady();
// Event waiting cannot be encoded if there is active encoder.
endEncoding(true);
mCmdBuffer.serverWaitEvent(event, value);
}
void ContextMtl::updateProgramExecutable(const gl::Context *context)
{
// Need to rebind textures

Просмотреть файл

@ -149,7 +149,9 @@ class DisplayMtl : public DisplayImpl
{
return mFormatTable.getVertexFormat(angleFormatId, tightlyPacked);
}
#if ANGLE_MTL_EVENT_AVAILABLE
mtl::AutoObjCObj<MTLSharedEventListener> getOrCreateSharedEventListener();
#endif
protected:
void generateExtensions(egl::DisplayExtensions *outExtensions) const override;
void generateCaps(egl::Caps *outCaps) const override;
@ -174,6 +176,9 @@ class DisplayMtl : public DisplayImpl
// Built-in Shaders
mtl::AutoObjCPtr<id<MTLLibrary>> mDefaultShaders = nil;
#if ANGLE_MTL_EVENT_AVAILABLE
mtl::AutoObjCObj<MTLSharedEventListener> mSharedEventListener;
#endif
mutable bool mCapsInitialized;
mutable gl::TextureCapsMap mNativeTextureCaps;

Просмотреть файл

@ -15,6 +15,7 @@
#include "libANGLE/renderer/glslang_wrapper_utils.h"
#include "libANGLE/renderer/metal/ContextMtl.h"
#include "libANGLE/renderer/metal/SurfaceMtl.h"
#include "libANGLE/renderer/metal/SyncMtl.h"
#include "libANGLE/renderer/metal/mtl_common.h"
#include "libANGLE/renderer/metal/shaders/compiled/mtl_default_shaders_autogen.inc"
#include "platform/Platform.h"
@ -99,8 +100,11 @@ void DisplayMtl::terminate()
{
mUtils.onDestroy();
mCmdQueue.reset();
mDefaultShaders = nil;
mMetalDevice = nil;
mDefaultShaders = nil;
mMetalDevice = nil;
#if ANGLE_MTL_EVENT_AVAILABLE
mSharedEventListener = nil;
#endif
mCapsInitialized = false;
mMetalDeviceVendorId = 0;
@ -158,7 +162,7 @@ egl::Error DisplayMtl::waitClient(const gl::Context *context)
egl::Error DisplayMtl::waitNative(const gl::Context *context, EGLint engine)
{
UNIMPLEMENTED();
return egl::EglBadAccess();
return egl::NoError();
}
SurfaceImpl *DisplayMtl::createWindowSurface(const egl::SurfaceState &state,
@ -241,8 +245,7 @@ gl::Version DisplayMtl::getMaxConformantESVersion() const
EGLSyncImpl *DisplayMtl::createSync(const egl::AttributeMap &attribs)
{
UNIMPLEMENTED();
return nullptr;
return new EGLSyncMtl(attribs);
}
egl::Error DisplayMtl::makeCurrent(egl::Display *display,
@ -266,6 +269,13 @@ void DisplayMtl::generateExtensions(egl::DisplayExtensions *outExtensions) const
outExtensions->displayTextureShareGroup = true;
outExtensions->displaySemaphoreShareGroup = true;
if (mFeatures.hasEvents.enabled)
{
// MTLSharedEvent is only available since Metal 2.1
outExtensions->fenceSync = true;
outExtensions->waitSync = true;
}
// Note that robust resource initialization is not yet implemented. We only expose
// this extension so that ANGLE can be initialized in Chrome. WebGL will fail to use
// this extension (anglebug.com/4929)
@ -651,6 +661,17 @@ void DisplayMtl::initializeExtensions() const
// GL_NV_pixel_buffer_object
mNativeExtensions.pixelBufferObjectNV = true;
if (mFeatures.hasEvents.enabled)
{
// MTLSharedEvent is only available since Metal 2.1
// GL_NV_fence
mNativeExtensions.fenceNV = true;
// GL_OES_EGL_sync
mNativeExtensions.eglSyncOES = true;
}
}
void DisplayMtl::initializeTextureCaps() const
@ -707,6 +728,8 @@ void DisplayMtl::initializeFeatures()
ANGLE_FEATURE_CONDITION((&mFeatures), hasTextureSwizzle,
isMetal2_2 && supportsEitherGPUFamily(1, 2));
ANGLE_FEATURE_CONDITION((&mFeatures), hasEvents, isMetal2_1);
#if !TARGET_OS_MACCATALYST && (TARGET_OS_IOS || TARGET_OS_TV)
// Base Vertex drawing is only supported since GPU family 3.
ANGLE_FEATURE_CONDITION((&mFeatures), hasBaseVertexInstancedDraw, supportsIOSGPUFamily(3));
@ -932,4 +955,18 @@ bool DisplayMtl::isNVIDIA() const
return angle::IsNVIDIA(mMetalDeviceVendorId);
}
#if ANGLE_MTL_EVENT_AVAILABLE
mtl::AutoObjCObj<MTLSharedEventListener> DisplayMtl::getOrCreateSharedEventListener()
{
if (!mSharedEventListener)
{
ANGLE_MTL_OBJC_SCOPE
{
mSharedEventListener = [[[MTLSharedEventListener alloc] init] ANGLE_MTL_AUTORELEASE];
}
}
return mSharedEventListener;
}
#endif
} // namespace rx

Просмотреть файл

@ -0,0 +1,163 @@
//
// Copyright 2020 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// SyncMtl:
// Defines the class interface for SyncMtl, implementing SyncImpl.
//
#ifndef LIBANGLE_RENDERER_METAL_SYNCMTL_H_
#define LIBANGLE_RENDERER_METAL_SYNCMTL_H_
#include <condition_variable>
#include <mutex>
#include "libANGLE/renderer/EGLSyncImpl.h"
#include "libANGLE/renderer/FenceNVImpl.h"
#include "libANGLE/renderer/SyncImpl.h"
#include "libANGLE/renderer/metal/mtl_common.h"
namespace egl
{
class AttributeMap;
}
namespace rx
{
class ContextMtl;
namespace mtl
{
// Common class to be used by both SyncImpl and EGLSyncImpl.
// NOTE: SharedEvent is only declared on iOS 12.0+ or mac 10.14+
#if ANGLE_MTL_EVENT_AVAILABLE
class Sync
{
public:
Sync();
~Sync();
void onDestroy();
angle::Result initialize(ContextMtl *contextMtl);
angle::Result set(ContextMtl *contextMtl, GLenum condition, GLbitfield flags);
angle::Result clientWait(ContextMtl *contextMtl,
bool flushCommands,
uint64_t timeout,
GLenum *outResult);
void serverWait(ContextMtl *contextMtl);
angle::Result getStatus(bool *signaled);
private:
SharedEventRef mMetalSharedEvent;
uint64_t mSetCounter = 0;
std::shared_ptr<std::condition_variable> mCv;
std::shared_ptr<std::mutex> mLock;
};
#else // #if ANGLE_MTL_EVENT_AVAILABLE
class Sync
{
public:
void onDestroy() { UNREACHABLE(); }
angle::Result initialize(ContextMtl *context)
{
UNREACHABLE();
return angle::Result::Stop;
}
angle::Result set(ContextMtl *contextMtl, GLenum condition, GLbitfield flags)
{
UNREACHABLE();
return angle::Result::Stop;
}
angle::Result clientWait(ContextMtl *context,
bool flushCommands,
uint64_t timeout,
GLenum *outResult)
{
UNREACHABLE();
return angle::Result::Stop;
}
void serverWait(ContextMtl *contextMtl) { UNREACHABLE(); }
angle::Result getStatus(bool *signaled)
{
UNREACHABLE();
return angle::Result::Stop;
}
};
#endif // #if ANGLE_MTL_EVENT_AVAILABLE
} // namespace mtl
class FenceNVMtl : public FenceNVImpl
{
public:
FenceNVMtl();
~FenceNVMtl() override;
void onDestroy(const gl::Context *context) override;
angle::Result set(const gl::Context *context, GLenum condition) override;
angle::Result test(const gl::Context *context, GLboolean *outFinished) override;
angle::Result finish(const gl::Context *context) override;
private:
mtl::Sync mSync;
};
class SyncMtl : public SyncImpl
{
public:
SyncMtl();
~SyncMtl() override;
void onDestroy(const gl::Context *context) override;
angle::Result set(const gl::Context *context, GLenum condition, GLbitfield flags) override;
angle::Result clientWait(const gl::Context *context,
GLbitfield flags,
GLuint64 timeout,
GLenum *outResult) override;
angle::Result serverWait(const gl::Context *context,
GLbitfield flags,
GLuint64 timeout) override;
angle::Result getStatus(const gl::Context *context, GLint *outResult) override;
private:
mtl::Sync mSync;
};
class EGLSyncMtl final : public EGLSyncImpl
{
public:
EGLSyncMtl(const egl::AttributeMap &attribs);
~EGLSyncMtl() override;
void onDestroy(const egl::Display *display) override;
egl::Error initialize(const egl::Display *display,
const gl::Context *context,
EGLenum type) override;
egl::Error clientWait(const egl::Display *display,
const gl::Context *context,
EGLint flags,
EGLTime timeout,
EGLint *outResult) override;
egl::Error serverWait(const egl::Display *display,
const gl::Context *context,
EGLint flags) override;
egl::Error getStatus(const egl::Display *display, EGLint *outStatus) override;
egl::Error dupNativeFenceFD(const egl::Display *display, EGLint *result) const override;
private:
mtl::Sync mSync;
};
} // namespace rx
#endif

Просмотреть файл

@ -0,0 +1,316 @@
//
// Copyright 2020 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// SyncMtl:
// Defines the class interface for SyncMtl, implementing SyncImpl.
//
#include "libANGLE/renderer/metal/SyncMtl.h"
#include <chrono>
#include "common/debug.h"
#include "libANGLE/Context.h"
#include "libANGLE/Display.h"
#include "libANGLE/renderer/metal/ContextMtl.h"
#include "libANGLE/renderer/metal/DisplayMtl.h"
namespace rx
{
namespace mtl
{
// SharedEvent is only available on iOS 12.0+ or mac 10.14+
#if ANGLE_MTL_EVENT_AVAILABLE
Sync::Sync() {}
Sync::~Sync() {}
void Sync::onDestroy()
{
mMetalSharedEvent = nil;
mCv = nullptr;
mLock = nullptr;
}
angle::Result Sync::initialize(ContextMtl *contextMtl)
{
ANGLE_MTL_OBJC_SCOPE
{
mMetalSharedEvent = [[contextMtl->getMetalDevice() newSharedEvent] ANGLE_MTL_AUTORELEASE];
}
mSetCounter = mMetalSharedEvent.get().signaledValue;
mCv.reset(new std::condition_variable());
mLock.reset(new std::mutex());
return angle::Result::Continue;
}
angle::Result Sync::set(ContextMtl *contextMtl, GLenum condition, GLbitfield flags)
{
if (!mMetalSharedEvent)
{
ANGLE_TRY(initialize(contextMtl));
}
ASSERT(condition == GL_SYNC_GPU_COMMANDS_COMPLETE);
ASSERT(flags == 0);
mSetCounter++;
contextMtl->queueEventSignal(mMetalSharedEvent, mSetCounter);
return angle::Result::Continue;
}
angle::Result Sync::clientWait(ContextMtl *contextMtl,
bool flushCommands,
uint64_t timeout,
GLenum *outResult)
{
std::unique_lock<std::mutex> lg(*mLock);
if (mMetalSharedEvent.get().signaledValue >= mSetCounter)
{
*outResult = GL_ALREADY_SIGNALED;
return angle::Result::Continue;
}
if (flushCommands)
{
contextMtl->flushCommandBufer();
}
if (timeout == 0)
{
*outResult = GL_TIMEOUT_EXPIRED;
return angle::Result::Continue;
}
// Create references to mutex and condition variable since they might be released in
// onDestroy(), but the callback might still not be fired yet.
std::shared_ptr<std::condition_variable> cvRef = mCv;
std::shared_ptr<std::mutex> lockRef = mLock;
AutoObjCObj<MTLSharedEventListener> eventListener =
contextMtl->getDisplay()->getOrCreateSharedEventListener();
[mMetalSharedEvent.get() notifyListener:eventListener
atValue:mSetCounter
block:^(id<MTLSharedEvent> sharedEvent, uint64_t value) {
std::unique_lock<std::mutex> lg(*lockRef);
cvRef->notify_one();
}];
if (!mCv->wait_for(lg, std::chrono::nanoseconds(timeout),
[this] { return mMetalSharedEvent.get().signaledValue >= mSetCounter; }))
{
*outResult = GL_TIMEOUT_EXPIRED;
return angle::Result::Incomplete;
}
ASSERT(mMetalSharedEvent.get().signaledValue >= mSetCounter);
*outResult = GL_CONDITION_SATISFIED;
return angle::Result::Continue;
}
void Sync::serverWait(ContextMtl *contextMtl)
{
contextMtl->serverWaitEvent(mMetalSharedEvent, mSetCounter);
}
angle::Result Sync::getStatus(bool *signaled)
{
*signaled = mMetalSharedEvent.get().signaledValue >= mSetCounter;
return angle::Result::Continue;
}
#endif // #if ANGLE_MTL_EVENT_AVAILABLE
} // namespace mtl
// FenceNVMtl implementation
FenceNVMtl::FenceNVMtl() : FenceNVImpl() {}
FenceNVMtl::~FenceNVMtl() {}
void FenceNVMtl::onDestroy(const gl::Context *context)
{
mSync.onDestroy();
}
angle::Result FenceNVMtl::set(const gl::Context *context, GLenum condition)
{
ASSERT(condition == GL_ALL_COMPLETED_NV);
ContextMtl *contextMtl = mtl::GetImpl(context);
return mSync.set(contextMtl, GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
}
angle::Result FenceNVMtl::test(const gl::Context *context, GLboolean *outFinished)
{
bool signaled = false;
ANGLE_TRY(mSync.getStatus(&signaled));
*outFinished = signaled ? GL_TRUE : GL_FALSE;
return angle::Result::Continue;
}
angle::Result FenceNVMtl::finish(const gl::Context *context)
{
ContextMtl *contextMtl = mtl::GetImpl(context);
uint64_t timeout = 1000000000ul;
GLenum result;
do
{
ANGLE_TRY(mSync.clientWait(contextMtl, true, timeout, &result));
} while (result == GL_TIMEOUT_EXPIRED);
if (result == GL_WAIT_FAILED)
{
UNREACHABLE();
return angle::Result::Stop;
}
return angle::Result::Continue;
}
// SyncMtl implementation
SyncMtl::SyncMtl() : SyncImpl() {}
SyncMtl::~SyncMtl() {}
void SyncMtl::onDestroy(const gl::Context *context)
{
mSync.onDestroy();
}
angle::Result SyncMtl::set(const gl::Context *context, GLenum condition, GLbitfield flags)
{
ContextMtl *contextMtl = mtl::GetImpl(context);
return mSync.set(contextMtl, condition, flags);
}
angle::Result SyncMtl::clientWait(const gl::Context *context,
GLbitfield flags,
GLuint64 timeout,
GLenum *outResult)
{
ContextMtl *contextMtl = mtl::GetImpl(context);
ASSERT((flags & ~GL_SYNC_FLUSH_COMMANDS_BIT) == 0);
bool flush = (flags & GL_SYNC_FLUSH_COMMANDS_BIT) != 0;
return mSync.clientWait(contextMtl, flush, timeout, outResult);
}
angle::Result SyncMtl::serverWait(const gl::Context *context, GLbitfield flags, GLuint64 timeout)
{
ASSERT(flags == 0);
ASSERT(timeout == GL_TIMEOUT_IGNORED);
ContextMtl *contextMtl = mtl::GetImpl(context);
mSync.serverWait(contextMtl);
return angle::Result::Continue;
}
angle::Result SyncMtl::getStatus(const gl::Context *context, GLint *outResult)
{
bool signaled = false;
ANGLE_TRY(mSync.getStatus(&signaled));
*outResult = signaled ? GL_SIGNALED : GL_UNSIGNALED;
return angle::Result::Continue;
}
// EGLSyncMtl implementation
EGLSyncMtl::EGLSyncMtl(const egl::AttributeMap &attribs) : EGLSyncImpl()
{
ASSERT(attribs.isEmpty());
}
EGLSyncMtl::~EGLSyncMtl() {}
void EGLSyncMtl::onDestroy(const egl::Display *display)
{
mSync.onDestroy();
}
egl::Error EGLSyncMtl::initialize(const egl::Display *display,
const gl::Context *context,
EGLenum type)
{
ASSERT(type == EGL_SYNC_FENCE_KHR);
ASSERT(context != nullptr);
ContextMtl *contextMtl = mtl::GetImpl(context);
if (IsError(mSync.set(contextMtl, GL_SYNC_GPU_COMMANDS_COMPLETE, 0)))
{
return egl::Error(EGL_BAD_ALLOC, "eglCreateSyncKHR failed to create sync object");
}
return egl::NoError();
}
egl::Error EGLSyncMtl::clientWait(const egl::Display *display,
const gl::Context *context,
EGLint flags,
EGLTime timeout,
EGLint *outResult)
{
ASSERT((flags & ~EGL_SYNC_FLUSH_COMMANDS_BIT_KHR) == 0);
bool flush = (flags & EGL_SYNC_FLUSH_COMMANDS_BIT_KHR) != 0;
GLenum result;
ContextMtl *contextMtl = mtl::GetImpl(context);
if (IsError(mSync.clientWait(contextMtl, flush, static_cast<uint64_t>(timeout), &result)))
{
return egl::Error(EGL_BAD_ALLOC);
}
switch (result)
{
case GL_ALREADY_SIGNALED:
// fall through. EGL doesn't differentiate between event being already set, or set
// before timeout.
case GL_CONDITION_SATISFIED:
*outResult = EGL_CONDITION_SATISFIED_KHR;
return egl::NoError();
case GL_TIMEOUT_EXPIRED:
*outResult = EGL_TIMEOUT_EXPIRED_KHR;
return egl::NoError();
default:
UNREACHABLE();
*outResult = EGL_FALSE;
return egl::Error(EGL_BAD_ALLOC);
}
}
egl::Error EGLSyncMtl::serverWait(const egl::Display *display,
const gl::Context *context,
EGLint flags)
{
// Server wait requires a valid bound context.
ASSERT(context);
// No flags are currently implemented.
ASSERT(flags == 0);
ContextMtl *contextMtl = mtl::GetImpl(context);
mSync.serverWait(contextMtl);
return egl::NoError();
}
egl::Error EGLSyncMtl::getStatus(const egl::Display *display, EGLint *outStatus)
{
bool signaled = false;
if (IsError(mSync.getStatus(&signaled)))
{
return egl::Error(EGL_BAD_ALLOC);
}
*outStatus = signaled ? EGL_SIGNALED_KHR : EGL_UNSIGNALED_KHR;
return egl::NoError();
}
egl::Error EGLSyncMtl::dupNativeFenceFD(const egl::Display *display, EGLint *result) const
{
UNREACHABLE();
return egl::EglBadDisplay();
}
}

Просмотреть файл

@ -113,6 +113,9 @@ class CommandBuffer final : public WrappedObject<id<MTLCommandBuffer>>, angle::N
void setReadDependency(const ResourceRef &resource);
void setReadDependency(Resource *resourcePtr);
void queueEventSignal(const mtl::SharedEventRef &event, uint64_t value);
void serverWaitEvent(const mtl::SharedEventRef &event, uint64_t value);
CommandQueue &cmdQueue() { return mCmdQueue; }
// Private use only
@ -127,6 +130,10 @@ class CommandBuffer final : public WrappedObject<id<MTLCommandBuffer>>, angle::N
void commitImpl();
void forceEndingCurrentEncoder();
void setPendingEvents();
void setEventImpl(const mtl::SharedEventRef &event, uint64_t value);
void waitEventImpl(const mtl::SharedEventRef &event, uint64_t value);
using ParentClass = WrappedObject<id<MTLCommandBuffer>>;
CommandQueue &mCmdQueue;
@ -137,6 +144,8 @@ class CommandBuffer final : public WrappedObject<id<MTLCommandBuffer>>, angle::N
mutable std::mutex mLock;
std::vector<std::pair<mtl::SharedEventRef, uint64_t>> mPendingSignalEvents;
bool mCommitted = false;
};

Просмотреть файл

@ -596,6 +596,32 @@ void CommandBuffer::restart()
ASSERT(metalCmdBuffer);
}
void CommandBuffer::queueEventSignal(const mtl::SharedEventRef &event, uint64_t value)
{
std::lock_guard<std::mutex> lg(mLock);
ASSERT(readyImpl());
if (mActiveCommandEncoder && mActiveCommandEncoder->getType() == CommandEncoder::RENDER)
{
// We cannot set event when there is an active render pass, defer the setting until the
// pass end.
mPendingSignalEvents.push_back({event, value});
}
else
{
setEventImpl(event, value);
}
}
void CommandBuffer::serverWaitEvent(const mtl::SharedEventRef &event, uint64_t value)
{
std::lock_guard<std::mutex> lg(mLock);
ASSERT(readyImpl());
waitEventImpl(event, value);
}
/** private use only */
void CommandBuffer::set(id<MTLCommandBuffer> metalBuffer)
{
@ -612,6 +638,9 @@ void CommandBuffer::invalidateActiveCommandEncoder(CommandEncoder *encoder)
if (mActiveCommandEncoder == encoder)
{
mActiveCommandEncoder = nullptr;
// No active command encoder, we can safely encode event signalling now.
setPendingEvents();
}
}
@ -642,6 +671,9 @@ void CommandBuffer::commitImpl()
// End the current encoder
forceEndingCurrentEncoder();
// Encoding any pending event's signalling.
setPendingEvents();
// Notify command queue
mCmdQueue.onCommandBufferCommitted(get(), mQueueSerial);
@ -660,6 +692,47 @@ void CommandBuffer::forceEndingCurrentEncoder()
}
}
void CommandBuffer::setPendingEvents()
{
for (const std::pair<mtl::SharedEventRef, uint64_t> &eventEntry : mPendingSignalEvents)
{
setEventImpl(eventEntry.first, eventEntry.second);
}
mPendingSignalEvents.clear();
}
void CommandBuffer::setEventImpl(const mtl::SharedEventRef &event, uint64_t value)
{
#if ANGLE_MTL_EVENT_AVAILABLE
ASSERT(!mActiveCommandEncoder || mActiveCommandEncoder->getType() != CommandEncoder::RENDER);
// For non-render command encoder, we can safely end it, so that we can encode a signal
// event.
forceEndingCurrentEncoder();
[get() encodeSignalEvent:event value:value];
#else
UNIMPLEMENTED();
UNREACHABLE();
#endif // #if ANGLE_MTL_EVENT_AVAILABLE
}
void CommandBuffer::waitEventImpl(const mtl::SharedEventRef &event, uint64_t value)
{
#if ANGLE_MTL_EVENT_AVAILABLE
ASSERT(!mActiveCommandEncoder || mActiveCommandEncoder->getType() != CommandEncoder::RENDER);
forceEndingCurrentEncoder();
// Encoding any pending event's signalling.
setPendingEvents();
[get() encodeWaitForEvent:event value:value];
#else
UNIMPLEMENTED();
UNREACHABLE();
#endif // #if ANGLE_MTL_EVENT_AVAILABLE
}
// CommandEncoder implementation
CommandEncoder::CommandEncoder(CommandBuffer *cmdBuffer, Type type)
: mType(type), mCmdBuffer(*cmdBuffer)

Просмотреть файл

@ -31,6 +31,10 @@
# endif
#endif
#if !defined(TARGET_OS_MACCATALYST)
# define TARGET_OS_MACCATALYST 0
#endif
#define ANGLE_MTL_OBJC_SCOPE @autoreleasepool
#if !__has_feature(objc_arc)
@ -326,6 +330,15 @@ class AutoObjCPtr : public WrappedObject<T>
template <typename T>
using AutoObjCObj = AutoObjCPtr<T *>;
// NOTE: SharedEvent is only declared on iOS 12.0+ or mac 10.14+
#if defined(__IPHONE_12_0) || defined(__MAC_10_14)
# define ANGLE_MTL_EVENT_AVAILABLE 1
using SharedEventRef = AutoObjCPtr<id<MTLSharedEvent>>;
#else
# define ANGLE_MTL_EVENT_AVAILABLE 0
using SharedEventRef = AutoObjCObj<NSObject>;
#endif
struct ClearOptions
{
Optional<MTLClearColor> clearColor;

Просмотреть файл

@ -482,6 +482,7 @@ TEST_P(EGLSyncTest, AndroidNativeFence_withFences)
ANGLE_INSTANTIATE_TEST(EGLSyncTest,
ES2_D3D9(),
ES2_D3D11(),
ES2_METAL(),
ES3_D3D11(),
ES2_OPENGL(),
ES3_OPENGL(),

Просмотреть файл

@ -262,4 +262,4 @@ TEST_P(FenceSyncTest, BasicOperations)
// Use this to select which configurations (e.g. which renderer, which GLES major version) these
// tests should be run against.
ANGLE_INSTANTIATE_TEST_ES2_AND_ES3(FenceNVTest);
ANGLE_INSTANTIATE_TEST_ES3(FenceSyncTest);
ANGLE_INSTANTIATE_TEST_ES3_AND(FenceSyncTest, ES3_METAL());