Skip to content

[Impeller][Vulkan] BlendMode.difference and BlendMode.exclusion draw grey thin line on canvas. #179547

Closed

Description

@shvets-oleksii

Steps to reproduce

Use BlendMode.difference or BlendMode.exclusion when draw something on canvas.

  • Tested on Android.

With default Impeller setup

  • Reproduced on Moto G13 (Android 14)
  • Not reproduced on Samsung Galaxy S10 (Android 12)
  • Not reproduced on Android emulators

OpenGl ES backend enabled

<meta-data android:name="io.flutter.embedding.android.ImpellerBackend" android:value="opengles" />

  • Not reproduced on Moto G13
  • Not reproduced on Samsung Galaxy S10
  • Not reproduced on Android emulators

Vulkan backend enabled

<meta-data android:name="io.flutter.embedding.android.ImpellerBackend" android:value="vulkan" />

  • Reproduced on Moto G13
  • Reproduced on Samsung Galaxy S10
  • Reproduced on Android emulators

Expected results

No any grey line present.

Actual results

Grey line present

Code sample

Code sample
void main() {
  runApp(const MyApp());
}

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

  @override
  Widget build(BuildContext context) {
    return PaintDemoApp();
  }
}

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(colorScheme: .fromSeed(seedColor: Colors.deepPurple)),
      home: Container(
        width: 400,
        height: 400,
        decoration: BoxDecoration(
          color: Colors.white,
          border: Border.all(color: Colors.green),
        ),
        child: CustomPaint(painter: DifferencePainter()),
      ),
    );
  }
}

class DifferencePainter extends CustomPainter {
  @override
  void paint(Canvas canvas, Size size) {
    final center = Offset(size.width / 2, size.height / 2);
    final rect = Rect.fromLTWH(0, 0, size.width, size.height);

    canvas.saveLayer(rect, Paint());

    final paintSquare = Paint()
      ..color = Colors.blue
      ..style = PaintingStyle.fill;

    const squareSize = 150.0;
    final squareRect = Rect.fromCenter(
      center: center.translate(-48, 0),
      width: squareSize,
      height: squareSize,
    );

    canvas.drawRect(squareRect, paintSquare);

    final paintCircle = Paint()
      ..color = Colors.yellow
      //TODO: Please try BlendMode.exclusion also
      ..blendMode = BlendMode.difference
      ..style = PaintingStyle.fill;

    const circleRadius = 80.0;
    final circleCenter = center.translate(48, 0);

    canvas.drawCircle(circleCenter, circleRadius, paintCircle);

    canvas.restore();

    final paintStroke = Paint()
      ..color = Colors.green
      ..style = PaintingStyle.stroke
      ..strokeWidth = 2.0;

    canvas.drawRect(squareRect, paintStroke);
    canvas.drawCircle(circleCenter, circleRadius, paintStroke);
  }

  @override
  bool shouldRepaint(covariant CustomPainter oldDelegate) {
    return false;
  }
}

Screenshots or Video

Screenshots / Video demonstration Actual Expected

Logs

Flutter Doctor output

Doctor output
[✓] Flutter (Channel stable, 3.38.4, on macOS 26.1 25B78 darwin-arm64, locale en-US) [232ms]
    • Flutter version 3.38.4 on channel stable at /Users/oleksii/development/flutter
    • Upstream repository https://github.com/flutter/flutter.git
    • Framework revision 66dd93f9a2 (3 days ago), 2025-12-03 14:56:10 -0800
    • Engine revision a5cb96369e
    • Dart version 3.10.3
    • DevTools version 2.51.1
    • Feature flags: enable-web, no-enable-linux-desktop, no-enable-macos-desktop, no-enable-windows-desktop, enable-android, enable-ios,
      cli-animations, enable-native-assets, omit-legacy-version-file, enable-lldb-debugging

[✓] Android toolchain - develop for Android devices (Android SDK version 36.0.0) [958ms]
    • Android SDK at /Users/oleksii/Library/Android/sdk
    • Emulator version 36.3.10.0 (build_id 14472402) (CL:N/A)
    • Platform android-36, build-tools 36.0.0
    • ANDROID_HOME = /Users/oleksii/Library/Android/sdk
    • Java binary at: /Applications/Android Studio.app/Contents/jbr/Contents/Home/bin/java
      This is the JDK bundled with the latest Android Studio installation on this machine.
      To manually set the JDK path, use: `flutter config --jdk-dir="path/to/jdk"`.
    • Java version OpenJDK Runtime Environment (build 21.0.8+-14196175-b1038.72)
    • All Android licenses accepted.

[✓] Xcode - develop for iOS and macOS (Xcode 26.1.1) [608ms]
    • Xcode at /Applications/Xcode.app/Contents/Developer
    • Build 17B100
    • CocoaPods version 1.16.2

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

[✓] Connected device (3 available) [5.9s]
    • SM G973F (mobile)           • RF8NB010WGW   • android-arm64  • Android 12 (API 31)
    • sdk gphone64 arm64 (mobile) • emulator-5554 • android-arm64  • Android 12 (API 31) (emulator)
    • Chrome (web)                • chrome        • web-javascript • Google Chrome 143.0.7499.40

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

• No issues found!

Activity

  1. shvets-oleksii commented on Dec 7, 2025

    @shvets-oleksii
    Author
  2. darshankawar commented on Dec 8, 2025

    @darshankawar
    Member

    Thanks for the detailed report. I was able to replicate the reported behavior on S10+ device with vulkan rendering using latest stable and master versions. This doesn't occur with OpenGLES rendering.

    stable: 3.38.4
    master: 3.40.0-1.0.pre-55
    
  3. added
    platform-androidAndroid applications specifically
    e: impellerImpeller rendering backend issues and features requests
    engineflutter/engine related. See also e: labels.
    has reproducible stepsThe issue has been confirmed reproducible and is ready to work on
    in triagePresently being triaged by the triage team
    and removed
    platform-androidAndroid applications specifically
    engineflutter/engine related. See also e: labels.
    in triagePresently being triaged by the triage team
    e: impellerImpeller rendering backend issues and features requests
    on Dec 8, 2025
  4. 4 remaining items

  5. added and removed
    in triagePresently being triaged by the triage team
    on Dec 8, 2025
  6. chinmaygarde commented on Dec 8, 2025

    @chinmaygarde
    Contributor

    Thanks for the excellent bug report with a clear reproduction steps. Based on details, it seems like an issue with Vulkan rendering on all devices.

  7. added
    P2Important issues not at the top of the work list
    on Dec 8, 2025
  8. sabreys commented on Dec 9, 2025

    @sabreys

    We encountered the same issue. On older Vulkan devices, the border lines of the inputs behind the bottomsheets are visible.

  9. jason-simmons commented on Dec 13, 2025

    @jason-simmons
    Contributor

    Reproduced this on a Pixel 6a.

    This issue does not occur if I patch the engine to disable framebuffer fetch in the Impeller Vulkan back end.

  10. gaaclarke commented on Jan 15, 2026

    @gaaclarke
    Member

    I stepped through this with a frame debugger, here's what I saw:

    1. When the circle is being drawn the resulting texture has no line.
    2. When that texture is then composited with the advanced blend the line appears
    3. The texture of the circle being drawn has the dimensions (422, 421) which is super suspicious because a circle should have a perfect square.
    4. The output of the vertex shader is a quad mesh whose diagonal line coincides with the artifact we are seeing
    5. Eyeballing the artifacts it looks like it is colored based on the color below the circle.
    6. Zooming into the artifact you can see it's not a perfect diagonal line. Sometimes it goes straight left, sometimes diagonally left-down

    Given all this info I believe the artifact is a result of slighting squishing the texture that is being drawn. I'd investigate why the texture doesn't have a square size and I'm audit the vertex shader's operation.

  11. gaaclarke commented on Jan 21, 2026

    @gaaclarke
    Member

    The problem doesn't manifest on my pixel 4a with vulkan (note: I had to hack the engine to enable vulkan since this device has been blocked from vulkan for other reasons)

    Image
  12. jason-simmons commented on Jan 21, 2026

    @jason-simmons
    Contributor

    I can reproduce it using this Impeller unit test when running with Vulkan on a Linux VM:

    TEST_P(DisplayListTest, Bug179547) {
      flutter::DisplayListBuilder builder;
    
      flutter::DlPaint paint_square;
      paint_square.setColor(flutter::DlColor::kBlue());
      paint_square.setDrawStyle(flutter::DlDrawStyle::kFill);
      builder.DrawRect(flutter::DlRect::MakeXYWH(50, 50, 400, 400), paint_square);
    
      flutter::DlPaint paint_circle;
      paint_circle.setColor(flutter::DlColor::kYellow());
      paint_circle.setDrawStyle(flutter::DlDrawStyle::kFill);
      paint_circle.setBlendMode(flutter::DlBlendMode::kDifference);
      builder.DrawCircle(DlPoint(450, 250), 200, paint_circle);
    
      ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
    }
    
  13. jason-simmons commented on Jan 21, 2026

    @jason-simmons
    Contributor

    The problem doesn't manifest on my pixel 4a with vulkan (note: I had to hack the engine to enable vulkan since this device has been blocked from vulkan for other reasons)

    To reproduce this, make sure that the Impeller Vulkan back end is using framebuffer fetch.

    Impeller disables usage of framebuffer fetch on some devices. See the rules in https://github.com/flutter/flutter/blob/master/engine/src/flutter/impeller/renderer/backend/vulkan/workarounds_vk.cc that set the input_attachment_self_dependency_broken flag.

    That flag is currently set for the older Adreno GPU in the Pixel 4a.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

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.38Found to occur in 3.38found in release: 3.40Found to occur in 3.40has reproducible stepsThe issue has been confirmed reproducible and is ready to work onplatform-androidAndroid applications specificallyteam-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