Skip to content

[Impeller] Improve performance when rendering contiguous backdrop filter layers. #131568

@knopp

Description

@knopp

On lower-end devices two small blurs tend to perform much worse than one large blur because of the extra render pass. But with wide-gamut, this is now an issue on high-end devices too.

Consider the following example:

code
import 'dart:ui';
import 'package:flutter/material.dart';

void main() {
  runApp(const MainApp());
}

const kSigma = 1.0;
const kNumberOfBlurs = 6;

class _Blur extends StatelessWidget {
  const _Blur();

  @override
  Widget build(BuildContext context) {
    return ClipRRect(
      child: BackdropFilter(
        blendMode: BlendMode.srcIn,
        filter: ImageFilter.blur(
          sigmaX: kSigma,
          sigmaY: kSigma,
        ),
        child: Container(
          color: Colors.red.withAlpha(30),
          child: const Text('Blur'),
        ),
      ),
    );
  }
}

class MainApp extends StatelessWidget {
  const MainApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        body: Stack(
          children: [
            ListView.builder(
                itemBuilder: (context, index) {
                  return Container(
                    padding: const EdgeInsets.all(10),
                    child: Text('Item $index'),
                  );
                },
                itemCount: 1000),
            for (var i = 0; i < kNumberOfBlurs; ++i) ...[
              Positioned(
                left: 0,
                right: 0,
                top: i * 150,
                height: 60,
                child: const _Blur(),
              ),
            ]
          ],
        ),
      ),
    );
  }
}
screenshot

Screen Shot 2023-07-30 at 09 49 18

With 6 backdrop this currently requires 7 passes to render. With wide gamut the cost of each pass can get quite high: #131567.

In this particular case all backdrops can be rendered in second pass, because for each backdrop nothing rendered before it in the second pass affects the area where the backdrop samples from.

Performance on iPhone 13 Pro (A15) with 7 passes:
Screenshot 2023-07-29 at 16 42 13

Performance with all backdrops rendered in second pass:
Screenshot 2023-07-29 at 23 55 20

I think something along "if this is not the first pass and nothing in this pass has rendered where the backdrop is sampling from don't end the pass" might be a significant improvement for common cases such as blurred header and tabbar.

cc @bdero @jonahwilliams

Metadata

Metadata

Assignees

No one assigned

    Labels

    P2Important issues not at the top of the work liste: impellerImpeller rendering backend issues and features requestsengineflutter/engine related. See also e: labels.team-engineOwned by Engine teamtriaged-engineTriaged by Engine team

    Type

    No type

    Projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions