Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

[Impeller] Add ColorBurn, fix SourceOver alpha, make default pipeline initialization robust #33289

Merged
merged 5 commits into from
May 16, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 6 additions & 4 deletions ci/licenses_golden/licenses_flutter
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down
20 changes: 14 additions & 6 deletions impeller/aiks/aiks_unittests.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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
Expand All @@ -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;
Expand All @@ -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();
Expand Down
2 changes: 1 addition & 1 deletion impeller/blobcat/blob.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
5 changes: 4 additions & 1 deletion impeller/display_list/display_list_dispatcher.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand All @@ -240,6 +242,7 @@ void DisplayListDispatcher::setBlendMode(flutter::DlBlendMode dl_mode) {
paint_.blend_mode = mode.value();
} else {
UNIMPLEMENTED;
paint_.blend_mode = Entity::BlendMode::kSourceOver;
}
}

Expand Down
21 changes: 11 additions & 10 deletions impeller/entity/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -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",
]
}

Expand Down
155 changes: 144 additions & 11 deletions impeller/entity/contents/content_context.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Loading