Skip to content

Commit 2586cbe

Browse files
authored
Revert "[ios_platform_view] only recycle maskView when the view is applying mutators flutter#41573" (flutter#42231)
Reverts flutter#42115 Failing on the framework tree as in https://ci.chromium.org/ui/p/flutter/builders/prod/Mac_ios%20platform_views_scroll_perf_ios__timeline_summary/11103/overview
1 parent 0ef9f91 commit 2586cbe

13 files changed

+67
-391
lines changed

shell/platform/darwin/ios/framework/Source/FlutterPlatformViews.mm

Lines changed: 7 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818
#import "flutter/shell/platform/darwin/ios/framework/Source/FlutterViewController_Internal.h"
1919
#import "flutter/shell/platform/darwin/ios/ios_surface.h"
2020

21+
static const NSUInteger kFlutterClippingMaskViewPoolCapacity = 5;
22+
2123
@implementation UIView (FirstResponder)
2224
- (BOOL)flt_hasFirstResponderInViewHierarchySubtree {
2325
if (self.isFirstResponder) {
@@ -445,8 +447,6 @@ static bool ClipRRectContainsPlatformViewBoundingRect(const SkRRect& clip_rrect,
445447
clipView.maskView = [mask_view_pool_.get() getMaskViewWithFrame:frame];
446448
}
447449

448-
// This method is only called when the `embedded_view` needs to be re-composited at the current
449-
// frame. See: `CompositeWithParams` for details.
450450
void FlutterPlatformViewsController::ApplyMutators(const MutatorsStack& mutators_stack,
451451
UIView* embedded_view,
452452
const SkRect& bounding_rect) {
@@ -461,10 +461,12 @@ static bool ClipRRectContainsPlatformViewBoundingRect(const SkRRect& clip_rrect,
461461
NSMutableArray* blurFilters = [[[NSMutableArray alloc] init] autorelease];
462462
FML_DCHECK(!clipView.maskView ||
463463
[clipView.maskView isKindOfClass:[FlutterClippingMaskView class]]);
464-
if (clipView.maskView) {
465-
[mask_view_pool_.get() insertViewToPoolIfNeeded:(FlutterClippingMaskView*)(clipView.maskView)];
466-
clipView.maskView = nil;
464+
if (mask_view_pool_.get() == nil) {
465+
mask_view_pool_.reset([[FlutterClippingMaskViewPool alloc]
466+
initWithCapacity:kFlutterClippingMaskViewPoolCapacity]);
467467
}
468+
[mask_view_pool_.get() recycleMaskViews];
469+
clipView.maskView = nil;
468470
CGFloat screenScale = [UIScreen mainScreen].scale;
469471
auto iter = mutators_stack.Begin();
470472
while (iter != mutators_stack.End()) {
@@ -568,14 +570,6 @@ static bool ClipRRectContainsPlatformViewBoundingRect(const SkRRect& clip_rrect,
568570
embedded_view.layer.transform = flutter::GetCATransform3DFromSkMatrix(transformMatrix);
569571
}
570572

571-
// Composite the PlatformView with `view_id`.
572-
//
573-
// Every frame, during the paint traversal of the layer tree, this method is called for all
574-
// the PlatformViews in `views_to_recomposite_`.
575-
//
576-
// Note that `views_to_recomposite_` does not represent all the views in the view hierarchy,
577-
// if a PlatformView does not change its composition parameter from last frame, it is not
578-
// included in the `views_to_recomposite_`.
579573
void FlutterPlatformViewsController::CompositeWithParams(int64_t view_id,
580574
const EmbeddedViewParams& params) {
581575
CGRect frame = CGRectMake(0, 0, params.sizePoints().width(), params.sizePoints().height());

shell/platform/darwin/ios/framework/Source/FlutterPlatformViewsTest.mm

Lines changed: 7 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -2649,15 +2649,12 @@ - (void)testFlutterClippingMaskViewPoolReuseViewsAfterRecycle {
26492649
[[[FlutterClippingMaskViewPool alloc] initWithCapacity:2] autorelease];
26502650
FlutterClippingMaskView* view1 = [pool getMaskViewWithFrame:CGRectZero];
26512651
FlutterClippingMaskView* view2 = [pool getMaskViewWithFrame:CGRectZero];
2652-
[pool insertViewToPoolIfNeeded:view1];
2653-
[pool insertViewToPoolIfNeeded:view2];
2652+
[pool recycleMaskViews];
26542653
CGRect newRect = CGRectMake(0, 0, 10, 10);
26552654
FlutterClippingMaskView* view3 = [pool getMaskViewWithFrame:newRect];
26562655
FlutterClippingMaskView* view4 = [pool getMaskViewWithFrame:newRect];
2657-
// view3 and view4 should randomly get either of view1 and view2.
2658-
NSSet* set1 = [NSSet setWithObjects:view1, view2, nil];
2659-
NSSet* set2 = [NSSet setWithObjects:view3, view4, nil];
2660-
XCTAssertEqualObjects(set1, set2);
2656+
XCTAssertEqual(view1, view3);
2657+
XCTAssertEqual(view2, view4);
26612658
XCTAssertTrue(CGRectEqualToRect(view3.frame, newRect));
26622659
XCTAssertTrue(CGRectEqualToRect(view4.frame, newRect));
26632660
}
@@ -2730,17 +2727,17 @@ - (void)testClipMaskViewIsReused {
27302727
auto embeddedViewParams1 = std::make_unique<flutter::EmbeddedViewParams>(
27312728
screenScaleMatrix, SkSize::Make(10, 10), stack1);
27322729

2730+
flutter::MutatorsStack stack2;
2731+
auto embeddedViewParams2 = std::make_unique<flutter::EmbeddedViewParams>(
2732+
screenScaleMatrix, SkSize::Make(10, 10), stack2);
2733+
27332734
flutterPlatformViewsController->PrerollCompositeEmbeddedView(1, std::move(embeddedViewParams1));
27342735
flutterPlatformViewsController->CompositeEmbeddedView(1);
27352736
UIView* childClippingView1 = gMockPlatformView.superview.superview;
27362737
UIView* maskView1 = childClippingView1.maskView;
27372738
XCTAssertNotNil(maskView1);
27382739

27392740
// Composite a new frame.
2740-
flutterPlatformViewsController->BeginFrame(SkISize::Make(100, 100));
2741-
flutter::MutatorsStack stack2;
2742-
auto embeddedViewParams2 = std::make_unique<flutter::EmbeddedViewParams>(
2743-
screenScaleMatrix, SkSize::Make(10, 10), stack2);
27442741
auto embeddedViewParams3 = std::make_unique<flutter::EmbeddedViewParams>(
27452742
screenScaleMatrix, SkSize::Make(10, 10), stack2);
27462743
flutterPlatformViewsController->PrerollCompositeEmbeddedView(1, std::move(embeddedViewParams3));
@@ -2766,77 +2763,6 @@ - (void)testClipMaskViewIsReused {
27662763
XCTAssertNil(childClippingView1.maskView);
27672764
}
27682765

2769-
- (void)testDifferentClipMaskViewIsUsedForEachView {
2770-
flutter::FlutterPlatformViewsTestMockPlatformViewDelegate mock_delegate;
2771-
auto thread_task_runner = CreateNewThread("FlutterPlatformViewsTest");
2772-
flutter::TaskRunners runners(/*label=*/self.name.UTF8String,
2773-
/*platform=*/thread_task_runner,
2774-
/*raster=*/thread_task_runner,
2775-
/*ui=*/thread_task_runner,
2776-
/*io=*/thread_task_runner);
2777-
auto flutterPlatformViewsController = std::make_shared<flutter::FlutterPlatformViewsController>();
2778-
auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
2779-
/*delegate=*/mock_delegate,
2780-
/*rendering_api=*/flutter::IOSRenderingAPI::kSoftware,
2781-
/*platform_views_controller=*/flutterPlatformViewsController,
2782-
/*task_runners=*/runners);
2783-
2784-
FlutterPlatformViewsTestMockFlutterPlatformFactory* factory =
2785-
[[FlutterPlatformViewsTestMockFlutterPlatformFactory new] autorelease];
2786-
flutterPlatformViewsController->RegisterViewFactory(
2787-
factory, @"MockFlutterPlatformView",
2788-
FlutterPlatformViewGestureRecognizersBlockingPolicyEager);
2789-
FlutterResult result = ^(id result) {
2790-
};
2791-
2792-
flutterPlatformViewsController->OnMethodCall(
2793-
[FlutterMethodCall
2794-
methodCallWithMethodName:@"create"
2795-
arguments:@{@"id" : @1, @"viewType" : @"MockFlutterPlatformView"}],
2796-
result);
2797-
UIView* view1 = gMockPlatformView;
2798-
2799-
// This overwrites `gMockPlatformView` to another view.
2800-
flutterPlatformViewsController->OnMethodCall(
2801-
[FlutterMethodCall
2802-
methodCallWithMethodName:@"create"
2803-
arguments:@{@"id" : @2, @"viewType" : @"MockFlutterPlatformView"}],
2804-
result);
2805-
UIView* view2 = gMockPlatformView;
2806-
2807-
XCTAssertNotNil(gMockPlatformView);
2808-
UIView* mockFlutterView = [[[UIView alloc] initWithFrame:CGRectMake(0, 0, 10, 10)] autorelease];
2809-
flutterPlatformViewsController->SetFlutterView(mockFlutterView);
2810-
// Create embedded view params
2811-
flutter::MutatorsStack stack1;
2812-
// Layer tree always pushes a screen scale factor to the stack
2813-
SkMatrix screenScaleMatrix =
2814-
SkMatrix::Scale([UIScreen mainScreen].scale, [UIScreen mainScreen].scale);
2815-
stack1.PushTransform(screenScaleMatrix);
2816-
// Push a clip rect
2817-
SkRect rect = SkRect::MakeXYWH(2, 2, 3, 3);
2818-
stack1.PushClipRect(rect);
2819-
2820-
auto embeddedViewParams1 = std::make_unique<flutter::EmbeddedViewParams>(
2821-
screenScaleMatrix, SkSize::Make(10, 10), stack1);
2822-
2823-
flutter::MutatorsStack stack2;
2824-
stack2.PushClipRect(rect);
2825-
auto embeddedViewParams2 = std::make_unique<flutter::EmbeddedViewParams>(
2826-
screenScaleMatrix, SkSize::Make(10, 10), stack2);
2827-
2828-
flutterPlatformViewsController->PrerollCompositeEmbeddedView(1, std::move(embeddedViewParams1));
2829-
flutterPlatformViewsController->CompositeEmbeddedView(1);
2830-
UIView* childClippingView1 = view1.superview.superview;
2831-
2832-
flutterPlatformViewsController->PrerollCompositeEmbeddedView(2, std::move(embeddedViewParams2));
2833-
flutterPlatformViewsController->CompositeEmbeddedView(2);
2834-
UIView* childClippingView2 = view2.superview.superview;
2835-
UIView* maskView1 = childClippingView1.maskView;
2836-
UIView* maskView2 = childClippingView2.maskView;
2837-
XCTAssertNotEqual(maskView1, maskView2);
2838-
}
2839-
28402766
// Return true if a correct visual effect view is found. It also implies all the validation in this
28412767
// method passes.
28422768
//

shell/platform/darwin/ios/framework/Source/FlutterPlatformViews_Internal.h

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@
5656
// in the pool. If there are none available, a new FlutterClippingMaskView is constructed. If the
5757
// capacity is reached, the newly constructed FlutterClippingMaskView is not added to the pool.
5858
//
59-
// Call |insertViewToPoolIfNeeded:| to return a maskView to the pool.
59+
// Call |recycleMaskViews| to mark all the FlutterClippingMaskViews in the pool available.
6060
@interface FlutterClippingMaskViewPool : NSObject
6161

6262
// Initialize the pool with `capacity`. When the `capacity` is reached, a FlutterClippingMaskView is
@@ -66,8 +66,8 @@
6666
// Reuse a maskView from the pool, or allocate a new one.
6767
- (FlutterClippingMaskView*)getMaskViewWithFrame:(CGRect)frame;
6868

69-
// Insert the `maskView` into the pool.
70-
- (void)insertViewToPoolIfNeeded:(FlutterClippingMaskView*)maskView;
69+
// Mark all the maskViews available.
70+
- (void)recycleMaskViews;
7171

7272
@end
7373

@@ -291,20 +291,27 @@ class FlutterPlatformViewsController {
291291
int CountClips(const MutatorsStack& mutators_stack);
292292

293293
void ClipViewSetMaskView(UIView* clipView);
294-
295294
// Applies the mutators in the mutators_stack to the UIView chain that was constructed by
296295
// `ReconstructClipViewsChain`
297296
//
298-
// Clips are applied to the `embedded_view`'s super view(|ChildClippingView|) using a
299-
// |FlutterClippingMaskView|. Transforms are applied to `embedded_view`
297+
// Clips are applied to the super view with a CALayer mask. Transforms are applied to the
298+
// current view that's at the head of the chain. For example the following mutators stack [T_1,
299+
// C_2, T_3, T_4, C_5, T_6] where T denotes a transform and C denotes a clip, will result in the
300+
// following UIView tree:
301+
//
302+
// C_2 -> C_5 -> PLATFORM_VIEW
303+
// (PLATFORM_VIEW is a subview of C_5 which is a subview of C_2)
304+
//
305+
// T_1 is applied to C_2, T_3 and T_4 are applied to C_5, and T_6 is applied to PLATFORM_VIEW.
306+
//
307+
// After each clip operation, we update the head to the super view of the current head.
300308
//
301309
// The `bounding_rect` is the final bounding rect of the PlatformView
302310
// (EmbeddedViewParams::finalBoundingRect). If a clip mutator's rect contains the final bounding
303311
// rect of the PlatformView, the clip mutator is not applied for performance optimization.
304312
void ApplyMutators(const MutatorsStack& mutators_stack,
305313
UIView* embedded_view,
306314
const SkRect& bounding_rect);
307-
308315
void CompositeWithParams(int64_t view_id, const EmbeddedViewParams& params);
309316

310317
// Allocates a new FlutterPlatformViewLayer if needed, draws the pixels within the rect from

shell/platform/darwin/ios/framework/Source/FlutterPlatformViews_Internal.mm

Lines changed: 27 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99
#import "flutter/shell/platform/darwin/ios/ios_surface.h"
1010

1111
static int kMaxPointsInVerb = 4;
12-
static const NSUInteger kFlutterClippingMaskViewPoolCapacity = 5;
1312

1413
namespace flutter {
1514

@@ -27,10 +26,7 @@
2726

2827
FlutterPlatformViewsController::FlutterPlatformViewsController()
2928
: layer_pool_(std::make_unique<FlutterPlatformViewLayerPool>()),
30-
weak_factory_(std::make_unique<fml::WeakPtrFactory<FlutterPlatformViewsController>>(this)) {
31-
mask_view_pool_.reset(
32-
[[FlutterClippingMaskViewPool alloc] initWithCapacity:kFlutterClippingMaskViewPoolCapacity]);
33-
};
29+
weak_factory_(std::make_unique<fml::WeakPtrFactory<FlutterPlatformViewsController>>(this)){};
3430

3531
FlutterPlatformViewsController::~FlutterPlatformViewsController() = default;
3632

@@ -462,53 +458,58 @@ @interface FlutterClippingMaskViewPool ()
462458
// The maximum number of `FlutterClippingMaskView` the pool can contain.
463459
// This prevents the pool to grow infinately and limits the maximum memory a pool can use.
464460
@property(assign, nonatomic) NSUInteger capacity;
465-
466-
// The pool contains the views that are available to use.
467-
// The number of items in the pool must not excceds `capacity`.
468-
@property(retain, nonatomic) NSMutableSet<FlutterClippingMaskView*>* pool;
461+
@property(retain, nonatomic) NSMutableArray<FlutterClippingMaskView*>* pool;
462+
// The index points to the first available FlutterClippingMaskView in the `pool`.
463+
@property(assign, nonatomic) NSUInteger availableIndex;
469464

470465
@end
471466

472467
@implementation FlutterClippingMaskViewPool : NSObject
473468

474469
- (instancetype)initWithCapacity:(NSInteger)capacity {
475470
if (self = [super init]) {
476-
// Most of cases, there are only one PlatformView in the scene.
477-
// Thus init with the capacity of 1.
478-
_pool = [[NSMutableSet alloc] initWithCapacity:1];
471+
_pool = [[NSMutableArray alloc] initWithCapacity:capacity];
479472
_capacity = capacity;
473+
_availableIndex = 0;
480474
}
481475
return self;
482476
}
483477

484478
- (FlutterClippingMaskView*)getMaskViewWithFrame:(CGRect)frame {
485-
FML_DCHECK(self.pool.count <= self.capacity);
479+
FML_DCHECK(self.availableIndex <= self.capacity);
486480
FlutterClippingMaskView* maskView;
487-
if (self.pool.count == 0) {
488-
// The pool is empty, alloc a new one.
481+
if (self.availableIndex == self.capacity) {
482+
// The pool is full, alloc a new one.
489483
maskView =
490484
[[[FlutterClippingMaskView alloc] initWithFrame:frame
491485
screenScale:[UIScreen mainScreen].scale] autorelease];
492486
return maskView;
493487
}
494-
maskView = [self.pool anyObject];
495-
maskView.frame = frame;
496-
[maskView reset];
497-
[self.pool removeObject:maskView];
488+
489+
if (self.availableIndex >= self.pool.count) {
490+
// The pool doesn't have enough maskViews, alloc a new one and add to the pool.
491+
maskView =
492+
[[[FlutterClippingMaskView alloc] initWithFrame:frame
493+
screenScale:[UIScreen mainScreen].scale] autorelease];
494+
[self.pool addObject:maskView];
495+
FML_DCHECK(self.pool.count <= self.capacity);
496+
} else {
497+
// Reuse a maskView from the pool.
498+
maskView = [self.pool objectAtIndex:self.availableIndex];
499+
maskView.frame = frame;
500+
[maskView reset];
501+
}
502+
self.availableIndex++;
498503
return maskView;
499504
}
500505

501-
- (void)insertViewToPoolIfNeeded:(FlutterClippingMaskView*)maskView {
502-
FML_DCHECK(![self.pool containsObject:maskView]);
503-
FML_DCHECK(self.pool.count <= self.capacity);
504-
if (self.pool.count == self.capacity) {
505-
return;
506-
}
507-
[self.pool addObject:maskView];
506+
- (void)recycleMaskViews {
507+
self.availableIndex = 0;
508508
}
509509

510510
- (void)dealloc {
511511
[_pool release];
512+
_pool = nil;
512513

513514
[super dealloc];
514515
}

0 commit comments

Comments
 (0)