From afb596d2b5c2b0e5519ac744c60b4f12dc818aef Mon Sep 17 00:00:00 2001 From: jonahwilliams Date: Tue, 4 Apr 2023 14:09:26 -0700 Subject: [PATCH 1/5] fix advanced blend inlining --- .../contents/filters/blend_filter_contents.cc | 11 +++++--- .../contents/foreground_blend_contents.cc | 26 +++++++++++++------ 2 files changed, 25 insertions(+), 12 deletions(-) diff --git a/impeller/entity/contents/filters/blend_filter_contents.cc b/impeller/entity/contents/filters/blend_filter_contents.cc index e8d7859845cee..5b02e04bb7355 100644 --- a/impeller/entity/contents/filters/blend_filter_contents.cc +++ b/impeller/entity/contents/filters/blend_filter_contents.cc @@ -382,10 +382,13 @@ std::optional BlendFilterContents::RenderFilter( contents->SetCoverage(coverage); contents->SetSrcInput(inputs[0]); contents->SetForegroundColor(foreground_color_.value()); - Entity entity; - entity.SetTransformation(Matrix::MakeTranslation(coverage.origin)); - entity.SetContents(std::move(contents)); - return entity; + + Entity sub_entity; + sub_entity.SetContents(std::move(contents)); + sub_entity.SetStencilDepth(entity.GetStencilDepth()); + sub_entity.SetTransformation(Matrix::MakeTranslation(coverage.origin) * + entity.GetTransformation()); + return sub_entity; } return advanced_blend_proc_(inputs, renderer, entity, coverage, diff --git a/impeller/entity/contents/foreground_blend_contents.cc b/impeller/entity/contents/foreground_blend_contents.cc index 93863efcabec5..7f62b94348af3 100644 --- a/impeller/entity/contents/foreground_blend_contents.cc +++ b/impeller/entity/contents/foreground_blend_contents.cc @@ -3,6 +3,7 @@ // found in the LICENSE file. #include "foreground_blend_contents.h" +#include #include "flutter/impeller/entity/contents/content_context.h" #include "flutter/impeller/renderer/render_pass.h" @@ -57,13 +58,23 @@ bool AdvancedForegroundBlendContents::Render(const ContentContext& renderer, auto size = rect_.size; VertexBufferBuilder vtx_builder; + // hack + dst_uvs[0] = Point(0.0, 0.0); + dst_uvs[1] = Point(1.0, 0.0); + dst_uvs[2] = Point(0.0, 1.0); + dst_uvs[3] = Point(1.0, 1.0); + vtx_builder.AddVertices({ - {Point(0, 0), dst_uvs[0], dst_uvs[0]}, - {Point(size.width, 0), dst_uvs[1], dst_uvs[1]}, - {Point(size.width, size.height), dst_uvs[3], dst_uvs[3]}, - {Point(0, 0), dst_uvs[0], dst_uvs[0]}, - {Point(size.width, size.height), dst_uvs[3], dst_uvs[3]}, - {Point(0, size.height), dst_uvs[2], dst_uvs[2]}, + {rect_.origin, dst_uvs[0], dst_uvs[0]}, + {Point(rect_.origin.x + size.width, rect_.origin.y), dst_uvs[1], + dst_uvs[1]}, + {Point(rect_.origin.x + size.width, rect_.origin.y + size.height), + dst_uvs[3], dst_uvs[3]}, + {rect_.origin, dst_uvs[0], dst_uvs[0]}, + {Point(rect_.origin.x + size.width, rect_.origin.y + size.height), + dst_uvs[3], dst_uvs[3]}, + {Point(rect_.origin.x, rect_.origin.y + size.height), dst_uvs[2], + dst_uvs[2]}, }); auto vtx_buffer = vtx_builder.CreateVertexBuffer(host_buffer); @@ -147,8 +158,7 @@ bool AdvancedForegroundBlendContents::Render(const ContentContext& renderer, auto blend_uniform = host_buffer.EmplaceUniform(blend_info); FS::BindBlendInfo(cmd, blend_uniform); - frame_info.mvp = Matrix::MakeOrthographic(pass.GetRenderTargetSize()) * - entity.GetTransformation(); + frame_info.mvp = Matrix::MakeOrthographic(pass.GetRenderTargetSize()); auto uniform_view = host_buffer.EmplaceUniform(frame_info); VS::BindFrameInfo(cmd, uniform_view); From 8cf02789941f61348b14a3fc0569cce1abe02b87 Mon Sep 17 00:00:00 2001 From: jonahwilliams Date: Tue, 4 Apr 2023 14:26:19 -0700 Subject: [PATCH 2/5] ++ --- .../contents/filters/blend_filter_contents.cc | 1 + .../contents/foreground_blend_contents.h | 50 +++++++++++++++++++ impeller/entity/entity_unittests.cc | 16 ++++++ 3 files changed, 67 insertions(+) create mode 100644 impeller/entity/contents/foreground_blend_contents.h diff --git a/impeller/entity/contents/filters/blend_filter_contents.cc b/impeller/entity/contents/filters/blend_filter_contents.cc index e80889183b71e..5b02e04bb7355 100644 --- a/impeller/entity/contents/filters/blend_filter_contents.cc +++ b/impeller/entity/contents/filters/blend_filter_contents.cc @@ -12,6 +12,7 @@ #include "impeller/entity/contents/content_context.h" #include "impeller/entity/contents/contents.h" #include "impeller/entity/contents/filters/inputs/filter_input.h" +#include "impeller/entity/contents/foreground_blend_contents.h" #include "impeller/entity/contents/solid_color_contents.h" #include "impeller/entity/entity.h" #include "impeller/geometry/path_builder.h" diff --git a/impeller/entity/contents/foreground_blend_contents.h b/impeller/entity/contents/foreground_blend_contents.h new file mode 100644 index 0000000000000..5a36353707410 --- /dev/null +++ b/impeller/entity/contents/foreground_blend_contents.h @@ -0,0 +1,50 @@ +// 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. + +#pragma once + +#include "flutter/fml/macros.h" +#include "flutter/impeller/core/texture.h" +#include "flutter/impeller/entity/contents/color_source_contents.h" +#include "flutter/impeller/entity/contents/filters/inputs/filter_input.h" +#include "flutter/impeller/entity/entity.h" + +namespace impeller { + +/// @brief Optimized advanced blend that avoids a second subpass when there is +/// only a single input and a foreground color. +/// +/// These contents cannot absorb opacity. +class AdvancedForegroundBlendContents : public Contents { + public: + AdvancedForegroundBlendContents(); + + ~AdvancedForegroundBlendContents(); + + void SetBlendMode(BlendMode blend_mode); + + void SetSrcInput(std::shared_ptr input); + + void SetForegroundColor(Color color); + + void SetCoverage(Rect rect); + + private: + // |Contents| + std::optional GetCoverage(const Entity& entity) const override; + + // |Contents| + bool Render(const ContentContext& renderer, + const Entity& entity, + RenderPass& pass) const override; + + Color foreground_color_; + BlendMode blend_mode_; + std::shared_ptr input_; + Rect rect_; + + FML_DISALLOW_COPY_AND_ASSIGN(AdvancedForegroundBlendContents); +}; + +} // namespace impeller diff --git a/impeller/entity/entity_unittests.cc b/impeller/entity/entity_unittests.cc index b7ad908cd0160..ab4ab77b1d9de 100644 --- a/impeller/entity/entity_unittests.cc +++ b/impeller/entity/entity_unittests.cc @@ -2451,5 +2451,21 @@ TEST_P(EntityTest, InheritOpacityTest) { ASSERT_FALSE(runtime_effect->CanInheritOpacity(entity)); } +TEST_P(EntityTest, ColorFilterWithForegroundColorAdvancedBlend) { + auto image = CreateTextureForFixture("boston.jpg"); + auto filter = ColorFilterContents::MakeBlend( + BlendMode::kColorBurn, FilterInput::Make({image}), Color::Red()); + + auto callback = [&](ContentContext& context, RenderPass& pass) -> bool { + Entity entity; + entity.SetTransformation(Matrix::MakeScale(GetContentScale()) * + Matrix::MakeTranslation({500, 300}) * + Matrix::MakeScale(Vector2{0.5, 0.5})); + entity.SetContents(filter); + return entity.Render(context, pass); + }; + ASSERT_TRUE(OpenPlaygroundHere(callback)); +} + } // namespace testing } // namespace impeller From 0410f7bbb8dbfd0ad6834542ed8a21fba45a23f3 Mon Sep 17 00:00:00 2001 From: jonahwilliams Date: Wed, 5 Apr 2023 19:03:14 -0700 Subject: [PATCH 3/5] move around --- impeller/entity/BUILD.gn | 2 - .../contents/filters/blend_filter_contents.cc | 151 +++++++++++++++- .../contents/filters/blend_filter_contents.h | 35 ++++ .../contents/foreground_blend_contents.cc | 169 ------------------ .../contents/foreground_blend_contents.h | 50 ------ 5 files changed, 185 insertions(+), 222 deletions(-) delete mode 100644 impeller/entity/contents/foreground_blend_contents.cc delete mode 100644 impeller/entity/contents/foreground_blend_contents.h diff --git a/impeller/entity/BUILD.gn b/impeller/entity/BUILD.gn index db1a195b55d3c..54af14f3796a6 100644 --- a/impeller/entity/BUILD.gn +++ b/impeller/entity/BUILD.gn @@ -180,8 +180,6 @@ impeller_component("entity") { "contents/filters/srgb_to_linear_filter_contents.h", "contents/filters/yuv_to_rgb_filter_contents.cc", "contents/filters/yuv_to_rgb_filter_contents.h", - "contents/foreground_blend_contents.cc", - "contents/foreground_blend_contents.h", "contents/framebuffer_blend_contents.cc", "contents/framebuffer_blend_contents.h", "contents/gradient_generator.cc", diff --git a/impeller/entity/contents/filters/blend_filter_contents.cc b/impeller/entity/contents/filters/blend_filter_contents.cc index 5b02e04bb7355..301ccc9c3c72f 100644 --- a/impeller/entity/contents/filters/blend_filter_contents.cc +++ b/impeller/entity/contents/filters/blend_filter_contents.cc @@ -12,7 +12,6 @@ #include "impeller/entity/contents/content_context.h" #include "impeller/entity/contents/contents.h" #include "impeller/entity/contents/filters/inputs/filter_input.h" -#include "impeller/entity/contents/foreground_blend_contents.h" #include "impeller/entity/contents/solid_color_contents.h" #include "impeller/entity/entity.h" #include "impeller/geometry/path_builder.h" @@ -399,4 +398,154 @@ std::optional BlendFilterContents::RenderFilter( FML_UNREACHABLE(); } +AdvancedForegroundBlendContents::AdvancedForegroundBlendContents() {} + +AdvancedForegroundBlendContents::~AdvancedForegroundBlendContents() {} + +void AdvancedForegroundBlendContents::SetBlendMode(BlendMode blend_mode) { + FML_DCHECK(blend_mode > Entity::kLastPipelineBlendMode); + blend_mode_ = blend_mode; +} + +void AdvancedForegroundBlendContents::SetSrcInput( + std::shared_ptr input) { + input_ = std::move(input); +} + +void AdvancedForegroundBlendContents::SetForegroundColor(Color color) { + foreground_color_ = color; +} + +void AdvancedForegroundBlendContents::SetCoverage(Rect rect) { + rect_ = rect; +} + +std::optional AdvancedForegroundBlendContents::GetCoverage( + const Entity& entity) const { + return rect_.TransformBounds(entity.GetTransformation()); +} + +bool AdvancedForegroundBlendContents::Render(const ContentContext& renderer, + const Entity& entity, + RenderPass& pass) const { + using VS = BlendScreenPipeline::VertexShader; + using FS = BlendScreenPipeline::FragmentShader; + + auto& host_buffer = pass.GetTransientsBuffer(); + + auto dst_snapshot = input_->GetSnapshot(renderer, entity); + if (!dst_snapshot.has_value()) { + return false; + } + + // This does not use the snapshot transform, since this value will + // be different depending on whether the filter was applied via a + // saveLayer or directly to a particular contents. By construction, + // the provided rectangle should exactly map to the texture coordinates. + std::array dst_uvs = {Point(0.0, 0.0), Point(1.0, 0.0), + Point(0.0, 1.0), Point(1.0, 1.0)}; + + auto size = rect_.size; + auto origin = rect_.origin; + VertexBufferBuilder vtx_builder; + vtx_builder.AddVertices({ + {origin, dst_uvs[0], dst_uvs[0]}, + {Point(origin.x + size.width, origin.y), dst_uvs[1], dst_uvs[1]}, + {Point(origin.x + size.width, origin.y + size.height), dst_uvs[3], + dst_uvs[3]}, + {origin, dst_uvs[0], dst_uvs[0]}, + {Point(origin.x + size.width, origin.y + size.height), dst_uvs[3], + dst_uvs[3]}, + {Point(origin.x, origin.y + size.height), dst_uvs[2], dst_uvs[2]}, + }); + auto vtx_buffer = vtx_builder.CreateVertexBuffer(host_buffer); + + Command cmd; + cmd.label = "Foreground Advanced Blend Filter"; + cmd.BindVertices(vtx_buffer); + cmd.stencil_reference = entity.GetStencilDepth(); + auto options = OptionsFromPass(pass); + + switch (blend_mode_) { + case BlendMode::kScreen: + cmd.pipeline = renderer.GetBlendScreenPipeline(options); + break; + case BlendMode::kOverlay: + cmd.pipeline = renderer.GetBlendOverlayPipeline(options); + break; + case BlendMode::kDarken: + cmd.pipeline = renderer.GetBlendDarkenPipeline(options); + break; + case BlendMode::kLighten: + cmd.pipeline = renderer.GetBlendLightenPipeline(options); + break; + case BlendMode::kColorDodge: + cmd.pipeline = renderer.GetBlendColorDodgePipeline(options); + break; + case BlendMode::kColorBurn: + cmd.pipeline = renderer.GetBlendColorBurnPipeline(options); + break; + case BlendMode::kHardLight: + cmd.pipeline = renderer.GetBlendHardLightPipeline(options); + break; + case BlendMode::kSoftLight: + cmd.pipeline = renderer.GetBlendSoftLightPipeline(options); + break; + case BlendMode::kDifference: + cmd.pipeline = renderer.GetBlendDifferencePipeline(options); + break; + case BlendMode::kExclusion: + cmd.pipeline = renderer.GetBlendExclusionPipeline(options); + break; + case BlendMode::kMultiply: + cmd.pipeline = renderer.GetBlendMultiplyPipeline(options); + break; + case BlendMode::kHue: + cmd.pipeline = renderer.GetBlendHuePipeline(options); + break; + case BlendMode::kSaturation: + cmd.pipeline = renderer.GetBlendSaturationPipeline(options); + break; + case BlendMode::kColor: + cmd.pipeline = renderer.GetBlendColorPipeline(options); + break; + case BlendMode::kLuminosity: + cmd.pipeline = renderer.GetBlendLuminosityPipeline(options); + break; + default: + return false; + } + + FS::BlendInfo blend_info; + VS::FrameInfo frame_info; + + auto dst_sampler_descriptor = dst_snapshot->sampler_descriptor; + if (renderer.GetDeviceCapabilities().SupportsDecalTileMode()) { + dst_sampler_descriptor.width_address_mode = SamplerAddressMode::kDecal; + dst_sampler_descriptor.height_address_mode = SamplerAddressMode::kDecal; + } + auto dst_sampler = renderer.GetContext()->GetSamplerLibrary()->GetSampler( + dst_sampler_descriptor); + FS::BindTextureSamplerDst(cmd, dst_snapshot->texture, dst_sampler); + frame_info.dst_y_coord_scale = dst_snapshot->texture->GetYCoordScale(); + blend_info.dst_input_alpha = dst_snapshot->opacity; + + blend_info.color_factor = 1; + blend_info.color = foreground_color_; + // This texture will not be sampled from due to the color factor. But + // this is present so that validation doesn't trip on a missing + // binding. + FS::BindTextureSamplerSrc(cmd, dst_snapshot->texture, dst_sampler); + + auto blend_uniform = host_buffer.EmplaceUniform(blend_info); + FS::BindBlendInfo(cmd, blend_uniform); + + frame_info.mvp = Matrix::MakeOrthographic(pass.GetRenderTargetSize()); + + auto uniform_view = host_buffer.EmplaceUniform(frame_info); + VS::BindFrameInfo(cmd, uniform_view); + + return pass.AddCommand(cmd); +} + } // namespace impeller diff --git a/impeller/entity/contents/filters/blend_filter_contents.h b/impeller/entity/contents/filters/blend_filter_contents.h index 1b7f51a839719..fb17beb5e1a8f 100644 --- a/impeller/entity/contents/filters/blend_filter_contents.h +++ b/impeller/entity/contents/filters/blend_filter_contents.h @@ -45,4 +45,39 @@ class BlendFilterContents : public ColorFilterContents { FML_DISALLOW_COPY_AND_ASSIGN(BlendFilterContents); }; +/// @brief Optimized advanced blend that avoids a second subpass when there is +/// only a single input and a foreground color. +/// +/// These contents cannot absorb opacity. +class AdvancedForegroundBlendContents : public Contents { + public: + AdvancedForegroundBlendContents(); + + ~AdvancedForegroundBlendContents(); + + void SetBlendMode(BlendMode blend_mode); + + void SetSrcInput(std::shared_ptr input); + + void SetForegroundColor(Color color); + + void SetCoverage(Rect rect); + + private: + // |Contents| + std::optional GetCoverage(const Entity& entity) const override; + + // |Contents| + bool Render(const ContentContext& renderer, + const Entity& entity, + RenderPass& pass) const override; + + Color foreground_color_; + BlendMode blend_mode_; + std::shared_ptr input_; + Rect rect_; + + FML_DISALLOW_COPY_AND_ASSIGN(AdvancedForegroundBlendContents); +}; + } // namespace impeller diff --git a/impeller/entity/contents/foreground_blend_contents.cc b/impeller/entity/contents/foreground_blend_contents.cc deleted file mode 100644 index 7f62b94348af3..0000000000000 --- a/impeller/entity/contents/foreground_blend_contents.cc +++ /dev/null @@ -1,169 +0,0 @@ -// 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 "foreground_blend_contents.h" -#include - -#include "flutter/impeller/entity/contents/content_context.h" -#include "flutter/impeller/renderer/render_pass.h" -#include "flutter/impeller/renderer/sampler_library.h" - -namespace impeller { - -AdvancedForegroundBlendContents::AdvancedForegroundBlendContents() {} - -AdvancedForegroundBlendContents::~AdvancedForegroundBlendContents() {} - -void AdvancedForegroundBlendContents::SetBlendMode(BlendMode blend_mode) { - FML_DCHECK(blend_mode > Entity::kLastPipelineBlendMode); - blend_mode_ = blend_mode; -} - -void AdvancedForegroundBlendContents::SetSrcInput( - std::shared_ptr input) { - input_ = std::move(input); -} - -void AdvancedForegroundBlendContents::SetForegroundColor(Color color) { - foreground_color_ = color; -} - -void AdvancedForegroundBlendContents::SetCoverage(Rect rect) { - rect_ = rect; -} - -std::optional AdvancedForegroundBlendContents::GetCoverage( - const Entity& entity) const { - return rect_.TransformBounds(entity.GetTransformation()); -} - -bool AdvancedForegroundBlendContents::Render(const ContentContext& renderer, - const Entity& entity, - RenderPass& pass) const { - using VS = BlendScreenPipeline::VertexShader; - using FS = BlendScreenPipeline::FragmentShader; - - auto& host_buffer = pass.GetTransientsBuffer(); - - auto dst_snapshot = input_->GetSnapshot(renderer, entity); - if (!dst_snapshot.has_value()) { - return false; - } - auto maybe_dst_uvs = dst_snapshot->GetCoverageUVs(rect_); - if (!maybe_dst_uvs.has_value()) { - return false; - } - auto dst_uvs = maybe_dst_uvs.value(); - - auto size = rect_.size; - VertexBufferBuilder vtx_builder; - // hack - dst_uvs[0] = Point(0.0, 0.0); - dst_uvs[1] = Point(1.0, 0.0); - dst_uvs[2] = Point(0.0, 1.0); - dst_uvs[3] = Point(1.0, 1.0); - - vtx_builder.AddVertices({ - {rect_.origin, dst_uvs[0], dst_uvs[0]}, - {Point(rect_.origin.x + size.width, rect_.origin.y), dst_uvs[1], - dst_uvs[1]}, - {Point(rect_.origin.x + size.width, rect_.origin.y + size.height), - dst_uvs[3], dst_uvs[3]}, - {rect_.origin, dst_uvs[0], dst_uvs[0]}, - {Point(rect_.origin.x + size.width, rect_.origin.y + size.height), - dst_uvs[3], dst_uvs[3]}, - {Point(rect_.origin.x, rect_.origin.y + size.height), dst_uvs[2], - dst_uvs[2]}, - }); - auto vtx_buffer = vtx_builder.CreateVertexBuffer(host_buffer); - - Command cmd; - cmd.label = "Foreground Advanced Blend Filter"; - cmd.BindVertices(vtx_buffer); - cmd.stencil_reference = entity.GetStencilDepth(); - auto options = OptionsFromPass(pass); - - switch (blend_mode_) { - case BlendMode::kScreen: - cmd.pipeline = renderer.GetBlendScreenPipeline(options); - break; - case BlendMode::kOverlay: - cmd.pipeline = renderer.GetBlendOverlayPipeline(options); - break; - case BlendMode::kDarken: - cmd.pipeline = renderer.GetBlendDarkenPipeline(options); - break; - case BlendMode::kLighten: - cmd.pipeline = renderer.GetBlendLightenPipeline(options); - break; - case BlendMode::kColorDodge: - cmd.pipeline = renderer.GetBlendColorDodgePipeline(options); - break; - case BlendMode::kColorBurn: - cmd.pipeline = renderer.GetBlendColorBurnPipeline(options); - break; - case BlendMode::kHardLight: - cmd.pipeline = renderer.GetBlendHardLightPipeline(options); - break; - case BlendMode::kSoftLight: - cmd.pipeline = renderer.GetBlendSoftLightPipeline(options); - break; - case BlendMode::kDifference: - cmd.pipeline = renderer.GetBlendDifferencePipeline(options); - break; - case BlendMode::kExclusion: - cmd.pipeline = renderer.GetBlendExclusionPipeline(options); - break; - case BlendMode::kMultiply: - cmd.pipeline = renderer.GetBlendMultiplyPipeline(options); - break; - case BlendMode::kHue: - cmd.pipeline = renderer.GetBlendHuePipeline(options); - break; - case BlendMode::kSaturation: - cmd.pipeline = renderer.GetBlendSaturationPipeline(options); - break; - case BlendMode::kColor: - cmd.pipeline = renderer.GetBlendColorPipeline(options); - break; - case BlendMode::kLuminosity: - cmd.pipeline = renderer.GetBlendLuminosityPipeline(options); - break; - default: - return false; - } - - FS::BlendInfo blend_info; - VS::FrameInfo frame_info; - - auto dst_sampler_descriptor = dst_snapshot->sampler_descriptor; - if (renderer.GetDeviceCapabilities().SupportsDecalTileMode()) { - dst_sampler_descriptor.width_address_mode = SamplerAddressMode::kDecal; - dst_sampler_descriptor.height_address_mode = SamplerAddressMode::kDecal; - } - auto dst_sampler = renderer.GetContext()->GetSamplerLibrary()->GetSampler( - dst_sampler_descriptor); - FS::BindTextureSamplerDst(cmd, dst_snapshot->texture, dst_sampler); - frame_info.dst_y_coord_scale = dst_snapshot->texture->GetYCoordScale(); - blend_info.dst_input_alpha = dst_snapshot->opacity; - - blend_info.color_factor = 1; - blend_info.color = foreground_color_; - // This texture will not be sampled from due to the color factor. But - // this is present so that validation doesn't trip on a missing - // binding. - FS::BindTextureSamplerSrc(cmd, dst_snapshot->texture, dst_sampler); - - auto blend_uniform = host_buffer.EmplaceUniform(blend_info); - FS::BindBlendInfo(cmd, blend_uniform); - - frame_info.mvp = Matrix::MakeOrthographic(pass.GetRenderTargetSize()); - - auto uniform_view = host_buffer.EmplaceUniform(frame_info); - VS::BindFrameInfo(cmd, uniform_view); - - return pass.AddCommand(cmd); -} - -} // namespace impeller diff --git a/impeller/entity/contents/foreground_blend_contents.h b/impeller/entity/contents/foreground_blend_contents.h deleted file mode 100644 index 5a36353707410..0000000000000 --- a/impeller/entity/contents/foreground_blend_contents.h +++ /dev/null @@ -1,50 +0,0 @@ -// 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. - -#pragma once - -#include "flutter/fml/macros.h" -#include "flutter/impeller/core/texture.h" -#include "flutter/impeller/entity/contents/color_source_contents.h" -#include "flutter/impeller/entity/contents/filters/inputs/filter_input.h" -#include "flutter/impeller/entity/entity.h" - -namespace impeller { - -/// @brief Optimized advanced blend that avoids a second subpass when there is -/// only a single input and a foreground color. -/// -/// These contents cannot absorb opacity. -class AdvancedForegroundBlendContents : public Contents { - public: - AdvancedForegroundBlendContents(); - - ~AdvancedForegroundBlendContents(); - - void SetBlendMode(BlendMode blend_mode); - - void SetSrcInput(std::shared_ptr input); - - void SetForegroundColor(Color color); - - void SetCoverage(Rect rect); - - private: - // |Contents| - std::optional GetCoverage(const Entity& entity) const override; - - // |Contents| - bool Render(const ContentContext& renderer, - const Entity& entity, - RenderPass& pass) const override; - - Color foreground_color_; - BlendMode blend_mode_; - std::shared_ptr input_; - Rect rect_; - - FML_DISALLOW_COPY_AND_ASSIGN(AdvancedForegroundBlendContents); -}; - -} // namespace impeller From f682b36c6150d368fb1e9bd0a61a1a78e506e21d Mon Sep 17 00:00:00 2001 From: jonahwilliams Date: Wed, 5 Apr 2023 20:49:13 -0700 Subject: [PATCH 4/5] use anon contents --- .../contents/filters/blend_filter_contents.cc | 309 +++++++++--------- .../contents/filters/blend_filter_contents.h | 46 +-- 2 files changed, 158 insertions(+), 197 deletions(-) diff --git a/impeller/entity/contents/filters/blend_filter_contents.cc b/impeller/entity/contents/filters/blend_filter_contents.cc index 301ccc9c3c72f..fe9332612a5c2 100644 --- a/impeller/entity/contents/filters/blend_filter_contents.cc +++ b/impeller/entity/contents/filters/blend_filter_contents.cc @@ -9,6 +9,7 @@ #include #include "impeller/core/formats.h" +#include "impeller/entity/contents/anonymous_contents.h" #include "impeller/entity/contents/content_context.h" #include "impeller/entity/contents/contents.h" #include "impeller/entity/contents/filters/inputs/filter_input.h" @@ -178,6 +179,150 @@ static std::optional AdvancedBlend( entity.GetBlendMode(), entity.GetStencilDepth()); } +Entity BlendFilterContents::CreateForgroundBlend( + const std::shared_ptr& input, + const ContentContext& renderer, + const Entity& entity, + const Rect& coverage, + Color foreground_color, + BlendMode blend_mode) const { + RenderProc render_proc = [foreground_color, coverage, input, blend_mode]( + const ContentContext& renderer, + const Entity& entity, RenderPass& pass) -> bool { + using VS = BlendScreenPipeline::VertexShader; + using FS = BlendScreenPipeline::FragmentShader; + + auto& host_buffer = pass.GetTransientsBuffer(); + + auto dst_snapshot = input->GetSnapshot(renderer, entity); + if (!dst_snapshot.has_value()) { + return false; + } + + // This does not use the snapshot transform, since this value will + // be different depending on whether the filter was applied via a + // saveLayer or directly to a particular contents. By construction, + // the provided rectangle should exactly map to the texture coordinates. + std::array dst_uvs = {Point(0.0, 0.0), Point(1.0, 0.0), + Point(0.0, 1.0), Point(1.0, 1.0)}; + + auto size = coverage.size; + auto origin = coverage.origin; + VertexBufferBuilder vtx_builder; + vtx_builder.AddVertices({ + {origin, dst_uvs[0], dst_uvs[0]}, + {Point(origin.x + size.width, origin.y), dst_uvs[1], dst_uvs[1]}, + {Point(origin.x + size.width, origin.y + size.height), dst_uvs[3], + dst_uvs[3]}, + {origin, dst_uvs[0], dst_uvs[0]}, + {Point(origin.x + size.width, origin.y + size.height), dst_uvs[3], + dst_uvs[3]}, + {Point(origin.x, origin.y + size.height), dst_uvs[2], dst_uvs[2]}, + }); + auto vtx_buffer = vtx_builder.CreateVertexBuffer(host_buffer); + + Command cmd; + cmd.label = "Foreground Advanced Blend Filter"; + cmd.BindVertices(vtx_buffer); + cmd.stencil_reference = entity.GetStencilDepth(); + auto options = OptionsFromPass(pass); + + switch (blend_mode) { + case BlendMode::kScreen: + cmd.pipeline = renderer.GetBlendScreenPipeline(options); + break; + case BlendMode::kOverlay: + cmd.pipeline = renderer.GetBlendOverlayPipeline(options); + break; + case BlendMode::kDarken: + cmd.pipeline = renderer.GetBlendDarkenPipeline(options); + break; + case BlendMode::kLighten: + cmd.pipeline = renderer.GetBlendLightenPipeline(options); + break; + case BlendMode::kColorDodge: + cmd.pipeline = renderer.GetBlendColorDodgePipeline(options); + break; + case BlendMode::kColorBurn: + cmd.pipeline = renderer.GetBlendColorBurnPipeline(options); + break; + case BlendMode::kHardLight: + cmd.pipeline = renderer.GetBlendHardLightPipeline(options); + break; + case BlendMode::kSoftLight: + cmd.pipeline = renderer.GetBlendSoftLightPipeline(options); + break; + case BlendMode::kDifference: + cmd.pipeline = renderer.GetBlendDifferencePipeline(options); + break; + case BlendMode::kExclusion: + cmd.pipeline = renderer.GetBlendExclusionPipeline(options); + break; + case BlendMode::kMultiply: + cmd.pipeline = renderer.GetBlendMultiplyPipeline(options); + break; + case BlendMode::kHue: + cmd.pipeline = renderer.GetBlendHuePipeline(options); + break; + case BlendMode::kSaturation: + cmd.pipeline = renderer.GetBlendSaturationPipeline(options); + break; + case BlendMode::kColor: + cmd.pipeline = renderer.GetBlendColorPipeline(options); + break; + case BlendMode::kLuminosity: + cmd.pipeline = renderer.GetBlendLuminosityPipeline(options); + break; + default: + return false; + } + + FS::BlendInfo blend_info; + VS::FrameInfo frame_info; + + auto dst_sampler_descriptor = dst_snapshot->sampler_descriptor; + if (renderer.GetDeviceCapabilities().SupportsDecalTileMode()) { + dst_sampler_descriptor.width_address_mode = SamplerAddressMode::kDecal; + dst_sampler_descriptor.height_address_mode = SamplerAddressMode::kDecal; + } + auto dst_sampler = renderer.GetContext()->GetSamplerLibrary()->GetSampler( + dst_sampler_descriptor); + FS::BindTextureSamplerDst(cmd, dst_snapshot->texture, dst_sampler); + frame_info.dst_y_coord_scale = dst_snapshot->texture->GetYCoordScale(); + blend_info.dst_input_alpha = dst_snapshot->opacity; + + blend_info.color_factor = 1; + blend_info.color = foreground_color; + // This texture will not be sampled from due to the color factor. But + // this is present so that validation doesn't trip on a missing + // binding. + FS::BindTextureSamplerSrc(cmd, dst_snapshot->texture, dst_sampler); + + auto blend_uniform = host_buffer.EmplaceUniform(blend_info); + FS::BindBlendInfo(cmd, blend_uniform); + + frame_info.mvp = Matrix::MakeOrthographic(pass.GetRenderTargetSize()); + + auto uniform_view = host_buffer.EmplaceUniform(frame_info); + VS::BindFrameInfo(cmd, uniform_view); + + return pass.AddCommand(cmd); + }; + CoverageProc coverage_proc = + [coverage](const Entity& entity) -> std::optional { + return coverage; + }; + + auto contents = AnonymousContents::Make(render_proc, coverage_proc); + + Entity sub_entity; + sub_entity.SetContents(std::move(contents)); + sub_entity.SetStencilDepth(entity.GetStencilDepth()); + sub_entity.SetTransformation(Matrix::MakeTranslation(coverage.origin) * + entity.GetTransformation()); + return sub_entity; +} + static std::optional PipelineBlend( const FilterInput::Vector& inputs, const ContentContext& renderer, @@ -376,18 +521,8 @@ std::optional BlendFilterContents::RenderFilter( auto potential_alpha = GetAlpha().value_or(1.0); if (inputs.size() == 1 && foreground_color_.has_value() && potential_alpha >= 1.0 - kEhCloseEnough) { - auto contents = std::make_shared(); - contents->SetBlendMode(blend_mode_); - contents->SetCoverage(coverage); - contents->SetSrcInput(inputs[0]); - contents->SetForegroundColor(foreground_color_.value()); - - Entity sub_entity; - sub_entity.SetContents(std::move(contents)); - sub_entity.SetStencilDepth(entity.GetStencilDepth()); - sub_entity.SetTransformation(Matrix::MakeTranslation(coverage.origin) * - entity.GetTransformation()); - return sub_entity; + return CreateForgroundBlend(inputs[0], renderer, entity, coverage, + foreground_color_.value(), blend_mode_); } return advanced_blend_proc_(inputs, renderer, entity, coverage, @@ -398,154 +533,4 @@ std::optional BlendFilterContents::RenderFilter( FML_UNREACHABLE(); } -AdvancedForegroundBlendContents::AdvancedForegroundBlendContents() {} - -AdvancedForegroundBlendContents::~AdvancedForegroundBlendContents() {} - -void AdvancedForegroundBlendContents::SetBlendMode(BlendMode blend_mode) { - FML_DCHECK(blend_mode > Entity::kLastPipelineBlendMode); - blend_mode_ = blend_mode; -} - -void AdvancedForegroundBlendContents::SetSrcInput( - std::shared_ptr input) { - input_ = std::move(input); -} - -void AdvancedForegroundBlendContents::SetForegroundColor(Color color) { - foreground_color_ = color; -} - -void AdvancedForegroundBlendContents::SetCoverage(Rect rect) { - rect_ = rect; -} - -std::optional AdvancedForegroundBlendContents::GetCoverage( - const Entity& entity) const { - return rect_.TransformBounds(entity.GetTransformation()); -} - -bool AdvancedForegroundBlendContents::Render(const ContentContext& renderer, - const Entity& entity, - RenderPass& pass) const { - using VS = BlendScreenPipeline::VertexShader; - using FS = BlendScreenPipeline::FragmentShader; - - auto& host_buffer = pass.GetTransientsBuffer(); - - auto dst_snapshot = input_->GetSnapshot(renderer, entity); - if (!dst_snapshot.has_value()) { - return false; - } - - // This does not use the snapshot transform, since this value will - // be different depending on whether the filter was applied via a - // saveLayer or directly to a particular contents. By construction, - // the provided rectangle should exactly map to the texture coordinates. - std::array dst_uvs = {Point(0.0, 0.0), Point(1.0, 0.0), - Point(0.0, 1.0), Point(1.0, 1.0)}; - - auto size = rect_.size; - auto origin = rect_.origin; - VertexBufferBuilder vtx_builder; - vtx_builder.AddVertices({ - {origin, dst_uvs[0], dst_uvs[0]}, - {Point(origin.x + size.width, origin.y), dst_uvs[1], dst_uvs[1]}, - {Point(origin.x + size.width, origin.y + size.height), dst_uvs[3], - dst_uvs[3]}, - {origin, dst_uvs[0], dst_uvs[0]}, - {Point(origin.x + size.width, origin.y + size.height), dst_uvs[3], - dst_uvs[3]}, - {Point(origin.x, origin.y + size.height), dst_uvs[2], dst_uvs[2]}, - }); - auto vtx_buffer = vtx_builder.CreateVertexBuffer(host_buffer); - - Command cmd; - cmd.label = "Foreground Advanced Blend Filter"; - cmd.BindVertices(vtx_buffer); - cmd.stencil_reference = entity.GetStencilDepth(); - auto options = OptionsFromPass(pass); - - switch (blend_mode_) { - case BlendMode::kScreen: - cmd.pipeline = renderer.GetBlendScreenPipeline(options); - break; - case BlendMode::kOverlay: - cmd.pipeline = renderer.GetBlendOverlayPipeline(options); - break; - case BlendMode::kDarken: - cmd.pipeline = renderer.GetBlendDarkenPipeline(options); - break; - case BlendMode::kLighten: - cmd.pipeline = renderer.GetBlendLightenPipeline(options); - break; - case BlendMode::kColorDodge: - cmd.pipeline = renderer.GetBlendColorDodgePipeline(options); - break; - case BlendMode::kColorBurn: - cmd.pipeline = renderer.GetBlendColorBurnPipeline(options); - break; - case BlendMode::kHardLight: - cmd.pipeline = renderer.GetBlendHardLightPipeline(options); - break; - case BlendMode::kSoftLight: - cmd.pipeline = renderer.GetBlendSoftLightPipeline(options); - break; - case BlendMode::kDifference: - cmd.pipeline = renderer.GetBlendDifferencePipeline(options); - break; - case BlendMode::kExclusion: - cmd.pipeline = renderer.GetBlendExclusionPipeline(options); - break; - case BlendMode::kMultiply: - cmd.pipeline = renderer.GetBlendMultiplyPipeline(options); - break; - case BlendMode::kHue: - cmd.pipeline = renderer.GetBlendHuePipeline(options); - break; - case BlendMode::kSaturation: - cmd.pipeline = renderer.GetBlendSaturationPipeline(options); - break; - case BlendMode::kColor: - cmd.pipeline = renderer.GetBlendColorPipeline(options); - break; - case BlendMode::kLuminosity: - cmd.pipeline = renderer.GetBlendLuminosityPipeline(options); - break; - default: - return false; - } - - FS::BlendInfo blend_info; - VS::FrameInfo frame_info; - - auto dst_sampler_descriptor = dst_snapshot->sampler_descriptor; - if (renderer.GetDeviceCapabilities().SupportsDecalTileMode()) { - dst_sampler_descriptor.width_address_mode = SamplerAddressMode::kDecal; - dst_sampler_descriptor.height_address_mode = SamplerAddressMode::kDecal; - } - auto dst_sampler = renderer.GetContext()->GetSamplerLibrary()->GetSampler( - dst_sampler_descriptor); - FS::BindTextureSamplerDst(cmd, dst_snapshot->texture, dst_sampler); - frame_info.dst_y_coord_scale = dst_snapshot->texture->GetYCoordScale(); - blend_info.dst_input_alpha = dst_snapshot->opacity; - - blend_info.color_factor = 1; - blend_info.color = foreground_color_; - // This texture will not be sampled from due to the color factor. But - // this is present so that validation doesn't trip on a missing - // binding. - FS::BindTextureSamplerSrc(cmd, dst_snapshot->texture, dst_sampler); - - auto blend_uniform = host_buffer.EmplaceUniform(blend_info); - FS::BindBlendInfo(cmd, blend_uniform); - - frame_info.mvp = Matrix::MakeOrthographic(pass.GetRenderTargetSize()); - - auto uniform_view = host_buffer.EmplaceUniform(frame_info); - VS::BindFrameInfo(cmd, uniform_view); - - return pass.AddCommand(cmd); -} - } // namespace impeller diff --git a/impeller/entity/contents/filters/blend_filter_contents.h b/impeller/entity/contents/filters/blend_filter_contents.h index fb17beb5e1a8f..1c2d9aad6708c 100644 --- a/impeller/entity/contents/filters/blend_filter_contents.h +++ b/impeller/entity/contents/filters/blend_filter_contents.h @@ -38,6 +38,17 @@ class BlendFilterContents : public ColorFilterContents { const Matrix& effect_transform, const Rect& coverage) const override; + /// @brief Optimized advanced blend that avoids a second subpass when there is + /// only a single input and a foreground color. + /// + /// These contents cannot absorb opacity. + Entity CreateForgroundBlend(const std::shared_ptr& input, + const ContentContext& renderer, + const Entity& entity, + const Rect& coverage, + Color foreground_color, + BlendMode blend_mode) const; + BlendMode blend_mode_ = BlendMode::kSourceOver; AdvancedBlendProc advanced_blend_proc_; std::optional foreground_color_; @@ -45,39 +56,4 @@ class BlendFilterContents : public ColorFilterContents { FML_DISALLOW_COPY_AND_ASSIGN(BlendFilterContents); }; -/// @brief Optimized advanced blend that avoids a second subpass when there is -/// only a single input and a foreground color. -/// -/// These contents cannot absorb opacity. -class AdvancedForegroundBlendContents : public Contents { - public: - AdvancedForegroundBlendContents(); - - ~AdvancedForegroundBlendContents(); - - void SetBlendMode(BlendMode blend_mode); - - void SetSrcInput(std::shared_ptr input); - - void SetForegroundColor(Color color); - - void SetCoverage(Rect rect); - - private: - // |Contents| - std::optional GetCoverage(const Entity& entity) const override; - - // |Contents| - bool Render(const ContentContext& renderer, - const Entity& entity, - RenderPass& pass) const override; - - Color foreground_color_; - BlendMode blend_mode_; - std::shared_ptr input_; - Rect rect_; - - FML_DISALLOW_COPY_AND_ASSIGN(AdvancedForegroundBlendContents); -}; - } // namespace impeller From 6d65a18aaf49e8617155669c43af7a6bacba072c Mon Sep 17 00:00:00 2001 From: jonahwilliams Date: Fri, 7 Apr 2023 11:21:31 -0700 Subject: [PATCH 5/5] use getCoverageUVs correctly --- .../contents/filters/blend_filter_contents.cc | 57 ++++++++++++------- .../contents/filters/blend_filter_contents.h | 15 +++-- 2 files changed, 46 insertions(+), 26 deletions(-) diff --git a/impeller/entity/contents/filters/blend_filter_contents.cc b/impeller/entity/contents/filters/blend_filter_contents.cc index fe9332612a5c2..c5e7c8c63cf8d 100644 --- a/impeller/entity/contents/filters/blend_filter_contents.cc +++ b/impeller/entity/contents/filters/blend_filter_contents.cc @@ -179,14 +179,22 @@ static std::optional AdvancedBlend( entity.GetBlendMode(), entity.GetStencilDepth()); } -Entity BlendFilterContents::CreateForgroundBlend( +std::optional BlendFilterContents::CreateForegroundBlend( const std::shared_ptr& input, const ContentContext& renderer, const Entity& entity, const Rect& coverage, Color foreground_color, - BlendMode blend_mode) const { - RenderProc render_proc = [foreground_color, coverage, input, blend_mode]( + BlendMode blend_mode, + std::optional alpha, + bool absorb_opacity) const { + auto dst_snapshot = input->GetSnapshot(renderer, entity); + if (!dst_snapshot.has_value()) { + return std::nullopt; + } + + RenderProc render_proc = [foreground_color, coverage, dst_snapshot, + blend_mode, alpha, absorb_opacity]( const ContentContext& renderer, const Entity& entity, RenderPass& pass) -> bool { using VS = BlendScreenPipeline::VertexShader; @@ -194,17 +202,11 @@ Entity BlendFilterContents::CreateForgroundBlend( auto& host_buffer = pass.GetTransientsBuffer(); - auto dst_snapshot = input->GetSnapshot(renderer, entity); - if (!dst_snapshot.has_value()) { + auto maybe_dst_uvs = dst_snapshot->GetCoverageUVs(coverage); + if (!maybe_dst_uvs.has_value()) { return false; } - - // This does not use the snapshot transform, since this value will - // be different depending on whether the filter was applied via a - // saveLayer or directly to a particular contents. By construction, - // the provided rectangle should exactly map to the texture coordinates. - std::array dst_uvs = {Point(0.0, 0.0), Point(1.0, 0.0), - Point(0.0, 1.0), Point(1.0, 1.0)}; + auto dst_uvs = maybe_dst_uvs.value(); auto size = coverage.size; auto origin = coverage.origin; @@ -289,7 +291,8 @@ Entity BlendFilterContents::CreateForgroundBlend( dst_sampler_descriptor); FS::BindTextureSamplerDst(cmd, dst_snapshot->texture, dst_sampler); frame_info.dst_y_coord_scale = dst_snapshot->texture->GetYCoordScale(); - blend_info.dst_input_alpha = dst_snapshot->opacity; + blend_info.dst_input_alpha = + absorb_opacity ? dst_snapshot->opacity * alpha.value_or(1.0) : 1.0; blend_info.color_factor = 1; blend_info.color = foreground_color; @@ -315,11 +318,26 @@ Entity BlendFilterContents::CreateForgroundBlend( auto contents = AnonymousContents::Make(render_proc, coverage_proc); + // If there is pending opacity but it was not absorbed by this entity, we have + // to convert this back to a snapshot so it can be passed on. This generally + // implies that there is another filter about to run, so we'd perform this + // operation anyway. + auto potential_opacity = alpha.value_or(1.0) * dst_snapshot->opacity; + if (!absorb_opacity && potential_opacity < 1.0) { + auto result_snapshot = contents->RenderToSnapshot(renderer, entity); + if (!result_snapshot.has_value()) { + return std::nullopt; + } + result_snapshot->opacity = potential_opacity; + return Entity::FromSnapshot(result_snapshot.value(), entity.GetBlendMode(), + entity.GetStencilDepth()); + } + Entity sub_entity; sub_entity.SetContents(std::move(contents)); sub_entity.SetStencilDepth(entity.GetStencilDepth()); - sub_entity.SetTransformation(Matrix::MakeTranslation(coverage.origin) * - entity.GetTransformation()); + sub_entity.SetTransformation(entity.GetTransformation()); + return sub_entity; } @@ -518,11 +536,10 @@ std::optional BlendFilterContents::RenderFilter( } if (blend_mode_ <= Entity::kLastAdvancedBlendMode) { - auto potential_alpha = GetAlpha().value_or(1.0); - if (inputs.size() == 1 && foreground_color_.has_value() && - potential_alpha >= 1.0 - kEhCloseEnough) { - return CreateForgroundBlend(inputs[0], renderer, entity, coverage, - foreground_color_.value(), blend_mode_); + if (inputs.size() == 1 && foreground_color_.has_value()) { + return CreateForegroundBlend(inputs[0], renderer, entity, coverage, + foreground_color_.value(), blend_mode_, + GetAlpha(), GetAbsorbOpacity()); } return advanced_blend_proc_(inputs, renderer, entity, coverage, diff --git a/impeller/entity/contents/filters/blend_filter_contents.h b/impeller/entity/contents/filters/blend_filter_contents.h index 1c2d9aad6708c..30bb6d401eb1f 100644 --- a/impeller/entity/contents/filters/blend_filter_contents.h +++ b/impeller/entity/contents/filters/blend_filter_contents.h @@ -42,12 +42,15 @@ class BlendFilterContents : public ColorFilterContents { /// only a single input and a foreground color. /// /// These contents cannot absorb opacity. - Entity CreateForgroundBlend(const std::shared_ptr& input, - const ContentContext& renderer, - const Entity& entity, - const Rect& coverage, - Color foreground_color, - BlendMode blend_mode) const; + std::optional CreateForegroundBlend( + const std::shared_ptr& input, + const ContentContext& renderer, + const Entity& entity, + const Rect& coverage, + Color foreground_color, + BlendMode blend_mode, + std::optional alpha, + bool absorb_opacity) const; BlendMode blend_mode_ = BlendMode::kSourceOver; AdvancedBlendProc advanced_blend_proc_;