Flutter CustomPainter with drawRawPoints still low FPS (Web + Android emulator) for 128×128 indexed framebuffer

Summary

The issue at hand is a low FPS (frames per second) rendering performance in a Flutter application using CustomPainter with canvas.drawRawPoints on Web and Android emulator, despite optimizations to reduce allocations. The goal is to reach a target of 60 FPS.

Root Cause

The root causes of this issue can be attributed to:

  • Inefficient rendering: The use of drawRawPoints for rendering a large number of points can be slow, especially on Web and Android emulator.
  • Frequent setState calls: Calling setState on every frame can lead to unnecessary rebuilds and impact performance.
  • Limited hardware capabilities: The Android emulator and Web platforms may have limited hardware capabilities, contributing to the low FPS.

Why This Happens in Real Systems

This issue occurs in real systems due to:

  • Rendering complexities: The rendering of a large number of points using drawRawPoints can be computationally expensive.
  • Platform limitations: Different platforms have varying levels of hardware capabilities, which can impact rendering performance.
  • Framework overhead: The Flutter framework itself can introduce some overhead, affecting performance.

Real-World Impact

The real-world impact of this issue includes:

  • Poor user experience: Low FPS can result in a stuttering or lagging user interface, negatively impacting the overall user experience.
  • Limited platform support: The issue may limit the application’s ability to run smoothly on certain platforms, such as Web or Android emulator.
  • Increased development complexity: Optimizing the application for different platforms can add complexity to the development process.

Example or Code

class PixelPainter extends CustomPainter {
  // ...

  @override
  void paint(Canvas canvas, Size size) {
    // ...
    for (var i = 0; i < 16; i++) {
      final count = buckets.counts[i];
      if (count == 0) continue;
      paint.color = Color(palette[i]);
      final points = Float32List.sublistView(buckets.points[i], 0, count * 2);
      canvas.drawRawPoints(ui.PointMode.points, points, paint);
    }
  }
}

How Senior Engineers Fix It

Senior engineers can address this issue by:

  • Optimizing rendering: Exploring alternative rendering methods, such as drawAtlas or RawImage with updated texture.
  • Reducing setState calls: Implementing a more efficient state management approach to minimize unnecessary rebuilds.
  • Leveraging platform-specific features: Utilizing platform-specific features, such as GPU acceleration, to improve rendering performance.

Why Juniors Miss It

Junior engineers may overlook this issue due to:

  • Lack of experience: Inadequate experience with optimizing rendering performance in Flutter applications.
  • Insufficient knowledge: Limited understanding of the underlying rendering mechanisms and platform-specific limitations.
  • Focus on functionality: Prioritizing feature implementation over performance optimization.

Leave a Comment