[Impeller] Avoid NaN values when setting up for the fast squircle blur shader (#162421)

Fixes https://github.com/flutter/flutter/issues/162128

Zero dimensioned rectangle blurs were causing the setup code to generate
NaN values. This condition could also happen for some very thin or short
rectangles so rather than just rule out zero-dimensioned rectangles, the
uniforms are checked for NaN values and the operation is skipped in
those cases.
This commit is contained in:
Jim Graham 2025-01-29 19:26:14 -08:00 committed by GitHub
parent 01a9aec444
commit e6185c3471
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 38 additions and 3 deletions

View File

@ -470,6 +470,28 @@ TEST_P(AiksTest, MaskBlurWithZeroSigmaIsSkipped) {
ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
}
TEST_P(AiksTest, MaskBlurOnZeroDimensionIsSkippedWideGamut) {
// Making sure this test is run on a wide gamut enabled backend
EXPECT_EQ(GetContext()->GetCapabilities()->GetDefaultColorFormat(),
PixelFormat::kB10G10R10A10XR);
DisplayListBuilder builder;
builder.DrawColor(DlColor::kWhite(), DlBlendMode::kSrc);
DlPaint paint;
paint.setColor(DlColor::kBlue());
paint.setMaskFilter(DlBlurMaskFilter::Make(DlBlurStyle::kNormal, 10));
// Zero height above
builder.DrawRect(DlRect::MakeLTRB(100, 250, 500, 250), paint);
// Regular rect
builder.DrawRect(DlRect::MakeLTRB(100, 300, 500, 600), paint);
// Zero width to the right
builder.DrawRect(DlRect::MakeLTRB(550, 300, 550, 600), paint);
ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
}
struct MaskBlurTestConfig {
DlBlurStyle style = DlBlurStyle::kNormal;
Scalar sigma = 1.0f;

View File

@ -68,7 +68,7 @@ static Point NegPos(Scalar v) {
return {std::min(v, 0.0f), std::max(v, 0.0f)};
}
static void SetupFragInfo(
static bool SetupFragInfo(
RRectBlurPipeline::FragmentShader::FragInfo& frag_info,
Scalar blurSigma,
Point center,
@ -96,6 +96,15 @@ static void SetupFragInfo(
frag_info.scale =
0.5 * computeErf7(frag_info.sInv * 0.5 *
(std::max(rSize.x, rSize.y) - 0.5 * radius));
return frag_info.center.IsFinite() && //
frag_info.adjust.IsFinite() && //
std::isfinite(frag_info.minEdge) && //
std::isfinite(frag_info.r1) && //
std::isfinite(frag_info.exponent) && //
std::isfinite(frag_info.sInv) && //
std::isfinite(frag_info.exponentInv) && //
std::isfinite(frag_info.scale);
}
std::optional<Rect> SolidRRectBlurContents::GetCoverage(
@ -159,8 +168,11 @@ bool SolidRRectBlurContents::Render(const ContentContext& renderer,
positive_rect.GetWidth() * 0.5f),
std::clamp(corner_radii_.height, kEhCloseEnough,
positive_rect.GetHeight() * 0.5f));
SetupFragInfo(frag_info, blur_sigma, positive_rect.GetCenter(),
Point(positive_rect.GetSize()), radius);
if (!SetupFragInfo(frag_info, blur_sigma, positive_rect.GetCenter(),
Point(positive_rect.GetSize()), radius)) {
return true;
}
auto& host_buffer = renderer.GetTransientsBuffer();
pass.SetCommandLabel("RRect Shadow");
pass.SetPipeline(renderer.GetRRectBlurPipeline(opts));

View File

@ -802,6 +802,7 @@ impeller_Play_AiksTest_LinearToSrgbFilterSubpassCollapseOptimization_Vulkan.png
impeller_Play_AiksTest_MaskBlurDoesntStretchContents_Metal.png
impeller_Play_AiksTest_MaskBlurDoesntStretchContents_OpenGLES.png
impeller_Play_AiksTest_MaskBlurDoesntStretchContents_Vulkan.png
impeller_Play_AiksTest_MaskBlurOnZeroDimensionIsSkippedWideGamut_Metal.png
impeller_Play_AiksTest_MaskBlurTexture_Metal.png
impeller_Play_AiksTest_MaskBlurTexture_OpenGLES.png
impeller_Play_AiksTest_MaskBlurTexture_Vulkan.png