mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
[Impeller] Add ColorBurn, fix SourceOver alpha, make default pipeline initialization robust (flutter/engine#33289)
This commit is contained in:
parent
c536f1f497
commit
2587e83eaa
@ -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
|
||||
|
||||
@ -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", ¤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();
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -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",
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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));
|
||||
});
|
||||
|
||||
@ -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++) {
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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.
|
||||
|
||||
@ -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);
|
||||
}
|
||||
@ -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);
|
||||
}
|
||||
@ -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);
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user