Reland: [Impeller] Use downsample shader for blur instead of mip levels. (flutter/engine#54149)
relands https://github.com/flutter/engine/pull/53760 reverted in https://github.com/flutter/engine/pull/54148 The fix for this was found with the help of Jonah. Part of a series of gaussian blur changes: 1) https://github.com/flutter/engine/pull/54148 1) https://github.com/flutter/engine/pull/54116 1) https://github.com/flutter/engine/pull/54150 1) https://github.com/flutter/engine/pull/54149 [C++, Objective-C, Java style guides]: https://github.com/flutter/engine/blob/main/CONTRIBUTING.md#style
This commit is contained in:
parent
62eab65524
commit
179daffb5a
@ -42203,6 +42203,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
|
||||
@ -45083,6 +45084,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
|
||||
|
@ -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> {
|
||||
|
@ -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,
|
||||
@ -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));
|
||||
@ -873,11 +837,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;
|
||||
|
@ -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",
|
||||
]
|
||||
}
|
||||
|
||||
|
@ -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});
|
||||
|
@ -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"
|
||||
@ -110,6 +111,9 @@ using RRectBlurPipeline =
|
||||
RenderPipelineHandle<RrectBlurVertexShader, RrectBlurFragmentShader>;
|
||||
using TexturePipeline =
|
||||
RenderPipelineHandle<TextureFillVertexShader, TextureFillFragmentShader>;
|
||||
using TextureDownsamplePipeline =
|
||||
RenderPipelineHandle<TextureFillVertexShader,
|
||||
TextureDownsampleFragmentShader>;
|
||||
using TextureStrictSrcPipeline =
|
||||
RenderPipelineHandle<TextureFillVertexShader,
|
||||
TextureFillStrictSrcFragmentShader>;
|
||||
@ -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 {
|
||||
@ -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>
|
||||
|
@ -9,6 +9,7 @@
|
||||
#include "flutter/fml/make_copyable.h"
|
||||
#include "impeller/entity/contents/clip_contents.h"
|
||||
#include "impeller/entity/contents/content_context.h"
|
||||
#include "impeller/entity/texture_downsample.frag.h"
|
||||
#include "impeller/entity/texture_fill.frag.h"
|
||||
#include "impeller/entity/texture_fill.vert.h"
|
||||
#include "impeller/renderer/render_pass.h"
|
||||
@ -19,8 +20,6 @@ namespace impeller {
|
||||
using GaussianBlurVertexShader = GaussianBlurPipeline::VertexShader;
|
||||
using GaussianBlurFragmentShader = GaussianBlurPipeline::FragmentShader;
|
||||
|
||||
const int32_t GaussianBlurFilterContents::kBlurFilterRequiredMipCount = 4;
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr Scalar kMaxSigma = 500.0f;
|
||||
@ -131,28 +130,13 @@ std::optional<Snapshot> GetSnapshot(const std::shared_ptr<FilterInput>& input,
|
||||
const ContentContext& renderer,
|
||||
const Entity& entity,
|
||||
const std::optional<Rect>& coverage_hint) {
|
||||
int32_t mip_count = GaussianBlurFilterContents::kBlurFilterRequiredMipCount;
|
||||
if (renderer.GetContext()->GetBackendType() ==
|
||||
Context::BackendType::kOpenGLES) {
|
||||
// TODO(https://github.com/flutter/flutter/issues/141732): Implement mip map
|
||||
// generation on opengles.
|
||||
mip_count = 1;
|
||||
}
|
||||
|
||||
std::optional<Snapshot> input_snapshot =
|
||||
input->GetSnapshot("GaussianBlur", renderer, entity,
|
||||
/*coverage_limit=*/coverage_hint,
|
||||
/*mip_count=*/mip_count);
|
||||
/*coverage_limit=*/coverage_hint);
|
||||
if (!input_snapshot.has_value()) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
// In order to avoid shimmering in downsampling step, we should have mips.
|
||||
if (input_snapshot->texture->GetMipCount() <= 1) {
|
||||
FML_DLOG(ERROR) << GaussianBlurFilterContents::kNoMipsError;
|
||||
}
|
||||
FML_DCHECK(!input_snapshot->texture->NeedsMipmapGeneration());
|
||||
|
||||
return input_snapshot;
|
||||
}
|
||||
|
||||
@ -242,6 +226,7 @@ DownsamplePassArgs CalculateDownsamplePassArgs(
|
||||
Scalar desired_scalar =
|
||||
std::min(GaussianBlurFilterContents::CalculateScale(scaled_sigma.x),
|
||||
GaussianBlurFilterContents::CalculateScale(scaled_sigma.y));
|
||||
|
||||
// TODO(jonahwilliams): If desired_scalar is 1.0 and we fully acquired the
|
||||
// gutter from the expanded_coverage_hint, we can skip the downsample pass.
|
||||
// pass.
|
||||
@ -344,6 +329,11 @@ fml::StatusOr<RenderTarget> MakeDownsampleSubpass(
|
||||
const SamplerDescriptor& sampler_descriptor,
|
||||
const DownsamplePassArgs& pass_args,
|
||||
Entity::TileMode tile_mode) {
|
||||
// If the texture already had mip levels generated, then we can use the
|
||||
// original downsample shader.
|
||||
if (pass_args.effective_scalar.x >= 0.5f ||
|
||||
(!input_texture->NeedsMipmapGeneration() &&
|
||||
input_texture->GetTextureDescriptor().mip_count > 1)) {
|
||||
ContentContext::SubpassCallback subpass_callback =
|
||||
[&](const ContentContext& renderer, RenderPass& pass) {
|
||||
HostBuffer& host_buffer = renderer.GetTransientsBuffer();
|
||||
@ -384,10 +374,64 @@ fml::StatusOr<RenderTarget> MakeDownsampleSubpass(
|
||||
|
||||
return pass.Draw().ok();
|
||||
};
|
||||
fml::StatusOr<RenderTarget> render_target =
|
||||
renderer.MakeSubpass("Gaussian Blur Filter", pass_args.subpass_size,
|
||||
return renderer.MakeSubpass("Gaussian Blur Filter", pass_args.subpass_size,
|
||||
command_buffer, subpass_callback);
|
||||
return render_target;
|
||||
} else {
|
||||
// This assumes we don't scale below 1/16.
|
||||
Scalar edge = 1.0;
|
||||
Scalar ratio = 0.25;
|
||||
if (pass_args.effective_scalar.x <= 0.0625f) {
|
||||
edge = 7.0;
|
||||
ratio = 1.0f / 64.0f;
|
||||
} else if (pass_args.effective_scalar.x <= 0.125f) {
|
||||
edge = 3.0;
|
||||
ratio = 1.0f / 16.0f;
|
||||
}
|
||||
ContentContext::SubpassCallback subpass_callback =
|
||||
[&](const ContentContext& renderer, RenderPass& pass) {
|
||||
HostBuffer& host_buffer = renderer.GetTransientsBuffer();
|
||||
|
||||
pass.SetCommandLabel("Gaussian blur downsample");
|
||||
auto pipeline_options = OptionsFromPass(pass);
|
||||
pipeline_options.primitive_type = PrimitiveType::kTriangleStrip;
|
||||
pass.SetPipeline(renderer.GetDownsamplePipeline(pipeline_options));
|
||||
|
||||
TextureFillVertexShader::FrameInfo frame_info;
|
||||
frame_info.mvp = Matrix::MakeOrthographic(ISize(1, 1));
|
||||
frame_info.texture_sampler_y_coord_scale = 1.0;
|
||||
|
||||
TextureDownsampleFragmentShader::FragInfo frag_info;
|
||||
frag_info.edge = edge;
|
||||
frag_info.ratio = ratio;
|
||||
frag_info.pixel_size = Vector2(1.0f / Size(input_texture->GetSize()));
|
||||
|
||||
const Quad& uvs = pass_args.uvs;
|
||||
BindVertices<TextureFillVertexShader>(pass, host_buffer,
|
||||
{
|
||||
{Point(0, 0), uvs[0]},
|
||||
{Point(1, 0), uvs[1]},
|
||||
{Point(0, 1), uvs[2]},
|
||||
{Point(1, 1), uvs[3]},
|
||||
});
|
||||
|
||||
SamplerDescriptor linear_sampler_descriptor = sampler_descriptor;
|
||||
SetTileMode(&linear_sampler_descriptor, renderer, tile_mode);
|
||||
linear_sampler_descriptor.mag_filter = MinMagFilter::kLinear;
|
||||
linear_sampler_descriptor.min_filter = MinMagFilter::kLinear;
|
||||
TextureFillVertexShader::BindFrameInfo(
|
||||
pass, host_buffer.EmplaceUniform(frame_info));
|
||||
TextureDownsampleFragmentShader::BindFragInfo(
|
||||
pass, host_buffer.EmplaceUniform(frag_info));
|
||||
TextureDownsampleFragmentShader::BindTextureSampler(
|
||||
pass, input_texture,
|
||||
renderer.GetContext()->GetSamplerLibrary()->GetSampler(
|
||||
linear_sampler_descriptor));
|
||||
|
||||
return pass.Draw().ok();
|
||||
};
|
||||
return renderer.MakeSubpass("Gaussian Blur Filter", pass_args.subpass_size,
|
||||
command_buffer, subpass_callback);
|
||||
}
|
||||
}
|
||||
|
||||
fml::StatusOr<RenderTarget> MakeBlurSubpass(
|
||||
@ -554,9 +598,6 @@ Entity ApplyBlurStyle(FilterContents::BlurStyle blur_style,
|
||||
}
|
||||
} // namespace
|
||||
|
||||
std::string_view GaussianBlurFilterContents::kNoMipsError =
|
||||
"Applying gaussian blur without mipmap.";
|
||||
|
||||
GaussianBlurFilterContents::GaussianBlurFilterContents(
|
||||
Scalar sigma_x,
|
||||
Scalar sigma_y,
|
||||
|
@ -46,9 +46,6 @@ GaussianBlurPipeline::FragmentShader::KernelSamples LerpHackKernelSamples(
|
||||
/// Note: This will replace `DirectionalGaussianBlurFilterContents`.
|
||||
class GaussianBlurFilterContents final : public FilterContents {
|
||||
public:
|
||||
static std::string_view kNoMipsError;
|
||||
static const int32_t kBlurFilterRequiredMipCount;
|
||||
|
||||
explicit GaussianBlurFilterContents(
|
||||
Scalar sigma_x,
|
||||
Scalar sigma_y,
|
||||
|
@ -0,0 +1,34 @@
|
||||
// Copyright 2013 The Flutter Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
precision mediump float;
|
||||
|
||||
#include <impeller/constants.glsl>
|
||||
#include <impeller/types.glsl>
|
||||
|
||||
uniform f16sampler2D texture_sampler;
|
||||
|
||||
uniform FragInfo {
|
||||
float edge;
|
||||
float ratio;
|
||||
vec2 pixel_size;
|
||||
}
|
||||
frag_info;
|
||||
|
||||
in highp vec2 v_texture_coords;
|
||||
|
||||
out vec4 frag_color;
|
||||
|
||||
void main() {
|
||||
vec4 total = vec4(0.0);
|
||||
for (float i = -frag_info.edge; i <= frag_info.edge; i += 2) {
|
||||
for (float j = -frag_info.edge; j <= frag_info.edge; j += 2) {
|
||||
total += (texture(texture_sampler,
|
||||
v_texture_coords + frag_info.pixel_size * vec2(i, j),
|
||||
float16_t(kDefaultMipBias)) *
|
||||
frag_info.ratio);
|
||||
}
|
||||
}
|
||||
frag_color = total;
|
||||
}
|
@ -4729,6 +4729,126 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"flutter/impeller/entity/gles/texture_downsample.frag.gles": {
|
||||
"Mali-G78": {
|
||||
"core": "Mali-G78",
|
||||
"filename": "flutter/impeller/entity/gles/texture_downsample.frag.gles",
|
||||
"has_side_effects": false,
|
||||
"has_uniform_computation": true,
|
||||
"modifies_coverage": false,
|
||||
"reads_color_buffer": false,
|
||||
"type": "Fragment",
|
||||
"uses_late_zs_test": false,
|
||||
"uses_late_zs_update": false,
|
||||
"variants": {
|
||||
"Main": {
|
||||
"fp16_arithmetic": 80,
|
||||
"has_stack_spilling": false,
|
||||
"performance": {
|
||||
"longest_path_bound_pipelines": [
|
||||
null
|
||||
],
|
||||
"longest_path_cycles": [
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null
|
||||
],
|
||||
"pipelines": [
|
||||
"arith_total",
|
||||
"arith_fma",
|
||||
"arith_cvt",
|
||||
"arith_sfu",
|
||||
"load_store",
|
||||
"varying",
|
||||
"texture"
|
||||
],
|
||||
"shortest_path_bound_pipelines": [
|
||||
"arith_total",
|
||||
"arith_cvt"
|
||||
],
|
||||
"shortest_path_cycles": [
|
||||
0.0625,
|
||||
0.0,
|
||||
0.0625,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0
|
||||
],
|
||||
"total_bound_pipelines": [
|
||||
"arith_total",
|
||||
"arith_cvt",
|
||||
"varying",
|
||||
"texture"
|
||||
],
|
||||
"total_cycles": [
|
||||
0.25,
|
||||
0.125,
|
||||
0.25,
|
||||
0.0,
|
||||
0.0,
|
||||
0.25,
|
||||
0.25
|
||||
]
|
||||
},
|
||||
"stack_spill_bytes": 0,
|
||||
"thread_occupancy": 100,
|
||||
"uniform_registers_used": 6,
|
||||
"work_registers_used": 19
|
||||
}
|
||||
}
|
||||
},
|
||||
"Mali-T880": {
|
||||
"core": "Mali-T880",
|
||||
"filename": "flutter/impeller/entity/gles/texture_downsample.frag.gles",
|
||||
"has_uniform_computation": false,
|
||||
"type": "Fragment",
|
||||
"variants": {
|
||||
"Main": {
|
||||
"has_stack_spilling": false,
|
||||
"performance": {
|
||||
"longest_path_bound_pipelines": [
|
||||
null
|
||||
],
|
||||
"longest_path_cycles": [
|
||||
null,
|
||||
null,
|
||||
null
|
||||
],
|
||||
"pipelines": [
|
||||
"arithmetic",
|
||||
"load_store",
|
||||
"texture"
|
||||
],
|
||||
"shortest_path_bound_pipelines": [
|
||||
"arithmetic",
|
||||
"load_store"
|
||||
],
|
||||
"shortest_path_cycles": [
|
||||
1.0,
|
||||
1.0,
|
||||
0.0
|
||||
],
|
||||
"total_bound_pipelines": [
|
||||
"arithmetic"
|
||||
],
|
||||
"total_cycles": [
|
||||
3.3333332538604736,
|
||||
1.0,
|
||||
1.0
|
||||
]
|
||||
},
|
||||
"thread_occupancy": 100,
|
||||
"uniform_registers_used": 1,
|
||||
"work_registers_used": 4
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"flutter/impeller/entity/gles/texture_fill.frag.gles": {
|
||||
"Mali-G78": {
|
||||
"core": "Mali-G78",
|
||||
@ -7322,6 +7442,78 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"flutter/impeller/entity/texture_downsample.frag.vkspv": {
|
||||
"Mali-G78": {
|
||||
"core": "Mali-G78",
|
||||
"filename": "flutter/impeller/entity/texture_downsample.frag.vkspv",
|
||||
"has_side_effects": false,
|
||||
"has_uniform_computation": true,
|
||||
"modifies_coverage": false,
|
||||
"reads_color_buffer": false,
|
||||
"type": "Fragment",
|
||||
"uses_late_zs_test": false,
|
||||
"uses_late_zs_update": false,
|
||||
"variants": {
|
||||
"Main": {
|
||||
"fp16_arithmetic": 40,
|
||||
"has_stack_spilling": false,
|
||||
"performance": {
|
||||
"longest_path_bound_pipelines": [
|
||||
null
|
||||
],
|
||||
"longest_path_cycles": [
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null
|
||||
],
|
||||
"pipelines": [
|
||||
"arith_total",
|
||||
"arith_fma",
|
||||
"arith_cvt",
|
||||
"arith_sfu",
|
||||
"load_store",
|
||||
"varying",
|
||||
"texture"
|
||||
],
|
||||
"shortest_path_bound_pipelines": [
|
||||
"arith_total",
|
||||
"arith_cvt"
|
||||
],
|
||||
"shortest_path_cycles": [
|
||||
0.109375,
|
||||
0.0,
|
||||
0.109375,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0
|
||||
],
|
||||
"total_bound_pipelines": [
|
||||
"arith_total",
|
||||
"arith_cvt"
|
||||
],
|
||||
"total_cycles": [
|
||||
0.328125,
|
||||
0.09375,
|
||||
0.328125,
|
||||
0.0,
|
||||
0.0,
|
||||
0.25,
|
||||
0.25
|
||||
]
|
||||
},
|
||||
"stack_spill_bytes": 0,
|
||||
"thread_occupancy": 100,
|
||||
"uniform_registers_used": 8,
|
||||
"work_registers_used": 14
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"flutter/impeller/entity/texture_fill.frag.vkspv": {
|
||||
"Mali-G78": {
|
||||
"core": "Mali-G78",
|
||||
|
Loading…
x
Reference in New Issue
Block a user