-
Notifications
You must be signed in to change notification settings - Fork 28.2k
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
[Impeller] Drawing lines results in ugly, jagged and aliased lines with Impeller, compared to Skia. #138682
Comments
Found this issue related, similar drawing bug: #121696 Hope that Impeller will at some point produce beautiful antialiased lines also, and at least if not exactly similar, then at least close to the results that Skia is achieving. We can't use Impeller right now because of this issue, the vector shape drawing quality is a very important factor in the app we are currently developing. Good thing is it works very well with Skia already. |
Hi @Sakari369, can you check on the master channel to see if this issue reproduces for you? I can quite discern any different between SKIA (left) and Impeller(Right) |
Hey @danagbemava-nc, thanks for the fast reply. That's pretty interesting .. for me, the results are different still.
Wondering why this is working with you and not with me 🤔 Tried cleaning the project also before building, no change. Saw some other comments in #121696 mentioning that similar issue would have been fixed already in master, and somebody saying it's still showing the erroneous drawing, maybe related ? |
I wonder if a difference is display resolution might be at play here. I tested on my iPad and I can see the difference clearly, on the latest master as well. Labeling for further investigation. code sample(for convenience)import 'package:flutter/material.dart';
import 'dart:math';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter lines antialiasing bug on Impeller',
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
useMaterial3: true,
),
home: MyHomePage()
);
}
}
class MyHomePage extends StatefulWidget {
@override
State<MyHomePage> createState() => _MyHomePageState();
}
class MyPainter extends CustomPainter {
final double zoom;
MyPainter({this.zoom = 0.3});
@override
void paint(Canvas canvas, Size size) {
double strokeWidth = 2.0;
Paint paintRed = Paint()
..strokeWidth = strokeWidth
..style = PaintingStyle.stroke
..color = const Color(0xFFFF0000);
Paint paintBlue = Paint()
..strokeWidth = strokeWidth
..style = PaintingStyle.stroke
..color = const Color(0xFF0000FF);
Paint paintGreen = Paint()
..strokeWidth = strokeWidth
..style = PaintingStyle.stroke
..color = const Color(0xFF00FF00);
double dist = 48;
canvas.save();
canvas.translate((size.width/2) - dist, size.height/2);
canvas.scale(zoom, zoom);
for (double radius=1100; radius>2; radius -= 64) {
final path = Path();
path.moveTo(radius * cos(0), radius * sin(0));
for (int i = 0; i < 6; i++) {
path.lineTo(
radius * cos(pi * i / 3),
radius * sin(pi * i / 3)
);
}
path.close();
canvas.drawPath(path, paintRed);
}
canvas.restore();
canvas.save();
canvas.translate((size.width/2), size.height/2);
canvas.scale(zoom, zoom);
for (double radius=1100; radius>2; radius -= 64) {
final path = Path();
path.moveTo(radius * cos(0), radius * sin(0));
for (int i = 0; i < 6; i++) {
path.lineTo(
radius * cos(pi * i / 3),
radius * sin(pi * i / 3)
);
}
path.close();
canvas.drawPath(path, paintBlue);
}
canvas.restore();
canvas.save();
canvas.translate((size.width/2) + dist, size.height/2);
canvas.scale(zoom, zoom);
for (double radius=1100; radius>2; radius -= 64) {
final path = Path();
path.moveTo(radius * cos(0), radius * sin(0));
for (int i = 0; i < 6; i++) {
path.lineTo(
radius * cos(pi * i / 3),
radius * sin(pi * i / 3)
);
}
path.close();
canvas.drawPath(path, paintGreen);
}
canvas.restore();
}
@override bool shouldRepaint(CustomPainter oldDelegate) => true;
}
class _MyHomePageState extends State<MyHomePage>
with SingleTickerProviderStateMixin {
late AnimationController _controller;
late Animation<double> _zoomAnimation;
@override
void initState() {
super.initState();
_controller = AnimationController(
vsync: this,
duration: const Duration(seconds: 15),
);
_zoomAnimation = Tween<double>(begin: 0.10, end: 0.20)
.animate(_controller)
..addListener(() {
setState(() {});
});
_controller.forward();
}
@override void dispose() {
_controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: const Color(0xFF000000),
body: Center(
child: CustomPaint(
size: const Size(1280, 1280), // size of canvas
painter: MyPainter(zoom: _zoomAnimation.value),
),
)
);
}
} flutter doctor -v
|
I tested on my 2560x1440 resolution external display, and also on my MacBook Pro retina display, and on two different iPads, all show the buggy behaviour with Impeller. Thank you for taking this forwards! |
Just to clarify, this same behaviour can be seen on iOS and Android. |
I investigated this a bit and found that we're not hitting the minimum stroke width, therefore the problem is primarily driven by anti-aliasing differences between Impeller and Skia. |
Thanks for the update, yeah that's what I thought by looking at the line drawing differences. |
@chinmaygarde had the suggestion that we could adjust the sizes of the lines + the apparent opacity to easily give them a better appearance. Waiting for more details on that. |
The more I look at this the less I can tell a difference between Skia and Impeller. Two questions Sakari369 , does this repro for you at ToT and what particular iPad models does it repro on otherwise? Its possible the iPhone I'm using is high enough resolution that it doesn't matter. |
The difference is definitely there. But at least the line widths below 1.0 (?) don't even matter with Impeller right now, and especially the interference patterns created by small lines, there you can see it clearly. Can you see the difference here? I tried to showcase it here on one of the progress videos of our app. What is ToT ? |
ToT is tip of tree aka latest master channel. |
Ah okay, I have not tested on that. Tested on 3.22, I can try master branch soon and report back 👍 |
We've been discussing various ways of addressing such differences within the bounds of the techniques currently used and I think we have a few leads. As I understand, this difference occurs when the stroke width is not quite a hairline but also not too wide. For both hairlines and wide stroke sizes, results are acceptable. The observation being that thin lines in a narrow stroke width range are "too opaque". The current thinking is that we can make the falloff more prominent by adjusting the sample contributions and also perhaps by adjusting the opacity within this narrow range of stroke widths (though Jonah mentions he didn't get good results using just this tweak). I prototyped a few techniques that showed some promise by allowing us to tinker on these parameters. Where I am stuck at the moment is figuring out a device on which this happens reliably to ensure we just don't make things worse. My observations on all devices I have are similar to the earlier comment. For this reason, I am removing this issue from the slimpeller blockers as those track on-device blockers. It may also be a good idea to port the the original posters code to a playground so we can tinker more easily as I found going through the framework to the adjust sizes and such to be a bit of a pain. More to come. |
Hey, thanks for looking at this. Easy way to see difference, is to run the provided example inside iOS Simulator, I did so using the 10.9 inch iPad device.
I ran the provided example project, both with '--no-enable-impeller' and without adding that flag using the Impeller engine. Here are the shots, magnified 300% to see more clearly: First, Skia version: Then the Impeller version: Here are versions with exposure increased in Affinity Photo, to see the difference more clearly: First Skia, looking good: Then Impeller, blocking us from using this: We are developing an application that draws a lot of thing vector lines, and the quality difference is very noticeable. I can maybe turn the project into a playground, but it is very easy to already run through the example project, no ? Anyway. maybe it is not so easy to see on a high DPI display, so I recommend running this on a normal DPI monitor inside the Simulator, you should see the difference clearly. And if it happens in the simulator, it is happening on the device also. |
If all the devices we support have retina-ish I'm not sure that is necessarily the case? We certainly don't want things to look bad on the simulator at any rate, but this may be sim specific for your example. |
Well I've observed the line rendering both on the device and simulator, and it is quite the same. Unfortunately I dont have my developer license right now up to date, waiting to get that re-newed, should be able to test next week on a device and try to showcase it from there. But according to my experience the simulator and device render the same contents, after all, what would be the point if that would differ ? Anyway the quality difference is more pronounced when you have a lot of lines going on and interfering, here are a couple of shots from our in development app: (expand images to see the difference better) With Skia: With Impeller: Trust me, I have looked at how to render beautiful lines for a long time, implemented many different methods myself also just to test out what works, I've written my own shaders for rendering lines, and I've observed and tested many different methods for rendering beautiful lines, it's not definitely an easy problem to solve with high quality results. Skia has nailed down that rendering to a point, so not wondering that Impeller has trouble matching that quality. We can always hopefully continue using Skia backend, so in that matter, it's not a total killer for us, and I know that our usecase is out of the ordinary, but we are trying to create a truly beautiful application here, and this kind of small details matter. |
I can make a playground demo that demonstrates the quality issues better and easier, but can't get to it right now as have other deadline on my back, but maybe that can help you see this quality difference ? |
No need to make a playground or anything like that. I want to make a distinction here, its not that we're looking for proof that there is pixelation on a desktop device, its that we're uncertain that there is pixelation on a physical iOS device. The artifacts are a result of the DPI of the screen. On mobile devices (and iOS devices in particular), the DPI is much higher than desktop monitors, which is why we don't think this is necessarily a problem for real devices. Unfortunately the simulators can only simulate so much. They can't effectively emulate the hardware features of iOS devices (which is why they're unusable for performance metrics) and they can't simulate the higher DPI either. Skia has very nice analytical approaches for AA. But we don't think we need these approaches for mobile screens;not using them lets Impeller be faster + smaller, while also fixing well known rendering artifacts caused by the analytical AA like #14288 . Now if this is a problem on physical devices, we can always use the technique that @chinmaygarde outlined to pump the fidelity a bit. |
Okay, making me jump through some hoops here :) but it seems I can run it on my device without having a valid ADC license these days, so I ran it on my 10.2" 9th gen iPad (using current master), here are the screenshots from the actual device: Skia: Impeller: I don't know maybe you just didn't see the difference when testing, but I guess it's pretty obvious ? Expand again and compare the full resolution screenshots. Hoping of course that quality would be up to par with Skia, as Skia line rendering is very essential to our app. |
Thanks, we'll look at getting a similar device so we can eyeball it in person. |
A suggestion here, how about having quality option for the line and vector rendering ? I would see it useful for applications that need to draw high quality vector graphics, to have analytical AA, with the best possible quality. For drawing the UI you would not probably need such high quality rendering. Personally, I love what Skia has done with the vector and line rendering quality. Would be a shame if you could not do that with Impeller at all. Of course platform views might be an option to do that, just have a single texture view that is rendered on the platform side with Skia linked to the application, if it's not possible with Impeller in the future. Or do you know if there are any plans to support like having Skia render only like contents of a CustomPainter for example ? Just thinking out loud here. |
This comment was marked as off-topic.
This comment was marked as off-topic.
@ZahraVe please file a new bug. |
We have a prototype of anti aliased lines we're currentlly investigating how much work it is to add to Impeller |
Thanks for the update! Was wondering if any update on this, as 3.29 removing opting out of Skia on iOS is gonna prevent us from updating from 3.27. Let me know if you need any help in testing ! |
issue: #138682 design doc: https://docs.google.com/document/d/19I6ToHCMlSgSava-niFWzMLGJEAd-rYiBQEGOMu8IJg/edit?tab=t.0 This puts an experimental line drawing approach behind the following flags: - iOS: `FLTAntialiasLines` boolean, default NO - Android: `io.flutter.embedding.android.ImpellerAntialiasLines` boolean, default false Right now they just support DrawLines and don't support line caps. A test was added that works as a playground for vulkan, opengles and metal. Only the Metal version was turned into a golden test though here. ## Pre-launch Checklist - [x] I read the [Contributor Guide] and followed the process outlined there for submitting PRs. - [x] I read the [Tree Hygiene] wiki page, which explains my responsibilities. - [x] I read and followed the [Flutter Style Guide], including [Features we expect every widget to implement]. - [x] I signed the [CLA]. - [x] I listed at least one issue that this PR fixes in the description above. - [x] I updated/added relevant documentation (doc comments with `///`). - [x] I added new tests to check the change I am making, or this PR is [test-exempt]. - [x] I followed the [breaking change policy] and added [Data Driven Fixes] where supported. - [x] All existing and new tests are passing. If you need help, consider asking for advice on the #hackers-new channel on [Discord]. <!-- Links --> [Contributor Guide]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#overview [Tree Hygiene]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md [test-exempt]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#tests [Flutter Style Guide]: https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md [Features we expect every widget to implement]: https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md#features-we-expect-every-widget-to-implement [CLA]: https://cla.developers.google.com/ [flutter/tests]: https://github.com/flutter/tests [breaking change policy]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#handling-breaking-changes [Discord]: https://github.com/flutter/flutter/blob/main/docs/contributing/Chat.md [Data Driven Fixes]: https://github.com/flutter/flutter/blob/main/docs/contributing/Data-driven-Fixes.md
Is there an existing issue for this?
Steps to reproduce
Expected results
Would expect the vector path and line drawing to match that of Skia, at least close to the quality or producing beautiful results.
Actual results
The rendered lines are ugly, jagged, aliased and are too opaque and bright compared to Skia.
Code sample
Code sample
See repository with example generating the screenshots below: https://github.com/Sakari369/flutter_lines_bug
Screenshots or Video
Screenshots / Video demonstration
Line rendering with Skia:
Line rendering with Impeller:
Logs
Logs
If I paste the logs here, github wont let me make the issue
Flutter Doctor output
Doctor output
The text was updated successfully, but these errors were encountered: