Skip to content

Commit

Permalink
Fix stale platform view gr context on iOS (flutter#13469)
Browse files Browse the repository at this point in the history
When gr context is changed (this happens when sending the app to the background and then to the foreground) we need to update it for all the platform view overlay surfaces.

The update logic was caching the previous gr context to figure if it had to be updated, but after updating it for a given overlay we were updating the cached context. In apps with multiple platform views this will result in overlays with a stale gr context.

This fixes flutter/flutter#36437
And I believe it should fix flutter/flutter#36999 as well (though I don't have repro code to verify).
  • Loading branch information
amirh authored Oct 31, 2019
1 parent 55e8ef9 commit 8997f34
Show file tree
Hide file tree
Showing 11 changed files with 135 additions and 8 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -476,8 +476,9 @@
}

if (overlay_it != overlays_.end()) {
if (gr_context != overlays_gr_context_) {
overlays_gr_context_ = gr_context;
FlutterPlatformViewLayer* overlay = overlay_it->second.get();
if (gr_context != overlay->gr_context) {
overlay->gr_context = gr_context;
// The overlay already exists, but the GrContext was changed so we need to recreate
// the rendering surface with the new GrContext.
IOSSurface* ios_surface = overlay_it->second->ios_surface.get();
Expand All @@ -497,7 +498,7 @@
std::unique_ptr<Surface> surface = ios_surface->CreateGPUSurface(gr_context);
overlays_[overlay_id] = std::make_unique<FlutterPlatformViewLayer>(
std::move(overlay_view), std::move(ios_surface), std::move(surface));
overlays_gr_context_ = gr_context;
overlays_[overlay_id]->gr_context = gr_context;
}

} // namespace flutter
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,11 @@ struct FlutterPlatformViewLayer {
fml::scoped_nsobject<UIView> overlay_view;
std::unique_ptr<IOSSurface> ios_surface;
std::unique_ptr<Surface> surface;

// The GrContext that is currently used by the overlay surfaces.
// We track this to know when the GrContext for the Flutter app has changed
// so we can update the overlay with the new context.
GrContext* gr_context;
};

class FlutterPlatformViewsController {
Expand Down Expand Up @@ -123,10 +128,6 @@ class FlutterPlatformViewsController {
// platform view last time it was composited.
std::map<int64_t, int64_t> clip_count_;
std::map<int64_t, std::unique_ptr<FlutterPlatformViewLayer>> overlays_;
// The GrContext that is currently used by all of the overlay surfaces.
// We track this to know when the GrContext for the Flutter app has changed
// so we can update the overlays with the new context.
GrContext* overlays_gr_context_;
SkISize frame_size_;

// This is the number of frames the task runners will stay
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
24D47D1D230CA2700069DD5E /* golden_platform_view_iPhone SE_simulator.png in Resources */ = {isa = PBXBuildFile; fileRef = 24D47D1C230CA2700069DD5E /* golden_platform_view_iPhone SE_simulator.png */; };
24F1FB89230B4579005ACE7C /* TextPlatformView.m in Sources */ = {isa = PBXBuildFile; fileRef = 24F1FB87230B4579005ACE7C /* TextPlatformView.m */; };
59A97FD8236A49D300B4C066 /* golden_platform_view_multiple_iPhone SE_simulator.png in Resources */ = {isa = PBXBuildFile; fileRef = 59A97FD7236A49D300B4C066 /* golden_platform_view_multiple_iPhone SE_simulator.png */; };
59A97FDA236B984300B4C066 /* golden_platform_view_multiple_background_foreground_iPhone SE_simulator.png in Resources */ = {isa = PBXBuildFile; fileRef = 59A97FD9236B984300B4C066 /* golden_platform_view_multiple_background_foreground_iPhone SE_simulator.png */; };
6816DB9E231750ED00A51400 /* GoldenPlatformViewTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 6816DB9D231750ED00A51400 /* GoldenPlatformViewTests.m */; };
6816DBA12317573300A51400 /* GoldenImage.m in Sources */ = {isa = PBXBuildFile; fileRef = 6816DBA02317573300A51400 /* GoldenImage.m */; };
6816DBA42318358200A51400 /* PlatformViewGoldenTestManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 6816DBA32318358200A51400 /* PlatformViewGoldenTestManager.m */; };
Expand Down Expand Up @@ -123,6 +124,7 @@
24F1FB87230B4579005ACE7C /* TextPlatformView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TextPlatformView.m; sourceTree = "<group>"; };
24F1FB88230B4579005ACE7C /* TextPlatformView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TextPlatformView.h; sourceTree = "<group>"; };
59A97FD7236A49D300B4C066 /* golden_platform_view_multiple_iPhone SE_simulator.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "golden_platform_view_multiple_iPhone SE_simulator.png"; sourceTree = "<group>"; };
59A97FD9236B984300B4C066 /* golden_platform_view_multiple_background_foreground_iPhone SE_simulator.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "golden_platform_view_multiple_background_foreground_iPhone SE_simulator.png"; sourceTree = "<group>"; };
6816DB9C231750ED00A51400 /* GoldenPlatformViewTests.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GoldenPlatformViewTests.h; sourceTree = "<group>"; };
6816DB9D231750ED00A51400 /* GoldenPlatformViewTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = GoldenPlatformViewTests.m; sourceTree = "<group>"; };
6816DB9F2317573300A51400 /* GoldenImage.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GoldenImage.h; sourceTree = "<group>"; };
Expand Down Expand Up @@ -218,6 +220,7 @@
248D76ED22E388380012F0C1 /* ScenariosUITests */ = {
isa = PBXGroup;
children = (
59A97FD9236B984300B4C066 /* golden_platform_view_multiple_background_foreground_iPhone SE_simulator.png */,
59A97FD7236A49D300B4C066 /* golden_platform_view_multiple_iPhone SE_simulator.png */,
244EA6CF230DBE8900B2D26E /* golden_platform_view_D21AP.png */,
24D47D1C230CA2700069DD5E /* golden_platform_view_iPhone SE_simulator.png */,
Expand Down Expand Up @@ -375,6 +378,7 @@
files = (
6816DBAE2318696600A51400 /* golden_platform_view_cliprrect_iPhone SE_simulator.png in Resources */,
6816DBAB2318696600A51400 /* golden_platform_view_transform_iPhone SE_simulator.png in Resources */,
59A97FDA236B984300B4C066 /* golden_platform_view_multiple_background_foreground_iPhone SE_simulator.png in Resources */,
6816DBAA2318696600A51400 /* golden_platform_view_clippath_iPhone SE_simulator.png in Resources */,
6816DBAD2318696600A51400 /* golden_platform_view_cliprect_iPhone SE_simulator.png in Resources */,
24D47D1B230C79840069DD5E /* golden_platform_view_D211AP.png in Resources */,
Expand Down
2 changes: 2 additions & 0 deletions testing/scenario_app/ios/Scenarios/Scenarios/AppDelegate.m
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ - (BOOL)application:(UIApplication*)application
NSDictionary<NSString*, NSString*>* launchArgsMap = @{
@"--platform-view" : @"platform_view",
@"--platform-view-multiple" : @"platform_view_multiple",
@"--platform-view-multiple-background-foreground" :
@"platform_view_multiple_background_foreground",
@"--platform-view-cliprect" : @"platform_view_cliprect",
@"--platform-view-cliprrect" : @"platform_view_cliprrect",
@"--platform-view-clippath" : @"platform_view_clippath",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ NS_ASSUME_NONNULL_BEGIN
// This base class doesn't run any test case on its own.
@interface GoldenPlatformViewTests : XCTestCase

@property(nonatomic, strong) XCUIApplication* application;

// Initialize with a `PlatformViewGoldenTestManager`.
- (instancetype)initWithManager:(PlatformViewGoldenTestManager*)manager
invocation:(NSInvocation*)invocation;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
@interface GoldenPlatformViewTests ()

@property(nonatomic, copy) NSString* goldenName;
@property(nonatomic, strong) XCUIApplication* application;

@property(nonatomic, strong) PlatformViewGoldenTestManager* manager;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ - (instancetype)initWithLaunchArg:(NSString*)launchArg {
launchArgsMap = @{
@"--platform-view" : @"platform_view",
@"--platform-view-multiple" : @"platform_view_multiple",
@"--platform-view-multiple-background-foreground" :
@"platform_view_multiple_background_foreground",
@"--platform-view-cliprect" : @"platform_view_cliprect",
@"--platform-view-cliprrect" : @"platform_view_cliprrect",
@"--platform-view-clippath" : @"platform_view_clippath",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,29 @@ - (instancetype)initWithInvocation:(NSInvocation*)invocation {
}

- (void)testPlatformView {
//[self checkGolden];
[[XCUIDevice sharedDevice] pressButton:XCUIDeviceButtonHome];
[self.application activate];
[self checkGolden];
}

@end

@interface MultiplePlatformViewsBackgroundForegroundTest : GoldenPlatformViewTests

@end

@implementation MultiplePlatformViewsBackgroundForegroundTest

- (instancetype)initWithInvocation:(NSInvocation*)invocation {
PlatformViewGoldenTestManager* manager = [[PlatformViewGoldenTestManager alloc]
initWithLaunchArg:@"--platform-view-multiple-background-foreground"];
return [super initWithManager:manager invocation:invocation];
}

- (void)testPlatformView {
[[XCUIDevice sharedDevice] pressButton:XCUIDeviceButtonHome];
[self.application activate];
[self checkGolden];
}

Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions testing/scenario_app/lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ Map<String, Scenario> _scenarios = <String, Scenario>{
'platform_view_transform': PlatformViewTransformScenario(window, 'PlatformViewTransform', id: 4),
'platform_view_opacity': PlatformViewOpacityScenario(window, 'PlatformViewOpacity', id: 5),
'platform_view_multiple': MultiPlatformViewScenario(window, firstId: 6, secondId: 7),
'platform_view_multiple_background_foreground': MultiPlatformViewBackgroundForegroundScenario(window, firstId: 8, secondId: 9),
'poppable_screen': PoppableScreenScenario(window),
};

Expand Down
92 changes: 92 additions & 0 deletions testing/scenario_app/lib/src/platform_view.dart
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,98 @@ class MultiPlatformViewScenario extends Scenario with _BasePlatformViewScenarioM
}
}

/// Scenario for verifying platform views after background and foregrounding the app.
///
/// Renders a frame with 2 platform views covered by a flutter drawn rectangle,
/// when the app goes to the background and comes back to the foreground renders a new frame
/// with the 2 platform views but without the flutter drawn rectangle.
class MultiPlatformViewBackgroundForegroundScenario extends Scenario with _BasePlatformViewScenarioMixin {
/// Creates the PlatformView scenario.
///
/// The [window] parameter must not be null.
MultiPlatformViewBackgroundForegroundScenario(Window window, {this.firstId, this.secondId})
: assert(window != null),
super(window) {
createPlatformView(window, 'platform view 1', firstId);
createPlatformView(window, 'platform view 2', secondId);
_nextFrame = _firstFrame;
}

/// The platform view identifier to use for the first platform view.
final int firstId;

/// The platform view identifier to use for the second platform view.
final int secondId;

@override
void onBeginFrame(Duration duration) {
_nextFrame();
}

VoidCallback _nextFrame;

void _firstFrame() {
final SceneBuilder builder = SceneBuilder();

builder.pushOffset(0, 0);

builder.pushOffset(0, 600);
_addPlatformViewtoScene(builder, firstId, 500, 500);
builder.pop();

_addPlatformViewtoScene(builder, secondId, 500, 500);

final PictureRecorder recorder = PictureRecorder();
final Canvas canvas = Canvas(recorder);
canvas.drawRect(
const Rect.fromLTRB(0, 0, 500, 1000),
Paint()..color = const Color(0xFFFF0000),
);
final Picture picture = recorder.endRecording();
builder.addPicture(const Offset(0, 0), picture);

builder.pop();
final Scene scene = builder.build();
window.render(scene);
scene.dispose();
}

void _secondFrame() {
final SceneBuilder builder = SceneBuilder();

builder.pushOffset(0, 0);

builder.pushOffset(0, 600);
_addPlatformViewtoScene(builder, firstId, 500, 500);
builder.pop();

_addPlatformViewtoScene(builder, secondId, 500, 500);
final Scene scene = builder.build();
window.render(scene);
scene.dispose();
}

String _lastLifecycleState = '';

@override
void onPlatformMessage(
String name,
ByteData data,
PlatformMessageResponseCallback callback,
) {
if (name != 'flutter/lifecycle') {
return;
}
final String message = utf8.decode(data.buffer.asUint8List());
if (_lastLifecycleState == 'AppLifecycleState.inactive' && message == 'AppLifecycleState.resumed') {
_nextFrame = _secondFrame;
window.scheduleFrame();
}

_lastLifecycleState = message;
}
}

/// Platform view with clip rect.
class PlatformViewClipRectScenario extends Scenario with _BasePlatformViewScenarioMixin {
/// Constructs a platform view with clip rect scenario.
Expand Down

0 comments on commit 8997f34

Please sign in to comment.