Skip to content
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

Using dart:ui from non-main-thread Isolates crashes #10647

Open
emshack opened this issue Jun 13, 2017 · 42 comments
Open

Using dart:ui from non-main-thread Isolates crashes #10647

emshack opened this issue Jun 13, 2017 · 42 comments
Labels
c: crash Stack traces logged to the console engine flutter/engine repository. See also e: labels. found in release: 3.7 Found to occur in 3.7 found in release: 3.9 Found to occur in 3.9 has reproducible steps The issue has been confirmed reproducible and is ready to work on P2 Important issues not at the top of the work list team-engine Owned by Engine team triaged-engine Triaged by Engine team

Comments

@emshack
Copy link

emshack commented Jun 13, 2017

Latest update (tl;dr: no current plans): #10647 (comment)

Steps to Reproduce

In a fresh codebase generated by flutter create, I added the following functions and amended the main() function. Code taken from this example:

void echo(SendPort sender) {
  print("echo() the Isolate has been spawned!");
  ReceivePort receivePort = new ReceivePort();
  sender.send(receivePort.sendPort);
  receivePort.listen((data) {
    String msg = data[0];
    SendPort replyTo = data[1];
    print("Isolate received: $msg");
    WidgetsFlutterBinding.ensureInitialized();
    replyTo.send("Greetings from echo() the Isolate!");
  });
}

Future sendReceive(SendPort port, String msg) {
  ReceivePort receivePort = new ReceivePort();
  port.send([msg, receivePort.sendPort]);
  return receivePort.first;
}

void main() {
  ReceivePort receivePort = new ReceivePort();
  Future<Isolate> remote = Isolate.spawn(echo, receivePort.sendPort);
  remote.then((_) => receivePort.first).then((sendPort) {
    sendReceive(sendPort, "message sent from main()").then((msg) {
      print("Main received: $msg");
    });
  });
  runApp(new MyApp());
}

When I comment out the WidgetsFlutterBinding.ensureInitialized(); call, everything runs smoothly. Leaving it in, the app crashes. When I run it in SkyShell with that call left in, I get a seg fault:

echo() the Isolate has been spawned!
Isolate received: message sent from main()
Segmentation fault: 11

What is happening here? Should WidgetsFlutterBinding.ensureInitialized() be able to be called from a spawned Isolate?

Flutter Doctor

[✓] Flutter (on Mac OS X 10.12.5 16F73, locale en-US, channel alpha)
    • Flutter at /Users/emshack/flutter
    • Framework revision e2f54df5ab (10 days ago), 2017-06-02 10:43:54 -0700
    • Engine revision 1f2aa07571
    • Tools Dart version 1.24.0-dev.3.0

[✓] Android toolchain - develop for Android devices (Android SDK 25.0.3)
    • Android SDK at /Users/emshack/Library/Android/sdk
    • Platform android-25, build-tools 25.0.3
    • Java binary at: /Applications/Android Studio.app/Contents/jre/jdk/Contents/Home/bin/java
    • Java version: OpenJDK Runtime Environment (build 1.8.0_112-release-b06)

[✓] iOS toolchain - develop for iOS devices (Xcode 8.3.2)
    • Xcode at /Applications/Xcode.app/Contents/Developer
    • Xcode 8.3.2, Build version 8E2002
    • ios-deploy 1.9.1
    • CocoaPods version 1.2.0

[✓] Android Studio (version 2.3)
    • Android Studio at /Applications/Android Studio.app/Contents
    • Gradle version 3.2
    • Java version: OpenJDK Runtime Environment (build 1.8.0_112-release-b06)

[✓] IntelliJ IDEA Community Edition (version 2016.3.4)
    • Dart plugin version 163.13137
    • Flutter plugin version 12.1

[✓] Connected devices
    • iPhone 7 Plus • 09A7F58D-C832-4D91-B681-F67134E64361 • ios • iOS 10.3 (simulator)
@eseidelGoogle
Copy link
Contributor

eseidelGoogle commented Jun 13, 2017

dart:ui doesn't exist in non-main isolates, so I wouldn't expect much of the Flutter framework to work there. FYI @Hixie.

We're currently in the process of making some improvements to our engine to allow exposing dart:ui on non-main isolates, but those are not yet complete.

@emshack
Copy link
Author

emshack commented Jun 13, 2017

Ok, please let me know when something like this would be possible!

