From 4f599e798b42f43071d42be5fff1724129836af2 Mon Sep 17 00:00:00 2001 From: Hparty <420024556@qq.com> Date: Thu, 28 Dec 2023 19:33:56 +0800 Subject: [PATCH] Fixed the issue of creating a surface in a non-main thread on the ios platform. * Fixed the issue of creating a surface in a non-main thread. * Fixing the deadlock when setting Sync * code format --- src/platform/ios/PAGView.mm | 9 +++++++ src/platform/ios/private/GPUDrawable.h | 3 +++ src/platform/ios/private/GPUDrawable.mm | 36 +++++++++++++++++++++++-- src/rendering/PAGAnimator.cpp | 16 +++++------ src/rendering/PAGAnimator.h | 1 - 5 files changed, 53 insertions(+), 12 deletions(-) diff --git a/src/platform/ios/PAGView.mm b/src/platform/ios/PAGView.mm index 8b1fde139f..165645886a 100644 --- a/src/platform/ios/PAGView.mm +++ b/src/platform/ios/PAGView.mm @@ -20,6 +20,7 @@ #import "PAGPlayer.h" #import "PAGSurface.h" #import "platform/cocoa/private/PAGAnimator.h" +#import "platform/ios/private/GPUDrawable.h" @implementation PAGView { PAGPlayer* pagPlayer; @@ -53,6 +54,10 @@ - (void)initPAG { selector:@selector(applicationDidReceiveMemoryWarning:) name:UIApplicationDidReceiveMemoryWarningNotification object:nil]; + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(AsyncSurfacePrepared:) + name:pag::kAsyncSurfacePreparedNotification + object:self.layer]; } - (void)dealloc { @@ -349,4 +354,8 @@ - (CGRect)getBounds:(PAGLayer*)pagLayer { } return CGRectNull; } + +- (void)AsyncSurfacePrepared:(NSNotification*)notification { + [animator update]; +} @end diff --git a/src/platform/ios/private/GPUDrawable.h b/src/platform/ios/private/GPUDrawable.h index 90157aa2f2..66aebd1517 100644 --- a/src/platform/ios/private/GPUDrawable.h +++ b/src/platform/ios/private/GPUDrawable.h @@ -23,6 +23,8 @@ namespace pag { +extern NSString* const kAsyncSurfacePreparedNotification; + class GPUDrawable : public Drawable { public: static std::shared_ptr FromLayer(CAEAGLLayer* layer); @@ -48,6 +50,7 @@ class GPUDrawable : public Drawable { int _height = 0; CAEAGLLayer* layer = nil; std::shared_ptr window = nullptr; + std::atomic bufferPreparing = false; explicit GPUDrawable(CAEAGLLayer* layer); diff --git a/src/platform/ios/private/GPUDrawable.mm b/src/platform/ios/private/GPUDrawable.mm index 1c1fca0d6e..cb12ee9c2c 100644 --- a/src/platform/ios/private/GPUDrawable.mm +++ b/src/platform/ios/private/GPUDrawable.mm @@ -19,6 +19,8 @@ #include "GPUDrawable.h" namespace pag { +NSString* const kAsyncSurfacePreparedNotification = @"pag.art.AsyncSurfacePrepared"; + std::shared_ptr GPUDrawable::FromLayer(CAEAGLLayer* layer) { if (layer == nil) { return nullptr; @@ -78,10 +80,40 @@ } std::shared_ptr GPUDrawable::onCreateSurface(tgfx::Context* context) { - if (window == nullptr) { + if (window == nullptr || bufferPreparing) { + return nullptr; + } + if (surface) { + return surface; + } + // https://github.com/Tencent/libpag/issues/1870 + // Creating a surface in a non-main thread may lead to a crash. + if (NSThread.isMainThread) { + surface = window->getSurface(context); + return surface; + } else { + bufferPreparing = true; + auto strongThis = weakThis.lock(); + [layer retain]; + dispatch_async(dispatch_get_main_queue(), ^{ + auto context = strongThis->window->getDevice()->lockContext(); + if (context == nullptr) { + strongThis->bufferPreparing = false; + [strongThis->layer release]; + return; + } + strongThis->surface = strongThis->window->getSurface(context); + strongThis->bufferPreparing = false; + strongThis->window->getDevice()->unlock(); + if (strongThis->surface) { + [[NSNotificationCenter defaultCenter] postNotificationName:kAsyncSurfacePreparedNotification + object:strongThis->layer + userInfo:nil]; + } + [strongThis->layer release]; + }); return nullptr; } - return window->getSurface(context); } void GPUDrawable::onFreeSurface() { diff --git a/src/rendering/PAGAnimator.cpp b/src/rendering/PAGAnimator.cpp index 3b9ab54626..71ed650cb7 100644 --- a/src/rendering/PAGAnimator.cpp +++ b/src/rendering/PAGAnimator.cpp @@ -107,13 +107,17 @@ bool PAGAnimator::isSync() { } void PAGAnimator::setSync(bool value) { - std::lock_guard autoLock(locker); + locker.lock(); if (_isSync == value) { + locker.unlock(); return; } _isSync = value; - if (_isSync) { - resetTask(); + auto tempTask = task; + task = nullptr; + locker.unlock(); + if (tempTask) { + tempTask->wait(); } } @@ -327,10 +331,4 @@ void PAGAnimator::resetStartTime() { _startTime = INT64_MIN; } -void PAGAnimator::resetTask() { - if (task != nullptr) { - task->wait(); - task = nullptr; - } -} } // namespace pag diff --git a/src/rendering/PAGAnimator.h b/src/rendering/PAGAnimator.h index d9a5939434..6f722a9e66 100644 --- a/src/rendering/PAGAnimator.h +++ b/src/rendering/PAGAnimator.h @@ -176,7 +176,6 @@ class PAGAnimator { void startAnimation(); void cancelAnimation(); void resetStartTime(); - void resetTask(); friend class AnimationTicker; };