Skip to content

[Impeller] CustomPaint flickers on left and top of a Path when arc is drawn and saveLayer() is used #128532

@ashishbeck

Description

@ashishbeck

Is there an existing issue for this?

Steps to reproduce

  1. Create a CustomPainter and make a path that draws an arc. Draw this path onto the canvas using the drawPath() method on canvas.
  2. Make a variable called startAngle and put it in the constructor so that we can modify the rotation of the painter to see the artifacts.
  3. Wrap the canvas.drawPath() method with saveLayer() and restore() functions which basically create a new stack onto the canvas.
  4. Use this custom painter in a CustomPaint widget and wrap it with an animation widget like the AnimatedBuilder and supply an animation to see the artifacts across multiple frames.

Note: drawing an arc using the drawArc() method of the canvas will not produce this error. And drawing a circle with the drawOval() method on path will also not produce the error. The arc has to be made with a Path using the drawArc() method.

Expected results

The flickering should not happen at the left and top portions of the painter when we use saveLayer() and restore(). When we do not use these functions, we do not get the flickering issue.

Actual results

We do see some flickering which most likely happens for some values of startAngle. Because when we pause the animation at random, we get a still frame with the artifact.

I don't have an iPhone to test on a real device but I can confirm this behaviour with impeller enabled on iOS and Android emulators along with physical Android device. On disabling impeller, we do not see these issues at all.

Code sample

Code sample
import 'dart:math';
import 'package:flutter/material.dart';

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

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        colorSchemeSeed: Colors.deepPurple,
        useMaterial3: true,
      ),
      home: const MyWidget(),
    );
  }
}

class MyWidget extends StatefulWidget {
  const MyWidget({super.key});

  @override
  State<MyWidget> createState() => _MyWidgetState();
}

class _MyWidgetState extends State<MyWidget>
    with SingleTickerProviderStateMixin {
  late AnimationController controller;

  @override
  void initState() {
    super.initState();
    controller =
        AnimationController(vsync: this, duration: const Duration(seconds: 5))
          ..repeat(reverse: true);
  }

  @override
  void dispose() {
    controller.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: Padding(
          padding: const EdgeInsets.all(8.0),
          child: AnimatedBuilder(
              animation: controller,
              builder: (context, _) {
                return CustomPaint(
                  size: Size(MediaQuery.of(context).size.width,
                      MediaQuery.of(context).size.width),
                  painter: MyPaint(startAngle: pi / 2 * controller.value),
                );
              }),
        ),
      ),
    );
  }
}

class MyPaint extends CustomPainter {
  final double startAngle;
  MyPaint({
    required this.startAngle,
  });

  @override
  void paint(Canvas canvas, Size size) {
    final width = size.width;
    final height = size.height;
    final center = Offset(width / 2, height / 2);

    final paint = Paint()
      ..color = Colors.orangeAccent
      ..style = PaintingStyle.fill;
    final path = Path()
      ..addArc(Rect.fromCenter(center: center, width: width, height: height),
          startAngle, 1.99 * pi);
    canvas.saveLayer(
      Rect.fromCenter(center: center, width: width, height: height),
      Paint(),
    );
    canvas.drawPath(path, paint);
    canvas.restore();
  }

  @override
  bool shouldRepaint(MyPaint oldDelegate) =>
      oldDelegate.startAngle != startAngle;
}

Screenshots or Video

Screenshots / Video demonstration
Simulator.Screen.Recording.-.iPhone.14.Pro.Max.-.2023-06-09.at.01.23.36.mp4

Logs

Logs

No logs produced

Flutter Doctor output

Doctor output
[✓] Flutter (Channel stable, 3.10.4, on macOS 13.4 22F66 darwin-arm64, locale en-IN)
    • Flutter version 3.10.4 on channel stable at /Users/ashishbeck/Dev/Tools/flutter
    • Upstream repository https://github.com/flutter/flutter.git
    • Framework revision 682aa387cf (3 days ago), 2023-06-05 18:04:56 -0500
    • Engine revision 2a3401c9bb
    • Dart version 3.0.3
    • DevTools version 2.23.1

[✓] Android toolchain - develop for Android devices (Android SDK version 33.0.0)
    • Android SDK at /Users/ashishbeck/Library/Android/sdk
    • Platform android-33, build-tools 33.0.0
    • Java binary at: /Applications/Android Studio.app/Contents/jre/Contents/Home/bin/java
    • Java version OpenJDK Runtime Environment (build 11.0.12+0-b1504.28-7817840)
    • All Android licenses accepted.

[✓] Xcode - develop for iOS and macOS (Xcode 14.3.1)
    • Xcode at /Applications/Xcode.app/Contents/Developer
    • Build 14E300c
    • CocoaPods version 1.12.1

[✓] Chrome - develop for the web
    • Chrome at /Applications/Google Chrome.app/Contents/MacOS/Google Chrome

[✓] Android Studio (version 2021.2)
    • Android Studio at /Applications/Android Studio.app/Contents
    • Flutter plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/9212-flutter
    • Dart plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/6351-dart
    • Java version OpenJDK Runtime Environment (build 11.0.12+0-b1504.28-7817840)

[✓] VS Code (version 1.78.2)
    • VS Code at /Applications/Visual Studio Code.app/Contents
    • Flutter extension version 3.64.0

[✓] Connected device (3 available)
    • iPhone 14 Pro Max (mobile) • CB613DEA-6EC4-46AC-A1C1-8E2C893480CB • ios            • com.apple.CoreSimulator.SimRuntime.iOS-16-4
      (simulator)
    • macOS (desktop)            • macos                                • darwin-arm64   • macOS 13.4 22F66 darwin-arm64
    • Chrome (web)               • chrome                               • web-javascript • Google Chrome 114.0.5735.106

[✓] Network resources
    • All expected network resources are available.

• No issues found!

Metadata

Metadata

Assignees

Labels

e: impellerImpeller rendering backend issues and features requestsengineflutter/engine related. See also e: labels.found in release: 3.10Found to occur in 3.10found in release: 3.12Found to occur in 3.12has reproducible stepsThe issue has been confirmed reproducible and is ready to work onplatform-iosiOS applications specificallyr: fixedIssue is closed as already fixed in a newer version

Type

No type

Projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions