-
Notifications
You must be signed in to change notification settings - Fork 29.7k
Make RenderColoredBox.paint() skip painting color if it's transparent #72526
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
|
Gold has detected about 1 untriaged digest(s) on patchset 1. |
dnfield
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
This makes me wonder if we could/should optimize dart:ui Canvas operations that are given a paint that results in nothing being drawn - or, if not optimize, warn about it.
|
Hmm. That golden diff is making me wonder if this is somehow breaking non-0 alpha painting... |
|
Golden file changes have been found for this pull request. Click here to view and triage (e.g. because this is an intentional change). If you are still iterating on this change and are not ready to resolve the images on the Flutter Gold dashboard, consider marking this PR as a draft pull request above. You will still be able to view image results on the dashboard, commenting will be silenced, and the check will not try to resolve itself until marked ready for review. For more guidance, visit Writing a golden file test for Reviewers: Read the Tree Hygiene page and make sure this patch meets those guidelines before LGTMing. Changes reported for pull request #72526 at sha 66c5f7e3ba2286230d394c8337eefe40e553e6af |
The golden failure is happening because when we use Is the current behavior working as intended? 🤔 It seems counterintuitive that painting a transparency could do anything... |
|
/cc @flar who would be able to provide details on the BackdropFilter side of things. |
|
I think this is probably working as intended, although it's a bit odd. The patch that added this was 11e1c24 (@Piinks). If I'm reading it right (and making other correct assumptions), we could use a e.g. import 'dart:ui';
import 'package:flutter/material.dart';
final Color darkBlue = Color.fromARGB(255, 18, 32, 47);
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData.dark().copyWith(scaffoldBackgroundColor: darkBlue),
debugShowCheckedModeBanner: false,
home: Scaffold(
body: Center(
child: MyWidget(),
),
),
);
}
}
class MyWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
SizedBox(
height: 200,
width: 200,
child: ClipRect(
child: Stack(
children: <Widget>[
Positioned.fill(child: Text('Hello 1')),
Positioned.fill(
child: BackdropFilter(
filter: ImageFilter.blur(sigmaX: 2.0, sigmaY: 2.0),
child: Container(color: Colors.transparent),
),
),
],
),
),
),
Divider(),
SizedBox(
height: 200,
width: 200,
child: ClipRect(
child: Stack(
children: <Widget>[
Positioned.fill(child: Text('Hello 2')),
Positioned.fill(
child: BackdropFilter(
filter: ImageFilter.blur(sigmaX: 2.0, sigmaY: 2.0),
child: Container(),
),
),
],
),
),
),
],
);
}
}Unfortunately, this program behaves differently on web (DOM) and VM. I assume CanvasKit would behave like VM but haven't checked. |
Should resolve interaction with BDF first
|
@flar probably will know more, but I wonder if this has anything to do with premul/unpremul colors.
|
|
There are a number of issues that make ignoring transparency problematic. One is that it is only a NOP on some blend modes. Most notably it is a NOP with the default blend mode of Another case where it might affect output is under an operation like a blur where the blur effect needs to read samples from outside the image to blend with the pixels that are near the edge of the source image. The default edge sampling mode for Consider if they animate the background from a solid color to transparency inside a blur. The edges would slowly fade and the content drawn on top of the background would animate from a blur into the initial color, slowly towards a blur into transparency as the animation progressed. If you suddenly omit the rendering of the opaque color at the end of the animation then the last frame would be a blur of just the bounds of the content and you would end up with that content smearing to the edge of the blurred result. Knowing whether you can omit the transparency would involve knowledge of a lot of factors about the parent widgets in the tree (and potentially knowledge of a BDF on top of the widget since a BDF might be clipped to the bounds of its child which can change if you render or do not render that transparent rectangle). |
|
@flar thanks for the great explanation! I updated this to simply add a comment to ward off well-meaning future-me 🙂 |
dnfield
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
All this does is avoid adding an animated container when the opacity is 0 (which it is most of the time). The new line avoids an unintuitive behavior of the Flutter Framework, in which a fully transparent overlay cannot be ignored by the rasterizer. More info here: flutter/flutter#72526 (comment). I wasn’t able to test this, but I’m pretty sure this will have the effect of skipping the overlay animation when the opacity goes from 0 to non-zero (because AnimatedContainer only animates itself if it’s there for both the before and after — and I’m removing the before). If this is too jarring, we can think about other creative ways to still get that performance boost.
All this does is avoid adding an animated container when the opacity is 0 (which it is most of the time). The new line avoids an unintuitive behavior of the Flutter Framework, in which a fully transparent overlay cannot be ignored by the rasterizer. More info here: flutter/flutter#72526 (comment). I wasn’t able to test this, but I’m pretty sure this will have the effect of skipping the overlay animation when the opacity goes from 0 to non-zero (because AnimatedContainer only animates itself if it’s there for both the before and after — and I’m removing the before). If this is too jarring, we can think about other creative ways to still get that performance boost.
All this does is avoid adding an animated container when the opacity is 0 (which it is most of the time). The new line avoids an unintuitive behavior of the Flutter Framework, in which a fully transparent overlay cannot be ignored by the rasterizer. More info here: flutter/flutter#72526 (comment). I wasn’t able to test this, but I’m pretty sure this will have the effect of skipping the overlay animation when the opacity goes from 0 to non-zero (because AnimatedContainer only animates itself if it’s there for both the before and after — and I’m removing the before). If this is too jarring, we can think about other creative ways to still get that performance boost.
Description
This avoids an unnecessary paint operation if you create a
ColoredBoxwith a fully transparent color.Use case
If apps want to toggle a color on and off, they might want to conditionally include a
ColoredBoxin their widget tree. But doing so will cause arebuild()and alayout()every time they toggle the color. By including theColoredBoxunconditionally in their widget tree and only changing the color, they will only trigger arepaint()every time they toggle the color. However, in this case, they'll be frequently using a fully transparent color and would like to avoid the associated dart:ui operation.Tests
I added the following tests:
Checklist
///).flutter analyze --flutter-repo) does not report any problems on my PR.Breaking Change