Skip to content

[Impeller] Especially complex paths cause rendering errors, freezes #126212

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

Closed
jonahwilliams opened this issue May 7, 2023 · 3 comments
Closed
Labels
e: impeller Impeller rendering backend issues and features requests engine flutter/engine repository. See also e: labels. P2 Important issues not at the top of the work list team-engine Owned by Engine team triaged-engine Triaged by Engine team

Comments

@jonahwilliams
Copy link
Member

This application chugs along with the Skia backend, but with Impeller we fail to even render a frame until it crashes. No errors, perhaps tessellation is just taking too long? But something else is going as the frame that is finally rendered is also incorrect. Perhaps we're overflowing the index buffer?

This code was taken from https://medium.com/@dev.n/flutter-generative-art-the-easy-way-99252486a338 . Originally canvas.drawCircle was used, but this led to a massive overhead in Rtree computation (see #126202). To work around this, I collapsed them into a single path with multiple arcs.

Skia

flutter_05

Impeller

Apologies for the picture, but the tool screenshot doesn't work when this happens and I've had no luck with photos importing.

image

import 'dart:math';
import 'dart:typed_data';
import 'dart:ui';

import 'package:flutter/material.dart';

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

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

  @override
  State<MyApp> createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  double iter = 0.0;

  // Choose a random color for this iteration
  var colors = List<ColorInfo>.generate(20, (int index) => ColorList[Random().nextInt(ColorList.length)]);

  @override
  void initState() {
    super.initState();
    Future.delayed(Duration(seconds: 1)).then((value) async {
      for (int i = 0; i < 2000000; i++) {
        setState(() {
          iter = iter + 0.00001;
        });
        await Future.delayed(Duration(milliseconds: 50));
      }
    });
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      debugShowCheckedModeBanner: false,
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: Scaffold(
        body: CustomPaint(
          painter: DemoPainter(iter, colors),
          child: Container(),
        ),
      ),
    );
  }
}

class DemoPainter extends CustomPainter {
  DemoPainter(this.iter, this.colors);

  final double iter;
  final List<ColorInfo> colors;

  @override
  void paint(Canvas canvas, Size size) {
    renderDrawing(canvas, size);
  }

  void renderDrawing(Canvas canvas, Size size) {
    canvas.drawPaint(Paint()..color = Colors.black87);

    renderStructure2(canvas, size, iter, colors, 9);
  }

  void renderStructure2(Canvas canvas, Size size, double iter, List<ColorInfo> colors, int totalIter) {

    var paint = Paint();

    for (int j = 0; j < totalIter; j++) {
      double distance = 0.0;
      double tempIter = totalIter - j + iter;

      // We draw a LOT of points
      var path = Path();
      paint
        ..style = PaintingStyle.fill
        ..color = colors[j].color;
      for (double i = 0; i < 80; i = i + 0.01) {
        var radius =  5.0 - (0.5 * (totalIter - tempIter));
        var center = Offset(
          (size.width / 2) + (distance * cos(distance) * sin(distance) * atan(distance)),
          (size.height / 2) + (distance * cos(distance) * sin(distance) * tan(distance)),
        );
        path.addArc(
          Rect.fromCircle(center: center, radius: radius),
          0,
          2 * pi,
        );
        path.close();

        // Change the "0.1" for varying point distances
        distance = distance + (0.2 + (0.1 * totalIter - tempIter));
      }
      canvas.drawPath(path, paint);
    }
  }

  @override
  bool shouldRepaint(DemoPainter oldDelegate) {
    return iter != oldDelegate.iter;
  }
}

// This could have been a list of colors, I just picked the list off another project of mine
var ColorList = [
  //ColorInfo("black", Colors.black, Colors.black.toString()),
  ColorInfo("red", Colors.red, Colors.red[500].toString()),
  ColorInfo("green", Colors.green, Colors.green[500].toString()),
  ColorInfo("blue", Colors.blue, Colors.blue[500].toString()),
  ColorInfo("yellow", Colors.yellow, Colors.yellow[500].toString()),
  ColorInfo("purple", Colors.purple, Colors.purple[500].toString()),
  ColorInfo("amber", Colors.amber, Colors.amber[500].toString()),
  ColorInfo("cyan", Colors.cyan, Colors.cyan[500].toString()),
  ColorInfo("grey", Colors.grey, Colors.grey[500].toString()),
  ColorInfo("teal", Colors.teal, Colors.teal[500].toString()),
  ColorInfo("pink", Colors.pink, Colors.pink[500].toString()),
  ColorInfo("orange", Colors.orange, Colors.orange[500].toString()),
  //ColorInfo("white", Colors.white, Colors.white.toString()),
  //ColorInfo("transparent", Colors.transparent, Colors.transparent.toString()),
];

class ColorInfo {
  String name;
  MaterialColor color;
  String hex;

  ColorInfo(this.name, this.color, this.hex);
}
@jonahwilliams jonahwilliams added engine flutter/engine repository. See also e: labels. e: impeller Impeller rendering backend issues and features requests labels May 7, 2023
@jonahwilliams
Copy link
Member Author

We may need to subdivide complex paths with many contours into separate tessellation and/or draw calls.

@chinmaygarde chinmaygarde added the P2 Important issues not at the top of the work list label May 8, 2023
@chinmaygarde chinmaygarde moved this from 🤔 Needs Triage to ⚙️ In Progress in Impeller May 8, 2023
@github-project-automation github-project-automation bot moved this to 🤔 Needs Triage in Impeller May 8, 2023
@chinmaygarde chinmaygarde moved this from ⚙️ In Progress to ⚡ Performance in Impeller May 8, 2023
@flutter-triage-bot flutter-triage-bot bot added team-engine Owned by Engine team triaged-engine Triaged by Engine team labels Jul 8, 2023
@jonahwilliams
Copy link
Member Author

Fixed via flutter/engine#46282

@github-actions
Copy link

This thread has been automatically locked since there has not been any recent activity after it was closed. If you are still experiencing a similar issue, please open a new bug, including the output of flutter doctor -v and a minimal reproduction of the issue.

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Oct 11, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
e: impeller Impeller rendering backend issues and features requests engine flutter/engine repository. See also e: labels. P2 Important issues not at the top of the work list team-engine Owned by Engine team triaged-engine Triaged by Engine team
Projects
No open projects
Archived in project
Development

No branches or pull requests

2 participants