这是indexloc提供的服务,不要输入任何密码
Skip to content

[DisplayList] implement shadow bounds without relying on Skia utilities #172572

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

Merged

Conversation

flar
Copy link
Contributor

@flar flar commented Jul 22, 2025

Right now DisplayList defers to Skia to compute the bounds of shadow operations, but we really need to own this code now that we are doing our own rendering so I ported it over and simplified it to just deal with the cases we care about.

Eliminates a bullet item in #161456

@flar flar requested a review from bdero July 22, 2025 20:14
@github-actions github-actions bot added engine flutter/engine repository. See also e: labels. e: impeller Impeller rendering backend issues and features requests labels Jul 22, 2025
@flar flar requested review from gaaclarke and chinmaygarde July 22, 2025 20:14

} // namespace

TEST(DlSkCanvas, ShadowBoundsCompatibilityTranslateScale) {
Copy link
Contributor Author

@flar flar Jul 22, 2025

Choose a reason for hiding this comment

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

Note: These tests make sure we return the same answers as the previous code, but they will be deleted summarily when we delete the Skia backend (this entire directory will be deleted in whole).

So, there are also some additional tests in dl_canvas_unittests.cc that test the raw answers without comparing to Skia and those will live on at that point...

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@gaaclarke here are the droi...tests you were looking for...

// need -B for the final quadratic equation computations anyway.)
double negB = a2 + d2;
double C = a2 * d2 - b2 * c2;
double B2minus4AC = negB * negB - 4 * 1.0f * C;
Copy link
Member

Choose a reason for hiding this comment

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

Here and elsewhere, use underscore_case

Copy link
Contributor Author

Choose a reason for hiding this comment

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

That gets tricky for these values that represent known variables in a common formula, so these would need to have capital A,B,C in them - but otherwise I can make them snake case.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

How about the new names?

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.

I'm assuming we have a lot of existing test coverage in the existing goldens, right?

Comment on lines +20 to +23
EXPECT_FLOAT_EQ(shadow_bounds.GetLeft(), 96.333336f);
EXPECT_FLOAT_EQ(shadow_bounds.GetTop(), 97.761909f);
EXPECT_FLOAT_EQ(shadow_bounds.GetRight(), 203.66667f);
EXPECT_FLOAT_EQ(shadow_bounds.GetBottom(), 205.09525f);
Copy link
Member

Choose a reason for hiding this comment

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

Can we compare this with the skia output since the intention is to replace it?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

That is done in the other file that will get deleted when the Skia source dependencies are deleted...

Copy link
Contributor Author

Choose a reason for hiding this comment

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

(see display_list/skia/dl_sk_canvas_unittests.cc)

@flar
Copy link
Contributor Author

flar commented Jul 22, 2025

I'm assuming we have a lot of existing test coverage in the existing goldens, right?

The shadow bounds get used to compute bounds for DLs and we do have some tests that make sure that DL bounds are reasonable (by comparing to Skia and by ensuring that we don't overdraw them in the rendertests).

See

TEST_F(DisplayListRendering, DrawShadow) {

And https://github.com/flutter/flutter/blob/be9526fbaaaab9474e95d196b70c41297eeda2d0/engine/src/flutter/display_list/testing/dl_rendering_unittests.cc#L2435C14-L2435C23

The only direct use of the method I see in the existing unit tests is

which is used to confirm that we chose appropriately for a DrawShadow call to fit within the bounds our test is designed for.

@flar flar requested review from chinmaygarde and gaaclarke July 22, 2025 21:02
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.

This looks good to me. I think the only thing it needs is a docstring for GetLocalBounds.

-zRatio * params.light_position.y);
}

DlRect GetLocalBounds(DlRect ambient_bounds,
Copy link
Member

Choose a reason for hiding this comment

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

Can you add a docstring here. It's not immediately easy to understand what this is doing. Here is the one for skia: https://github.com/google/skia/blob/d43c7d1ea21a80982b926be4f72f48b64fa4bfa6/include/utils/SkShadowUtils.h#L66

The name isn't quite obvious like the skia version either IMO since it's laking the "shadow" context.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Well, that's the implementation function which never has a doc string. The doc string should be in the header file and that didn't change so it isn't in the diffs.

But, if you go look there you'll notice that it is also missing a doc comment, so the point is still valid. ;)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

None of the methods in DlCanvas are documented as they are assumed to be just duplicates of the SkCanvas methods, but we need to fix that at some point. For now, I'm also adding a doc comment to DrawShadow as well as the ComputeBounds function to help fully document what we mean by shadows (ComputeBounds refers to DrawShadow as "I'm the bounds for that guy" so it helps to nail down what "that guy" does). The rest of the methods in DlCanvas should be documented later as a low priority task in the de-skiafication mini-project.

/// @brief Return the smaller of the two non-negative scales that will
/// be applied to 2D coordinates by this matrix. If the matrix
/// has perspective components or the value cannot be computed,
/// the method will return -1.
Copy link
Member

Choose a reason for hiding this comment

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

Why not use std::optional? It seems like accidentally using -1 isn't going to give the results you want, right?

Copy link
Contributor Author

@flar flar Jul 22, 2025

Choose a reason for hiding this comment

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

Technically this method would not be involved in any computation inside a perspective coordinate system, so this method shouldn't even be called on one. Any code that called this without knowing up front that the result would be successful would be considered poorly written (most likely didn't bother to have a plan for what to do when the matrix is perspective) and this method would not likely be called until well after the perspective condition was noted and branched away.

But there is no good way to "enforce" that with our API, so while using optional is more of a nuisance than informative for well-written code, its use would raise the visibility of the inappropriateness of using these methods with a perspective transform. Hopefully someone modifying code in Impeller to use this method would be motivated to think more about how their code should work in a perspective situation.

@@ -358,6 +360,76 @@ std::optional<MatrixDecomposition> Matrix::Decompose() const {
return result;
}

std::optional<std::pair<Scalar, Scalar>> Matrix::GetScales2D() const {
Copy link
Member

Choose a reason for hiding this comment

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

Couldn't you just transform 2 unit vectors to calculate this?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

No, this isn't the scale factor for the unit vectors - that's what the basis methods return. This is the expansion factor in any direction. For skewed transforms, the unit axis vectors are not scaled, but the 45-degree unit vector is scaled by more than 1, and the perpendicular to that vector is scaled by less than 1.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'm creating a doc comment for the GetMaxBasis method to clarify its limitation.

I note that there is a GetScale() method also, which doesn't return a true scale and is only used in one location:

GetCanvas().GetCurrentTransform().GetScale().y},

I'll file a bug for the latter and leave it for now. See #172611

@gaaclarke gaaclarke enabled auto-merge July 22, 2025 23:43
@flar flar requested a review from gaaclarke July 23, 2025 07:09
@flar
Copy link
Contributor Author

flar commented Jul 23, 2025

I assume that I'll have to merge with the post-license-cpp revert and do the appropriate manual licensing stuff, but the code itself should be in a hopefully final form.

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, thanks

@gaaclarke gaaclarke added this pull request to the merge queue Jul 23, 2025
Merged via the queue into flutter:master with commit 3deedd2 Jul 23, 2025
178 checks passed
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 repository. See also e: labels.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants