[Impeller] Avoid unnecessary pre-pass when filtering images (flutter/engine#35422)

This commit is contained in:
Brandon DeRosier 2022-08-16 14:03:36 -07:00 committed by GitHub
parent b14d555542
commit c033c0ed34
8 changed files with 61 additions and 21 deletions

View File

@ -274,8 +274,7 @@ void Canvas::DrawImageRect(std::shared_ptr<Image> image,
return;
}
auto contents = std::make_shared<TextureContents>();
contents->SetPath(PathBuilder{}.AddRect(dest).TakePath());
auto contents = TextureContents::MakeRect(dest);
contents->SetTexture(image->GetTexture());
contents->SetSourceRect(source);
contents->SetSamplerDescriptor(std::move(sampler));

View File

@ -34,9 +34,7 @@ bool PaintPassDelegate::CanCollapseIntoParentPass() {
// |EntityPassDelgate|
std::shared_ptr<Contents> PaintPassDelegate::CreateContentsForSubpassTarget(
std::shared_ptr<Texture> target) {
auto contents = std::make_shared<TextureContents>();
contents->SetPath(
PathBuilder{}.AddRect(Rect::MakeSize(target->GetSize())).TakePath());
auto contents = TextureContents::MakeRect(Rect::MakeSize(target->GetSize()));
contents->SetTexture(target);
contents->SetSourceRect(Rect::MakeSize(target->GetSize()));
contents->SetOpacity(paint_.color.alpha);

View File

@ -152,10 +152,9 @@ bool FilterContents::Render(const ContentContext& renderer,
// Draw the result texture, respecting the transform and clip stack.
auto contents = std::make_shared<TextureContents>();
contents->SetPath(
PathBuilder{}.AddRect(filter_coverage.value()).GetCurrentPath());
auto contents = TextureContents::MakeRect(filter_coverage.value());
contents->SetTexture(snapshot.texture);
contents->SetSamplerDescriptor(snapshot.sampler_descriptor);
contents->SetSourceRect(Rect::MakeSize(snapshot.texture->GetSize()));
Entity e;

View File

@ -104,6 +104,7 @@ std::optional<Snapshot> DirectionalGaussianBlurFilterContents::RenderFilter(
if (!input_snapshot.has_value()) {
return std::nullopt;
}
auto maybe_input_uvs = input_snapshot->GetCoverageUVs(coverage);
if (!maybe_input_uvs.has_value()) {
return std::nullopt;
@ -164,12 +165,6 @@ std::optional<Snapshot> DirectionalGaussianBlurFilterContents::RenderFilter(
frag_info.outer_blur_factor = outer_blur_factor_;
frag_info.texture_size = Point(input_snapshot->GetCoverage().value().size);
SamplerDescriptor sampler_desc;
sampler_desc.min_filter = MinMagFilter::kLinear;
sampler_desc.mag_filter = MinMagFilter::kLinear;
auto sampler =
renderer.GetContext()->GetSamplerLibrary()->GetSampler(sampler_desc);
Command cmd;
cmd.label = "Gaussian Blur Filter";
auto options = OptionsFromPass(pass);
@ -177,8 +172,14 @@ std::optional<Snapshot> DirectionalGaussianBlurFilterContents::RenderFilter(
cmd.pipeline = renderer.GetGaussianBlurPipeline(options);
cmd.BindVertices(vtx_buffer);
FS::BindTextureSampler(cmd, input_snapshot->texture, sampler);
FS::BindAlphaMaskSampler(cmd, source_snapshot->texture, sampler);
FS::BindTextureSampler(
cmd, input_snapshot->texture,
renderer.GetContext()->GetSamplerLibrary()->GetSampler(
input_snapshot->sampler_descriptor));
FS::BindAlphaMaskSampler(
cmd, source_snapshot->texture,
renderer.GetContext()->GetSamplerLibrary()->GetSampler(
source_snapshot->sampler_descriptor));
VS::BindFrameInfo(cmd, host_buffer.EmplaceUniform(frame_info));
FS::BindFragInfo(cmd, host_buffer.EmplaceUniform(frag_info));
@ -191,8 +192,13 @@ std::optional<Snapshot> DirectionalGaussianBlurFilterContents::RenderFilter(
}
out_texture->SetLabel("DirectionalGaussianBlurFilter Texture");
SamplerDescriptor sampler_desc;
sampler_desc.min_filter = MinMagFilter::kLinear;
sampler_desc.mag_filter = MinMagFilter::kLinear;
return Snapshot{.texture = out_texture,
.transform = Matrix::MakeTranslation(coverage.origin)};
.transform = Matrix::MakeTranslation(coverage.origin),
.sampler_descriptor = sampler_desc};
}
std::optional<Rect> DirectionalGaussianBlurFilterContents::GetFilterCoverage(

View File

@ -4,12 +4,14 @@
#include "texture_contents.h"
#include <memory>
#include <optional>
#include "impeller/entity/contents/content_context.h"
#include "impeller/entity/entity.h"
#include "impeller/entity/texture_fill.frag.h"
#include "impeller/entity/texture_fill.vert.h"
#include "impeller/geometry/path_builder.h"
#include "impeller/renderer/render_pass.h"
#include "impeller/renderer/sampler_library.h"
#include "impeller/tessellator/tessellator.h"
@ -20,8 +22,16 @@ TextureContents::TextureContents() = default;
TextureContents::~TextureContents() = default;
std::shared_ptr<TextureContents> TextureContents::MakeRect(Rect destination) {
auto contents = std::make_shared<TextureContents>();
contents->path_ = PathBuilder{}.AddRect(destination).TakePath();
contents->is_rect_ = true;
return contents;
}
void TextureContents::SetPath(Path path) {
path_ = std::move(path);
is_rect_ = false;
}
void TextureContents::SetTexture(std::shared_ptr<Texture> texture) {
@ -43,6 +53,22 @@ std::optional<Rect> TextureContents::GetCoverage(const Entity& entity) const {
return path_.GetTransformedBoundingBox(entity.GetTransformation());
};
std::optional<Snapshot> TextureContents::RenderToSnapshot(
const ContentContext& renderer,
const Entity& entity) const {
// Passthrough textures that have simple rectangle paths and complete source
// rects.
if (is_rect_ && source_rect_ == Rect::MakeSize(texture_->GetSize())) {
auto scale =
Vector2(path_.GetBoundingBox()->size / Size(texture_->GetSize()));
return Snapshot{
.texture = texture_,
.transform = entity.GetTransformation() * Matrix::MakeScale(scale),
.sampler_descriptor = sampler_descriptor_};
}
return Contents::RenderToSnapshot(renderer, entity);
}
bool TextureContents::Render(const ContentContext& renderer,
const Entity& entity,
RenderPass& pass) const {

View File

@ -23,6 +23,11 @@ class TextureContents final : public Contents {
~TextureContents() override;
/// @brief A common case factory that marks the texture contents as having a
/// destination rectangle. In this situation, a subpass can be avoided
/// when image filters are applied.
static std::shared_ptr<TextureContents> MakeRect(Rect destination);
void SetPath(Path path);
void SetTexture(std::shared_ptr<Texture> texture);
@ -42,13 +47,18 @@ class TextureContents final : public Contents {
// |Contents|
std::optional<Rect> GetCoverage(const Entity& entity) const override;
// |Contents|
std::optional<Snapshot> RenderToSnapshot(const ContentContext& renderer,
const Entity& entity) const override;
// |Contents|
bool Render(const ContentContext& renderer,
const Entity& entity,
RenderPass& pass) const override;
public:
private:
Path path_;
bool is_rect_ = false;
std::shared_ptr<Texture> texture_;
SamplerDescriptor sampler_descriptor_ = {};

View File

@ -161,8 +161,7 @@ bool EntityPass::Render(ContentContext& renderer,
{
auto size_rect = Rect::MakeSize(offscreen_target.GetRenderTargetSize());
auto contents = std::make_shared<TextureContents>();
contents->SetPath(PathBuilder{}.AddRect(size_rect).TakePath());
auto contents = TextureContents::MakeRect(size_rect);
contents->SetTexture(offscreen_target.GetRenderTargetTexture());
contents->SetSourceRect(size_rect);

View File

@ -11,6 +11,7 @@
#include "flutter/fml/macros.h"
#include "impeller/geometry/matrix.h"
#include "impeller/geometry/rect.h"
#include "impeller/renderer/sampler_descriptor.h"
#include "impeller/renderer/texture.h"
namespace impeller {
@ -18,12 +19,14 @@ namespace impeller {
class ContentContext;
class Entity;
/// Represents a texture and its intended draw position.
/// Represents a texture and its intended draw transform/sampler configuration.
struct Snapshot {
std::shared_ptr<Texture> texture;
/// The transform that should be applied to this texture for rendering.
Matrix transform;
SamplerDescriptor sampler_descriptor;
std::optional<Rect> GetCoverage() const;
/// @brief Get the transform that converts screen space coordinates to the UV