Skip to content

[Impeller] Enabling RTree regressed canvas drawing with a large number of operations #126202

Closed
flutter/engine
#42399
@jonahwilliams

Description

@jonahwilliams

Consider an application that does a large amount of Canvas drawing. After flutter/engine#41606 , the computation of the Rtree can easily dwarf other costs in the raster thread, especially if the culling is unsuccessful.

We should be smarter about this, potentially by avoiding reaching into individual pictures and using those bounds as opposed to the individual ops.

Here is an application that will stress this code by drawing a large number of small objects. I was investigating this as a motivating case for a shape buffer to avoid circle tesellation.

// Copyright 2014 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

import 'dart:async';
import 'dart:math' as math;

import 'package:flutter/material.dart';
void main() {
  runApp(const Example());
}

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

  @override
  State<Example> createState() => _ExampleState();
}

class _ExampleState extends State<Example> {
  late Timer timer;

  @override
  void initState() {
    super.initState();
    timer = Timer.periodic(const Duration(milliseconds: 4), (t) {
      setState(() {

      });
    });
  }

  @override
  void dispose() {
    timer.cancel();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Center(child:CustomPaint(painter: RandomCirclesPainter(
    color: Colors.red,
    radius: 0.5,
    count: 5000
  ), size: const Size(400, 400),));
  }
}

class RandomCirclesPainter extends CustomPainter {
  RandomCirclesPainter({
    required this.count,
    required this.radius,
    required this.color,
  });

  final int count;
  final double radius;
  final Color color;

  @override
  void paint(Canvas canvas, Size size) {
    // Create a paint object with the specified color.
    Paint paint = Paint()..color = color;

    // Generate a random list of offsets for the circles.
    List<Offset> offsets = List.generate(
      count,
      (_) => Offset(
        math.Random().nextDouble() * size.width,
        math.Random().nextDouble() * size.height,
      ),
    );

    // Draw the circles at the specified offsets.
    for (Offset offset in offsets) {
      canvas.drawCircle(
        offset,
        radius,
        paint,
      );
    }
  }

  @override
  bool shouldRepaint(RandomCirclesPainter oldDelegate) {
    return true;
  }
}

image

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 repository. See also e: labels.

    Type

    No type

    Projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions