diff --git a/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter index 4232df30490d0..ec5979222801b 100644 --- a/ci/licenses_golden/licenses_flutter +++ b/ci/licenses_golden/licenses_flutter @@ -529,6 +529,12 @@ FILE: ../../../flutter/impeller/entity/entity_pass_delegate.h FILE: ../../../flutter/impeller/entity/entity_playground.cc FILE: ../../../flutter/impeller/entity/entity_playground.h FILE: ../../../flutter/impeller/entity/entity_unittests.cc +FILE: ../../../flutter/impeller/entity/shaders/advanced_blend.vert +FILE: ../../../flutter/impeller/entity/shaders/advanced_blend_colorburn.frag +FILE: ../../../flutter/impeller/entity/shaders/advanced_blend_screen.frag +FILE: ../../../flutter/impeller/entity/shaders/blend.frag +FILE: ../../../flutter/impeller/entity/shaders/blend.vert +FILE: ../../../flutter/impeller/entity/shaders/blending.glsl FILE: ../../../flutter/impeller/entity/shaders/border_mask_blur.frag FILE: ../../../flutter/impeller/entity/shaders/border_mask_blur.vert FILE: ../../../flutter/impeller/entity/shaders/gaussian_blur.frag @@ -541,10 +547,6 @@ FILE: ../../../flutter/impeller/entity/shaders/solid_fill.frag FILE: ../../../flutter/impeller/entity/shaders/solid_fill.vert FILE: ../../../flutter/impeller/entity/shaders/solid_stroke.frag FILE: ../../../flutter/impeller/entity/shaders/solid_stroke.vert -FILE: ../../../flutter/impeller/entity/shaders/texture_blend.frag -FILE: ../../../flutter/impeller/entity/shaders/texture_blend.vert -FILE: ../../../flutter/impeller/entity/shaders/texture_blend_screen.frag -FILE: ../../../flutter/impeller/entity/shaders/texture_blend_screen.vert FILE: ../../../flutter/impeller/entity/shaders/texture_fill.frag FILE: ../../../flutter/impeller/entity/shaders/texture_fill.vert FILE: ../../../flutter/impeller/fixtures/airplane.jpg diff --git a/impeller/aiks/aiks_unittests.cc b/impeller/aiks/aiks_unittests.cc index 120ffdb7cef19..2872892b7ce67 100644 --- a/impeller/aiks/aiks_unittests.cc +++ b/impeller/aiks/aiks_unittests.cc @@ -493,6 +493,7 @@ TEST_P(AiksTest, CanDrawWithAdvancedBlend) { {"Modulate", Entity::BlendMode::kModulate}, // Advanced blends (non Porter-Duff/color blends) {"Screen", Entity::BlendMode::kScreen}, + {"ColorBurn", Entity::BlendMode::kColorBurn}, }; assert(blends.size() == static_cast(Entity::BlendMode::kLastAdvancedBlendMode) + 1); @@ -520,6 +521,7 @@ TEST_P(AiksTest, CanDrawWithAdvancedBlend) { }; Paint paint; + paint.blend_mode = Entity::BlendMode::kSourceOver; // Draw a fancy color wheel for the backdrop. // https://www.desmos.com/calculator/xw7kafthwd @@ -546,10 +548,16 @@ TEST_P(AiksTest, CanDrawWithAdvancedBlend) { ImGui::SetNextWindowPos({325, 550}); } - ImGui::Begin("Controls"); + // UI state. static int current_blend_index = 3; - ImGui::ListBox("Blending mode", ¤t_blend_index, - blend_mode_names.data(), blend_mode_names.size()); + static float alpha = 1; + + ImGui::Begin("Controls"); + { + ImGui::ListBox("Blending mode", ¤t_blend_index, + blend_mode_names.data(), blend_mode_names.size()); + ImGui::SliderFloat("Alpha", &alpha, 0, 1); + } ImGui::End(); Canvas canvas; @@ -569,11 +577,11 @@ TEST_P(AiksTest, CanDrawWithAdvancedBlend) { paint.blend_mode = Entity::BlendMode::kPlus; const Scalar x = std::sin(k2Pi / 3); const Scalar y = -std::cos(k2Pi / 3); - paint.color = Color::Red(); + paint.color = Color::Red().WithAlpha(alpha); canvas.DrawCircle(Point(-x, y) * 45, 65, paint); - paint.color = Color::Green(); + paint.color = Color::Green().WithAlpha(alpha); canvas.DrawCircle(Point(0, -1) * 45, 65, paint); - paint.color = Color::Blue(); + paint.color = Color::Blue().WithAlpha(alpha); canvas.DrawCircle(Point(x, y) * 45, 65, paint); } canvas.Restore(); diff --git a/impeller/blobcat/blob.h b/impeller/blobcat/blob.h index 70e864191aff9..dc8ec7e472c15 100644 --- a/impeller/blobcat/blob.h +++ b/impeller/blobcat/blob.h @@ -26,7 +26,7 @@ struct Blob { kFragment, }; - static constexpr size_t kMaxNameLength = 24u; + static constexpr size_t kMaxNameLength = 32u; ShaderType type = ShaderType::kVertex; uint64_t offset = 0; diff --git a/impeller/display_list/display_list_dispatcher.cc b/impeller/display_list/display_list_dispatcher.cc index 017359b1fb211..5841bc168564d 100644 --- a/impeller/display_list/display_list_dispatcher.cc +++ b/impeller/display_list/display_list_dispatcher.cc @@ -214,11 +214,13 @@ static std::optional ToBlendMode(flutter::DlBlendMode mode) { case flutter::DlBlendMode::kModulate: return Entity::BlendMode::kModulate; case flutter::DlBlendMode::kScreen: + return Entity::BlendMode::kScreen; + case flutter::DlBlendMode::kColorBurn: + return Entity::BlendMode::kColorBurn; case flutter::DlBlendMode::kOverlay: case flutter::DlBlendMode::kDarken: case flutter::DlBlendMode::kLighten: case flutter::DlBlendMode::kColorDodge: - case flutter::DlBlendMode::kColorBurn: case flutter::DlBlendMode::kHardLight: case flutter::DlBlendMode::kSoftLight: case flutter::DlBlendMode::kDifference: @@ -240,6 +242,7 @@ void DisplayListDispatcher::setBlendMode(flutter::DlBlendMode dl_mode) { paint_.blend_mode = mode.value(); } else { UNIMPLEMENTED; + paint_.blend_mode = Entity::BlendMode::kSourceOver; } } diff --git a/impeller/entity/BUILD.gn b/impeller/entity/BUILD.gn index c821b4ba83f81..c7aa23c24d828 100644 --- a/impeller/entity/BUILD.gn +++ b/impeller/entity/BUILD.gn @@ -8,24 +8,25 @@ impeller_shaders("entity_shaders") { name = "entity" shaders = [ + "shaders/advanced_blend.vert", + "shaders/advanced_blend_colorburn.frag", + "shaders/advanced_blend_screen.frag", + "shaders/blend.frag", + "shaders/blend.vert", + "shaders/border_mask_blur.frag", + "shaders/border_mask_blur.vert", + "shaders/gaussian_blur.frag", + "shaders/gaussian_blur.vert", + "shaders/glyph_atlas.frag", + "shaders/glyph_atlas.vert", "shaders/gradient_fill.frag", "shaders/gradient_fill.vert", "shaders/solid_fill.frag", "shaders/solid_fill.vert", "shaders/solid_stroke.frag", "shaders/solid_stroke.vert", - "shaders/texture_blend.frag", - "shaders/texture_blend.vert", - "shaders/texture_blend_screen.frag", - "shaders/texture_blend_screen.vert", - "shaders/gaussian_blur.frag", - "shaders/gaussian_blur.vert", - "shaders/border_mask_blur.frag", - "shaders/border_mask_blur.vert", "shaders/texture_fill.frag", "shaders/texture_fill.vert", - "shaders/glyph_atlas.frag", - "shaders/glyph_atlas.vert", ] } diff --git a/impeller/entity/contents/content_context.cc b/impeller/entity/contents/content_context.cc index 3681f1e4025af..106eccf966ff4 100644 --- a/impeller/entity/contents/content_context.cc +++ b/impeller/entity/contents/content_context.cc @@ -13,28 +13,161 @@ namespace impeller { +void ContentContextOptions::ApplyToPipelineDescriptor( + PipelineDescriptor& desc) const { + auto pipeline_blend = blend_mode; + if (blend_mode > Entity::BlendMode::kLastPipelineBlendMode) { + VALIDATION_LOG << "Cannot use blend mode " << static_cast(blend_mode) + << " as a pipeline blend."; + pipeline_blend = Entity::BlendMode::kSourceOver; + } + + desc.SetSampleCount(sample_count); + + ColorAttachmentDescriptor color0 = *desc.GetColorAttachmentDescriptor(0u); + color0.alpha_blend_op = BlendOperation::kAdd; + color0.color_blend_op = BlendOperation::kAdd; + + static_assert(Entity::BlendMode::kLastPipelineBlendMode == + Entity::BlendMode::kModulate); + + switch (pipeline_blend) { + case Entity::BlendMode::kClear: + color0.dst_alpha_blend_factor = BlendFactor::kZero; + color0.dst_color_blend_factor = BlendFactor::kZero; + color0.src_alpha_blend_factor = BlendFactor::kZero; + color0.src_color_blend_factor = BlendFactor::kZero; + break; + case Entity::BlendMode::kSource: + color0.dst_alpha_blend_factor = BlendFactor::kZero; + color0.dst_color_blend_factor = BlendFactor::kZero; + color0.src_alpha_blend_factor = BlendFactor::kSourceAlpha; + color0.src_color_blend_factor = BlendFactor::kOne; + break; + case Entity::BlendMode::kDestination: + color0.dst_alpha_blend_factor = BlendFactor::kDestinationAlpha; + color0.dst_color_blend_factor = BlendFactor::kOne; + color0.src_alpha_blend_factor = BlendFactor::kZero; + color0.src_color_blend_factor = BlendFactor::kZero; + break; + case Entity::BlendMode::kSourceOver: + color0.dst_alpha_blend_factor = BlendFactor::kOneMinusSourceAlpha; + color0.dst_color_blend_factor = BlendFactor::kOneMinusSourceAlpha; + color0.src_alpha_blend_factor = BlendFactor::kOne; + color0.src_color_blend_factor = BlendFactor::kOne; + break; + case Entity::BlendMode::kDestinationOver: + color0.dst_alpha_blend_factor = BlendFactor::kDestinationAlpha; + color0.dst_color_blend_factor = BlendFactor::kOne; + color0.src_alpha_blend_factor = BlendFactor::kOneMinusDestinationAlpha; + color0.src_color_blend_factor = BlendFactor::kOneMinusDestinationAlpha; + break; + case Entity::BlendMode::kSourceIn: + color0.dst_alpha_blend_factor = BlendFactor::kZero; + color0.dst_color_blend_factor = BlendFactor::kZero; + color0.src_alpha_blend_factor = BlendFactor::kDestinationAlpha; + color0.src_color_blend_factor = BlendFactor::kDestinationAlpha; + break; + case Entity::BlendMode::kDestinationIn: + color0.dst_alpha_blend_factor = BlendFactor::kSourceAlpha; + color0.dst_color_blend_factor = BlendFactor::kSourceAlpha; + color0.src_alpha_blend_factor = BlendFactor::kZero; + color0.src_color_blend_factor = BlendFactor::kZero; + break; + case Entity::BlendMode::kSourceOut: + color0.dst_alpha_blend_factor = BlendFactor::kZero; + color0.dst_color_blend_factor = BlendFactor::kZero; + color0.src_alpha_blend_factor = BlendFactor::kOneMinusDestinationAlpha; + color0.src_color_blend_factor = BlendFactor::kOneMinusDestinationAlpha; + break; + case Entity::BlendMode::kDestinationOut: + color0.dst_alpha_blend_factor = BlendFactor::kOneMinusSourceAlpha; + color0.dst_color_blend_factor = BlendFactor::kOneMinusSourceAlpha; + color0.src_alpha_blend_factor = BlendFactor::kZero; + color0.src_color_blend_factor = BlendFactor::kZero; + break; + case Entity::BlendMode::kSourceATop: + color0.dst_alpha_blend_factor = BlendFactor::kOneMinusSourceAlpha; + color0.dst_color_blend_factor = BlendFactor::kOneMinusSourceAlpha; + color0.src_alpha_blend_factor = BlendFactor::kDestinationAlpha; + color0.src_color_blend_factor = BlendFactor::kDestinationAlpha; + break; + case Entity::BlendMode::kDestinationATop: + color0.dst_alpha_blend_factor = BlendFactor::kSourceAlpha; + color0.dst_color_blend_factor = BlendFactor::kSourceAlpha; + color0.src_alpha_blend_factor = BlendFactor::kOneMinusDestinationAlpha; + color0.src_color_blend_factor = BlendFactor::kOneMinusDestinationAlpha; + break; + case Entity::BlendMode::kXor: + color0.dst_alpha_blend_factor = BlendFactor::kOneMinusSourceAlpha; + color0.dst_color_blend_factor = BlendFactor::kOneMinusSourceAlpha; + color0.src_alpha_blend_factor = BlendFactor::kOneMinusDestinationAlpha; + color0.src_color_blend_factor = BlendFactor::kOneMinusDestinationAlpha; + break; + case Entity::BlendMode::kPlus: + color0.dst_alpha_blend_factor = BlendFactor::kOne; + color0.dst_color_blend_factor = BlendFactor::kOne; + color0.src_alpha_blend_factor = BlendFactor::kOne; + color0.src_color_blend_factor = BlendFactor::kOne; + break; + case Entity::BlendMode::kModulate: + // kSourceColor and kDestinationColor override the alpha blend factor. + color0.dst_alpha_blend_factor = BlendFactor::kZero; + color0.dst_color_blend_factor = BlendFactor::kSourceColor; + color0.src_alpha_blend_factor = BlendFactor::kZero; + color0.src_color_blend_factor = BlendFactor::kZero; + break; + default: + FML_UNREACHABLE(); + } + desc.SetColorAttachmentDescriptor(0u, std::move(color0)); + + if (desc.GetFrontStencilAttachmentDescriptor().has_value()) { + StencilAttachmentDescriptor stencil = + desc.GetFrontStencilAttachmentDescriptor().value(); + stencil.stencil_compare = stencil_compare; + stencil.depth_stencil_pass = stencil_operation; + desc.SetStencilAttachmentDescriptors(stencil); + } +} + +template +static std::unique_ptr CreateDefaultPipeline( + const Context& context) { + auto desc = PipelineT::Builder::MakeDefaultPipelineDescriptor(context); + if (!desc.has_value()) { + return nullptr; + } + // Apply default ContentContextOptions to the descriptor. + ContentContextOptions{}.ApplyToPipelineDescriptor(*desc); + return std::make_unique(context, desc); +} + ContentContext::ContentContext(std::shared_ptr context) : context_(std::move(context)) { if (!context_ || !context_->IsValid()) { return; } - // Pipelines whose default descriptors work fine for the entity framework. gradient_fill_pipelines_[{}] = - std::make_unique(*context_); - solid_fill_pipelines_[{}] = std::make_unique(*context_); + CreateDefaultPipeline(*context_); + solid_fill_pipelines_[{}] = + CreateDefaultPipeline(*context_); texture_blend_pipelines_[{}] = - std::make_unique(*context_); - texture_blend_screen_pipelines_[{}] = - std::make_unique(*context_); - texture_pipelines_[{}] = std::make_unique(*context_); + CreateDefaultPipeline(*context_); + blend_screen_pipelines_[{}] = + CreateDefaultPipeline(*context_); + blend_colorburn_pipelines_[{}] = + CreateDefaultPipeline(*context_); + texture_pipelines_[{}] = CreateDefaultPipeline(*context_); gaussian_blur_pipelines_[{}] = - std::make_unique(*context_); + CreateDefaultPipeline(*context_); border_mask_blur_pipelines_[{}] = - std::make_unique(*context_); + CreateDefaultPipeline(*context_); solid_stroke_pipelines_[{}] = - std::make_unique(*context_); - glyph_atlas_pipelines_[{}] = std::make_unique(*context_); + CreateDefaultPipeline(*context_); + glyph_atlas_pipelines_[{}] = + CreateDefaultPipeline(*context_); // Pipelines that are variants of the base pipelines with custom descriptors. // TODO(98684): Rework this API to allow fetching the descriptor without diff --git a/impeller/entity/contents/content_context.h b/impeller/entity/contents/content_context.h index 9898b217add98..552429f0d2486 100644 --- a/impeller/entity/contents/content_context.h +++ b/impeller/entity/contents/content_context.h @@ -11,6 +11,11 @@ #include "flutter/fml/macros.h" #include "fml/logging.h" #include "impeller/base/validation.h" +#include "impeller/entity/advanced_blend.vert.h" +#include "impeller/entity/advanced_blend_colorburn.frag.h" +#include "impeller/entity/advanced_blend_screen.frag.h" +#include "impeller/entity/blend.frag.h" +#include "impeller/entity/blend.vert.h" #include "impeller/entity/border_mask_blur.frag.h" #include "impeller/entity/border_mask_blur.vert.h" #include "impeller/entity/entity.h" @@ -24,10 +29,6 @@ #include "impeller/entity/solid_fill.vert.h" #include "impeller/entity/solid_stroke.frag.h" #include "impeller/entity/solid_stroke.vert.h" -#include "impeller/entity/texture_blend.frag.h" -#include "impeller/entity/texture_blend.vert.h" -#include "impeller/entity/texture_blend_screen.frag.h" -#include "impeller/entity/texture_blend_screen.vert.h" #include "impeller/entity/texture_fill.frag.h" #include "impeller/entity/texture_fill.vert.h" #include "impeller/renderer/formats.h" @@ -38,10 +39,11 @@ using GradientFillPipeline = PipelineT; using SolidFillPipeline = PipelineT; -using TextureBlendPipeline = - PipelineT; -using TextureBlendScreenPipeline = - PipelineT; +using BlendPipeline = PipelineT; +using BlendScreenPipeline = + PipelineT; +using BlendColorburnPipeline = + PipelineT; using TexturePipeline = PipelineT; using GaussianBlurPipeline = @@ -78,6 +80,8 @@ struct ContentContextOptions { lhs.stencil_operation == rhs.stencil_operation; } }; + + void ApplyToPipelineDescriptor(PipelineDescriptor& desc) const; }; class ContentContext { @@ -98,14 +102,18 @@ class ContentContext { return GetPipeline(solid_fill_pipelines_, opts); } - std::shared_ptr GetTextureBlendPipeline( - ContentContextOptions opts) const { + std::shared_ptr GetBlendPipeline(ContentContextOptions opts) const { return GetPipeline(texture_blend_pipelines_, opts); } - std::shared_ptr GetTextureBlendScreenPipeline( + std::shared_ptr GetBlendScreenPipeline( + ContentContextOptions opts) const { + return GetPipeline(blend_screen_pipelines_, opts); + } + + std::shared_ptr GetBlendColorburnPipeline( ContentContextOptions opts) const { - return GetPipeline(texture_blend_screen_pipelines_, opts); + return GetPipeline(blend_colorburn_pipelines_, opts); } std::shared_ptr GetTexturePipeline( @@ -161,8 +169,9 @@ class ContentContext { // map. mutable Variants gradient_fill_pipelines_; mutable Variants solid_fill_pipelines_; - mutable Variants texture_blend_pipelines_; - mutable Variants texture_blend_screen_pipelines_; + mutable Variants texture_blend_pipelines_; + mutable Variants blend_screen_pipelines_; + mutable Variants blend_colorburn_pipelines_; mutable Variants texture_pipelines_; mutable Variants gaussian_blur_pipelines_; mutable Variants border_mask_blur_pipelines_; @@ -170,125 +179,6 @@ class ContentContext { mutable Variants clip_pipelines_; mutable Variants glyph_atlas_pipelines_; - static void ApplyOptionsToDescriptor(PipelineDescriptor& desc, - const ContentContextOptions& options) { - auto blend_mode = options.blend_mode; - if (blend_mode > Entity::BlendMode::kLastPipelineBlendMode) { - VALIDATION_LOG << "Cannot use blend mode " - << static_cast(options.blend_mode) - << " as a pipeline blend."; - blend_mode = Entity::BlendMode::kSourceOver; - } - - desc.SetSampleCount(options.sample_count); - - ColorAttachmentDescriptor color0 = *desc.GetColorAttachmentDescriptor(0u); - color0.alpha_blend_op = BlendOperation::kAdd; - color0.color_blend_op = BlendOperation::kAdd; - - static_assert(Entity::BlendMode::kLastPipelineBlendMode == - Entity::BlendMode::kModulate); - - switch (blend_mode) { - case Entity::BlendMode::kClear: - color0.dst_alpha_blend_factor = BlendFactor::kZero; - color0.dst_color_blend_factor = BlendFactor::kZero; - color0.src_alpha_blend_factor = BlendFactor::kZero; - color0.src_color_blend_factor = BlendFactor::kZero; - break; - case Entity::BlendMode::kSource: - color0.dst_alpha_blend_factor = BlendFactor::kZero; - color0.dst_color_blend_factor = BlendFactor::kZero; - color0.src_alpha_blend_factor = BlendFactor::kSourceAlpha; - color0.src_color_blend_factor = BlendFactor::kOne; - break; - case Entity::BlendMode::kDestination: - color0.dst_alpha_blend_factor = BlendFactor::kDestinationAlpha; - color0.dst_color_blend_factor = BlendFactor::kOne; - color0.src_alpha_blend_factor = BlendFactor::kZero; - color0.src_color_blend_factor = BlendFactor::kZero; - break; - case Entity::BlendMode::kSourceOver: - color0.dst_alpha_blend_factor = BlendFactor::kOneMinusSourceAlpha; - color0.dst_color_blend_factor = BlendFactor::kOneMinusSourceAlpha; - color0.src_alpha_blend_factor = BlendFactor::kSourceAlpha; - color0.src_color_blend_factor = BlendFactor::kOne; - break; - case Entity::BlendMode::kDestinationOver: - color0.dst_alpha_blend_factor = BlendFactor::kDestinationAlpha; - color0.dst_color_blend_factor = BlendFactor::kOne; - color0.src_alpha_blend_factor = BlendFactor::kOneMinusDestinationAlpha; - color0.src_color_blend_factor = BlendFactor::kOneMinusDestinationAlpha; - break; - case Entity::BlendMode::kSourceIn: - color0.dst_alpha_blend_factor = BlendFactor::kZero; - color0.dst_color_blend_factor = BlendFactor::kZero; - color0.src_alpha_blend_factor = BlendFactor::kDestinationAlpha; - color0.src_color_blend_factor = BlendFactor::kDestinationAlpha; - break; - case Entity::BlendMode::kDestinationIn: - color0.dst_alpha_blend_factor = BlendFactor::kSourceAlpha; - color0.dst_color_blend_factor = BlendFactor::kSourceAlpha; - color0.src_alpha_blend_factor = BlendFactor::kZero; - color0.src_color_blend_factor = BlendFactor::kZero; - break; - case Entity::BlendMode::kSourceOut: - color0.dst_alpha_blend_factor = BlendFactor::kZero; - color0.dst_color_blend_factor = BlendFactor::kZero; - color0.src_alpha_blend_factor = BlendFactor::kOneMinusDestinationAlpha; - color0.src_color_blend_factor = BlendFactor::kOneMinusDestinationAlpha; - break; - case Entity::BlendMode::kDestinationOut: - color0.dst_alpha_blend_factor = BlendFactor::kOneMinusSourceAlpha; - color0.dst_color_blend_factor = BlendFactor::kOneMinusSourceAlpha; - color0.src_alpha_blend_factor = BlendFactor::kZero; - color0.src_color_blend_factor = BlendFactor::kZero; - break; - case Entity::BlendMode::kSourceATop: - color0.dst_alpha_blend_factor = BlendFactor::kOneMinusSourceAlpha; - color0.dst_color_blend_factor = BlendFactor::kOneMinusSourceAlpha; - color0.src_alpha_blend_factor = BlendFactor::kDestinationAlpha; - color0.src_color_blend_factor = BlendFactor::kDestinationAlpha; - break; - case Entity::BlendMode::kDestinationATop: - color0.dst_alpha_blend_factor = BlendFactor::kSourceAlpha; - color0.dst_color_blend_factor = BlendFactor::kSourceAlpha; - color0.src_alpha_blend_factor = BlendFactor::kOneMinusDestinationAlpha; - color0.src_color_blend_factor = BlendFactor::kOneMinusDestinationAlpha; - break; - case Entity::BlendMode::kXor: - color0.dst_alpha_blend_factor = BlendFactor::kOneMinusSourceAlpha; - color0.dst_color_blend_factor = BlendFactor::kOneMinusSourceAlpha; - color0.src_alpha_blend_factor = BlendFactor::kOneMinusDestinationAlpha; - color0.src_color_blend_factor = BlendFactor::kOneMinusDestinationAlpha; - break; - case Entity::BlendMode::kPlus: - color0.dst_alpha_blend_factor = BlendFactor::kOne; - color0.dst_color_blend_factor = BlendFactor::kOne; - color0.src_alpha_blend_factor = BlendFactor::kOne; - color0.src_color_blend_factor = BlendFactor::kOne; - break; - case Entity::BlendMode::kModulate: - // kSourceColor and kDestinationColor override the alpha blend factor. - color0.dst_alpha_blend_factor = BlendFactor::kZero; - color0.dst_color_blend_factor = BlendFactor::kSourceColor; - color0.src_alpha_blend_factor = BlendFactor::kZero; - color0.src_color_blend_factor = BlendFactor::kZero; - break; - default: - FML_UNREACHABLE(); - } - desc.SetColorAttachmentDescriptor(0u, std::move(color0)); - - if (desc.GetFrontStencilAttachmentDescriptor().has_value()) { - StencilAttachmentDescriptor stencil = - desc.GetFrontStencilAttachmentDescriptor().value(); - stencil.stencil_compare = options.stencil_compare; - stencil.depth_stencil_pass = options.stencil_operation; - desc.SetStencilAttachmentDescriptors(stencil); - } - } - template std::shared_ptr GetPipeline(Variants& container, ContentContextOptions opts) const { @@ -307,7 +197,7 @@ class ContentContext { auto variant_future = prototype->second->WaitAndGet()->CreateVariant( [&opts, variants_count = container.size()](PipelineDescriptor& desc) { - ApplyOptionsToDescriptor(desc, opts); + opts.ApplyToPipelineDescriptor(desc); desc.SetLabel( SPrintF("%s V#%zu", desc.GetLabel().c_str(), variants_count)); }); diff --git a/impeller/entity/contents/filters/blend_filter_contents.cc b/impeller/entity/contents/filters/blend_filter_contents.cc index 5ff7e746770b1..2db7d86573c12 100644 --- a/impeller/entity/contents/filters/blend_filter_contents.cc +++ b/impeller/entity/contents/filters/blend_filter_contents.cc @@ -5,6 +5,7 @@ #include "impeller/entity/contents/filters/blend_filter_contents.h" #include "impeller/entity/contents/content_context.h" +#include "impeller/entity/contents/contents.h" #include "impeller/entity/contents/filters/inputs/filter_input.h" #include "impeller/renderer/render_pass.h" #include "impeller/renderer/sampler_library.h" @@ -20,13 +21,16 @@ BlendFilterContents::~BlendFilterContents() = default; using PipelineProc = std::shared_ptr (ContentContext::*)(ContentContextOptions) const; -template +template static bool AdvancedBlend(const FilterInput::Vector& inputs, const ContentContext& renderer, const Entity& entity, RenderPass& pass, const Rect& coverage, PipelineProc pipeline_proc) { + using VS = typename TPipeline::VertexShader; + using FS = typename TPipeline::FragmentShader; + if (inputs.size() < 2) { return false; } @@ -65,8 +69,7 @@ static bool AdvancedBlend(const FilterInput::Vector& inputs, }); auto vtx_buffer = vtx_builder.CreateVertexBuffer(host_buffer); - auto options = OptionsFromPass(pass); - options.blend_mode = Entity::BlendMode::kSource; + auto options = OptionsFromPassAndEntity(pass, entity); std::shared_ptr pipeline = std::invoke(pipeline_proc, renderer, options); @@ -99,7 +102,7 @@ void BlendFilterContents::SetBlendMode(Entity::BlendMode blend_mode) { if (blend_mode > Entity::BlendMode::kLastPipelineBlendMode) { static_assert(Entity::BlendMode::kLastAdvancedBlendMode == - Entity::BlendMode::kScreen); + Entity::BlendMode::kColorBurn); switch (blend_mode) { case Entity::BlendMode::kScreen: @@ -107,10 +110,19 @@ void BlendFilterContents::SetBlendMode(Entity::BlendMode blend_mode) { const ContentContext& renderer, const Entity& entity, RenderPass& pass, const Rect& coverage) { - PipelineProc p = &ContentContext::GetTextureBlendScreenPipeline; - return AdvancedBlend( - inputs, renderer, entity, pass, coverage, p); + PipelineProc p = &ContentContext::GetBlendScreenPipeline; + return AdvancedBlend(inputs, renderer, entity, + pass, coverage, p); + }; + break; + case Entity::BlendMode::kColorBurn: + advanced_blend_proc_ = [](const FilterInput::Vector& inputs, + const ContentContext& renderer, + const Entity& entity, RenderPass& pass, + const Rect& coverage) { + PipelineProc p = &ContentContext::GetBlendColorburnPipeline; + return AdvancedBlend(inputs, renderer, entity, + pass, coverage, p); }; break; default: @@ -125,8 +137,8 @@ static bool BasicBlend(const FilterInput::Vector& inputs, RenderPass& pass, const Rect& coverage, Entity::BlendMode basic_blend) { - using VS = TextureBlendPipeline::VertexShader; - using FS = TextureBlendPipeline::FragmentShader; + using VS = BlendPipeline::VertexShader; + using FS = BlendPipeline::FragmentShader; auto& host_buffer = pass.GetTransientsBuffer(); @@ -175,7 +187,7 @@ static bool BasicBlend(const FilterInput::Vector& inputs, // Draw the first texture using kSource. options.blend_mode = Entity::BlendMode::kSource; - cmd.pipeline = renderer.GetTextureBlendPipeline(options); + cmd.pipeline = renderer.GetBlendPipeline(options); if (!add_blend_command(inputs[0]->GetSnapshot(renderer, entity))) { return true; } @@ -187,7 +199,7 @@ static bool BasicBlend(const FilterInput::Vector& inputs, // Write subsequent textures using the selected blend mode. options.blend_mode = basic_blend; - cmd.pipeline = renderer.GetTextureBlendPipeline(options); + cmd.pipeline = renderer.GetBlendPipeline(options); for (auto texture_i = inputs.begin() + 1; texture_i < inputs.end(); texture_i++) { diff --git a/impeller/entity/entity.h b/impeller/entity/entity.h index 8566b99bddd45..f1fea96b3e7b6 100644 --- a/impeller/entity/entity.h +++ b/impeller/entity/entity.h @@ -43,9 +43,10 @@ class Entity { // pipelines on most graphics devices without extensions, and so they are // only able to be used via `BlendFilterContents`. kScreen, + kColorBurn, kLastPipelineBlendMode = kModulate, - kLastAdvancedBlendMode = kScreen, + kLastAdvancedBlendMode = kColorBurn, }; enum class ClipOperation { diff --git a/impeller/entity/entity_pass.cc b/impeller/entity/entity_pass.cc index 5ba104f9e2d9b..fba0a0f0fa3e9 100644 --- a/impeller/entity/entity_pass.cc +++ b/impeller/entity/entity_pass.cc @@ -153,7 +153,7 @@ bool EntityPass::Render(ContentContext& renderer, Entity entity; entity.SetContents(contents); - entity.SetBlendMode(Entity::BlendMode::kSource); + entity.SetBlendMode(Entity::BlendMode::kSourceOver); entity.Render(renderer, *render_pass); } @@ -322,7 +322,7 @@ bool EntityPass::RenderInternal(ContentContext& renderer, element_entity.GetTransformation().Invert())}; element_entity.SetContents( FilterContents::MakeBlend(element_entity.GetBlendMode(), inputs)); - element_entity.SetBlendMode(Entity::BlendMode::kSource); + element_entity.SetBlendMode(Entity::BlendMode::kSourceOver); } // Create a new render pass to render the element if one isn't active. diff --git a/impeller/entity/shaders/texture_blend_screen.vert b/impeller/entity/shaders/advanced_blend.vert similarity index 100% rename from impeller/entity/shaders/texture_blend_screen.vert rename to impeller/entity/shaders/advanced_blend.vert diff --git a/impeller/entity/shaders/advanced_blend_colorburn.frag b/impeller/entity/shaders/advanced_blend_colorburn.frag new file mode 100644 index 0000000000000..297893d201477 --- /dev/null +++ b/impeller/entity/shaders/advanced_blend_colorburn.frag @@ -0,0 +1,30 @@ +// 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 "blending.glsl" + +uniform sampler2D texture_sampler_dst; +uniform sampler2D texture_sampler_src; + +in vec2 v_dst_texture_coords; +in vec2 v_src_texture_coords; + +out vec4 frag_color; + +vec3 ComponentIsValue(vec3 n, float value) { + return vec3(n.r == value, n.g == value, n.b == value); +} + +void main() { + const vec4 dst = Unpremultiply( + SampleWithBorder(texture_sampler_dst, v_dst_texture_coords)); + const vec4 src = Unpremultiply( + SampleWithBorder(texture_sampler_src, v_src_texture_coords)); + + vec3 color = 1 - min(vec3(1), (1 - dst.rgb) / src.rgb); + color = mix(color, vec3(1), ComponentIsValue(dst.rgb, 1.0)); + color = mix(color, vec3(0), ComponentIsValue(src.rgb, 0.0)); + + frag_color = vec4(color * src.a, src.a); +} diff --git a/impeller/entity/shaders/advanced_blend_screen.frag b/impeller/entity/shaders/advanced_blend_screen.frag new file mode 100644 index 0000000000000..cd4253af005b5 --- /dev/null +++ b/impeller/entity/shaders/advanced_blend_screen.frag @@ -0,0 +1,23 @@ +// 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 "blending.glsl" + +uniform sampler2D texture_sampler_dst; +uniform sampler2D texture_sampler_src; + +in vec2 v_dst_texture_coords; +in vec2 v_src_texture_coords; + +out vec4 frag_color; + +void main() { + const vec4 dst = Unpremultiply( + SampleWithBorder(texture_sampler_dst, v_dst_texture_coords)); + const vec4 src = Unpremultiply( + SampleWithBorder(texture_sampler_src, v_src_texture_coords)); + + vec3 color = dst.rgb + src.rgb - (dst.rgb * src.rgb); + frag_color = vec4(color * src.a, src.a); +} diff --git a/impeller/entity/shaders/texture_blend.frag b/impeller/entity/shaders/blend.frag similarity index 100% rename from impeller/entity/shaders/texture_blend.frag rename to impeller/entity/shaders/blend.frag diff --git a/impeller/entity/shaders/texture_blend.vert b/impeller/entity/shaders/blend.vert similarity index 100% rename from impeller/entity/shaders/texture_blend.vert rename to impeller/entity/shaders/blend.vert diff --git a/impeller/entity/shaders/texture_blend_screen.frag b/impeller/entity/shaders/blending.glsl similarity index 50% rename from impeller/entity/shaders/texture_blend_screen.frag rename to impeller/entity/shaders/blending.glsl index 421125a2d54b7..05b46eb084253 100644 --- a/impeller/entity/shaders/texture_blend_screen.frag +++ b/impeller/entity/shaders/blending.glsl @@ -2,14 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -uniform sampler2D texture_sampler_dst; -uniform sampler2D texture_sampler_src; - -in vec2 v_dst_texture_coords; -in vec2 v_src_texture_coords; - -out vec4 frag_color; - // Emulate SamplerAddressMode::ClampToBorder. vec4 SampleWithBorder(sampler2D tex, vec2 uv) { if (uv.x > 0 && uv.y > 0 && uv.x < 1 && uv.y < 1) { @@ -24,13 +16,3 @@ vec4 Unpremultiply(vec4 color) { } return vec4(color.rgb / color.a, color.a); } - -void main() { - vec4 dst = SampleWithBorder(texture_sampler_dst, v_dst_texture_coords); - vec4 d = Unpremultiply(dst); - vec4 src = SampleWithBorder(texture_sampler_src, v_src_texture_coords); - vec4 s = Unpremultiply(src); - - vec3 color = d.rgb + s.rgb - (d.rgb * s.rgb); - frag_color = vec4(color, d.a - s.a + s.a); -}