Skip to content

[Impeller] Fix new convex path shadow generation in perspective#183187

Merged
auto-submit[bot] merged 5 commits intoflutter:masterfrom
flar:impeller-fix-convex-shadow-perspective
Mar 6, 2026
Merged

[Impeller] Fix new convex path shadow generation in perspective#183187
auto-submit[bot] merged 5 commits intoflutter:masterfrom
flar:impeller-fix-convex-shadow-perspective

Conversation

@flar
Copy link
Contributor

@flar flar commented Mar 3, 2026

Fixes: #182659

Shadows were generated in device space and then inverse transformed back into local space to interact with the rest of the pipelines well. Transforming by a perspective transforming, tessellating the shadow, and then transforming back by the inverse of the perspective transform seems to have artifacts.

To simplify the process, we only need to work in "device space scaled" coordinate system so instead of using the entire transform we just extract the scales and work in that space instead - an operation which appears to inverse cleanly.

@github-actions github-actions bot added engine flutter/engine related. See also e: labels. e: impeller Impeller rendering backend issues and features requests labels Mar 3, 2026
Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request addresses an issue with convex path shadow generation under perspective transforms. The fix involves modifying PolygonInfo::CalculateConvexShadowMesh to perform shadow tessellation in a scale-only coordinate space by extracting scale components from the incoming transformation matrix. This approach avoids rendering artifacts that occurred when tessellating directly in a space with a perspective transform. A new visual test, CanDrawPerspectiveConvexShadow, has been added to verify the fix for both simple and general convex paths under perspective. The change is logical and the new test provides good coverage. I have one suggestion to simplify a conditional check by removing a redundant condition.

@flar
Copy link
Contributor Author

flar commented Mar 3, 2026

It occurs to me that using a 4x4 matrix to transform a 2D point to a 2D answer and then trying to transform it by the inverse would not be reversible because there was information lost in the first operation that cannot be restored in the reverse.

The new matrix being used should generally be sufficient because the original geometry is in the 2D (x,y,0) plane and so its shadow (while being offset in Z in theory, but not really implemented that way in practice) is just another 2D operation that will be geometrically computed in just the XY plane and then fully transformed by the full 4x4 matrix. Just extracting the 2D scales for transforming and un-transforming the geometry is thus the right way to apply this "device space" algorithm.

@flutter-dashboard
Copy link

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 package:flutter.

Reviewers: Read the Tree Hygiene page and make sure this patch meets those guidelines before LGTMing.

Changes reported for pull request #183187 at sha 40c779f

@flutter-dashboard flutter-dashboard bot added the will affect goldens Changes to golden files label Mar 3, 2026
@flar
Copy link
Contributor Author

flar commented Mar 4, 2026

/gemini review

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request modifies the convex path shadow generation to handle perspective transforms. The change involves extracting the 2D scale from the transformation matrix and performing shadow tessellation in a "device-scaled" space, rather than the fully transformed space. The resulting vertices are then transformed back to local space using an inverse scale transformation. This avoids issues with non-affine transformations during tessellation. New unit tests have been added to verify shadow rendering with perspective, rotation, and non-uniform scaling.

@flar
Copy link
Contributor Author

flar commented Mar 5, 2026

/gemini review

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces new test cases for convex shadow generation under various transformations (perspective, rotation, and non-uniform scale) in aiks_dl_shadow_unittests.cc. The core fix addresses artifacts in perspective shadow generation by modifying shadow_path_geometry.cc to operate in a "2D device space scaled" coordinate system, extracting 2D scales from the transformation matrix instead of relying on full matrix inversions. New helper methods (GetBasisX2D, GetBasisY2D, GetBasisScaleXY) have been added to the Matrix class in matrix.h to facilitate this, along with corresponding unit tests in matrix_unittests.cc. Additionally, the GetLengthSquared and GetLength methods in point.h have been updated to return Scalar types for improved precision and type correctness.

// and just use those measurements to guide our tessellation.
Vector2 scale_2d = matrix.GetBasisScaleXY();

FML_DCHECK(scale_2d.x >= 0.0f && scale_2d.y >= 0.0f);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The FML_DCHECK on line 508 asserts that scale_2d.x and scale_2d.y are non-negative. The subsequent if condition !(scale_2d.x * scale_2d.y > 0.0f) correctly handles cases where either scale is zero or NaN. However, if scale_2d.x or scale_2d.y could theoretically be negative (e.g., due to a reflection), the FML_DCHECK would fail, but the if condition would still catch the zero case. If negative scales are possible and should be handled differently than zero scales, this logic might need refinement. If negative scales are truly impossible here, the FML_DCHECK is sufficient for debugging purposes.

Copy link
Contributor Author

@flar flar Mar 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The values can't be negative because of the way that GetBasisScale2D performs its work. The (debug) check is there to make it more obvious to maintainers that we didn't forget this when we wrote the production condition. And just a little bit to make sure we understood that part correctly.

Comment on lines +205 to +207
constexpr Scalar GetLengthSquared() const {
return static_cast<Scalar>(static_cast<double>(x) * x +
static_cast<double>(y) * y);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Changing the return type of GetLengthSquared() to Scalar is a good improvement for type correctness, as the result of a squared length calculation (especially with floating-point inputs) is inherently a floating-point value. The explicit cast to double for intermediate calculation ensures precision before converting to Scalar.

Comment on lines 209 to +210

constexpr Type GetLength() const { return std::sqrt(GetLengthSquared()); }
constexpr Scalar GetLength() const { return sqrt(GetLengthSquared()); }
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Similarly, changing the return type of GetLength() to Scalar is appropriate. The square root of a sum of squares will almost always be a floating-point number, so Scalar is the correct type.

@flutter-dashboard
Copy link

Golden file changes are available for triage from new commit, Click here to view.

For more guidance, visit Writing a golden file test for package:flutter.

Reviewers: Read the Tree Hygiene page and make sure this patch meets those guidelines before LGTMing.

Changes reported for pull request #183187 at sha 06c9775

@flar flar requested a review from gaaclarke March 5, 2026 19:03
@flar
Copy link
Contributor Author

flar commented Mar 5, 2026

The golden files are all "off by 1" diffs in the blur output because of the slight change in scaling math. I'm not sure why the Google Testing step didn't generate a bunch of diffs, though.

Copy link
Member

@gaaclarke gaaclarke left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, just some suggestions on making the test assertions more clear.

@flutter-dashboard
Copy link

Golden file changes are available for triage from new commit, Click here to view.

For more guidance, visit Writing a golden file test for package:flutter.

Reviewers: Read the Tree Hygiene page and make sure this patch meets those guidelines before LGTMing.

Changes reported for pull request #183187 at sha 45b7426

@flar flar added the autosubmit Merge PR when tree becomes green via auto submit App label Mar 5, 2026
@auto-submit auto-submit bot added this pull request to the merge queue Mar 5, 2026
@github-merge-queue github-merge-queue bot removed this pull request from the merge queue due to failed status checks Mar 6, 2026
@flutter-dashboard flutter-dashboard bot removed the autosubmit Merge PR when tree becomes green via auto submit App label Mar 6, 2026
@flar flar added the autosubmit Merge PR when tree becomes green via auto submit App label Mar 6, 2026
@auto-submit auto-submit bot added this pull request to the merge queue Mar 6, 2026
Merged via the queue into flutter:master with commit 22b0a75 Mar 6, 2026
187 checks passed
@flutter-dashboard flutter-dashboard bot removed the autosubmit Merge PR when tree becomes green via auto submit App label Mar 6, 2026
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Mar 6, 2026
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Mar 6, 2026
auto-submit bot pushed a commit to flutter/packages that referenced this pull request Mar 6, 2026
Roll Flutter from d3dd7744e81f to d18214307703 (33 revisions)

flutter/flutter@d3dd774...d182143

2026-03-06 [email protected] Roll Packages from 8d5c5cd to fe3de64 (2 revisions) (flutter/flutter#183308)
2026-03-06 [email protected] Roll Dart SDK from 1b51451cdb99 to 7c7c1e3d024d (2 revisions) (flutter/flutter#183294)
2026-03-06 [email protected] Roll Dart SDK from 9ac06cdd1801 to 1b51451cdb99 (9 revisions) (flutter/flutter#183289)
2026-03-06 [email protected] Add GitHub workflows to assist with release tasks (flutter/flutter#181978)
2026-03-06 [email protected] [Impeller] Fix new convex path shadow generation in perspective (flutter/flutter#183187)
2026-03-06 [email protected] Roll pub packages (flutter/flutter#183178)
2026-03-05 [email protected] fix: use double quotes in settings.gradle.kts template (flutter/flutter#183081)
2026-03-05 [email protected] Add fallbackColor for PredictiveBackPageTransitionBuilder and PredictiveBackFullscreenPageTransitionBuilder (flutter/flutter#182690)
2026-03-05 [email protected] Simplify TesterContextGLES (multithreading logic not needed), and enable some tests that now pass (flutter/flutter#183250)
2026-03-05 [email protected] Roll Skia from a94df1cdabb0 to a69ef43650ee (14 revisions) (flutter/flutter#183280)
2026-03-05 [email protected] Windowing implementation of `showDialog` that uses a native desktop window to display the content  (flutter/flutter#181861)
2026-03-05 [email protected] Build CocoaPod plugin frameworks for Add to App FlutterPluginRegistrant (flutter/flutter#183239)
2026-03-05 [email protected] Extend the Linux web_skwasm_tests_1 timeout to 45 minutes (flutter/flutter#183247)
2026-03-05 [email protected] Update Dart to 3.12 beta 2 (flutter/flutter#183251)
2026-03-05 [email protected] Replace the rest of the references to `flutter/engine` with `flutter/flutter` (flutter/flutter#182938)
2026-03-05 [email protected] chore: convert android_verified_input to pub-workspace (flutter/flutter#183175)
2026-03-05 [email protected] Add await to flutter_test callsites (flutter/flutter#182983)
2026-03-05 [email protected] [iOS] Skip gesture recognizer reset workaround on iOS 26+  (flutter/flutter#183186)
2026-03-05 [email protected] Add warning for plugins not migrated to UIScene (flutter/flutter#182826)
2026-03-05 [email protected] Roll Fuchsia Linux SDK from JJw5EJ87vLGqFVl4h... to 8ay15_eQOEgPHCypm... (flutter/flutter#183255)
2026-03-05 [email protected] Roll Skia from ada0b7628c79 to a94df1cdabb0 (2 revisions) (flutter/flutter#183249)
2026-03-05 [email protected] Roll Packages from 82baf93 to 8d5c5cd (2 revisions) (flutter/flutter#183269)
2026-03-05 [email protected] Add `UnlabaledLeafNodeEvaluation` (flutter/flutter#182872)
2026-03-04 [email protected] Re-specify the ndk version in various test apps, to prevent ndk download (flutter/flutter#183134)
2026-03-04 [email protected] Eliminate rebuilds for Scaffold FAB animation (flutter/flutter#182331)
2026-03-04 [email protected] Add Michal Kucharski to AUTHORS (flutter/flutter#182366)
2026-03-04 [email protected] Merge changelog from 3.41.4 stable. (flutter/flutter#183243)
2026-03-04 [email protected] Allow stylus support on windows (flutter/flutter#165323)
2026-03-04 [email protected] Fix docs on SingletonFlutterWindow.supportsShowingSystemContextMenu (flutter/flutter#183142)
2026-03-04 [email protected] Roll Packages from 9083bc9 to 82baf93 (5 revisions) (flutter/flutter#183240)
2026-03-04 [email protected] Fixes FocusHighlightMode on Android when typing in software keyboard (flutter/flutter#180753)
2026-03-04 [email protected] Make compileShader() retry without sksl if it fails with sksl. (flutter/flutter#183146)
2026-03-04 [email protected] [web] Use pointer-events: auto for non-interactive leaf semantics nodes (flutter/flutter#183077)

If this roll has caused a breakage, revert this CL and stop the roller
using the controls here:
https://autoroll.skia.org/r/flutter-packages
Please CC [email protected],[email protected] on the revert to ensure that a human
is aware of the problem.

To file a bug in Packages: https://github.com/flutter/flutter/issues/new/choose

To report a problem with the AutoRoller itself, please file a bug:
https://issues.skia.org/issues/new?component=1389291&template=1850622

Documentation for the AutoRoller is here:
...
xxxOVALxxx pushed a commit to xxxOVALxxx/flutter that referenced this pull request Mar 10, 2026
…ter#183187)

Fixes: flutter#182659

Shadows were generated in device space and then inverse transformed back
into local space to interact with the rest of the pipelines well.
Transforming by a perspective transforming, tessellating the shadow, and
then transforming back by the inverse of the perspective transform seems
to have artifacts.

To simplify the process, we only need to work in "device space scaled"
coordinate system so instead of using the entire transform we just
extract the scales and work in that space instead - an operation which
appears to inverse cleanly.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

e: impeller Impeller rendering backend issues and features requests engine flutter/engine related. See also e: labels. will affect goldens Changes to golden files

Projects

None yet

2 participants