@mishadynin
Copy link
Contributor

This will also help another part of our project where we currently spawn another process and communicate via HTTP as a workaround. So +1 to making this work in an isolate.

@eseidelGoogle
Copy link
Contributor

eseidelGoogle commented Jun 14, 2017

@GaryQian is currently working on wiring up libtxt as our new txt backend. I'm told that's the largest single blocker to being able to use dart:ui off the main thread. I suspect it may be several months before that's all landed and integrated to unblock any off-main-thread dart:ui support at our current schedules though. @abarth or @Hixie may correct my estimates however.

@Hixie
Copy link
Contributor

Hixie commented Jun 14, 2017

Running code that uses dart:ui off the main thread isn't on our priority list, so there's no ETA currently.

@Hixie Hixie changed the title Seg Fault on WidgetsFlutterBinding.ensureInitialized() from Isolate Using dart:ui from non-main-thread Isolates crashes May 1, 2018
@Hixie Hixie added the engine flutter/engine repository. See also e: labels. label May 1, 2018
@Hixie Hixie added this to the Goals milestone May 1, 2018
@Hixie Hixie added the c: crash Stack traces logged to the console label May 1, 2018
@Hixie
Copy link
Contributor

Hixie commented May 1, 2018

@chinmaygarde Any idea what the current status of this is?

We will have to come to a decision on what needs to be supported here by 1.0.

@chinmaygarde
Copy link
Member

Launching multiple Flutter views in their own isolates when their own dedicated threads is now supported (and is the default). Having multiple isolates talk to the same view is not currently supported and is not a priority.

We should probably not crash when WidgetsFlutterBinding.ensureInitialized is called from a secondary isolate however. Happy to work towards understanding if the current scheme of having multiple Flutter views solves @emshack's use case.

@paramita
Copy link

I need this so much, especially for a heavy things like Path.combine.
I'm having a frame running for 3 seconds because there is no way to isolate native executions on Path.

Annotation 2020-04-19 014846

@kf6gpe kf6gpe added the P2 Important issues not at the top of the work list label May 29, 2020
@kf6gpe kf6gpe removed this from the Goals milestone Jun 2, 2020
@Hixie Hixie removed this from the Goals milestone Jun 2, 2020
@sgehrman

This comment was marked as abuse.

@mtiziano
Copy link
Contributor

Same problem

@Hixie Hixie removed this from the None. milestone Aug 17, 2020
@ramesh456
Copy link

Did you guys find any solution to open UI from isolate ?

@darshankawar
Copy link
Member

Issue replicable on latest beta.

I/flutter (16811): echo() the Isolate has been spawned!
I/flutter (16811): Isolate received: message sent from main()
E/flutter (16811): [ERROR:flutter/runtime/dart_isolate.cc(882)] Unhandled exception:
E/flutter (16811): UI actions are only available on root isolate.

Although moving WidgetsFlutterBinding.ensureInitialized(); inside main() method doesn't throw the said error.

flutter doctor -v
[✓] Flutter (Channel beta, 1.22.0-12.2.pre, on Mac OS X 10.15.4 19E2269, locale
    en-IN)
    • Flutter version 1.22.0-12.2.pre at /Users/dhs/documents/Fluttersdk/flutter
    • Framework revision 2bafdc8226 (4 days ago), 2020-09-25 12:48:22 -0700
    • Engine revision f763b5b9b9
    • Dart version 2.10.0 (build 2.10.0-110.5.beta)

[✓] Android toolchain - develop for Android devices (Android SDK version 30.0.0)
    • Android SDK at /Users/dhs/Library/Android/sdk
    • Platform android-30, build-tools 30.0.0
    • Java binary at: /Applications/Android
      Studio.app/Contents/jre/jdk/Contents/Home/bin/java
    • Java version OpenJDK Runtime Environment (build
      1.8.0_242-release-1644-b3-6222593)
    • All Android licenses accepted.

[✓] Xcode - develop for iOS and macOS (Xcode 11.5)
    • Xcode at /Applications/Xcode.app/Contents/Developer
    • Xcode 11.5, Build version 11E608c
    • CocoaPods version 1.9.3

[✓] Chrome - develop for the web
    • Chrome at /Applications/Google Chrome.app/Contents/MacOS/Google Chrome

[✓] Android Studio (version 4.0)
    • Android Studio at /Applications/Android Studio.app/Contents
    • Flutter plugin version 46.0.2
    • Dart plugin version 193.7361
    • Java version OpenJDK Runtime Environment (build
      1.8.0_242-release-1644-b3-6222593)

[✓] VS Code (version 1.49.1)
    • VS Code at /Applications/Visual Studio Code.app/Contents
    • Flutter extension version 3.11.0

 
[✓] Connected device (2 available)            
    • Web Server (web) • web-server • web-javascript • Flutter Tools
    • Chrome (web)     • chrome     • web-javascript • Google Chrome
      85.0.4183.121

• No issues found!

@darshankawar darshankawar added found in release: 1.22 Found to occur in 1.22 has reproducible steps The issue has been confirmed reproducible and is ready to work on labels Sep 29, 2020
@ershat-dl
Copy link

Issue replicable on latest beta.

I/flutter (16811): echo() the Isolate has been spawned!
I/flutter (16811): Isolate received: message sent from main()
E/flutter (16811): [ERROR:flutter/runtime/dart_isolate.cc(882)] Unhandled exception:
E/flutter (16811): UI actions are only available on root isolate.

Although moving WidgetsFlutterBinding.ensureInitialized(); inside main() method doesn't throw the said error.

flutter doctor -v

could you give a small example , please? thank you

@rlueders
Copy link

rlueders commented Dec 7, 2022

From a Flutter application developer’s perspective, dart:ui is no different from any other general purpose dart library. For example, an application developer might use dart:math for literally infinite many use cases, some of which might need to run inside an isolate for performance reasons. The developer would be surprised and disappointed to find that after successfully compiling their Flutter application, a call to dart:math breaks when called from an isolate at runtime. This is exactly what happens with dart:ui as evidenced by the number of issues I have stumbled across that are all asking to use some component of dart:ui in an isolate. Within each of those issues, there are many additional use cases contributed by other users via comments. Most of these use cases are attempting to use dart:ui as a generic drawing or image processing tool.

I gather that there are some “unsafe” components in dart:ui that should not be called from an isolate that can impact application rendering and frame scheduling. But, to reiterate, many of these use cases are looking to use the “safe” components of dart:ui (Canvas, Picture, PictureRecorder, Paint, Path, Radius, Rect, Offset, Image, Gradient, etc.), using dart:ui as a generic drawing or image manipulation tool. But then, why are these "safe" generic drawing utilities packaged with “unsafe” Flutter components? Alternatively, why are the “safe” generic drawing utilities indiscriminately restricted from isolates along with the “unsafe” Flutter components. To go back to the analogy, would it make sense for the Flutter team to restrict dart:math from isolates if there was some special Flutter code packaged with dart:math. Of course it doesn't, but it appears that that is exactly what is happening with dart:ui.

@xErik
Copy link

xErik commented Jan 22, 2023

Use case:

My app generates and saves thousands of images using dart:ui / Canvas.

To speed things up, running multiple isolates is necessary.

As mentioned above, dart:ui is not available in isolates.

@danagbemava-nc
Copy link
Member

Reproduces on the latest versions of flutter. Updating labels.

code sample
import 'dart:isolate';

import 'package:flutter/material.dart';

void echo(SendPort sender) {
  print("echo() the Isolate has been spawned!");
  ReceivePort receivePort = ReceivePort();
  sender.send(receivePort.sendPort);
  receivePort.listen((data) {
    String msg = data[0];
    SendPort replyTo = data[1];
    print("Isolate received: $msg");
    WidgetsFlutterBinding.ensureInitialized();
    replyTo.send("Greetings from echo() the Isolate!");
  });
}

Future sendReceive(SendPort port, String msg) {
  ReceivePort receivePort = ReceivePort();
  port.send([msg, receivePort.sendPort]);
  return receivePort.first;
}

void main() {
  ReceivePort receivePort = ReceivePort();
  Future<Isolate> remote = Isolate.spawn(echo, receivePort.sendPort);
  remote.then((_) => receivePort.first).then((sendPort) {
    sendReceive(sendPort, "message sent from main()").then((msg) {
      print("Main received: $msg");
    });
  });
  runApp(const MyApp());
}

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Material App',
      theme: ThemeData.dark(),
      home: const Home(),
    );
  }
}

