Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Reland [ios] Refactor IOSSurface factory and unify surface creation #22016

Merged
merged 3 commits into from
Oct 29, 2020

Conversation

iskakaushik
Copy link
Contributor

@iskakaushik iskakaushik commented Oct 20, 2020

This refactor is to enable the separation of Surface from External View Embedder. As it stands Surface has GetExternalViewEmbedder which inturn has the ability to create surfaces. This refactor enables us to separate these concepts.

This is driven by the goal to share some components between ios and macOS.

@iskakaushik
Copy link
Contributor Author

I've added a test that would've caught this problem.

@iskakaushik iskakaushik force-pushed the ios-refactor-eve branch 2 times, most recently from 3d78d0b to fd3fdc2 Compare October 22, 2020 16:08
@xster xster requested a review from gaaclarke October 22, 2020 18:56
@@ -27,7 +27,7 @@

static const char* kApplicationKernelSnapshotFileName = "kernel_blob.bin";

static flutter::Settings DefaultSettingsForProcess(NSBundle* bundle = nil) {
flutter::Settings FLTDefaultSettingsForProcess(NSBundle* bundle) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: this name is goofy, a bundle isn't a process. If we are going to make this function visible we should maybe give it an appropriate name.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good call, will do

/**
* This is currently used for *only for tests* to override settings.
*/
- (instancetype)initWithSettings:(flutter::Settings)settings;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: const flutter::Settings&

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yup, will do

@@ -485,6 +501,7 @@ - (BOOL)createShell:(NSString*)entrypoint

auto settings = [_dartProject.get() settings];
FlutterView.forceSoftwareRendering = settings.enable_software_rendering;
NSLog(@"software!!! > %@", @(FlutterView.forceSoftwareRendering));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

stray print statement

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oops

~IOSSurfaceFactory();

void SetPlatformViewsController(
FlutterPlatformViewsController* platform_views_controller);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You aren't suppose to pass objects via raw pointers: https://google.github.io/styleguide/cppguide.html#Ownership_and_Smart_Pointers

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This style isn't really respected in the rest of the codebase. There are multiple places where platform_views_controller is passed as a raw pointer. I looked at changing it to a smart pointer, it's a pretty big refactor.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's the motto on the team, embrace Zach's shave?

The codebase purports to follow Google C++ Style of which this is in violation. This violate isn't really style like where to put curly braces, but is policy to avoid creating runtime minefields. I don't even think there is a good justification for this class but if you want to keep it and not use smart pointers you could pass the FlutterPlatformViewsController as an argument to the CreateSurface. That way you would be avoiding the creation of another mine.

void SetPlatformViewsController(
FlutterPlatformViewsController* platform_views_controller);

std::unique_ptr<IOSSurface> CreateSurface(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's the point of a factory that doesn't have virtual methods? This could just be a function call.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you elaborate?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep, right now IOSSurfaceFactory is just an obfuscation on flutter::IOSSurface::Create

this:

IOSSurfaceFactory factory = IOSSurfaceFactory.create(renderingApi);
factory.setPlatformViewsController(platformViewsController);
return factory.createSurface(layer);

could just be this:

return CreateSurface(renderingApi, platformViewsController, layer);

The factory object doesn't actually add any functionality, it just obscures the logic and worse it creates a mine by storing a raw pointer. Typically factories are used to allow us to swap out the creation of an object, since this is a c++ class without virtual methods, it can't actually be swapped out.

FML_DISALLOW_COPY_AND_ASSIGN(FlutterPlatformViewLayerPool);
};

class FlutterPlatformViewsController {
public:
FlutterPlatformViewsController();
FlutterPlatformViewsController(std::shared_ptr<IOSSurfaceFactory> surface_factory);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: const std::shared_ptr<IOSurfaceFactory>& shared_ptr's are threadsafe so copying the objects incurs locking primitives which are system calls that slow down execution.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is interesting, I've been passing shared_ptr<T> by value rather than const shared_ptr<T>& as a convention. But clearly that has very little use, I will change it to const shared_ptr<T>& given that FlutterPlatformViewsController has no intention of sharing ownership of surface_factory. Also came across this which makes sense.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yea, the engine doesn't use const refs for passing arguments when it should. I got yelled at in the past for passing std::functions by const reference. We don't use shared_ptr's much but they are particularly important to pass by const reference because of the mutex inside them. I've worked on projects that have been crippled by that overhead.

Copy link
Member

@xster xster left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Which test covers flutter/flutter#68399?

@@ -485,6 +501,7 @@ - (BOOL)createShell:(NSString*)entrypoint

auto settings = [_dartProject.get() settings];
FlutterView.forceSoftwareRendering = settings.enable_software_rendering;
NSLog(@"software!!! > %@", @(FlutterView.forceSoftwareRendering));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this intentional?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oops

@@ -63,6 +65,8 @@ @implementation FlutterEngine {
fml::WeakPtr<FlutterViewController> _viewController;
fml::scoped_nsobject<FlutterObservatoryPublisher> _publisher;

flutter::IOSRenderingAPI _renderingApi;
std::shared_ptr<flutter::IOSSurfaceFactory> _surfaceFactory;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@gaaclarke might relate to the work you're doing now

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yea, it's probably going to create merge conflicts for me. I don't think it necessarily helps or hurts what I was doing.

FlutterEngine* engine = [[FlutterEngine alloc] init];

// Run with an initial route.
[engine runWithEntrypoint:FlutterDefaultDartEntrypoint initialRoute:@"test"];
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

seems like the entrypoint/initialroute doesn't really matter? If so, you can just call run

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yup, will change it.

@iskakaushik
Copy link
Contributor Author

Which test covers flutter/flutter#68399?

https://github.com/flutter/engine/pull/22016/files#diff-32d133f42e4c4efe9a1d50c25f673993fafd3b22c2fa8d6bf990e5aa6edf0383R105 the last test in this file captures the issue. The problem earlier was once the platform view controller was set, it wasn't recreated once the rendering api changes. This happens on simulators where createShell is when the rendering api is set.

@xster
Copy link
Member

xster commented Oct 23, 2020

ah interesting. For future archeologists, can you describe what the issue was on flutter/flutter#68399 and also fill out the PR description with a FR bug or describe a bit what the intent of the PR is and the nature of the fix for flutter/flutter#68399?

Otherwise, test LGTM. Please address @gaaclarke's review.

@iskakaushik
Copy link
Contributor Author

The issue flutter/flutter#68399 was because my original attempt at the refactor inadvertently made it so that we weren't re-creating the platform views controller once it was created. This is fine on real devices but on simulators this flow would break as follows:

  1. initWithName on FlutterEngine gets called and that would create the platform views controller with the wrong rendering API as FlutterView.forceSoftwareRendering isn't yet set.
  2. createShell gets called which sets FlutterView.forceSoftwareRendering, we ensure the platform views controller exists, which it already is.
  3. Fail.

My current attempt at the refactor #22016 makes it so that instead of just ensuring that platform views controller exists, we re-create it after createShell gets called, this ensures that the platform views controller is created for the right rendering api. I've also added a test for this over here.

@iskakaushik iskakaushik force-pushed the ios-refactor-eve branch 2 times, most recently from 2923694 to 2a1a735 Compare October 26, 2020 17:55
@iskakaushik
Copy link
Contributor Author

@gaaclarke I've rebased it on-top of the PR that moves FlutterPlatformViewsController to be a smart pointer. PTAL

- (void)recreatePlatformViewController {
_renderingApi = flutter::GetRenderingAPIForProcess(FlutterView.forceSoftwareRendering);
_surfaceFactory = flutter::IOSSurfaceFactory::Create(_renderingApi);
auto pvc = new flutter::FlutterPlatformViewsController(_surfaceFactory);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: You aren't suppose to use abbreviations in variable names

https://google.github.io/styleguide/cppguide.html#General_Naming_Rules

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch. Removed this now.

@@ -61,6 +61,7 @@ void ResetAnchor(CALayer* layer);

class IOSContextGL;
class IOSSurface;
class IOSSurfaceFactory;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: You are suppose to avoid forward declarations in C++

https://google.github.io/styleguide/cppguide.html#Forward_Declarations

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is a cyclical dependency here. IOSSurfaceFactory holds a platform views controller via SetPlatformViewsController and platform views controller also needs a surface factory for creating surfaces. I will simplify this in the follow-up PRs.

Copy link
Member

@gaaclarke gaaclarke left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the changes, LGTM

@iskakaushik iskakaushik added the waiting for tree to go green This PR is approved and tested, but waiting for the tree to be green to land. label Oct 26, 2020
@iskakaushik iskakaushik force-pushed the ios-refactor-eve branch 2 times, most recently from 2f24554 to 3c63cd7 Compare October 27, 2020 16:47
@fluttergithubbot
Copy link
Contributor

This pull request is not suitable for automatic merging in its current state.

  • The status or check suite Mac iOS Engine has failed. Please fix the issues identified (or deflake) before re-applying this label.

@fluttergithubbot fluttergithubbot removed the waiting for tree to go green This PR is approved and tested, but waiting for the tree to be green to land. label Oct 27, 2020
On simulator for example we instantiate the app with
`initWithName` after this is done, we might still not
have set the `FlutterView.forceSoftwareRendering` which
is done in `createShell`.

This will ensure that we create the platform view controller
with the right rendering api.
@iskakaushik iskakaushik added the waiting for tree to go green This PR is approved and tested, but waiting for the tree to be green to land. label Oct 29, 2020
@fluttergithubbot fluttergithubbot merged commit d6627c6 into flutter:master Oct 29, 2020
engine-flutter-autoroll added a commit to engine-flutter-autoroll/flutter that referenced this pull request Oct 29, 2020
engine-flutter-autoroll added a commit to engine-flutter-autoroll/flutter that referenced this pull request Oct 29, 2020
engine-flutter-autoroll added a commit to engine-flutter-autoroll/flutter that referenced this pull request Oct 29, 2020
engine-flutter-autoroll added a commit to engine-flutter-autoroll/flutter that referenced this pull request Oct 30, 2020
engine-flutter-autoroll added a commit to engine-flutter-autoroll/flutter that referenced this pull request Oct 30, 2020
GaryQian pushed a commit to flutter/flutter that referenced this pull request Oct 30, 2020
* 53d5d68 Add dart-lang/sdk's new package:clock dependency (flutter/engine#22142)

* c32e3d8 Roll Skia from 7737a5bd2510 to 5567a6091ceb (8 revisions) (flutter/engine#22146)

* 376045c Roll Fuchsia Linux SDK from XYN02FThN... to UKgKCjxSA... (flutter/engine#22147)

* 03395de Roll Fuchsia Mac SDK from GKPwGj1Ux... to xHjtLQPQ5... (flutter/engine#22151)

* 0c7e952 Manual Dart SDK roll 6e015bd9cddb to 9c6e76468ca4 (6 revisions (flutter/engine#22153)

* e5f168a Update constraint to latest integration test (flutter/engine#22169)

* e61e8c2 Smooth window resizing on macOS (flutter/engine#21525)

* acece00 Allow parse_and_send to use access tokens (flutter/engine#22019)

* 0270632 Includes roles for links, checkboxes, and radio buttons in semantics (flutter/engine#22061)

* 632354d Roll Fuchsia Linux SDK from UKgKCjxSA... to PY5hNI-wY... (flutter/engine#22175)

* 62d50af Add plumbing for command line arguments on Windows (flutter/engine#22094)

* 06b0910 Fix possible use of std::moved value in Rasterizer (flutter/engine#22125)

* 005dec4 [web] Clean up unused previousStyle logic (flutter/engine#22150)

* ca05bdc Roll Skia from 5567a6091ceb to f548a028ce70 (7 revisions) (flutter/engine#22155)

* 5b07ac4 Roll Fuchsia Mac SDK from xHjtLQPQ5... to ICK_JlnKJ... (flutter/engine#22188)

* d615a97 Roll Fuchsia Linux SDK from PY5hNI-wY... to Usec4YBzR... (flutter/engine#22197)

* 11ed711 Invalidate the cached SkParagraph font collection when a new font manager is installed (flutter/engine#22157)

* 07c780b [web] Assign default natural width/height for svgs that report 0,0 on firefox and ie11 (flutter/engine#22184)

* b54bb88 Migrate runZoned to runZonedGuarded (flutter/engine#22198)

* 247139a [web] Fix transform not invalidating path bounds causing debugValidate failure (flutter/engine#22172)

* e4dffc1 [web] Fix scroll wheel line delta on Firefox. (flutter/engine#21928)

* d6627c6 Reland [ios] Refactor IOSSurface factory and unify surface creation (flutter/engine#22016)

* ce1dd11 Standardize macro names for dartdoc macros (flutter/engine#22180)

* f81bc37 [profiling] Handle thread_info to account for killed threads (flutter/engine#22170)

* fd94c86 Fix for firefox custom clipping (flutter/engine#22182)

* 9ccf9f1 bring back build_test to ensure we validate licenses (flutter/engine#22201)

* 38f6665 Set strut font to Roboto if the given font hasn't been registered (flutter/engine#22129)

* caf32d5 Add a proc table version of embedder API (flutter/engine#21813)

* ed0f477 Use preTranslate when applying offset to matrix (flutter/engine#21648)

* b457e2d Refactor make_mock_engine into fl_test (flutter/engine#21585)

* 28497c8 Fix typos in FlValue docs (flutter/engine#21875)

* bb32446 Fix FlTextInputPlugin tear down (flutter/engine#22007)

* 7a7804b Add "input shield" to capture pointer input for reinjection (flutter/engine#22067)

* fe85f94 Update painting.dart (flutter/engine#22195)

* 99cc50d [ios] Surface factory holds the canonical reference to the external view embedder (flutter/engine#22206)
engine-flutter-autoroll added a commit to engine-flutter-autoroll/flutter that referenced this pull request Oct 30, 2020
@xster
Copy link
Member

xster commented Nov 17, 2020

@iskakaushik @gaaclarke

I was just checking our performance and noticed we're making a lot of metal contexts.

Looks like we make one in recreatePlatformViewController in initWithName, one in a recreatePlatformViewController in FlutterEngine createShell and our normal metal context. Looks like all 3 are persisted too. These things are expensive. Do we really need 3? Could we create the first platform view metal context when users actually use platform view?

Screen Shot 2020-11-17 at 12 14 01 AM

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
cla: yes platform-ios waiting for tree to go green This PR is approved and tested, but waiting for the tree to be green to land.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants