blob: 4db42708a4b93ca1e790a2770e78270d73d176c0 [file] [log] [blame]
// 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.
#include "impeller/entity/contents/filters/filter_contents.h"
#include <algorithm>
#include <cmath>
#include <cstddef>
#include <memory>
#include <optional>
#include <tuple>
#include <utility>
#include "flutter/fml/logging.h"
#include "impeller/core/formats.h"
#include "impeller/entity/contents/content_context.h"
#include "impeller/entity/contents/filters/border_mask_blur_filter_contents.h"
#include "impeller/entity/contents/filters/gaussian_blur_filter_contents.h"
#include "impeller/entity/contents/filters/inputs/filter_input.h"
#include "impeller/entity/contents/filters/local_matrix_filter_contents.h"
#include "impeller/entity/contents/filters/matrix_filter_contents.h"
#include "impeller/entity/contents/filters/morphology_filter_contents.h"
#include "impeller/entity/contents/filters/yuv_to_rgb_filter_contents.h"
#include "impeller/entity/contents/texture_contents.h"
#include "impeller/entity/entity.h"
#include "impeller/geometry/path_builder.h"
#include "impeller/renderer/command_buffer.h"
#include "impeller/renderer/render_pass.h"
namespace impeller {
const int32_t FilterContents::kBlurFilterRequiredMipCount =
GaussianBlurFilterContents::kBlurFilterRequiredMipCount;
std::shared_ptr<FilterContents> FilterContents::MakeGaussianBlur(
const FilterInput::Ref& input,
Sigma sigma_x,
Sigma sigma_y,
Entity::TileMode tile_mode,
FilterContents::BlurStyle mask_blur_style,
const std::shared_ptr<Geometry>& mask_geometry) {
auto blur = std::make_shared<GaussianBlurFilterContents>(
sigma_x.sigma, sigma_y.sigma, tile_mode, mask_blur_style, mask_geometry);
blur->SetInputs({input});
return blur;
}
std::shared_ptr<FilterContents> FilterContents::MakeBorderMaskBlur(
FilterInput::Ref input,
Sigma sigma_x,
Sigma sigma_y,
BlurStyle blur_style) {
auto filter = std::make_shared<BorderMaskBlurFilterContents>();
filter->SetInputs({std::move(input)});
filter->SetSigma(sigma_x, sigma_y);
filter->SetBlurStyle(blur_style);
return filter;
}
std::shared_ptr<FilterContents> FilterContents::MakeDirectionalMorphology(
FilterInput::Ref input,
Radius radius,
Vector2 direction,
MorphType morph_type) {
auto filter = std::make_shared<DirectionalMorphologyFilterContents>();
filter->SetInputs({std::move(input)});
filter->SetRadius(radius);
filter->SetDirection(direction);
filter->SetMorphType(morph_type);
return filter;
}
std::shared_ptr<FilterContents> FilterContents::MakeMorphology(
FilterInput::Ref input,
Radius radius_x,
Radius radius_y,
MorphType morph_type) {
auto x_morphology = MakeDirectionalMorphology(std::move(input), radius_x,
Point(1, 0), morph_type);
auto y_morphology = MakeDirectionalMorphology(
FilterInput::Make(x_morphology), radius_y, Point(0, 1), morph_type);
return y_morphology;
}
std::shared_ptr<FilterContents> FilterContents::MakeMatrixFilter(
FilterInput::Ref input,
const Matrix& matrix,
const SamplerDescriptor& desc) {
auto filter = std::make_shared<MatrixFilterContents>();
filter->SetInputs({std::move(input)});
filter->SetMatrix(matrix);
filter->SetSamplerDescriptor(desc);
return filter;
}
std::shared_ptr<FilterContents> FilterContents::MakeLocalMatrixFilter(
FilterInput::Ref input,
const Matrix& matrix) {
auto filter = std::make_shared<LocalMatrixFilterContents>();
filter->SetInputs({std::move(input)});
filter->SetMatrix(matrix);
return filter;
}
std::shared_ptr<FilterContents> FilterContents::MakeYUVToRGBFilter(
std::shared_ptr<Texture> y_texture,
std::shared_ptr<Texture> uv_texture,
YUVColorSpace yuv_color_space) {
auto filter = std::make_shared<impeller::YUVToRGBFilterContents>();
filter->SetInputs({impeller::FilterInput::Make(y_texture),
impeller::FilterInput::Make(uv_texture)});
filter->SetYUVColorSpace(yuv_color_space);
return filter;
}
FilterContents::FilterContents() = default;
FilterContents::~FilterContents() = default;
void FilterContents::SetInputs(FilterInput::Vector inputs) {
inputs_ = std::move(inputs);
}
void FilterContents::SetEffectTransform(const Matrix& effect_transform) {
effect_transform_ = effect_transform;
for (auto& input : inputs_) {
input->SetEffectTransform(effect_transform);
}
}
bool FilterContents::Render(const ContentContext& renderer,
const Entity& entity,
RenderPass& pass) const {
auto filter_coverage = GetCoverage(entity);
if (!filter_coverage.has_value()) {
return true;
}
// Run the filter.
auto maybe_entity = GetEntity(renderer, entity, GetCoverageHint());
if (!maybe_entity.has_value()) {
return true;
}
maybe_entity->SetNewClipDepth(entity.GetNewClipDepth());
return maybe_entity->Render(renderer, pass);
}
std::optional<Rect> FilterContents::GetLocalCoverage(
const Entity& local_entity) const {
auto coverage = GetFilterCoverage(inputs_, local_entity, effect_transform_);
auto coverage_hint = GetCoverageHint();
if (coverage_hint.has_value() && coverage.has_value()) {
coverage = coverage->Intersection(coverage_hint.value());
}
return coverage;
}
std::optional<Rect> FilterContents::GetCoverage(const Entity& entity) const {
Entity entity_with_local_transform = entity.Clone();
entity_with_local_transform.SetTransform(GetTransform(entity.GetTransform()));
return GetLocalCoverage(entity_with_local_transform);
}
void FilterContents::PopulateGlyphAtlas(
const std::shared_ptr<LazyGlyphAtlas>& lazy_glyph_atlas,
Scalar scale) {
for (auto& input : inputs_) {
input->PopulateGlyphAtlas(lazy_glyph_atlas, scale);
}
}
std::optional<Rect> FilterContents::GetFilterCoverage(
const FilterInput::Vector& inputs,
const Entity& entity,
const Matrix& effect_transform) const {
// The default coverage of FilterContents is just the union of its inputs'
// coverage. FilterContents implementations may choose to adjust this
// coverage depending on the use case.
if (inputs_.empty()) {
return std::nullopt;
}
std::optional<Rect> result;
for (const auto& input : inputs) {
auto coverage = input->GetCoverage(entity);
if (!coverage.has_value()) {
continue;
}
if (!result.has_value()) {
result = coverage;
continue;
}
result = result->Union(coverage.value());
}
return result;
}
std::optional<Rect> FilterContents::GetSourceCoverage(
const Matrix& effect_transform,
const Rect& output_limit) const {
auto filter_input_coverage =
GetFilterSourceCoverage(effect_transform_, output_limit);
if (!filter_input_coverage.has_value()) {
return std::nullopt;
}
std::optional<Rect> inputs_coverage;
for (const auto& input : inputs_) {
auto input_coverage = input->GetSourceCoverage(
effect_transform, filter_input_coverage.value());
if (!input_coverage.has_value()) {
return std::nullopt;
}
inputs_coverage = Rect::Union(inputs_coverage, input_coverage.value());
}
return inputs_coverage;
}
std::optional<Entity> FilterContents::GetEntity(
const ContentContext& renderer,
const Entity& entity,
const std::optional<Rect>& coverage_hint) const {
Entity entity_with_local_transform = entity.Clone();
entity_with_local_transform.SetTransform(GetTransform(entity.GetTransform()));
auto coverage = GetLocalCoverage(entity_with_local_transform);
if (!coverage.has_value() || coverage->IsEmpty()) {
return std::nullopt;
}
return RenderFilter(inputs_, renderer, entity_with_local_transform,
effect_transform_, coverage.value(), coverage_hint);
}
std::optional<Snapshot> FilterContents::RenderToSnapshot(
const ContentContext& renderer,
const Entity& entity,
std::optional<Rect> coverage_limit,
const std::optional<SamplerDescriptor>& sampler_descriptor,
bool msaa_enabled,
int32_t mip_count,
const std::string& label) const {
// Resolve the render instruction (entity) from the filter and render it to a
// snapshot.
if (std::optional<Entity> result =
GetEntity(renderer, entity, coverage_limit);
result.has_value()) {
return result->GetContents()->RenderToSnapshot(
renderer, // renderer
result.value(), // entity
coverage_limit, // coverage_limit
std::nullopt, // sampler_descriptor
true, // msaa_enabled
/*mip_count=*/mip_count,
label); // label
}
return std::nullopt;
}
const FilterContents* FilterContents::AsFilter() const {
return this;
}
Matrix FilterContents::GetLocalTransform(const Matrix& parent_transform) const {
return Matrix();
}
Matrix FilterContents::GetTransform(const Matrix& parent_transform) const {
return parent_transform * GetLocalTransform(parent_transform);
}
bool FilterContents::IsTranslationOnly() const {
for (auto& input : inputs_) {
if (!input->IsTranslationOnly()) {
return false;
}
}
return true;
}
bool FilterContents::IsLeaf() const {
for (auto& input : inputs_) {
if (!input->IsLeaf()) {
return false;
}
}
return true;
}
void FilterContents::SetLeafInputs(const FilterInput::Vector& inputs) {
if (IsLeaf()) {
inputs_ = inputs;
return;
}
for (auto& input : inputs_) {
input->SetLeafInputs(inputs);
}
}
void FilterContents::SetRenderingMode(Entity::RenderingMode rendering_mode) {
for (auto& input : inputs_) {
input->SetRenderingMode(rendering_mode);
}
}
} // namespace impeller