class Home extends StatelessWidget {
  const Home({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Material App Bar'),
      ),
      body: const Center(
        child: Text('some text'),
      ),
      floatingActionButton: FloatingActionButton(
        child: const Icon(Icons.add),
        onPressed: () {},
      ),
    );
  }
}
logs
Launching lib/main.dart on macOS in debug mode...
Building macOS application...
--- xcodebuild: WARNING: Using the first of multiple matching destinations:
{ platform:macOS, arch:arm64, id:00008103-000329201AD1001E }
{ platform:macOS, arch:x86_64, id:00008103-000329201AD1001E }
Debug service listening on ws://127.0.0.1:51624/HWY-7KvoUsw=/ws
Syncing files to device macOS...
flutter: echo() the Isolate has been spawned!
flutter: Isolate received: message sent from main()
[ERROR:flutter/runtime/dart_isolate.cc(1097)] Unhandled exception:
UI actions are only available on root isolate.
#0      FfiTrampoline____nativeSetNeedsReportTimings$Method$FfiNative$Ptr (dart:ffi)
#1      PlatformDispatcher.__nativeSetNeedsReportTimings (dart:ui/platform_dispatcher.dart:546:24)
#2      PlatformDispatcher._nativeSetNeedsReportTimings (dart:ui/platform_dispatcher.dart:543:52)
#3      PlatformDispatcher.onReportTimings= (dart:ui/platform_dispatcher.dart:535:29)
#4      SchedulerBinding.addTimingsCallback (package:flutter/src/scheduler/binding.dart:308:26)
#5      SchedulerBinding.initInstances (package:flutter/src/scheduler/binding.dart:240:7)
#6      ServicesBinding.initInstances (package:flutter/src/services/binding.dart:37:11)
#7      PaintingBinding.initInstances (package:flutter/src/painting/binding.dart:20:11)
#8      SemanticsBinding.initInstances (package:flutter/src/semantics/binding.dart:18:11)
#9      RendererBinding.initInstances (package:flutter/src/rendering/binding.dart:30:11)
#10     WidgetsBinding.initInstances (package:flutter/src/widgets/binding.dart:249:11)
#11     new BindingBase (package:flutter/src/foundation/binding.dart:151:5)
#12     new _WidgetsFlutterBinding&BindingBase&GestureBinding (package:flutter/src/widgets/binding.dart)
#13     new _WidgetsFlutterBinding&BindingBase&GestureBinding&SchedulerBinding (package:flutter/src/widgets/binding.dart)
#14     new _WidgetsFlutterBinding&BindingBase&GestureBinding&SchedulerBinding&ServicesBinding (package:flutter/src/widgets/binding.dart)
#15     new _WidgetsFlutterBinding&BindingBase&GestureBinding&SchedulerBinding&ServicesBinding&PaintingBinding (package:flutter/src/widgets/binding.dart)
#16     new _WidgetsFlutterBinding&BindingBase&GestureBinding&SchedulerBinding&ServicesBinding&PaintingBinding&SemanticsBinding (package:flutter/src/widgets/binding.dart)
#17     new _WidgetsFlutterBinding&BindingBase&GestureBinding&SchedulerBinding&ServicesBinding&PaintingBinding&SemanticsBinding&RendererBinding (package:flutter/src/widgets/binding.dart)
#18     new _WidgetsFlutterBinding&BindingBase&GestureBinding&SchedulerBinding&ServicesBinding&PaintingBinding&SemanticsBinding&RendererBinding&WidgetsBinding (package:flutter/src/widgets/binding.dart)
#19     new WidgetsFlutterBinding (package:flutter/src/widgets/binding.dart)
#20     WidgetsFlutterBinding.ensureInitialized (package:flutter/src/widgets/binding.dart:1260:7)
#21     echo.<anonymous closure> (package:ent/main.dart:13:27)
#22     _RootZone.runUnaryGuarded (dart:async/zone.dart:1593:10)
#23     _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:339:11)
#24     _BufferingStreamSubscription._add (dart:async/stream_impl.dart:271:7)
#25     _SyncStreamControllerDispatch._sendData (dart:async/stream_controller.dart:774:19)
#26     _StreamController._add (dart:async/stream_controller.dart:648:7)
#27     _StreamController.add (dart:async/stream_controller.dart:596:5)
#28     _RawReceivePort._handleMessage (dart:isolate-patch/isolate_patch.dart:189:12)
Application finished.
flutter doctor -v
[✓] Flutter (Channel stable, 3.7.7, on macOS 13.2.1 22D68 darwin-arm64, locale en-GB)
    • Flutter version 3.7.7 on channel stable at /Users/nexus/dev/sdks/flutter
    • Upstream repository https://github.com/flutter/flutter.git
    • Framework revision 2ad6cd72c0 (9 days ago), 2023-03-08 09:41:59 -0800
    • Engine revision 1837b5be5f
    • Dart version 2.19.4
    • DevTools version 2.20.1

[✓] Android toolchain - develop for Android devices (Android SDK version 33.0.0)
    • Android SDK at /Users/nexus/Library/Android/sdk
    • Platform android-33, build-tools 33.0.0
    • Java binary at: /Users/nexus/Library/Application Support/JetBrains/Toolbox/apps/AndroidStudio/ch-0/221.6008.13.2211.9477386/Android Studio.app/Contents/jbr/Contents/Home/bin/java
    • Java version OpenJDK Runtime Environment (build 11.0.15+0-b2043.56-8887301)
    • All Android licenses accepted.

[✓] Xcode - develop for iOS and macOS (Xcode 14.2)
    • Xcode at /Applications/Xcode.app/Contents/Developer
    • Build 14C18
    • CocoaPods version 1.11.3

[✓] Chrome - develop for the web
    • Chrome at /Applications/Google Chrome.app/Contents/MacOS/Google Chrome

[✓] Android Studio (version 2022.1)
    • Android Studio at /Applications/Android Studio.app/Contents
    • 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 11.0.15+0-b2043.56-8887301)

[✓] Android Studio (version 2022.1)
    • Android Studio at /Users/nexus/Library/Application Support/JetBrains/Toolbox/apps/AndroidStudio/ch-0/221.6008.13.2211.9477386/Android Studio.app/Contents
    • 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 11.0.15+0-b2043.56-8887301)

[✓] IntelliJ IDEA Community Edition (version 2022.3.3)
    • IntelliJ at /Applications/IntelliJ IDEA CE.app
    • Flutter plugin version 72.1.4
    • Dart plugin version 223.8888

[✓] VS Code (version 1.76.1)
    • VS Code at /Applications/Visual Studio Code.app/Contents
    • Flutter extension version 3.60.0

[✓] Connected device (2 available)
    • macOS (desktop) • macos  • darwin-arm64   • macOS 13.2.1 22D68 darwin-arm64
    • Chrome (web)    • chrome • web-javascript • Google Chrome 111.0.5563.64

[✓] HTTP Host Availability
    • All required HTTP hosts are available

• No issues found!
[!] Flutter (Channel master, 3.9.0-9.0.pre.32, on macOS 13.2.1 22D68 darwin-arm64, locale en-GB)
    • Flutter version 3.9.0-9.0.pre.32 on channel master at /Users/nexus/dev/sdks/flutters
    ! Warning: `flutter` on your path resolves to /Users/nexus/dev/sdks/flutter/bin/flutter, which is not inside your current Flutter SDK checkout at /Users/nexus/dev/sdks/flutters. Consider adding /Users/nexus/dev/sdks/flutters/bin to the front of your path.
    ! Warning: `dart` on your path resolves to /Users/nexus/dev/sdks/flutter/bin/dart, which is not inside your current Flutter SDK checkout at /Users/nexus/dev/sdks/flutters. Consider adding /Users/nexus/dev/sdks/flutters/bin to the front of your path.
    • Upstream repository https://github.com/flutter/flutter.git
    • Framework revision 53dfd23b04 (4 hours ago), 2023-03-17 01:59:19 -0400
    • Engine revision d9e65441ea
    • Dart version 3.0.0 (build 3.0.0-339.0.dev)
    • DevTools version 2.22.2
    • If those were intentional, you can disregard the above warnings; however it is recommended to use "git" directly to perform update checks and upgrades.

[✓] Android toolchain - develop for Android devices (Android SDK version 33.0.0)
    • Android SDK at /Users/nexus/Library/Android/sdk
    • Platform android-33, build-tools 33.0.0
    • Java binary at: /Users/nexus/Library/Application Support/JetBrains/Toolbox/apps/AndroidStudio/ch-0/221.6008.13.2211.9477386/Android Studio.app/Contents/jbr/Contents/Home/bin/java
    • Java version OpenJDK Runtime Environment (build 11.0.15+0-b2043.56-8887301)
    • All Android licenses accepted.

[✓] Xcode - develop for iOS and macOS (Xcode 14.2)
    • Xcode at /Applications/Xcode.app/Contents/Developer
    • Build 14C18
    • CocoaPods version 1.11.3

[✓] Chrome - develop for the web
    • Chrome at /Applications/Google Chrome.app/Contents/MacOS/Google Chrome

[✓] Android Studio (version 2022.1)
    • Android Studio at /Applications/Android Studio.app/Contents
    • 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 11.0.15+0-b2043.56-8887301)

[✓] Android Studio (version 2022.1)
    • Android Studio at /Users/nexus/Library/Application Support/JetBrains/Toolbox/apps/AndroidStudio/ch-0/221.6008.13.2211.9477386/Android Studio.app/Contents
    • 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 11.0.15+0-b2043.56-8887301)

[✓] IntelliJ IDEA Community Edition (version 2022.3.3)
    • IntelliJ at /Applications/IntelliJ IDEA CE.app
    • Flutter plugin version 72.1.4
    • Dart plugin version 223.8888

[✓] VS Code (version 1.76.1)
    • VS Code at /Applications/Visual Studio Code.app/Contents
    • Flutter extension version 3.60.0

[✓] Connected device (2 available)
    • macOS (desktop) • macos  • darwin-arm64   • macOS 13.2.1 22D68 darwin-arm64
    • Chrome (web)    • chrome • web-javascript • Google Chrome 111.0.5563.64

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

! Doctor found issues in 1 category.

@danagbemava-nc danagbemava-nc added found in release: 3.7 Found to occur in 3.7 found in release: 3.9 Found to occur in 3.9 and removed found in release: 1.22 Found to occur in 1.22 labels Mar 17, 2023
@ydotmalik
Copy link

ydotmalik commented Mar 18, 2023

If the Flutter team does not want to fix this issue, can they provide a workaround with a working example?

@MikeFP
Copy link

MikeFP commented Apr 3, 2023

From a Flutter application developer’s perspective, dart:ui is no different from any other general purpose dart library. For example, an application developer might use dart:math for literally infinite many use cases, some of which might need to run inside an isolate for performance reasons. The developer would be surprised and disappointed to find that after successfully compiling their Flutter application, a call to dart:math breaks when called from an isolate at runtime. This is exactly what happens with dart:ui as evidenced by the number of issues I have stumbled across that are all asking to use some component of dart:ui in an isolate. Within each of those issues, there are many additional use cases contributed by other users via comments. Most of these use cases are attempting to use dart:ui as a generic drawing or image processing tool.

I gather that there are some “unsafe” components in dart:ui that should not be called from an isolate that can impact application rendering and frame scheduling. But, to reiterate, many of these use cases are looking to use the “safe” components of dart:ui (Canvas, Picture, PictureRecorder, Paint, Path, Radius, Rect, Offset, Image, Gradient, etc.), using dart:ui as a generic drawing or image manipulation tool. But then, why are these "safe" generic drawing utilities packaged with “unsafe” Flutter components? Alternatively, why are the “safe” generic drawing utilities indiscriminately restricted from isolates along with the “unsafe” Flutter components. To go back to the analogy, would it make sense for the Flutter team to restrict dart:math from isolates if there was some special Flutter code packaged with dart:math. Of course it doesn't, but it appears that that is exactly what is happening with dart:ui.

I second that. In my point of view, there are two main usecases:

  • Run intensive rendering-related code in other Isolates as to not block main thread.
  • Use general classes related to rendering, but not coupled to Flutter, to implement custom render-related code.

The 1st one is harder to implement, since it requires changing the engine, and is related to other limitations of the current state of threading in Dart.

The 2nd one is simpler, and could be easier to implement. I imagine Dart can easily choose to allow importing files from dart:ui that do not import from anything related to Flutter. I don't know if that's possible, but is sounds more doable than solving the 1st point.

Personally, more than a couple times I had to implement code related to rendering, either as a Dart library or to run in an Isolate, not neccessarily on Flutter. Being unable to use Offset, Rect, Size, Color etc. is just a weird decision. Why should I manually implement Rect if there is a perfect implementation available in core? Instead, devs are expected to make them from scratch (a 3rd-party library for those rendering utils would be nice), basically making libraries naturally incompatible with each other, for not adhering to a common interface.

@sgehrman

This comment was marked as duplicate.

@Medit8r
Copy link

Medit8r commented Apr 6, 2023

Would one way of potentially working around this be to use Lightweight flutter engines in a pure Flutter app? (ie. notAdd-to-App). Since instances of the Lightweight flutter engines have their own threads but share some resources they would be fast to start up and perhaps could be used for offscreen rendering? (Please note: I'm a Flutter newbie, so there could be gaps in my understanding, so pardon if it is a stupid question). There are so many use cases which require being able to draw to a canvas in an isolate is required to get Flutter to perform any where near native solutions.

@Somtobro

This comment was marked as duplicate.

@Medit8r

This comment was marked as duplicate.

@hahouari
Copy link

hahouari commented Sep 3, 2023

@Medit8r I hit this issue back in 2021, not sure if I commented here, but seems like this issue is not going to be fixed unless there is a change in the flutter design itself, something I doubt they will pull anytime soon, the project I started back then in flutter I had to rewrite twice to go around this issue with no luck sadly, I went to discover different technologies and as far as I know Xamarin is Xml based, not much what a flutter dev would like to move to, the technology I recommend is Jetpack compose and Compose Multiplatform, developed by JetBrains themselves, I worked with it, they have coroutines where u can pull some ui logic into another thread (if safe to call it a thread), but basically what we exactly want! which is to offload some ui code into another isolate. Kotlin is also super cool as well, so no complains so far, apart from being relatively new, back then I doubted the move from flutter, but looking into 2023, Although flutter is very promising and I like it, I simply don't regret the move I made. So I recommend it to everyone.👌

@rlueders
Copy link

rlueders commented Sep 3, 2023

Isolates from the Flutter Isolates package works fine with calls to dart.ui on both IOS and Android. I have been using it to generate lots of images from a pool of Flutter Isolates.

@chipweinberger
Copy link
Contributor

Just want to add my use case:

I use dart:ui & Canvas to render thousands of video frames.

I'd like to use multiple isolates to increase speed.

@chipweinberger
Copy link
Contributor

chipweinberger commented Jan 31, 2024

I've released a new plugin. https://pub.dev/packages/dart_ui_isolate

It is very similar to the flutter_isolate package, but is specifically for allowing dart:ui to run in an isolate, without the additional complexity of external plugin support.

Due to that, it supports FlutterEngineGroup which saves 100s of megabytes of memory.

@maganap
Copy link

maganap commented Jan 31, 2024

@chipweinberger Thank you for that! We dropped a project a couple of years ago because of this issue. We're planning to give it another chance in the next couple of months, so I'll be testing your plugin then.

@Hellomik2002
Copy link

I've released a new plugin. https://pub.dev/packages/dart_ui_isolate

It is very similar to the flutter_isolate package, but is specifically for allowing dart:ui to run in an isolate, without the additional complexity of external plugin support.

Due to that, it supports FlutterEngineGroup which saves 100s of megabytes of memory.

Can you show an example of how to use it with widgets?

@ignatz
Copy link

ignatz commented Mar 4, 2024

What I understood from @chipweinberger, ui isolates can be used from Android, iOS and OSX. Are there any plans to support the other platforms?

Independently, even when using this functionality on supported platforms, I'm either holding it wrong or it's pretty clunky. Let's say I rasterize an image with dart:ui on a child ui isolate, I then have to copy the image bytes into the dart isolate to then send it over, to then decode the image which will copy the bytes back to native. Naively, I would have hope to use ImageDescriptor, i.e. just sending a pointer to the image in memory, however ImageDescriptor doesn't seem to be serializable1. With this new functionality, should it be?

Can you show an example of how to use it with widgets?

Non-authoritatively: I don't think that's an intended use-case


Footnotes

  1. Unhandled Exception: Invalid argument: is a regular instance reachable via : Instance of '_NativeImageDescriptor'

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
c: crash Stack traces logged to the console engine flutter/engine repository. See also e: labels. found in release: 3.7 Found to occur in 3.7 found in release: 3.9 Found to occur in 3.9 has reproducible steps The issue has been confirmed reproducible and is ready to work on P2 Important issues not at the top of the work list team-engine Owned by Engine team triaged-engine Triaged by Engine team
Projects
None yet
Development

No branches or pull requests