| Flutter Impeller |

paint.cc
Go to the documentation of this file.
1 // Copyright 2013 The Flutter Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "impeller/aiks/paint.h"
6
7 #include <memory>
8
9 #include "impeller/entity/contents/color_source_contents.h"
10 #include "impeller/entity/contents/filters/color_filter_contents.h"
11 #include "impeller/entity/contents/filters/filter_contents.h"
12 #include "impeller/entity/contents/solid_color_contents.h"
13 #include "impeller/entity/geometry/geometry.h"
14
15 namespace impeller {
16
17 /// A color matrix which inverts colors.
18 // clang-format off
19 constexpr ColorMatrix kColorInversion = {
20 .array = {
21 -1.0, 0, 0, 1.0, 0, //
22 0, -1.0, 0, 1.0, 0, //
23 0, 0, -1.0, 1.0, 0, //
24 1.0, 1.0, 1.0, 1.0, 0 //
25 }
26 };
27 // clang-format on
28
29 std::shared_ptr<Contents> Paint::CreateContentsForGeometry(
30 const std::shared_ptr<Geometry>& geometry) const {
31 auto contents = color_source.GetContents(*this);
32
33 // Attempt to apply the color filter on the CPU first.
34 // Note: This is not just an optimization; some color sources rely on
35 // CPU-applied color filters to behave properly.
36 auto color_filter = GetColorFilter();
37 bool needs_color_filter = !!color_filter;
38 if (color_filter &&
39 contents->ApplyColorFilter(color_filter->GetCPUColorFilterProc())) {
40 needs_color_filter = false;
41 }
42
43 contents->SetGeometry(geometry);
44 if (mask_blur_descriptor.has_value()) {
45 // If there's a mask blur and we need to apply the color filter on the GPU,
46 // we need to be careful to only apply the color filter to the source
47 // colors. CreateMaskBlur is able to handle this case.
48 return mask_blur_descriptor->CreateMaskBlur(
49 contents, needs_color_filter ? color_filter : nullptr);
50 }
51
52 return contents;
53 }
54
55 std::shared_ptr<Contents> Paint::WithFilters(
56 std::shared_ptr<Contents> input) const {
57 input = WithColorFilter(input, ColorFilterContents::AbsorbOpacity::kYes);
58 auto image_filter =
59 WithImageFilter(input, Matrix(), Entity::RenderingMode::kDirect);
60 if (image_filter) {
61 input = image_filter;
62 }
63 return input;
64 }
65
66 std::shared_ptr<Contents> Paint::WithFiltersForSubpassTarget(
67 std::shared_ptr<Contents> input,
68 const Matrix& effect_transform) const {
69 auto image_filter =
70 WithImageFilter(input, effect_transform, Entity::RenderingMode::kSubpass);
71 if (image_filter) {
72 input = image_filter;
73 }
74 input = WithColorFilter(input, ColorFilterContents::AbsorbOpacity::kYes);
75 return input;
76 }
77
78 std::shared_ptr<Contents> Paint::WithMaskBlur(std::shared_ptr<Contents> input,
79 bool is_solid_color) const {
80 if (mask_blur_descriptor.has_value()) {
81 input = mask_blur_descriptor->CreateMaskBlur(FilterInput::Make(input),
82 is_solid_color);
83 }
84 return input;
85 }
86
87 std::shared_ptr<FilterContents> Paint::WithImageFilter(
88 const FilterInput::Variant& input,
89 const Matrix& effect_transform,
90 Entity::RenderingMode rendering_mode) const {
91 if (!image_filter) {
92 return nullptr;
93 }
94 auto filter = image_filter->WrapInput(FilterInput::Make(input));
95 filter->SetRenderingMode(rendering_mode);
96 filter->SetEffectTransform(effect_transform);
97 return filter;
98 }
99
100 std::shared_ptr<Contents> Paint::WithColorFilter(
101 std::shared_ptr<Contents> input,
102 ColorFilterContents::AbsorbOpacity absorb_opacity) const {
103 // Image input types will directly set their color filter,
104 // if any. See `TiledTextureContents.SetColorFilter`.
105 if (color_source.GetType() == ColorSource::Type::kImage) {
106 return input;
107 }
108
109 auto color_filter = GetColorFilter();
110 if (!color_filter) {
111 return input;
112 }
113
114 // Attempt to apply the color filter on the CPU first.
115 // Note: This is not just an optimization; some color sources rely on
116 // CPU-applied color filters to behave properly.
117 if (input->ApplyColorFilter(color_filter->GetCPUColorFilterProc())) {
118 return input;
119 }
120 return color_filter->WrapWithGPUColorFilter(FilterInput::Make(input),
121 absorb_opacity);
122 }
123
124 std::shared_ptr<FilterContents> Paint::MaskBlurDescriptor::CreateMaskBlur(
125 std::shared_ptr<ColorSourceContents> color_source_contents,
126 const std::shared_ptr<ColorFilter>& color_filter) const {
127 // If it's a solid color and there is no color filter, then we can just get
128 // away with doing one Gaussian blur.
129 if (color_source_contents->IsSolidColor() && !color_filter) {
130 return FilterContents::MakeGaussianBlur(
131 FilterInput::Make(color_source_contents), sigma, sigma, style,
132 Entity::TileMode::kDecal);
133 }
134
135 /// 1. Create an opaque white mask of the original geometry.
136
137 auto mask = std::make_shared<SolidColorContents>();
138 mask->SetColor(Color::White());
139 mask->SetGeometry(color_source_contents->GetGeometry());
140
141 /// 2. Blur the mask.
142
143 auto blurred_mask = FilterContents::MakeGaussianBlur(
144 FilterInput::Make(mask), sigma, sigma, style, Entity::TileMode::kDecal);
145
146 /// 3. Replace the geometry of the original color source with a rectangle that
147 /// covers the full region of the blurred mask. Note that geometry is in
148 /// local bounds.
149
150 auto expanded_local_bounds = blurred_mask->GetCoverage({});
151 if (!expanded_local_bounds.has_value()) {
152 expanded_local_bounds = Rect();
153 }
154 color_source_contents->SetGeometry(
155 Geometry::MakeRect(*expanded_local_bounds));
156
157 std::shared_ptr<Contents> color_contents = color_source_contents;
158
159 /// 4. Apply the user set color filter on the GPU, if applicable.
160
161 if (color_filter) {
162 color_contents = color_filter->WrapWithGPUColorFilter(
163 FilterInput::Make(color_source_contents),
164 ColorFilterContents::AbsorbOpacity::kYes);
165 }
166
167 /// 5. Composite the color source with the blurred mask.
168
169 return ColorFilterContents::MakeBlend(
170 BlendMode::kSourceIn,
171 {FilterInput::Make(blurred_mask), FilterInput::Make(color_contents)});
172 }
173
174 std::shared_ptr<FilterContents> Paint::MaskBlurDescriptor::CreateMaskBlur(
175 const FilterInput::Ref& input,
176 bool is_solid_color) const {
177 if (is_solid_color) {
178 return FilterContents::MakeGaussianBlur(input, sigma, sigma, style,
179 Entity::TileMode::kDecal);
180 }
181 return FilterContents::MakeBorderMaskBlur(input, sigma, sigma, style);
182 }
183
184 std::shared_ptr<ColorFilter> Paint::GetColorFilter() const {
185 if (invert_colors && color_filter) {
186 auto filter = ColorFilter::MakeMatrix(kColorInversion);
187 return ColorFilter::MakeComposed(filter, color_filter);
188 }
189 if (invert_colors) {
190 return ColorFilter::MakeMatrix(kColorInversion);
191 }
192 if (color_filter) {
193 return color_filter;
194 }
195 return nullptr;
196 }
197
198 bool Paint::HasColorFilter() const {
199 return !!color_filter || invert_colors;
200 }
201
202 } // namespace impeller
impeller::Paint::WithMaskBlur
std::shared_ptr< Contents > WithMaskBlur(std::shared_ptr< Contents > input, bool is_solid_color) const
Definition: paint.cc:78
impeller::ColorSource::GetContents
std::shared_ptr< ColorSourceContents > GetContents(const Paint &paint) const
Definition: color_source.cc:234
solid_color_contents.h
impeller::FilterInput::Make
static FilterInput::Ref Make(Variant input, bool msaa_enabled=true)
Definition: filter_input.cc:19
impeller::Paint::MaskBlurDescriptor::sigma
Sigma sigma
Definition: paint.h:40
impeller::Entity::TileMode::kDecal
@ kDecal
impeller::ColorFilter::MakeComposed
static std::shared_ptr< ColorFilter > MakeComposed(const std::shared_ptr< ColorFilter > &outer, const std::shared_ptr< ColorFilter > &inner)
Definition: color_filter.cc:40
impeller::Paint::MaskBlurDescriptor::style
FilterContents::BlurStyle style
Definition: paint.h:39
impeller::FilterInput::Ref
std::shared_ptr< FilterInput > Ref
Definition: filter_input.h:32
impeller::Paint::MaskBlurDescriptor::CreateMaskBlur
std::shared_ptr< FilterContents > CreateMaskBlur(std::shared_ptr< ColorSourceContents > color_source_contents, const std::shared_ptr< ColorFilter > &color_filter) const
Definition: paint.cc:124
impeller::Paint::color_source
ColorSource color_source
Definition: paint.h:52
impeller::Paint::color_filter
std::shared_ptr< ColorFilter > color_filter
Definition: paint.h:64
impeller::FilterContents::MakeGaussianBlur
static std::shared_ptr< FilterContents > MakeGaussianBlur(const FilterInput::Ref &input, Sigma sigma_x, Sigma sigma_y, BlurStyle blur_style=BlurStyle::kNormal, Entity::TileMode tile_mode=Entity::TileMode::kDecal)
Definition: filter_contents.cc:53
impeller::kColorInversion
constexpr ColorMatrix kColorInversion
A color matrix which inverts colors.
Definition: paint.cc:19
filter_contents.h
color_source_contents.h
impeller::Paint::GetColorFilter
std::shared_ptr< ColorFilter > GetColorFilter() const
Definition: paint.cc:184
impeller::Paint::style
Style style
Definition: paint.h:59
impeller::ColorMatrix::array
Scalar array[20]
Definition: color.h:118
geometry.h
impeller::Color::White
static constexpr Color White()
Definition: color.h:256
impeller::Entity::RenderingMode::kDirect
@ kDirect
impeller::FilterInput::Variant
std::variant< std::shared_ptr< FilterContents >, std::shared_ptr< Contents >, std::shared_ptr< Texture >, Rect > Variant
Definition: filter_input.h:37
impeller::Rect
TRect< Scalar > Rect
Definition: rect.h:488
impeller::FilterContents::MakeBorderMaskBlur
static std::shared_ptr< FilterContents > MakeBorderMaskBlur(FilterInput::Ref input, Sigma sigma_x, Sigma sigma_y, BlurStyle blur_style=BlurStyle::kNormal)
Definition: filter_contents.cc:93
color_filter_contents.h
impeller::Entity::RenderingMode::kSubpass
@ kSubpass
impeller::ColorFilter::MakeMatrix
static std::shared_ptr< ColorFilter > MakeMatrix(ColorMatrix color_matrix)
Definition: color_filter.cc:28
impeller::Geometry::MakeRect
static std::shared_ptr< Geometry > MakeRect(const Rect &rect)
Definition: geometry.cc:179
impeller::ColorSource::Type::kImage
@ kImage
impeller::Paint::WithImageFilter
std::shared_ptr< FilterContents > WithImageFilter(const FilterInput::Variant &input, const Matrix &effect_transform, Entity::RenderingMode rendering_mode) const
Definition: paint.cc:87
impeller::Paint::invert_colors
bool invert_colors
Definition: paint.h:61
impeller::BlendMode::kSourceIn
@ kSourceIn
paint.h
impeller::Paint::HasColorFilter
bool HasColorFilter() const
Whether this paint has a color filter that can apply opacity.
Definition: paint.cc:198
impeller::Entity::RenderingMode
RenderingMode
Definition: entity.h:26
impeller::ColorFilterContents::AbsorbOpacity::kYes
@ kYes
impeller::ColorMatrix
Definition: color.h:117
impeller::ColorFilterContents::MakeBlend
static std::shared_ptr< ColorFilterContents > MakeBlend(BlendMode blend_mode, FilterInput::Vector inputs, std::optional< Color > foreground_color=std::nullopt)
the [inputs] are expected to be in the order of dst, src.
Definition: color_filter_contents.cc:17
impeller::ColorFilterContents::AbsorbOpacity
AbsorbOpacity
Definition: color_filter_contents.h:14
impeller
Definition: aiks_context.cc:10
impeller::Paint::mask_blur_descriptor
std::optional< MaskBlurDescriptor > mask_blur_descriptor
Definition: paint.h:65
impeller::Paint::WithFilters
std::shared_ptr< Contents > WithFilters(std::shared_ptr< Contents > input) const
Wrap this paint's configured filters to the given contents.
Definition: paint.cc:55
impeller::ColorSource::GetType
Type GetType() const
Definition: color_source.cc:230
impeller::Matrix
A 4x4 matrix using column-major storage.
Definition: matrix.h:37
impeller::Paint::WithFiltersForSubpassTarget
std::shared_ptr< Contents > WithFiltersForSubpassTarget(std::shared_ptr< Contents > input, const Matrix &effect_transform=Matrix()) const
Wrap this paint's configured filters to the given contents of subpass target.
Definition: paint.cc:66
impeller::Paint::CreateContentsForGeometry
std::shared_ptr< Contents > CreateContentsForGeometry(const std::shared_ptr< Geometry > &geometry) const
Definition: paint.cc:29
impeller::Paint::image_filter
std::shared_ptr< ImageFilter > image_filter
Definition: paint.h:63