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

Conversation

@jonahwilliams
Copy link
Contributor

this setting improves the performance of the "CPU TO Display Latency" metric in metal system trace. On high frame rate devices, this reduces the time we spend waiting for drawable availibility. This only applies if the CAMetalLayer is fullscreen, as it allows a direct to display optimization that reduces "CPU TO Display Latency" from about 21 ms down to 14ms.

Xref: flutter/flutter#134959

@flutter-dashboard
Copy link

It looks like this pull request may not have tests. Please make sure to add tests before merging. If you need an exemption to this rule, contact Hixie or stuartmorgan on the #hackers channel in Chat (don't just cc them here, they won't see it! Use Discord!).

If you are not sure if you need tests, consider this rule of thumb: the purpose of a test is to make sure someone doesn't accidentally revert the fix. Ask yourself, is there anything in your PR that you feel it is important we not accidentally revert back to how it was before your fix?

Reviewers: Read the Tree Hygiene page and make sure this patch meets those guidelines before LGTMing.

@jonahwilliams jonahwilliams changed the title Update CAMetalLayer to be opaque. Update CAMetalLayer to be opaque, remove waitUntilScheduled for background rendering. Sep 18, 2023
Comment on lines 267 to 270
} else {
[command_buffer presentDrawable:drawable_];
[command_buffer commit];
}
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 should be safe if we're not presenting with transaction, but needs more testing from me.

// disable opaque, which on full screen flutter apps removes the direct to display
// optimization. This can increase presentation time by a frame interval, which
// is problematic on high frame rate devices.
if (!opaque) {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

@luckysmg , I found that if we set the background color to any value, it resets the value of layer.opaque. If you have a fullscreen flutter view and opaque is true, then we get a direct to display optimization and the presentation delay decreases from ~21ms to ~14ms, which is particularly important for high frame rate devices.

See some findings in flutter/flutter#134959

How are you using a FlutterView? Is it an add2app case where it is not the only view in the scene?

Copy link
Contributor

Choose a reason for hiding this comment

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

Yes. We will change the layer's opaque to make the flutter view to be transparent and present it. The scene is that the new page is the transparent page, and it is presented on current page to do some thing like modal bottom sheet.

See https://github.com/alibaba/flutter_boost/blob/13eb9aed1dff9fcdfa6066666ba08a11b231af9f/ios/Classes/container/FBFlutterViewContainer.m#L137

Copy link
Contributor

Choose a reason for hiding this comment

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

Copy link
Contributor

Choose a reason for hiding this comment

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

If !opaque and set a white color, will it make the FlutterView not transparent?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

ahh ok. Right now the problem is that we're unconditionally setting this clear color here. But setting the background color resets the value of opaque to NO, even if we requested it to be YES. So I think as long as your code is setting opaque = NO, this should keep working for you?

Copy link
Contributor

Choose a reason for hiding this comment

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

Seems not working... Here init with delegate is too early to set bg color to white.

See
https://github.com/alibaba/flutter_boost/blob/13eb9aed1dff9fcdfa6066666ba08a11b231af9f/ios/Classes/container/FBFlutterViewContainer.m#L220

If we need the view is transparent, we will set the opaque to NO and don't set bg color(in above link's code)

Before this patch: the result FlutterView is will be not opaque and with clear color, so it will be transparent ✅
After this patch: the result FlutterView is will be not opaque and with white color, so it will not be transparent ❌

Copy link
Contributor Author

Choose a reason for hiding this comment

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

So your code is starting out with opaque = YES, then you're setting it to opaque = NO later? I'm not really familiar enough with flutter_boost to follow the rendering paths there. I can change this so that if you later set opaque = NO, then we also set the background color to the clearColor?

Copy link
Contributor

@luckysmg luckysmg Sep 19, 2023

Choose a reason for hiding this comment

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

I can change this so that if you later set opaque = NO, then we also set the background color to the clearColor?

I think this can work. But I m not sure this is good or not... Because this has a implicit operation: Change opaquealso change the bg color. Maybe sometimes will confusing the developer..

Edited: For me this is good ^_^

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah good point. I need to test if setting opaque after we set the background color also resets the background color too. If not, maybe I just change the order and leave this as is.

Copy link
Contributor

Choose a reason for hiding this comment

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

^_^

@chinmaygarde chinmaygarde changed the title Update CAMetalLayer to be opaque, remove waitUntilScheduled for background rendering. [Impeller] Update CAMetalLayer to be opaque, remove waitUntilScheduled for background rendering. Sep 19, 2023
// Note: this setting improves the performance of the "CPU TO Display Latency" metric in
// metal system trace. On high frame rate devices, this reduces the time we spend waiting
// for drawable availibility.
layer.opaque = YES;
Copy link
Contributor

Choose a reason for hiding this comment

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

Emm If we set this opaque=YES, means our the change to opaque is invalid? Since this will be called every frame.

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'll remove this

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 testing 😄

Copy link
Contributor

Choose a reason for hiding this comment

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

Yeah ^_^

layer.allowsGroupOpacity = YES;
layer.contentsScale = screenScale;
layer.rasterizationScale = screenScale;
layer.framebufferOnly = flutter::Settings::kSurfaceDataAccessible ? NO : YES;
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 value should match what we set in

@luckysmg
Copy link
Contributor

Have a locally test for current patch. The constant junk is regression. I think the patch will also impact device not on iOS16.6. 😭

normal.video.mp4

@jonahwilliams
Copy link
Contributor Author

Are you setting your FlutterViews opaque to YES or are you relying on the side effect of the bgcolor setting to make it opaque?

@jonahwilliams jonahwilliams changed the title [Impeller] Update CAMetalLayer to be opaque, remove waitUntilScheduled for background rendering. [Impeller] Update CAMetalLayer to be opaque Sep 19, 2023
@jonahwilliams
Copy link
Contributor Author

I wouldn't consider this a fix for 16.6, the fix for that is to update to 17. But this does help, and fixes a bug since right now we're ignoring the opaque property entirely

@luckysmg
Copy link
Contributor

luckysmg commented Sep 19, 2023

I test current patch with a pure flutter example without add to app. I didn't change any code of flutter view manually

@jonahwilliams
Copy link
Contributor Author

Can you run metal system trace and share a screenshot of the LCD category? For me, this is showing ~8ms faster presentations with this change.

@luckysmg
Copy link
Contributor

Will have a check later

@luckysmg
Copy link
Contributor

luckysmg commented Sep 19, 2023

Tested on iPhone 13Pro iOS16.6.1
At begining is ok. But after scrolling the page some time it will have constant junk. Just the issue fixed in #39359
20230919121613

@jonahwilliams
Copy link
Contributor Author

I'm testing on 17, but even on 16.6 I don't see this causing regressions - if anything its stabilizing things and I'm seeing more throughput. But event with a fast app we'll always hit a point where we're limited by drawables, given that there are only 3.

I'm not sure what to make of this right now.

@jonahwilliams
Copy link
Contributor Author

If this is the case, then I suspect that setting the background color to the clearColor in #39359 fixed things for you by way of reseting the opaque bit. But I'm not sure why that would improve performance, since that seems to disable direct to display.

I'm not sure if we use that opaque bit elsewhere, but we might be in a bit of an inconsistent state because while the layer is no opaque NO, the viewcontroller things opaque is YES 🤔

@luckysmg
Copy link
Contributor

luckysmg commented Sep 19, 2023

Yes. Confusing..... I will have a recheck to check whether my code applying your patch is correct.

@jonahwilliams
Copy link
Contributor Author

You might also try patching in a change that remove the backgroundColor but makes the default opaque to NO, to see if it has consistent performance. That should verify if it is the opaque field or the background color that is helping your case.

@luckysmg
Copy link
Contributor

luckysmg commented Sep 19, 2023

Have a retest.

  1. The patch on my iPhone indeed regress the constant junk issue.
  2. After I set the code like this.
// This line is necessary. CoreAnimation(or UIKit) may take this to do
    // something to compute the final frame presented on screen, if we don't set this,
    // it will make it take long time for us to take next CAMetalDrawable and will
    // cause constant junk during rendering. Note: setting any background color will
    // disable opaque, which on full screen flutter apps removes the direct to display
    // optimization. This can increase presentation time by a frame interval, which
    // is problematic on high frame rate devices.
//    self.backgroundColor = UIColor.clearColor;
    // Make sure to set this value after backgroundColor above, otherwise it will
    // reset the value of opaque.
    self.layer.opaque = NO;

The screen will have jitter, but behavior is different from 1 point. I think this is because my iPhone is 16.6, I think maybe this code have no jitter on other version of iOS, but I have no other version of high FPS iPhone ... Maybe I will go to find one to take a look later

@luckysmg
Copy link
Contributor

@jonahwilliams I have a project to fire on later, not sure how long to have next response.. (just ensure you are not waiting for my resp because it is mid night in your time haha ^_^)

@jonahwilliams
Copy link
Contributor Author

No worries, I'm marking this as a draft for now while I investigate other things!

@jonahwilliams jonahwilliams marked this pull request as draft September 19, 2023 06:47
@luckysmg
Copy link
Contributor

@jonahwilliams I retest using iPhone13 Pro Max on iOS 16.0

  1. Using the code below:
//    self.backgroundColor = UIColor.clearColor;
    self.layer.opaque = YES;

Will regress the constant junk issue fixed in #39359

  1. Using the code in this patch: The same as 1, will also regress constant junk.
  2. Using the code below:
//    self.backgroundColor = UIColor.clearColor;
    self.layer.opaque = NO;

The app is smooth without any junk.

Also I see the CALayer's opaque default value is NO, I m not sure whether that is apple's suggestion and indicates the performance will be better.
image

@jonahwilliams
Copy link
Contributor Author

OK, I think we can work with this. I suspect this explains why setting the background color improved performance then, because we were defaulting to Opaque = YES, and then changing the color reset it to NO?

@jonahwilliams
Copy link
Contributor Author

I'll need to do some follow ups and figure out what the official story is on Layer.opaque.

@luckysmg
Copy link
Contributor

because we were defaulting to Opaque = YES, and then changing the color reset it to NO?

Yes. I think so..

@jonahwilliams
Copy link
Contributor Author

Sorry to ping on this again @luckysmg , but what is the CPU to display latency look like if you don't have this change patched in?

@luckysmg
Copy link
Contributor

I think without this change, it is the same in main channel, maybe you could have a try. Because I only have a iOS16.6 device, I m afraid the behavior on my device can not be referred to....

@jonahwilliams
Copy link
Contributor Author

Makes sense, no worries. Still researching this 💻 🧑‍🔬 !

@jonahwilliams
Copy link
Contributor Author

Closing as this seems to be a dead end.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

No open projects
Archived in project

Development

Successfully merging this pull request may close these issues.

3 participants