Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

[Impeller] Use downsample shader for blur instead of mip levels. #53760

Merged
merged 10 commits into from
Jul 9, 2024
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions ci/licenses_golden/licenses_flutter
Original file line number Diff line number Diff line change
Expand Up @@ -42118,6 +42118,7 @@ ORIGIN: ../../../flutter/impeller/entity/shaders/rrect_blur.vert + ../../../flut
ORIGIN: ../../../flutter/impeller/entity/shaders/runtime_effect.vert + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/entity/shaders/solid_fill.frag + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/entity/shaders/solid_fill.vert + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/entity/shaders/texture_downsample.frag + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/entity/shaders/texture_fill.frag + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/entity/shaders/texture_fill.vert + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/entity/shaders/texture_fill_strict_src.frag + ../../../flutter/LICENSE
Expand Down Expand Up @@ -44984,6 +44985,7 @@ FILE: ../../../flutter/impeller/entity/shaders/rrect_blur.vert
FILE: ../../../flutter/impeller/entity/shaders/runtime_effect.vert
FILE: ../../../flutter/impeller/entity/shaders/solid_fill.frag
FILE: ../../../flutter/impeller/entity/shaders/solid_fill.vert
FILE: ../../../flutter/impeller/entity/shaders/texture_downsample.frag
FILE: ../../../flutter/impeller/entity/shaders/texture_fill.frag
FILE: ../../../flutter/impeller/entity/shaders/texture_fill.vert
FILE: ../../../flutter/impeller/entity/shaders/texture_fill_strict_src.frag
Expand Down
154 changes: 0 additions & 154 deletions impeller/aiks/aiks_blur_unittests.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1041,160 +1041,6 @@ TEST_P(AiksTest, GuassianBlurUpdatesMipmapContents) {
ASSERT_TRUE(OpenPlaygroundHere(callback));
}

TEST_P(AiksTest, GaussianBlurSetsMipCountOnPass) {
Canvas canvas;
canvas.DrawCircle({100, 100}, 50, {.color = Color::CornflowerBlue()});
canvas.SaveLayer({}, std::nullopt,
ImageFilter::MakeBlur(Sigma(3), Sigma(3),
FilterContents::BlurStyle::kNormal,
Entity::TileMode::kClamp));
canvas.Restore();

Picture picture = canvas.EndRecordingAsPicture();
EXPECT_EQ(4, picture.pass->GetRequiredMipCount());
}

TEST_P(AiksTest, GaussianBlurAllocatesCorrectMipCountRenderTarget) {
size_t blur_required_mip_count =
GetParam() == PlaygroundBackend::kOpenGLES ? 1 : 4;

Canvas canvas;
canvas.DrawCircle({100, 100}, 50, {.color = Color::CornflowerBlue()});
canvas.SaveLayer({}, std::nullopt,
ImageFilter::MakeBlur(Sigma(3), Sigma(3),
FilterContents::BlurStyle::kNormal,
Entity::TileMode::kClamp));
canvas.Restore();

Picture picture = canvas.EndRecordingAsPicture();
std::shared_ptr<RenderTargetCache> cache =
std::make_shared<RenderTargetCache>(GetContext()->GetResourceAllocator());
AiksContext aiks_context(GetContext(), nullptr, cache);
picture.ToImage(aiks_context, {100, 100});

size_t max_mip_count = 0;
for (auto it = cache->GetRenderTargetDataBegin();
it != cache->GetRenderTargetDataEnd(); ++it) {
max_mip_count = std::max(it->config.mip_count, max_mip_count);
}
EXPECT_EQ(max_mip_count, blur_required_mip_count);
}

TEST_P(AiksTest, GaussianBlurMipMapNestedLayer) {
fml::testing::LogCapture log_capture;
size_t blur_required_mip_count =
GetParam() == PlaygroundBackend::kOpenGLES ? 1 : 4;

Canvas canvas;
canvas.DrawPaint({.color = Color::Wheat()});
canvas.SaveLayer({.blend_mode = BlendMode::kMultiply});
canvas.DrawCircle({100, 100}, 50, {.color = Color::CornflowerBlue()});
canvas.SaveLayer({}, std::nullopt,
ImageFilter::MakeBlur(Sigma(30), Sigma(30),
FilterContents::BlurStyle::kNormal,
Entity::TileMode::kClamp));
canvas.DrawCircle({200, 200}, 50, {.color = Color::Chartreuse()});

Picture picture = canvas.EndRecordingAsPicture();
std::shared_ptr<RenderTargetCache> cache =
std::make_shared<RenderTargetCache>(GetContext()->GetResourceAllocator());
AiksContext aiks_context(GetContext(), nullptr, cache);
picture.ToImage(aiks_context, {100, 100});

size_t max_mip_count = 0;
for (auto it = cache->GetRenderTargetDataBegin();
it != cache->GetRenderTargetDataEnd(); ++it) {
max_mip_count = std::max(it->config.mip_count, max_mip_count);
}
EXPECT_EQ(max_mip_count, blur_required_mip_count);
// The log is FML_DLOG, so only check in debug builds.
#ifndef NDEBUG
if (GetParam() != PlaygroundBackend::kOpenGLES) {
EXPECT_EQ(log_capture.str().find(GaussianBlurFilterContents::kNoMipsError),
std::string::npos);
} else {
EXPECT_NE(log_capture.str().find(GaussianBlurFilterContents::kNoMipsError),
std::string::npos);
}
#endif
}

TEST_P(AiksTest, GaussianBlurMipMapImageFilter) {
size_t blur_required_mip_count =
GetParam() == PlaygroundBackend::kOpenGLES ? 1 : 4;
fml::testing::LogCapture log_capture;
Canvas canvas;
canvas.SaveLayer(
{.image_filter = ImageFilter::MakeBlur(Sigma(30), Sigma(30),
FilterContents::BlurStyle::kNormal,
Entity::TileMode::kClamp)});
canvas.DrawCircle({200, 200}, 50, {.color = Color::Chartreuse()});

Picture picture = canvas.EndRecordingAsPicture();
std::shared_ptr<RenderTargetCache> cache =
std::make_shared<RenderTargetCache>(GetContext()->GetResourceAllocator());
AiksContext aiks_context(GetContext(), nullptr, cache);
picture.ToImage(aiks_context, {1024, 768});

size_t max_mip_count = 0;
for (auto it = cache->GetRenderTargetDataBegin();
it != cache->GetRenderTargetDataEnd(); ++it) {
max_mip_count = std::max(it->config.mip_count, max_mip_count);
}
EXPECT_EQ(max_mip_count, blur_required_mip_count);
// The log is FML_DLOG, so only check in debug builds.
#ifndef NDEBUG
if (GetParam() != PlaygroundBackend::kOpenGLES) {
EXPECT_EQ(log_capture.str().find(GaussianBlurFilterContents::kNoMipsError),
std::string::npos);
} else {
EXPECT_NE(log_capture.str().find(GaussianBlurFilterContents::kNoMipsError),
std::string::npos);
}
#endif
}

TEST_P(AiksTest, GaussianBlurMipMapSolidColor) {
size_t blur_required_mip_count =
GetParam() == PlaygroundBackend::kOpenGLES ? 1 : 4;
fml::testing::LogCapture log_capture;
Canvas canvas;
canvas.DrawPath(PathBuilder{}
.MoveTo({100, 100})
.LineTo({200, 100})
.LineTo({150, 200})
.LineTo({50, 200})
.Close()
.TakePath(),
{.color = Color::Chartreuse(),
.image_filter = ImageFilter::MakeBlur(
Sigma(30), Sigma(30), FilterContents::BlurStyle::kNormal,
Entity::TileMode::kClamp)});

Picture picture = canvas.EndRecordingAsPicture();
std::shared_ptr<RenderTargetCache> cache =
std::make_shared<RenderTargetCache>(GetContext()->GetResourceAllocator());
AiksContext aiks_context(GetContext(), nullptr, cache);
picture.ToImage(aiks_context, {1024, 768});

size_t max_mip_count = 0;
for (auto it = cache->GetRenderTargetDataBegin();
it != cache->GetRenderTargetDataEnd(); ++it) {
max_mip_count = std::max(it->config.mip_count, max_mip_count);
}
EXPECT_EQ(max_mip_count, blur_required_mip_count);
// The log is FML_DLOG, so only check in debug builds.
#ifndef NDEBUG
if (GetParam() != PlaygroundBackend::kOpenGLES) {
EXPECT_EQ(log_capture.str().find(GaussianBlurFilterContents::kNoMipsError),
std::string::npos);
} else {
EXPECT_NE(log_capture.str().find(GaussianBlurFilterContents::kNoMipsError),
std::string::npos);
}
#endif
}

TEST_P(AiksTest, MaskBlurDoesntStretchContents) {
Scalar sigma = 70;
auto callback = [&](AiksContext& renderer) -> std::optional<Picture> {
Expand Down
41 changes: 0 additions & 41 deletions impeller/aiks/canvas.cc
Original file line number Diff line number Diff line change
Expand Up @@ -185,37 +185,6 @@ void Canvas::Save(uint32_t total_content_depth) {
Save(false, total_content_depth);
}

namespace {
class MipCountVisitor : public ImageFilterVisitor {
public:
virtual void Visit(const BlurImageFilter& filter) {
required_mip_count_ = FilterContents::kBlurFilterRequiredMipCount;
}
virtual void Visit(const LocalMatrixImageFilter& filter) {
required_mip_count_ = 1;
}
virtual void Visit(const DilateImageFilter& filter) {
required_mip_count_ = 1;
}
virtual void Visit(const ErodeImageFilter& filter) {
required_mip_count_ = 1;
}
virtual void Visit(const MatrixImageFilter& filter) {
required_mip_count_ = 1;
}
virtual void Visit(const ComposeImageFilter& filter) {
required_mip_count_ = 1;
}
virtual void Visit(const ColorImageFilter& filter) {
required_mip_count_ = 1;
}
int32_t GetRequiredMipCount() const { return required_mip_count_; }

private:
int32_t required_mip_count_ = -1;
};
} // namespace

void Canvas::Save(bool create_subpass,
uint32_t total_content_depth,
BlendMode blend_mode,
Expand All @@ -240,11 +209,6 @@ void Canvas::Save(bool create_subpass,
return filter;
};
subpass->SetBackdropFilter(backdrop_filter_proc);
MipCountVisitor mip_count_visitor;
backdrop_filter->Visit(mip_count_visitor);
current_pass_->SetRequiredMipCount(
std::max(current_pass_->GetRequiredMipCount(),
mip_count_visitor.GetRequiredMipCount()));
}
subpass->SetBlendMode(blend_mode);
current_pass_ = GetCurrentPass().AddSubpass(std::move(subpass));
Expand Down Expand Up @@ -868,11 +832,6 @@ void Canvas::SaveLayer(const Paint& paint,
new_layer_pass.SetBoundsLimit(bounds, bounds_promise);
}

if (paint.image_filter) {
MipCountVisitor mip_count_visitor;
paint.image_filter->Visit(mip_count_visitor);
new_layer_pass.SetRequiredMipCount(mip_count_visitor.GetRequiredMipCount());
}
// When applying a save layer, absorb any pending distributed opacity.
Paint paint_copy = paint;
paint_copy.color.alpha *= transform_stack_.back().distributed_opacity;
Expand Down
1 change: 1 addition & 0 deletions impeller/entity/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ impeller_shaders("entity_shaders") {
"shaders/blending/vertices_uber.frag",
"shaders/gradients/fast_gradient.vert",
"shaders/gradients/fast_gradient.frag",
"shaders/texture_downsample.frag",
]
}

Expand Down
1 change: 1 addition & 0 deletions impeller/entity/contents/content_context.cc
Original file line number Diff line number Diff line change
Expand Up @@ -428,6 +428,7 @@ ContentContext::ContentContext(
{static_cast<Scalar>(BlendSelectValues::kSoftLight), supports_decal});
}

texture_downsample_pipelines_.CreateDefault(*context_, options_trianglestrip);
rrect_blur_pipelines_.CreateDefault(*context_, options_trianglestrip);
texture_strict_src_pipelines_.CreateDefault(*context_, options);
tiled_texture_pipelines_.CreateDefault(*context_, options, {supports_decal});
Expand Down
10 changes: 10 additions & 0 deletions impeller/entity/contents/content_context.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
#include "impeller/entity/solid_fill.vert.h"
#include "impeller/entity/srgb_to_linear_filter.frag.h"
#include "impeller/entity/sweep_gradient_fill.frag.h"
#include "impeller/entity/texture_downsample.frag.h"
#include "impeller/entity/texture_fill.frag.h"
#include "impeller/entity/texture_fill.vert.h"
#include "impeller/entity/texture_fill_strict_src.frag.h"
Expand Down Expand Up @@ -110,6 +111,9 @@ using RRectBlurPipeline =
RenderPipelineHandle<RrectBlurVertexShader, RrectBlurFragmentShader>;
using TexturePipeline =
RenderPipelineHandle<TextureFillVertexShader, TextureFillFragmentShader>;
using TextureDownsamplePipeline =
RenderPipelineHandle<TextureFillVertexShader,
TextureDownsampleFragmentShader>;
using TextureStrictSrcPipeline =
RenderPipelineHandle<TextureFillVertexShader,
TextureFillStrictSrcFragmentShader>;
Expand Down Expand Up @@ -590,6 +594,11 @@ class ContentContext {
return GetPipeline(blend_softlight_pipelines_, opts);
}

std::shared_ptr<Pipeline<PipelineDescriptor>> GetDownsamplePipeline(
ContentContextOptions opts) const {
return GetPipeline(texture_downsample_pipelines_, opts);
}

// Framebuffer Advanced Blends
std::shared_ptr<Pipeline<PipelineDescriptor>>
GetFramebufferBlendColorPipeline(ContentContextOptions opts) const {
Expand Down Expand Up @@ -881,6 +890,7 @@ class ContentContext {
sweep_gradient_ssbo_fill_pipelines_;
mutable Variants<RRectBlurPipeline> rrect_blur_pipelines_;
mutable Variants<TexturePipeline> texture_pipelines_;
mutable Variants<TextureDownsamplePipeline> texture_downsample_pipelines_;
mutable Variants<TextureStrictSrcPipeline> texture_strict_src_pipelines_;
#ifdef IMPELLER_ENABLE_OPENGLES
mutable Variants<TiledTextureExternalPipeline>
Expand Down
Loading