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

Platform View implemenation for Metal #11070

Merged
merged 18 commits into from
Aug 23, 2019
Merged

Conversation

dnfield
Copy link
Contributor

@dnfield dnfield commented Aug 17, 2019

I've refactored bits and pieces to try to make more sense of this - in particular, some of the different methods for GL vs not GL have been merged and may do nothing on Software.

Fixes flutter/flutter#33487

@dnfield
Copy link
Contributor Author

dnfield commented Aug 18, 2019

This is ready for review.

It still needs a test, which I'll work on as we go through review.

@dnfield dnfield marked this pull request as ready for review August 18, 2019 06:12
@@ -27,22 +27,27 @@ Animator::Animator(Delegate& delegate,
waiter_(std::move(waiter)),
last_begin_frame_time_(),
dart_frame_deadline_(0),
#if FLUTTER_SHELL_ENABLE_METAL
layer_tree_pipeline_(fml::MakeRefCounted<LayerTreePipeline>(2)),
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 isn't an issue on Metal, I believe because we're controlling when we actually present the frame so that it always happens before the transaction is committed.

Can we do that on OpenGL?

Copy link
Member

@chinmaygarde chinmaygarde Aug 19, 2019

Choose a reason for hiding this comment

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

I don't think the issue was identified when using OpenGL. IIRC this was a speculative fix for the keyboard lag.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes - but the keyboard lag doesn't happen on metal. Without the wait added in this PR for metal, similar issues are seen but much worse.

[command_buffer.get() commit];
if (!wait) {
Copy link
Member

@chinmaygarde chinmaygarde Aug 19, 2019

Choose a reason for hiding this comment

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

IIRC, presentDrawable is just waiting (asynchronously) for the command buffer to be scheduled and the and then presenting the same. Since you want the wait to happen now, the following code should be equivalent and more readable.

if (wait) {
 [command_buffer waitUntilScheduled];
}
[command_buffer presentDrawable:drawable];

Nit: Just a suggestion that I found more readable.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'm a little concerned that presentDrawable could end up unexpectedly yielding - the documentation on presentsWithTransaction says to use present instead of presentDrawable for this reason.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Just had to update this - the current formulation doesn't work, we have to call the presentDrawable before we commit otherwise it throws an exception sometimes.

@@ -33,6 +33,10 @@ class IOSSurface {

virtual std::unique_ptr<Surface> CreateGPUSurface() = 0;

// Creates a secondary surface using the supplied GrContext, if supported.
// Otherwise, the same as CreateGPUSurface.
virtual std::unique_ptr<Surface> CreateGPUSurface(GrContext* gr_context) = 0;
Copy link
Member

Choose a reason for hiding this comment

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

Can we just remove the no argument CreateGPUSurface and make the argument nullable?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done

pending_frame_semaphore_(1),
frame_number_(1),
paused_(false),
regenerate_layer_tree_(false),
frame_scheduled_(false),
notify_idle_task_id_(0),
dimension_change_pending_(false),
weak_factory_(this) {}
weak_factory_(this) {
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 may require a clang-format pass.

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 how clang-format is putting it - maybe it's confused by the preprocessor macros?

Copy link
Member

@chinmaygarde chinmaygarde left a comment

Choose a reason for hiding this comment

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

Some nits. All minor. Otherwise looks good. Thanks!

// https://developer.apple.com/documentation/quartzcore/cametallayer/1478157-presentswithtransaction
// TODO(dnfield): only do this if transactions are actually being used.
// https://github.com/flutter/flutter/issues/24133
bool wait = delegate_->GetExternalViewEmbedder() != nullptr;
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: may be clearer if we call this hasExternalViewEmbedder and move the comment above the if.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done

[command_buffer.get() commit];
} else {
[command_buffer.get() commit];
[command_buffer.get() waitUntilScheduled];
Copy link
Contributor

Choose a reason for hiding this comment

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

Would it make sense to not block here but instead finish rasterizing, and then do all the waits, present, and commit the transaction?

[Not asking to do it in this PR, just wondering whether it is possible and whether we think it can be more performant]

Copy link
Contributor Author

Choose a reason for hiding this comment

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

We should do as much work as we possibly can before getting the next drawable - guidelines from Apple say to hold it for as little time as possible. But if we use transactions, we have to block before presenting so that we are sure to present in the transaction. Alternatively, we have to make sure to not commit until we've presented in a callback.

} else if ([self.layer isKindOfClass:[CAMetalLayer class]]) {
fml::scoped_nsobject<CAMetalLayer> metalLayer(
reinterpret_cast<CAMetalLayer*>([self.layer retain]));
if (@available(iOS 8.0, *)) {
Copy link
Contributor

Choose a reason for hiding this comment

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

woohoo

} else if ([self.layer isKindOfClass:[CAMetalLayer class]]) {
fml::scoped_nsobject<CAMetalLayer> metalLayer(
reinterpret_cast<CAMetalLayer*>([self.layer retain]));
if (@available(iOS 8.0, *)) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Do we need a guard for iOS 8 features?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Probably not, but it doesn't hurt either right? I can remove if you want.

overlays_[overlay_id] = std::make_unique<FlutterPlatformViewLayer>(
fml::scoped_nsobject<UIView>(overlay_view), std::move(ios_surface), std::move(surface));
std::move(overlay_view), std::move(ios_surface), std::move(surface));
Copy link
Contributor

Choose a reason for hiding this comment

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

Reading this code again I realize we have a bug here (we had it before this change): If we have multiple overlays and the gr_context is changed we only update it for the first overlay (as we immediately follow by updating overlays_gr_context_). We should probably instead update overlays_gr_context after iterating on composition_order_.

FML_DCHECK(flutter_view_);

auto overlay_it = overlays_.find(overlay_id);

Copy link
Contributor

Choose a reason for hiding this comment

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

The flow for this function is getting a little confusing, how about we do:

EnsureGrContextIsCurrent(overlay_id, gr_context);
if (overlays_.count(overlay_id) != 0) {
 return;
}

// single copy of the overlay view creation code.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

We create the overlay view differently if there is or is not a GrContext, and in the software backend there is none.

@@ -63,6 +63,7 @@ struct FlutterPlatformViewLayer {
fml::scoped_nsobject<UIView> overlay_view;
std::unique_ptr<IOSSurface> ios_surface;
std::unique_ptr<Surface> surface;
void UpdateSurface();
Copy link
Contributor

Choose a reason for hiding this comment

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

Forgot to implement?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Removed - I thought I'd need this and didn't.

@@ -31,7 +31,10 @@ class IOSSurface {

virtual void UpdateStorageSizeIfNecessary() = 0;

virtual std::unique_ptr<Surface> CreateGPUSurface() = 0;
// Creates a secondary surface using the supplied GrContext, if supported.
// The gr_context argument may be nullptr.
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: mention that it creates a new GrContext if gr_context is null

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Updated this comment to make more sense.

@dnfield dnfield merged commit 66636ea into flutter:master Aug 23, 2019
@dnfield dnfield deleted the metal_pview branch August 23, 2019 23:15
engine-flutter-autoroll added a commit to engine-flutter-autoroll/flutter that referenced this pull request Aug 24, 2019
engine-flutter-autoroll added a commit to flutter/flutter that referenced this pull request Aug 24, 2019
git@github.com:flutter/engine.git/compare/dfd281bcaefe...00b72a1

git log dfd281b..00b72a1 --no-merges --oneline
2019-08-23 50503328+flar@users.noreply.github.com Add tracing of the number of frames in flight in the pipeline. (flutter/engine#11423)
2019-08-23 dnfield@google.com Platform View implemenation for Metal (flutter/engine#11070)
2019-08-23 bkonyi@google.com Roll src/third_party/dart 2e4c89aa73..ef07c76302 (5 commits)

The AutoRoll server is located here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll

Documentation for the AutoRoller is here:
https://skia.googlesource.com/buildbot/+/master/autoroll/README.md

If the roll is causing failures, please contact the current sheriff (liyuqian@google.com), and stop
the roller if necessary.
amirh added a commit that referenced this pull request Oct 31, 2019
Having 2 or more platform views simultaneously in the layer tree was crashing immediately on iOS with GL backend.

This regressed in #11070 which passed gl_context to a function in a loop using std::move (which meant on the second iteration the caller is no longer the owner of the field).

I added a scenarios_app test, though this test doesn't run on a physical device on CI so it would have only caught the problem when running locally (flutter/flutter#43852).
Partizann pushed a commit to Partizann/engine that referenced this pull request Mar 23, 2020
…13449)

Having 2 or more platform views simultaneously in the layer tree was crashing immediately on iOS with GL backend.

This regressed in flutter#11070 which passed gl_context to a function in a loop using std::move (which meant on the second iteration the caller is no longer the owner of the field).

I added a scenarios_app test, though this test doesn't run on a physical device on CI so it would have only caught the problem when running locally (flutter/flutter#43852).
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

PlatformViews need implemenation for Metal
4 participants