[Impeller] Add ColorBurn, fix SourceOver alpha, make default pipeline initialization robust (flutter/engine#33289)

This commit is contained in:
Brandon DeRosier 2022-05-16 11:11:53 -07:00 committed by GitHub
parent c536f1f497
commit 2587e83eaa
16 changed files with 285 additions and 200 deletions

View File

@ -530,6 +530,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
@ -542,10 +548,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

View File

@ -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<size_t>(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", &current_blend_index,
blend_mode_names.data(), blend_mode_names.size());
static float alpha = 1;
ImGui::Begin("Controls");
{
ImGui::ListBox("Blending mode", &current_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();

View File

@ -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;

View File

@ -214,11 +214,13 @@ static std::optional<Entity::BlendMode> 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;
}
}

View File

@ -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",
]
}

View File

@ -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<int>(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 <typename PipelineT>
static std::unique_ptr<PipelineT> 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<PipelineT>(context, desc);
}
ContentContext::ContentContext(std::shared_ptr<Context> 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<GradientFillPipeline>(*context_);
solid_fill_pipelines_[{}] = std::make_unique<SolidFillPipeline>(*context_);
CreateDefaultPipeline<GradientFillPipeline>(*context_);
solid_fill_pipelines_[{}] =
CreateDefaultPipeline<SolidFillPipeline>(*context_);
texture_blend_pipelines_[{}] =
std::make_unique<TextureBlendPipeline>(*context_);
texture_blend_screen_pipelines_[{}] =
std::make_unique<TextureBlendScreenPipeline>(*context_);
texture_pipelines_[{}] = std::make_unique<TexturePipeline>(*context_);
CreateDefaultPipeline<BlendPipeline>(*context_);
blend_screen_pipelines_[{}] =
CreateDefaultPipeline<BlendScreenPipeline>(*context_);
blend_colorburn_pipelines_[{}] =
CreateDefaultPipeline<BlendColorburnPipeline>(*context_);
texture_pipelines_[{}] = CreateDefaultPipeline<TexturePipeline>(*context_);
gaussian_blur_pipelines_[{}] =
std::make_unique<GaussianBlurPipeline>(*context_);
CreateDefaultPipeline<GaussianBlurPipeline>(*context_);
border_mask_blur_pipelines_[{}] =
std::make_unique<BorderMaskBlurPipeline>(*context_);
CreateDefaultPipeline<BorderMaskBlurPipeline>(*context_);
solid_stroke_pipelines_[{}] =
std::make_unique<SolidStrokePipeline>(*context_);
glyph_atlas_pipelines_[{}] = std::make_unique<GlyphAtlasPipeline>(*context_);
CreateDefaultPipeline<SolidStrokePipeline>(*context_);
glyph_atlas_pipelines_[{}] =
CreateDefaultPipeline<GlyphAtlasPipeline>(*context_);
// Pipelines that are variants of the base pipelines with custom descriptors.
// TODO(98684): Rework this API to allow fetching the descriptor without

View File

@ -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<GradientFillVertexShader, GradientFillFragmentShader>;
using SolidFillPipeline =
PipelineT<SolidFillVertexShader, SolidFillFragmentShader>;
using TextureBlendPipeline =
PipelineT<TextureBlendVertexShader, TextureBlendFragmentShader>;
using TextureBlendScreenPipeline =
PipelineT<TextureBlendScreenVertexShader, TextureBlendScreenFragmentShader>;
using BlendPipeline = PipelineT<BlendVertexShader, BlendFragmentShader>;
using BlendScreenPipeline =
PipelineT<AdvancedBlendVertexShader, AdvancedBlendScreenFragmentShader>;
using BlendColorburnPipeline =
PipelineT<AdvancedBlendVertexShader, AdvancedBlendColorburnFragmentShader>;
using TexturePipeline =
PipelineT<TextureFillVertexShader, TextureFillFragmentShader>;
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<Pipeline> GetTextureBlendPipeline(
ContentContextOptions opts) const {
std::shared_ptr<Pipeline> GetBlendPipeline(ContentContextOptions opts) const {
return GetPipeline(texture_blend_pipelines_, opts);
}
std::shared_ptr<Pipeline> GetTextureBlendScreenPipeline(
std::shared_ptr<Pipeline> GetBlendScreenPipeline(
ContentContextOptions opts) const {
return GetPipeline(texture_blend_screen_pipelines_, opts);
return GetPipeline(blend_screen_pipelines_, opts);
}
std::shared_ptr<Pipeline> GetBlendColorburnPipeline(
ContentContextOptions opts) const {
return GetPipeline(blend_colorburn_pipelines_, opts);
}
std::shared_ptr<Pipeline> GetTexturePipeline(
@ -161,8 +169,9 @@ class ContentContext {
// map.
mutable Variants<GradientFillPipeline> gradient_fill_pipelines_;
mutable Variants<SolidFillPipeline> solid_fill_pipelines_;
mutable Variants<TextureBlendPipeline> texture_blend_pipelines_;
mutable Variants<TextureBlendScreenPipeline> texture_blend_screen_pipelines_;
mutable Variants<BlendPipeline> texture_blend_pipelines_;
mutable Variants<BlendScreenPipeline> blend_screen_pipelines_;
mutable Variants<BlendColorburnPipeline> blend_colorburn_pipelines_;
mutable Variants<TexturePipeline> texture_pipelines_;
mutable Variants<GaussianBlurPipeline> gaussian_blur_pipelines_;
mutable Variants<BorderMaskBlurPipeline> border_mask_blur_pipelines_;
@ -170,125 +179,6 @@ class ContentContext {
mutable Variants<ClipPipeline> clip_pipelines_;
mutable Variants<GlyphAtlasPipeline> 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<int>(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 <class TypedPipeline>
std::shared_ptr<Pipeline> GetPipeline(Variants<TypedPipeline>& 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));
});

View File

@ -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<Pipeline> (ContentContext::*)(ContentContextOptions) const;
template <typename VS, typename FS>
template <typename TPipeline>
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> 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<TextureBlendScreenPipeline::VertexShader,
TextureBlendScreenPipeline::FragmentShader>(
inputs, renderer, entity, pass, coverage, p);
PipelineProc p = &ContentContext::GetBlendScreenPipeline;
return AdvancedBlend<BlendScreenPipeline>(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<BlendColorburnPipeline>(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++) {

View File

@ -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 {

View File

@ -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.

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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);
}