Skip to content

drawRawPoints inside layers with very small scales (<1e-5) draws its points too large #152794

@Hixie

Description

@Hixie

The combination of pushing a transform layer and using drawRawPoints leads to strange effects on Impeller. It (mostly) works fine on Skia (Skia does weird things near 1e38/1e-38, see also #152520).

Sample code
import 'dart:async';
import 'dart:typed_data';
import 'dart:ui';

import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter/widgets.dart';

void main() async {
  runApp(const Root());
}

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

  @override
  State<Root> createState() => _RootState();
}

class _RootState extends State<Root> {
  Timer? _timer;
  double _scale = 1.0;
  
  @override
  void initState() {
    super.initState();
    _timer = Timer.periodic(const Duration(milliseconds: 16), _update);
  }

  void _update(Timer timer) {
    setState(() {
      _scale *= 1.5;
      if (_scale > 1e38) {
        _scale = 1e-15; // this should work all the way down to 1e-38 at least, but currently it crashes for really small scales
      }
    });
  }
  
  @override
  void dispose() {
    _timer?.cancel();
    super.dispose();
  }
  
  @override
  Widget build(BuildContext context) {
    return Stack(
      textDirection: TextDirection.ltr,
      children: [
        TestWidget(scale: _scale),
        Positioned(
          top: 60.0,
          left: 20.0,
          child: Text(_scale.toStringAsExponential(1), textDirection: TextDirection.ltr),
        ),
      ],
    );
  }
}

class TestWidget extends LeafRenderObjectWidget {
  const TestWidget({
    super.key,
    this.scale = 1.0,
  });

  final double scale;
  
  @override
  RenderTest createRenderObject(BuildContext context) {
    return RenderTest(scale: scale);
  }

  @override
  void updateRenderObject(BuildContext context, RenderTest renderObject) {
    renderObject.scale = scale;
  }
}

class RenderTest extends RenderBox {
  RenderTest({ double scale = 1.0 }) : _scale = scale;

  double get scale => _scale;
  double _scale;
  set scale(double value) {
    if (_scale != value) {
      _scale = value;
      markNeedsPaint();
    }
  }
  
  @override
  void performLayout() {
    size = constraints.biggest;
  }

  TransformLayer? _transformLayer;
  
  @override
  void paint(PaintingContext context, Offset offset) {
    final transform = Matrix4.identity()
      ..scale(100 / scale);
    _transformLayer = context.pushTransform(
      needsCompositing,
      offset,
      transform,
      _paintDots,
      oldLayer: _transformLayer,
    );
  }
  
  void _paintDots(PaintingContext context, Offset offset) {
    // context.canvas.scale(100 / scale); // scaling here instead, for values bigger than about 1e13, causes a crash, sometimes of the entire phone
    final coordinates = Float32List.fromList(<double>[
      1 * scale, 3 * scale,
      2 * scale, 4 * scale,
      3 * scale, 5 * scale,
    ]);
    final paint = Paint()
      ..color = const Color(0x7f00cc66)
      ..strokeWidth = scale;
    context.canvas.drawRawPoints(PointMode.points, coordinates, paint);

    // control
    context.canvas.drawCircle(Offset.zero, 10.0 * scale / 8.0, Paint()..color = const Color(0xFF663399));
  }
}
flutter doctor -v
[✓] Flutter (Channel main, 3.24.0-1.0.pre.333, on Ubuntu 22.04.3 LTS 5.15.0-94-generic, locale
    C.UTF-8)
    • Flutter version 3.24.0-1.0.pre.333 on channel main at /home/ianh/dev/flutter
    • Upstream repository [email protected]:flutter/flutter.git
    • Framework revision 634ff77381 (4 days ago), 2024-07-29 14:30:21 -0400
    • Engine revision d1995f302c
    • Dart version 3.6.0 (build 3.6.0-89.0.dev)
    • DevTools version 2.37.1

[✓] Android toolchain - develop for Android devices (Android SDK version 35.0.0)
    • Android SDK at /home/ianh/Android/Sdk
    • Platform android-35, build-tools 35.0.0
    • Java binary at: /home/ianh/bin/android-studio/jbr/bin/java
    • Java version OpenJDK Runtime Environment (build 17.0.11+0-17.0.11b1207.24-11852314)
    • All Android licenses accepted.

[✓] Chrome - develop for the web
    • Chrome at google-chrome

[✓] Linux toolchain - develop for Linux desktop
    • Ubuntu clang version 14.0.0-1ubuntu1.1
    • cmake version 3.22.1
    • ninja version 1.10.1
    • pkg-config version 0.29.2

[✓] Android Studio (version 2024.1)
    • Android Studio at /home/ianh/bin/android-studio
    • 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 17.0.11+0-17.0.11b1207.24-11852314)

[✓] IntelliJ IDEA Community Edition (version 2022.1)
    • IntelliJ at /home/ianh/bin/idea-IC-221.5921.22
    • 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

[✓] Connected device (3 available)
    • Pixel 6a (mobile) • 35301JEGR05976 • android-arm64  • Android 13 (API 33)
    • Linux (desktop)   • linux          • linux-x64      • Ubuntu 22.04.3 LTS 5.15.0-94-generic
    • Chrome (web)      • chrome         • web-javascript • Google Chrome 123.0.6312.58

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

• No issues found!

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 related. See also e: labels.found in release: 3.22Found to occur in 3.22found in release: 3.24Found to occur in 3.24has reproducible stepsThe issue has been confirmed reproducible and is ready to work onr: fixedIssue is closed as already fixed in a newer versionteam-engineOwned by Engine teamtriaged-engineTriaged by Engine team

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions