-
Notifications
You must be signed in to change notification settings - Fork 6k
[Impeller] Add support for ImageFilter.shader #53490
Changes from all commits
95a3554
587271b
a299234
ec1b101
2f9f72d
1f206da
0ec37a8
c3d1e0d
c4ce95d
b07ef04
216b604
e851999
217253b
6ead435
d848d66
59cecc3
c786ea8
cda52b0
77e290b
5bb8824
4c55427
8355d5c
7772b8c
beac90a
eab80e0
2f9dc47
15378eb
fe023c7
65e8525
2e00903
0684931
67cc655
eba4796
6f824b0
7d90603
b6a8a23
d61c68c
bc0a436
f592560
933a4ce
2edae62
8b8b6ee
41f333c
a876417
117ed3e
eaf4ac4
f16d0c6
9dd17af
c6d3248
10e9e59
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -7,6 +7,7 @@ | |
|
|
||
| #include <utility> | ||
|
|
||
| #include "display_list/effects/dl_color_source.h" | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is this stale now?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We need this for the samplers field on the DlRuntimeEffect filter |
||
| #include "flutter/display_list/dl_attributes.h" | ||
| #include "flutter/display_list/dl_sampling_options.h" | ||
| #include "flutter/display_list/dl_tile_mode.h" | ||
|
|
@@ -34,6 +35,7 @@ enum class DlImageFilterType { | |
| kCompose, | ||
| kColorFilter, | ||
| kLocalMatrix, | ||
| kRuntimeEffect, | ||
| }; | ||
|
|
||
| class DlBlurImageFilter; | ||
|
|
@@ -43,6 +45,7 @@ class DlMatrixImageFilter; | |
| class DlLocalMatrixImageFilter; | ||
| class DlComposeImageFilter; | ||
| class DlColorFilterImageFilter; | ||
| class DlRuntimeEffectImageFilter; | ||
|
|
||
| class DlImageFilter : public DlAttribute<DlImageFilter, DlImageFilterType> { | ||
| public: | ||
|
|
@@ -85,6 +88,12 @@ class DlImageFilter : public DlAttribute<DlImageFilter, DlImageFilterType> { | |
| return nullptr; | ||
| } | ||
|
|
||
| // Return a DlRuntimeEffectImageFilter pointer to this object iff it is a | ||
| // DlRuntimeEffectImageFilter type of ImageFilter, otherwise return nullptr. | ||
| virtual const DlRuntimeEffectImageFilter* asRuntimeEffectFilter() const { | ||
| return nullptr; | ||
| } | ||
|
|
||
| // Return a boolean indicating whether the image filtering operation will | ||
| // modify transparent black. This is typically used to determine if applying | ||
| // the ImageFilter to a temporary saveLayer buffer will turn the surrounding | ||
|
|
@@ -742,6 +751,101 @@ class DlLocalMatrixImageFilter final : public DlImageFilter { | |
| std::shared_ptr<const DlImageFilter> image_filter_; | ||
| }; | ||
|
|
||
| class DlRuntimeEffectImageFilter final : public DlImageFilter { | ||
| public: | ||
| explicit DlRuntimeEffectImageFilter( | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit: I wish these were in a .cc file. Recompilation time was killing me the other day.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There are a few things I'd like to clean up here as well (and the other files in this directory). (There is a .cc file for each, we just don't use it much.)
|
||
| sk_sp<DlRuntimeEffect> runtime_effect, | ||
| std::vector<std::shared_ptr<DlColorSource>> samplers, | ||
| std::shared_ptr<std::vector<uint8_t>> uniform_data) | ||
| : runtime_effect_(std::move(runtime_effect)), | ||
| samplers_(std::move(samplers)), | ||
| uniform_data_(std::move(uniform_data)) {} | ||
|
|
||
| std::shared_ptr<DlImageFilter> shared() const override { | ||
| return std::make_shared<DlRuntimeEffectImageFilter>( | ||
| this->runtime_effect_, this->samplers_, this->uniform_data_); | ||
| } | ||
|
|
||
| static std::shared_ptr<DlImageFilter> Make( | ||
| sk_sp<DlRuntimeEffect> runtime_effect, | ||
| std::vector<std::shared_ptr<DlColorSource>> samplers, | ||
| std::shared_ptr<std::vector<uint8_t>> uniform_data) { | ||
| return std::make_shared<DlRuntimeEffectImageFilter>( | ||
| std::move(runtime_effect), std::move(samplers), | ||
| std::move(uniform_data)); | ||
| } | ||
|
|
||
| DlImageFilterType type() const override { | ||
| return DlImageFilterType::kRuntimeEffect; | ||
| } | ||
| size_t size() const override { return sizeof(*this); } | ||
|
|
||
| bool modifies_transparent_black() const override { return false; } | ||
|
|
||
| SkRect* map_local_bounds(const SkRect& input_bounds, | ||
| SkRect& output_bounds) const override { | ||
| output_bounds = input_bounds; | ||
| return &output_bounds; | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This gets tricky. Can they implement a custom image filter that does something like a blur - i.e. expands the bounds of the pixels?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We talked about this offline and discussed that there doesn't seem to be a good way to express all of the general purpose transformations that can be done with an image filter. |
||
| } | ||
|
|
||
| SkIRect* map_device_bounds(const SkIRect& input_bounds, | ||
| const SkMatrix& ctm, | ||
| SkIRect& output_bounds) const override { | ||
| output_bounds = input_bounds; | ||
| return &output_bounds; | ||
| } | ||
|
|
||
| SkIRect* get_input_device_bounds(const SkIRect& output_bounds, | ||
| const SkMatrix& ctm, | ||
| SkIRect& input_bounds) const override { | ||
| input_bounds = output_bounds; | ||
| return &input_bounds; | ||
| } | ||
|
|
||
| const DlRuntimeEffectImageFilter* asRuntimeEffectFilter() const override { | ||
| return this; | ||
| } | ||
|
|
||
| const sk_sp<DlRuntimeEffect> runtime_effect() const { | ||
| return runtime_effect_; | ||
| } | ||
|
|
||
| const std::vector<std::shared_ptr<DlColorSource>>& samplers() const { | ||
| return samplers_; | ||
| } | ||
|
|
||
| const std::shared_ptr<std::vector<uint8_t>>& uniform_data() const { | ||
| return uniform_data_; | ||
| } | ||
|
|
||
| protected: | ||
| bool equals_(const DlImageFilter& other) const override { | ||
| FML_DCHECK(other.type() == DlImageFilterType::kRuntimeEffect); | ||
| auto that = static_cast<const DlRuntimeEffectImageFilter*>(&other); | ||
| if (runtime_effect_ != that->runtime_effect_ || | ||
| samplers_.size() != that->samplers().size() || | ||
| uniform_data_->size() != that->uniform_data()->size()) { | ||
| return false; | ||
| } | ||
| for (auto i = 0u; i < samplers_.size(); i++) { | ||
| if (samplers_[i] != that->samplers()[i]) { | ||
| return false; | ||
| } | ||
| } | ||
| for (auto i = 0u; i < uniform_data_->size(); i++) { | ||
| if (uniform_data_->at(i) != that->uniform_data()->at(i)) { | ||
| return false; | ||
| } | ||
| } | ||
| return true; | ||
| } | ||
|
|
||
| private: | ||
| sk_sp<DlRuntimeEffect> runtime_effect_; | ||
| std::vector<std::shared_ptr<DlColorSource>> samplers_; | ||
| std::shared_ptr<std::vector<uint8_t>> uniform_data_; | ||
| }; | ||
|
|
||
| } // namespace flutter | ||
|
|
||
| #endif // FLUTTER_DISPLAY_LIST_EFFECTS_DL_IMAGE_FILTER_H_ | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -12,6 +12,8 @@ | |
| #include "flutter/display_list/utils/dl_comparable.h" | ||
| #include "gtest/gtest.h" | ||
|
|
||
| #include "include/core/SkMatrix.h" | ||
| #include "include/core/SkRect.h" | ||
| #include "third_party/skia/include/core/SkBlendMode.h" | ||
| #include "third_party/skia/include/core/SkColorFilter.h" | ||
| #include "third_party/skia/include/core/SkSamplingOptions.h" | ||
|
|
@@ -823,5 +825,87 @@ TEST(DisplayListImageFilter, LocalImageFilterBounds) { | |
| } | ||
| } | ||
|
|
||
| TEST(DisplayListImageFilter, RuntimeEffectEquality) { | ||
| DlRuntimeEffectImageFilter filter_a(nullptr, {nullptr}, | ||
| std::make_shared<std::vector<uint8_t>>()); | ||
| DlRuntimeEffectImageFilter filter_b(nullptr, {nullptr}, | ||
| std::make_shared<std::vector<uint8_t>>()); | ||
|
|
||
| EXPECT_EQ(filter_a, filter_b); | ||
|
|
||
| DlRuntimeEffectImageFilter filter_c( | ||
| nullptr, {nullptr}, std::make_shared<std::vector<uint8_t>>(1)); | ||
|
|
||
| EXPECT_NE(filter_a, filter_c); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Also a version that is different based on samplers? I suppose it would be too hard to test equality if the shader was different - or do we have a RTE test fixture somewhere you could use for testing?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done |
||
| } | ||
|
|
||
| TEST(DisplayListImageFilter, RuntimeEffectEqualityWithSamplers) { | ||
| auto image_a = std::make_shared<DlImageColorSource>( | ||
| nullptr, DlTileMode::kClamp, DlTileMode::kDecal); | ||
| auto image_b = std::make_shared<DlImageColorSource>( | ||
| nullptr, DlTileMode::kClamp, DlTileMode::kClamp); | ||
|
|
||
| DlRuntimeEffectImageFilter filter_a(nullptr, {nullptr, image_a}, | ||
| std::make_shared<std::vector<uint8_t>>()); | ||
| DlRuntimeEffectImageFilter filter_b(nullptr, {nullptr, image_a}, | ||
| std::make_shared<std::vector<uint8_t>>()); | ||
|
|
||
| EXPECT_EQ(filter_a, filter_b); | ||
|
|
||
| DlRuntimeEffectImageFilter filter_c(nullptr, {nullptr, image_b}, | ||
| std::make_shared<std::vector<uint8_t>>()); | ||
|
|
||
| EXPECT_NE(filter_a, filter_c); | ||
| } | ||
|
|
||
| TEST(DisplayListImageFilter, RuntimeEffectMapDeviceBounds) { | ||
| DlRuntimeEffectImageFilter filter_a(nullptr, {nullptr}, | ||
| std::make_shared<std::vector<uint8_t>>()); | ||
|
|
||
| auto input_bounds = SkIRect::MakeLTRB(0, 0, 100, 100); | ||
| SkMatrix identity; | ||
| SkIRect output_bounds; | ||
| SkIRect* result = | ||
| filter_a.map_device_bounds(input_bounds, identity, output_bounds); | ||
|
|
||
| EXPECT_NE(result, nullptr); | ||
| EXPECT_EQ(output_bounds, input_bounds); | ||
| } | ||
|
|
||
| TEST(DisplayListImageFilter, RuntimeEffectMapInputBounds) { | ||
| DlRuntimeEffectImageFilter filter_a(nullptr, {nullptr}, | ||
| std::make_shared<std::vector<uint8_t>>()); | ||
|
|
||
| auto input_bounds = SkRect::MakeLTRB(0, 0, 100, 100); | ||
|
|
||
| SkRect output_bounds; | ||
| SkRect* result = filter_a.map_local_bounds(input_bounds, output_bounds); | ||
|
|
||
| EXPECT_NE(result, nullptr); | ||
| EXPECT_EQ(output_bounds, input_bounds); | ||
| } | ||
|
|
||
| TEST(DisplayListImageFilter, RuntimeEffectGetInputDeviceBounds) { | ||
| DlRuntimeEffectImageFilter filter_a(nullptr, {nullptr}, | ||
| std::make_shared<std::vector<uint8_t>>()); | ||
|
|
||
| auto output_bounds = SkIRect::MakeLTRB(0, 0, 100, 100); | ||
|
|
||
| SkMatrix identity; | ||
| SkIRect input_bounds; | ||
| SkIRect* result = | ||
| filter_a.get_input_device_bounds(output_bounds, identity, input_bounds); | ||
|
|
||
| EXPECT_NE(result, nullptr); | ||
| EXPECT_EQ(output_bounds, input_bounds); | ||
| } | ||
|
|
||
| TEST(DisplayListImageFilter, RuntimeEffectModifiesTransparentBlack) { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not an issue with this PR, but this engaged a more global thought in me... This reminds me that the name is a little off because the shader might modify transparent black and that's OK. What this method really is asking/answering is "does it modify transparent black pixels everywhere on the entire plane regardless of whether they were really "involved" in the original operation" which is a question apropos mostly for a CF, but IF needs to answer as well in case it is wrapping a CF. But the name itself doesn't really capture the question being asked. Perhaps |
||
| DlRuntimeEffectImageFilter filter_a(nullptr, {nullptr}, | ||
| std::make_shared<std::vector<uint8_t>>()); | ||
|
|
||
| EXPECT_FALSE(filter_a.modifies_transparent_black()); | ||
| } | ||
|
|
||
| } // namespace testing | ||
| } // namespace flutter | ||
Uh oh!
There was an error while loading. Please reload this page.