Flutter CustomPainter with drawRawPoints still low FPS (Web + Android emulator) for 128x128 indexed framebuffer
I'm rendering a retro-style 128x128 framebuffer in Flutter using CustomPainter + canvas.drawRawPoints.
I already removed per-frame allocations by preallocating typed buffers per palette index, but FPS is still very low on Web (~12 FPS) and also low on Android emulator after testing. iOS is much better.
I profiled the engine loop separately and it seems fast enough (simulation step is around 1-2ms per frame), so this looks like a presentation/render bottleneck.
Simplified code (anonymized):
class FrameScreen extends StatefulWidget { const FrameScreen({super.key, required this.frames}); final Stream<FrameData> frames; State<FrameScreen> createState() => _FrameScreenState(); } class _FrameScreenState extends State<FrameScreen> { final PixelBuckets _pixelBuckets = PixelBuckets(); FrameData? _lastFrame; StreamSubscription<FrameData>? _sub; void initState() { super.initState(); _sub = widget.frames.listen((frame) { _lastFrame = frame; _pixelBuckets.update(frame.indices); // 16 color buckets, reused arrays if (mounted) setState(() {}); }); } Widget build(BuildContext context) { if (_lastFrame == null) return const SizedBox.shrink(); return CustomPaint( painter: PixelPainter( buckets: _pixelBuckets, palette: _lastFrame!.palette, ), child: const SizedBox.expand(), ); } } class PixelPainter extends CustomPainter { PixelPainter({required this.buckets, required this.palette}); final PixelBuckets buckets; final List<int> palette; void paint(Canvas canvas, Size size) { canvas.scale(size.width / 128, size.height / 128); final paint = Paint() ..strokeWidth = 1.0 ..strokeCap = StrokeCap.square; 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); } } bool shouldRepaint(covariant PixelPainter oldDelegate) => true; }
I also draw optional overlays (grid/vignette/shader mode), but low FPS occurs even in mostly "pixel-perfect" mode.
Questions:
drawRawPoints expected to be this slow on Web/Android emulator even for 128x128?drawAtlas, RawImage with updated texture, SceneBuilder, etc.)?setState on every frame for this pattern?Constraints: