Don't use UberSDF for paint with incompatible blend modes#184889
Conversation
There was a problem hiding this comment.
Code Review
This pull request adds a unit test for blend modes and introduces the IsCompatibleWithUberSDF helper function in canvas.cc to refine the conditions under which SDFs are used in DrawRect and DrawCircle. A review comment suggests adding a default case to the switch statement within IsCompatibleWithUberSDF to prevent potential undefined behavior and ensure compliance with the Google C++ Style Guide.
| switch (paint.blend_mode) { | ||
| // Incompatible blend modes: | ||
| case BlendMode::kClear: | ||
| case BlendMode::kSrc: | ||
| case BlendMode::kSrcIn: | ||
| case BlendMode::kDstIn: | ||
| case BlendMode::kSrcOut: | ||
| case BlendMode::kDstATop: | ||
| case BlendMode::kModulate: | ||
| return false; | ||
| // Compatible blend modes: | ||
| case BlendMode::kDst: | ||
| case BlendMode::kSrcOver: | ||
| case BlendMode::kDstOver: | ||
| case BlendMode::kDstOut: | ||
| case BlendMode::kSrcATop: | ||
| case BlendMode::kXor: | ||
| case BlendMode::kPlus: | ||
| case BlendMode::kScreen: | ||
| case BlendMode::kOverlay: | ||
| case BlendMode::kDarken: | ||
| case BlendMode::kLighten: | ||
| case BlendMode::kColorDodge: | ||
| case BlendMode::kColorBurn: | ||
| case BlendMode::kHardLight: | ||
| case BlendMode::kSoftLight: | ||
| case BlendMode::kDifference: | ||
| case BlendMode::kExclusion: | ||
| case BlendMode::kMultiply: | ||
| case BlendMode::kHue: | ||
| case BlendMode::kSaturation: | ||
| case BlendMode::kColor: | ||
| case BlendMode::kLuminosity: | ||
| return true; | ||
| } |
There was a problem hiding this comment.
The switch statement is unnecessarily verbose and lacks a default case. This can lead to undefined behavior if the BlendMode enum is extended in the future without updating this function, as it would reach the end of a non-void function without a return statement.
Following the Google C++ Style Guide (referenced in the repository style guide), it is safer and more maintainable to list only the incompatible modes and use a default case to return true for all others. This ensures the function always returns a value and improves readability.
switch (paint.blend_mode) {
// Incompatible blend modes:
case BlendMode::kClear:
case BlendMode::kSrc:
case BlendMode::kSrcIn:
case BlendMode::kDstIn:
case BlendMode::kSrcOut:
case BlendMode::kDstATop:
case BlendMode::kModulate:
return false;
default:
return true;
}References
- C++ code should follow the Google C++ Style Guide. Switch statements should generally have a default case, and non-void functions must return a value on all paths to avoid undefined behavior. (link)
There was a problem hiding this comment.
Default is not needed when the cases cover every enum value. This won't compile if not every enum value is handled. This ensures that if a new value is added in the future, it must be explicitly added here and we won't unintentionally let it slip through a default case.
There was a problem hiding this comment.
It compiles with the default I believe, but I like seeing every one of them for reviewing the correctness.
|
Golden file changes have been found for this pull request. Click here to view and triage (e.g. because this is an intentional change). If you are still iterating on this change and are not ready to resolve the images on the Flutter Gold dashboard, consider marking this PR as a draft pull request above. You will still be able to view image results on the dashboard, commenting will be silenced, and the check will not try to resolve itself until marked ready for review. For more guidance, visit Writing a golden file test for Reviewers: Read the Tree Hygiene page and make sure this patch meets those guidelines before LGTMing. |
flar
left a comment
There was a problem hiding this comment.
I'm still looking over the math, but wanted to recommend adding a comment...
| ); | ||
| } | ||
|
|
||
| bool IsCompatibleWithUberSDF(const Paint& paint) { |
There was a problem hiding this comment.
Add a comment that (for now?) we implement the SDF shader as just a modulation of the alpha of the color and only blend modes for which a modulation of alpha towards 0 is equivalent to modulating it towards a NOP are compatible...?
There was a problem hiding this comment.
I think a good expression of the constraint is this equation, does this make sense to anyone but me?
mix(blend(src, dst), dst, sdf_result) == blend(src * sdf_result, dst)
There was a problem hiding this comment.
Done. I updated this PR to have a test that checks this condition for every blend mode.
My original eyeball-based categorization of the blend modes were mostly correct. The only one that changed was BlendMode::kPlus, which is now correctly put in the incompatible category.
| switch (paint.blend_mode) { | ||
| // Incompatible blend modes: | ||
| case BlendMode::kClear: | ||
| case BlendMode::kSrc: | ||
| case BlendMode::kSrcIn: | ||
| case BlendMode::kDstIn: | ||
| case BlendMode::kSrcOut: | ||
| case BlendMode::kDstATop: | ||
| case BlendMode::kModulate: | ||
| return false; | ||
| // Compatible blend modes: | ||
| case BlendMode::kDst: | ||
| case BlendMode::kSrcOver: | ||
| case BlendMode::kDstOver: | ||
| case BlendMode::kDstOut: | ||
| case BlendMode::kSrcATop: | ||
| case BlendMode::kXor: | ||
| case BlendMode::kPlus: | ||
| case BlendMode::kScreen: | ||
| case BlendMode::kOverlay: | ||
| case BlendMode::kDarken: | ||
| case BlendMode::kLighten: | ||
| case BlendMode::kColorDodge: | ||
| case BlendMode::kColorBurn: | ||
| case BlendMode::kHardLight: | ||
| case BlendMode::kSoftLight: | ||
| case BlendMode::kDifference: | ||
| case BlendMode::kExclusion: | ||
| case BlendMode::kMultiply: | ||
| case BlendMode::kHue: | ||
| case BlendMode::kSaturation: | ||
| case BlendMode::kColor: | ||
| case BlendMode::kLuminosity: | ||
| return true; | ||
| } |
There was a problem hiding this comment.
It compiles with the default I believe, but I like seeing every one of them for reviewing the correctness.
|
This pull request has been changed to a draft. The currently pending flutter-gold status will not be able to resolve until a new commit is pushed or the change is marked ready for review again. For more guidance, visit Writing a golden file test for Reviewers: Read the Tree Hygiene page and make sure this patch meets those guidelines before LGTMing. |
There was a problem hiding this comment.
Code Review
This pull request introduces the IsCompatibleWithSDFRendering helper function to centralize Signed Distance Field (SDF) rendering compatibility logic and updates drawing methods to use it. A unit test was added to verify blend mode compatibility. Feedback identifies a missing return statement in the new function that could cause undefined behavior and recommends using an epsilon for color comparisons in tests to avoid issues with floating-point precision.
| case BlendMode::kLuminosity: | ||
| return true; | ||
| } | ||
| } |
There was a problem hiding this comment.
The IsCompatibleWithSDFRendering function is missing a return statement after the switch block. If paint.blend_mode contains a value not explicitly handled in the switch (e.g., via an invalid cast or a future enum addition), the function will reach the end without returning a value, which is undefined behavior in C++. Adding a default return of false ensures safety and satisfies compiler requirements.
| case BlendMode::kLuminosity: | |
| return true; | |
| } | |
| } | |
| case BlendMode::kLuminosity: | |
| return true; | |
| } | |
| return false; | |
| } |
There was a problem hiding this comment.
We don't want a default. We explicitly want every case to be listed. If one is missing, it's a compilation error, which is what we want to happen.
| if (blended_then_sdf_alpha_applied != | ||
| sdf_alpha_applied_then_blended) { |
There was a problem hiding this comment.
Comparing colors using the != operator performs an exact floating-point comparison for each component (r, g, b, a). Since Color::Lerp and Color::Blend involve multiple floating-point operations, small precision differences are likely to occur between the two calculation paths. This can lead to compatible blend modes being incorrectly marked as incompatible, making the test fragile. Consider using a small epsilon for the comparison.
auto colors_nearly_equal = [](const Color& a, const Color& b) {
return std::abs(a.r - b.r) < 1e-4 && std::abs(a.g - b.g) < 1e-4 &&
std::abs(a.b - b.b) < 1e-4 && std::abs(a.a - b.a) < 1e-4;
};
if (!colors_nearly_equal(blended_then_sdf_alpha_applied,
sdf_alpha_applied_then_blended)) {There was a problem hiding this comment.
The equality operator for colors already has a built-in epsilon:
flutter/engine/src/flutter/impeller/geometry/color.h
Lines 167 to 170 in 4c7bc6a
|
Golden file changes are available for triage from new commit, Click here to view. For more guidance, visit Writing a golden file test for Reviewers: Read the Tree Hygiene page and make sure this patch meets those guidelines before LGTMing. |
flar
left a comment
There was a problem hiding this comment.
LGTM (Some suggestions for the test case)
|
autosubmit label was removed for flutter/flutter/184889, because - The status or check suite Mac tool_integration_tests_2_5 has failed. Please fix the issues identified (or deflake) before re-applying this label. |
|
autosubmit label was removed for flutter/flutter/184889, because - The status or check suite Mac mac_unopt has failed. Please fix the issues identified (or deflake) before re-applying this label. |
|
Golden file changes are available for triage from new commit, Click here to view. For more guidance, visit Writing a golden file test for Reviewers: Read the Tree Hygiene page and make sure this patch meets those guidelines before LGTMing. |
…11595) Manual roll Flutter from 31001886cbe8 to 61fca76dd523 (53 revisions) Manual roll requested by tarrinneal@google.com flutter/flutter@3100188...61fca76 2026-04-27 30870216+gaaclarke@users.noreply.github.com Adds integration test for the FLTEnableSDFs flag for iOS (flutter/flutter#185637) 2026-04-27 97480502+b-luk@users.noreply.github.com Fix sdfs being enabled for MacOS regardless of FLTEnableSDFs value (flutter/flutter#185565) 2026-04-27 97480502+b-luk@users.noreply.github.com Don't use UberSDF for paint with incompatible blend modes (flutter/flutter#184889) 2026-04-27 engine-flutter-autoroll@skia.org Roll Dart SDK from de495e3de9a0 to 941ca325cfc9 (2 revisions) (flutter/flutter#185653) 2026-04-27 jhy03261997@gmail.com [a11y] Add CONTENT_CHANGE_TYPE_EXPANDED support on android. (flutter/flutter#185305) 2026-04-27 137456488+flutter-pub-roller-bot@users.noreply.github.com Roll pub packages (flutter/flutter#185641) 2026-04-27 1063596+reidbaker@users.noreply.github.com Modify analyze.dart to have flags to run only or exclude each verification step. (flutter/flutter#185618) 2026-04-27 meylis@divine.video Fix debugNeedsPaint/Layout/CompositedLayerUpdate crashing in release mode (flutter/flutter#184627) 2026-04-27 kallentu@google.com Enable `var_with_no_type_annotation` lint. (flutter/flutter#185215) 2026-04-27 53523825+JhonaCodes@users.noreply.github.com Fix SelectionArea handles overlapping context menu on Android (flutter/flutter#182663) 2026-04-27 30870216+gaaclarke@users.noreply.github.com Adds debugging information to compiled metal shaders (flutter/flutter#185629) 2026-04-27 137456488+flutter-pub-roller-bot@users.noreply.github.com Roll pub packages (flutter/flutter#185638) 2026-04-27 84978733+alejandro-all-win-software@users.noreply.github.com Use null-aware elements in dev/devicelab/lib/framework/browser.dart (flutter/flutter#184778) 2026-04-27 154381524+flutteractionsbot@users.noreply.github.com Sync CHANGELOG.md from stable (flutter/flutter#185633) 2026-04-27 31591868+zawhtetnaing10@users.noreply.github.com Added useOriginalColors flag which allows ImageIcon to bypass IconTheme colorization and use the original colors (flutter/flutter#180491) 2026-04-27 engine-flutter-autoroll@skia.org Roll Packages from 8400f71 to 23280da (2 revisions) (flutter/flutter#185619) 2026-04-27 engine-flutter-autoroll@skia.org Roll Skia from f1238e0f1022 to ce82d32b3e03 (1 revision) (flutter/flutter#185616) 2026-04-27 15619084+vashworth@users.noreply.github.com [SwiftPM] Enable package resolution on xcodebuild commands (flutter/flutter#185208) 2026-04-27 chris@bracken.jp [iOS] Refactor keyboard inset logic into FlutterKeyboardInsetManager (flutter/flutter#185535) 2026-04-27 matej.knopp@gmail.com [Win32] FlutterDesktopEngineGetGraphicsAdapter should use out parameter (flutter/flutter#185590) 2026-04-27 engine-flutter-autoroll@skia.org Roll Skia from d77e3356d526 to f1238e0f1022 (4 revisions) (flutter/flutter#185604) 2026-04-27 engine-flutter-autoroll@skia.org Roll Fuchsia Linux SDK from flsn8jC4LkTn6WECf... to i6d0NoDueUiXpePfX... (flutter/flutter#185601) 2026-04-26 engine-flutter-autoroll@skia.org Roll Dart SDK from a108dfe2d227 to de495e3de9a0 (1 revision) (flutter/flutter#185599) 2026-04-26 engine-flutter-autoroll@skia.org Roll Skia from ce9aa2231292 to d77e3356d526 (1 revision) (flutter/flutter#185596) 2026-04-26 engine-flutter-autoroll@skia.org Roll Skia from 622fff4c24d2 to ce9aa2231292 (1 revision) (flutter/flutter#185588) 2026-04-25 engine-flutter-autoroll@skia.org Roll Fuchsia Linux SDK from 9fPnyEo9PaNdXtasl... to flsn8jC4LkTn6WECf... (flutter/flutter#185585) 2026-04-25 engine-flutter-autoroll@skia.org Roll Dart SDK from 605a8faf0dda to a108dfe2d227 (1 revision) (flutter/flutter#185584) 2026-04-25 engine-flutter-autoroll@skia.org Roll Dart SDK from 6b8c39765f17 to 605a8faf0dda (1 revision) (flutter/flutter#185578) 2026-04-25 engine-flutter-autoroll@skia.org Roll Skia from 185f6b57d64f to 622fff4c24d2 (1 revision) (flutter/flutter#185573) 2026-04-25 evanwall@buffalo.edu Implement square-like round superellipses with circular corners in the SDF uber shader (flutter/flutter#185370) 2026-04-25 victorsanniay@gmail.com Add @awaitNotRequired annotation to flutter sdk (flutter/flutter#181513) 2026-04-25 engine-flutter-autoroll@skia.org Roll Dart SDK from 01228cb7af42 to 6b8c39765f17 (2 revisions) (flutter/flutter#185569) 2026-04-25 flar@google.com Adapt the DisplayList benchmarks into a primitive rendering benchmark suite (flutter/flutter#185270) 2026-04-25 okorohelijah@google.com Enable SPM for GoogleMobileAds (flutter/flutter#185548) 2026-04-25 engine-flutter-autoroll@skia.org Roll Skia from 3f467a581942 to 185f6b57d64f (1 revision) (flutter/flutter#185564) 2026-04-25 victorsanniay@gmail.com Fix Table crash when a cell child paints below the row bottom (flutter/flutter#185323) 2026-04-24 ahmedsameha1@gmail.com Make sure that an Image doesn't crash in 0x0 environment (flutter/flutter#181154) 2026-04-24 engine-flutter-autoroll@skia.org Roll Skia from 300d432048b0 to 3f467a581942 (3 revisions) (flutter/flutter#185558) 2026-04-24 engine-flutter-autoroll@skia.org Roll Dart SDK from c26627715892 to 01228cb7af42 (4 revisions) (flutter/flutter#185559) 2026-04-24 jacksongardner@google.com Reland "[web] Fix LateInitializationError in CkSurface and SkwasmSurface (#185116)" (flutter/flutter#185553) 2026-04-24 41930132+hellohuanlin@users.noreply.github.com [github]fix git ls-file glob pattern in labeler.yml instruction (flutter/flutter#185495) 2026-04-24 41930132+hellohuanlin@users.noreply.github.com [ios]update ios-reviewers tags to include more files (flutter/flutter#185490) 2026-04-24 tomac@google.com Add initial support for Cross-Origin Storage (flutter/flutter#184149) 2026-04-24 30870216+gaaclarke@users.noreply.github.com tool: Skip cached engine artifacts with local engine (flutter/flutter#185546) ...
…lutter#11595) Manual roll Flutter from 31001886cbe8 to 61fca76dd523 (53 revisions) Manual roll requested by tarrinneal@google.com flutter/flutter@3100188...61fca76 2026-04-27 30870216+gaaclarke@users.noreply.github.com Adds integration test for the FLTEnableSDFs flag for iOS (flutter/flutter#185637) 2026-04-27 97480502+b-luk@users.noreply.github.com Fix sdfs being enabled for MacOS regardless of FLTEnableSDFs value (flutter/flutter#185565) 2026-04-27 97480502+b-luk@users.noreply.github.com Don't use UberSDF for paint with incompatible blend modes (flutter/flutter#184889) 2026-04-27 engine-flutter-autoroll@skia.org Roll Dart SDK from de495e3de9a0 to 941ca325cfc9 (2 revisions) (flutter/flutter#185653) 2026-04-27 jhy03261997@gmail.com [a11y] Add CONTENT_CHANGE_TYPE_EXPANDED support on android. (flutter/flutter#185305) 2026-04-27 137456488+flutter-pub-roller-bot@users.noreply.github.com Roll pub packages (flutter/flutter#185641) 2026-04-27 1063596+reidbaker@users.noreply.github.com Modify analyze.dart to have flags to run only or exclude each verification step. (flutter/flutter#185618) 2026-04-27 meylis@divine.video Fix debugNeedsPaint/Layout/CompositedLayerUpdate crashing in release mode (flutter/flutter#184627) 2026-04-27 kallentu@google.com Enable `var_with_no_type_annotation` lint. (flutter/flutter#185215) 2026-04-27 53523825+JhonaCodes@users.noreply.github.com Fix SelectionArea handles overlapping context menu on Android (flutter/flutter#182663) 2026-04-27 30870216+gaaclarke@users.noreply.github.com Adds debugging information to compiled metal shaders (flutter/flutter#185629) 2026-04-27 137456488+flutter-pub-roller-bot@users.noreply.github.com Roll pub packages (flutter/flutter#185638) 2026-04-27 84978733+alejandro-all-win-software@users.noreply.github.com Use null-aware elements in dev/devicelab/lib/framework/browser.dart (flutter/flutter#184778) 2026-04-27 154381524+flutteractionsbot@users.noreply.github.com Sync CHANGELOG.md from stable (flutter/flutter#185633) 2026-04-27 31591868+zawhtetnaing10@users.noreply.github.com Added useOriginalColors flag which allows ImageIcon to bypass IconTheme colorization and use the original colors (flutter/flutter#180491) 2026-04-27 engine-flutter-autoroll@skia.org Roll Packages from 8400f71 to 23280da (2 revisions) (flutter/flutter#185619) 2026-04-27 engine-flutter-autoroll@skia.org Roll Skia from f1238e0f1022 to ce82d32b3e03 (1 revision) (flutter/flutter#185616) 2026-04-27 15619084+vashworth@users.noreply.github.com [SwiftPM] Enable package resolution on xcodebuild commands (flutter/flutter#185208) 2026-04-27 chris@bracken.jp [iOS] Refactor keyboard inset logic into FlutterKeyboardInsetManager (flutter/flutter#185535) 2026-04-27 matej.knopp@gmail.com [Win32] FlutterDesktopEngineGetGraphicsAdapter should use out parameter (flutter/flutter#185590) 2026-04-27 engine-flutter-autoroll@skia.org Roll Skia from d77e3356d526 to f1238e0f1022 (4 revisions) (flutter/flutter#185604) 2026-04-27 engine-flutter-autoroll@skia.org Roll Fuchsia Linux SDK from flsn8jC4LkTn6WECf... to i6d0NoDueUiXpePfX... (flutter/flutter#185601) 2026-04-26 engine-flutter-autoroll@skia.org Roll Dart SDK from a108dfe2d227 to de495e3de9a0 (1 revision) (flutter/flutter#185599) 2026-04-26 engine-flutter-autoroll@skia.org Roll Skia from ce9aa2231292 to d77e3356d526 (1 revision) (flutter/flutter#185596) 2026-04-26 engine-flutter-autoroll@skia.org Roll Skia from 622fff4c24d2 to ce9aa2231292 (1 revision) (flutter/flutter#185588) 2026-04-25 engine-flutter-autoroll@skia.org Roll Fuchsia Linux SDK from 9fPnyEo9PaNdXtasl... to flsn8jC4LkTn6WECf... (flutter/flutter#185585) 2026-04-25 engine-flutter-autoroll@skia.org Roll Dart SDK from 605a8faf0dda to a108dfe2d227 (1 revision) (flutter/flutter#185584) 2026-04-25 engine-flutter-autoroll@skia.org Roll Dart SDK from 6b8c39765f17 to 605a8faf0dda (1 revision) (flutter/flutter#185578) 2026-04-25 engine-flutter-autoroll@skia.org Roll Skia from 185f6b57d64f to 622fff4c24d2 (1 revision) (flutter/flutter#185573) 2026-04-25 evanwall@buffalo.edu Implement square-like round superellipses with circular corners in the SDF uber shader (flutter/flutter#185370) 2026-04-25 victorsanniay@gmail.com Add @awaitNotRequired annotation to flutter sdk (flutter/flutter#181513) 2026-04-25 engine-flutter-autoroll@skia.org Roll Dart SDK from 01228cb7af42 to 6b8c39765f17 (2 revisions) (flutter/flutter#185569) 2026-04-25 flar@google.com Adapt the DisplayList benchmarks into a primitive rendering benchmark suite (flutter/flutter#185270) 2026-04-25 okorohelijah@google.com Enable SPM for GoogleMobileAds (flutter/flutter#185548) 2026-04-25 engine-flutter-autoroll@skia.org Roll Skia from 3f467a581942 to 185f6b57d64f (1 revision) (flutter/flutter#185564) 2026-04-25 victorsanniay@gmail.com Fix Table crash when a cell child paints below the row bottom (flutter/flutter#185323) 2026-04-24 ahmedsameha1@gmail.com Make sure that an Image doesn't crash in 0x0 environment (flutter/flutter#181154) 2026-04-24 engine-flutter-autoroll@skia.org Roll Skia from 300d432048b0 to 3f467a581942 (3 revisions) (flutter/flutter#185558) 2026-04-24 engine-flutter-autoroll@skia.org Roll Dart SDK from c26627715892 to 01228cb7af42 (4 revisions) (flutter/flutter#185559) 2026-04-24 jacksongardner@google.com Reland "[web] Fix LateInitializationError in CkSurface and SkwasmSurface (#185116)" (flutter/flutter#185553) 2026-04-24 41930132+hellohuanlin@users.noreply.github.com [github]fix git ls-file glob pattern in labeler.yml instruction (flutter/flutter#185495) 2026-04-24 41930132+hellohuanlin@users.noreply.github.com [ios]update ios-reviewers tags to include more files (flutter/flutter#185490) 2026-04-24 tomac@google.com Add initial support for Cross-Origin Storage (flutter/flutter#184149) 2026-04-24 30870216+gaaclarke@users.noreply.github.com tool: Skip cached engine artifacts with local engine (flutter/flutter#185546) ...
Add a blend mode compatibility filter before using UberSDF in canvas.cc.
The condition for compatibility with SDFs is
mix(blend(src, dst), dst, 1 - sdf_alpha) == blend(src * sdf_alpha, dst).Added a test that verifies this condition passes for all the compatible blend modes and does not pass for all incompatible blend modes.
Fixes #184828
Fixes the impeller_Play_AiksTest_ClearBlend_MetalSDF golden test:

Pre-launch Checklist
///).If you need help, consider asking for advice on the #hackers-new channel on Discord.
If this change needs to override an active code freeze, provide a comment explaining why. The code freeze workflow can be overridden by code reviewers. See pinned issues for any active code freezes with guidance.
Note: The Flutter team is currently trialing the use of Gemini Code Assist for GitHub. Comments from the
gemini-code-assistbot should not be taken as authoritative feedback from the Flutter team. If you find its comments useful you can update your code accordingly, but if you are unsure or disagree with the feedback, please feel free to wait for a Flutter team member's review for guidance on which automated comments should be addressed.