diff --git a/impeller/aiks/aiks_blur_unittests.cc b/impeller/aiks/aiks_blur_unittests.cc index 90492e95c8875..d6ad5ebe41884 100644 --- a/impeller/aiks/aiks_blur_unittests.cc +++ b/impeller/aiks/aiks_blur_unittests.cc @@ -644,5 +644,33 @@ TEST_P(AiksTest, GaussianBlurStyleOuter) { ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture())); } +TEST_P(AiksTest, GaussianBlurStyleSolid) { + Canvas canvas; + canvas.Scale(GetContentScale()); + + canvas.DrawPaint({.color = Color(0.1, 0.1, 0.1, 1.0)}); + + Paint paint; + paint.color = Color::Green(); + paint.mask_blur_descriptor = Paint::MaskBlurDescriptor{ + .style = FilterContents::BlurStyle::kSolid, + .sigma = Sigma(30), + }; + canvas.DrawPath(PathBuilder() + .MoveTo({200, 200}) + .LineTo({300, 400}) + .LineTo({100, 400}) + .Close() + .TakePath(), + paint); + + // Draw another thing to make sure the clip area is reset. + Paint red; + red.color = Color::Red(); + canvas.DrawRect(Rect::MakeXYWH(0, 0, 200, 200), red); + + ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture())); +} + } // namespace testing } // namespace impeller diff --git a/impeller/entity/contents/filters/blend_filter_contents.cc b/impeller/entity/contents/filters/blend_filter_contents.cc index 1018acffde16b..60d8a233360a1 100644 --- a/impeller/entity/contents/filters/blend_filter_contents.cc +++ b/impeller/entity/contents/filters/blend_filter_contents.cc @@ -111,7 +111,7 @@ static std::optional AdvancedBlend( if (!dst_snapshot.has_value()) { return std::nullopt; } - return Entity::FromSnapshot(dst_snapshot, entity.GetBlendMode(), + return Entity::FromSnapshot(dst_snapshot.value(), entity.GetBlendMode(), entity.GetClipDepth()); } auto maybe_src_uvs = src_snapshot->GetCoverageUVs(coverage); @@ -119,7 +119,7 @@ static std::optional AdvancedBlend( if (!dst_snapshot.has_value()) { return std::nullopt; } - return Entity::FromSnapshot(dst_snapshot, entity.GetBlendMode(), + return Entity::FromSnapshot(dst_snapshot.value(), entity.GetBlendMode(), entity.GetClipDepth()); } src_uvs = maybe_src_uvs.value(); @@ -426,7 +426,7 @@ std::optional BlendFilterContents::CreateForegroundPorterDuffBlend( } if (blend_mode == BlendMode::kDestination) { - return Entity::FromSnapshot(dst_snapshot, entity.GetBlendMode(), + return Entity::FromSnapshot(dst_snapshot.value(), entity.GetBlendMode(), entity.GetClipDepth()); } diff --git a/impeller/entity/contents/filters/gaussian_blur_filter_contents.cc b/impeller/entity/contents/filters/gaussian_blur_filter_contents.cc index 62a2bd490baef..46513f3b4bf85 100644 --- a/impeller/entity/contents/filters/gaussian_blur_filter_contents.cc +++ b/impeller/entity/contents/filters/gaussian_blur_filter_contents.cc @@ -204,31 +204,12 @@ int ScaleBlurRadius(Scalar radius, Scalar scalar) { return static_cast(std::round(radius * scalar)); } -Entity ApplyBlurStyle(FilterContents::BlurStyle blur_style, - const Entity& entity, - const std::shared_ptr& input, - const Snapshot& input_snapshot, - Entity blur_entity, - const std::shared_ptr& geometry) { - if (blur_style == FilterContents::BlurStyle::kNormal) { - return blur_entity; - } - Entity::ClipOperation clip_operation; - switch (blur_style) { - case FilterContents::BlurStyle::kNormal: - FML_UNREACHABLE(); - break; - case FilterContents::BlurStyle::kInner: - clip_operation = Entity::ClipOperation::kIntersect; - break; - case FilterContents::BlurStyle::kOuter: - clip_operation = Entity::ClipOperation::kDifference; - break; - case FilterContents::BlurStyle::kSolid: - FML_DLOG(ERROR) << "Unimplemented blur style"; - return blur_entity; - } - +Entity ApplyClippedBlurStyle(Entity::ClipOperation clip_operation, + const Entity& entity, + const std::shared_ptr& input, + const Snapshot& input_snapshot, + Entity blur_entity, + const std::shared_ptr& geometry) { auto shared_blur_entity = std::make_shared(std::move(blur_entity)); shared_blur_entity->SetNewClipDepth(entity.GetNewClipDepth()); auto clipper = std::make_unique(); @@ -255,6 +236,48 @@ Entity ApplyBlurStyle(FilterContents::BlurStyle blur_style, })); return result; } + +Entity ApplyBlurStyle(FilterContents::BlurStyle blur_style, + const Entity& entity, + const std::shared_ptr& input, + const Snapshot& input_snapshot, + Entity blur_entity, + const std::shared_ptr& geometry) { + switch (blur_style) { + case FilterContents::BlurStyle::kNormal: + return blur_entity; + case FilterContents::BlurStyle::kInner: + return ApplyClippedBlurStyle(Entity::ClipOperation::kIntersect, entity, + input, input_snapshot, + std::move(blur_entity), geometry); + break; + case FilterContents::BlurStyle::kOuter: + return ApplyClippedBlurStyle(Entity::ClipOperation::kDifference, entity, + input, input_snapshot, + std::move(blur_entity), geometry); + case FilterContents::BlurStyle::kSolid: { + Entity blurred = ApplyClippedBlurStyle(Entity::ClipOperation::kIntersect, + entity, input, input_snapshot, + std::move(blur_entity), geometry); + Entity snapshot_entity = Entity::FromSnapshot( + input_snapshot, entity.GetBlendMode(), entity.GetClipDepth()); + Entity result; + std::optional coverage = blurred.GetCoverage(); + result.SetContents(Contents::MakeAnonymous( + fml::MakeCopyable([blurred = std::move(blurred), + snapshot_entity = std::move(snapshot_entity)]( + const ContentContext& renderer, + const Entity& entity, + RenderPass& pass) mutable { + return blurred.Render(renderer, pass) && + snapshot_entity.Render(renderer, pass); + }), + fml::MakeCopyable( + [coverage](const Entity& entity) { return coverage; }))); + return result; + } + } +} } // namespace std::string_view GaussianBlurFilterContents::kNoMipsError = @@ -499,7 +522,7 @@ std::optional GaussianBlurFilterContents::RenderFilter( SamplerDescriptor sampler_desc = MakeSamplerDescriptor( MinMagFilter::kLinear, SamplerAddressMode::kClampToEdge); - auto blur_output_entity = Entity::FromSnapshot( + Entity blur_output_entity = Entity::FromSnapshot( Snapshot{.texture = pass3_out.value().GetRenderTargetTexture(), .transform = input_snapshot->transform * padding_snapshot_adjustment * @@ -508,13 +531,9 @@ std::optional GaussianBlurFilterContents::RenderFilter( .opacity = input_snapshot->opacity}, entity.GetBlendMode(), entity.GetClipDepth()); - if (!blur_output_entity.has_value()) { - return std::nullopt; - } - return ApplyBlurStyle(mask_blur_style_, entity, inputs[0], - input_snapshot.value(), - std::move(blur_output_entity.value()), mask_geometry_); + input_snapshot.value(), std::move(blur_output_entity), + mask_geometry_); } Scalar GaussianBlurFilterContents::CalculateBlurRadius(Scalar sigma) { diff --git a/impeller/entity/contents/filters/local_matrix_filter_contents.cc b/impeller/entity/contents/filters/local_matrix_filter_contents.cc index e30edbd04e8d0..d5b52ef615349 100644 --- a/impeller/entity/contents/filters/local_matrix_filter_contents.cc +++ b/impeller/entity/contents/filters/local_matrix_filter_contents.cc @@ -37,9 +37,13 @@ std::optional LocalMatrixFilterContents::RenderFilter( const Matrix& effect_transform, const Rect& coverage, const std::optional& coverage_hint) const { - return Entity::FromSnapshot( - inputs[0]->GetSnapshot("LocalMatrix", renderer, entity), - entity.GetBlendMode(), entity.GetClipDepth()); + std::optional snapshot = + inputs[0]->GetSnapshot("LocalMatrix", renderer, entity); + if (!snapshot.has_value()) { + return std::nullopt; + } + return Entity::FromSnapshot(snapshot.value(), entity.GetBlendMode(), + entity.GetClipDepth()); } } // namespace impeller diff --git a/impeller/entity/contents/filters/matrix_filter_contents.cc b/impeller/entity/contents/filters/matrix_filter_contents.cc index 6bce41f2acfc7..7fe455c79d387 100644 --- a/impeller/entity/contents/filters/matrix_filter_contents.cc +++ b/impeller/entity/contents/filters/matrix_filter_contents.cc @@ -64,7 +64,10 @@ std::optional MatrixFilterContents::RenderFilter( snapshot->transform; snapshot->sampler_descriptor = sampler_descriptor_; - return Entity::FromSnapshot(snapshot, entity.GetBlendMode(), + if (!snapshot.has_value()) { + return std::nullopt; + } + return Entity::FromSnapshot(snapshot.value(), entity.GetBlendMode(), entity.GetClipDepth()); } diff --git a/impeller/entity/entity.cc b/impeller/entity/entity.cc index 472f4b534bee8..356dbe7e8086f 100644 --- a/impeller/entity/entity.cc +++ b/impeller/entity/entity.cc @@ -19,26 +19,21 @@ namespace impeller { -std::optional Entity::FromSnapshot( - const std::optional& snapshot, - BlendMode blend_mode, - uint32_t clip_depth) { - if (!snapshot.has_value()) { - return std::nullopt; - } - - auto texture_rect = Rect::MakeSize(snapshot->texture->GetSize()); +Entity Entity::FromSnapshot(const Snapshot& snapshot, + BlendMode blend_mode, + uint32_t clip_depth) { + auto texture_rect = Rect::MakeSize(snapshot.texture->GetSize()); auto contents = TextureContents::MakeRect(texture_rect); - contents->SetTexture(snapshot->texture); - contents->SetSamplerDescriptor(snapshot->sampler_descriptor); + contents->SetTexture(snapshot.texture); + contents->SetSamplerDescriptor(snapshot.sampler_descriptor); contents->SetSourceRect(texture_rect); - contents->SetOpacity(snapshot->opacity); + contents->SetOpacity(snapshot.opacity); Entity entity; entity.SetBlendMode(blend_mode); entity.SetClipDepth(clip_depth); - entity.SetTransform(snapshot->transform); + entity.SetTransform(snapshot.transform); entity.SetContents(contents); return entity; } diff --git a/impeller/entity/entity.h b/impeller/entity/entity.h index 430a0423e5257..d964dcd631987 100644 --- a/impeller/entity/entity.h +++ b/impeller/entity/entity.h @@ -62,10 +62,9 @@ class Entity { }; /// @brief Create an entity that can be used to render a given snapshot. - static std::optional FromSnapshot( - const std::optional& snapshot, - BlendMode blend_mode = BlendMode::kSourceOver, - uint32_t clip_depth = 0); + static Entity FromSnapshot(const Snapshot& snapshot, + BlendMode blend_mode = BlendMode::kSourceOver, + uint32_t clip_depth = 0); Entity(); diff --git a/testing/impeller_golden_tests_output.txt b/testing/impeller_golden_tests_output.txt index aeb18abee22e6..06783ca01e5e7 100644 --- a/testing/impeller_golden_tests_output.txt +++ b/testing/impeller_golden_tests_output.txt @@ -491,6 +491,9 @@ impeller_Play_AiksTest_GaussianBlurStyleInner_Vulkan.png impeller_Play_AiksTest_GaussianBlurStyleOuter_Metal.png impeller_Play_AiksTest_GaussianBlurStyleOuter_OpenGLES.png impeller_Play_AiksTest_GaussianBlurStyleOuter_Vulkan.png +impeller_Play_AiksTest_GaussianBlurStyleSolid_Metal.png +impeller_Play_AiksTest_GaussianBlurStyleSolid_OpenGLES.png +impeller_Play_AiksTest_GaussianBlurStyleSolid_Vulkan.png impeller_Play_AiksTest_GaussianBlurWithoutDecalSupport_Metal.png impeller_Play_AiksTest_GradientStrokesRenderCorrectly_Metal.png impeller_Play_AiksTest_GradientStrokesRenderCorrectly_OpenGLES.png