| Flutter Impeller |

morphology_filter_contents.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/entity/contents/filters/morphology_filter_contents.h"
6
7 #include <cmath>
8
9 #include "impeller/core/formats.h"
10 #include "impeller/entity/contents/content_context.h"
11 #include "impeller/entity/contents/contents.h"
12 #include "impeller/renderer/render_pass.h"
13 #include "impeller/renderer/vertex_buffer_builder.h"
14
15 namespace impeller {
16
17 DirectionalMorphologyFilterContents::DirectionalMorphologyFilterContents() =
18 default;
19
20 DirectionalMorphologyFilterContents::~DirectionalMorphologyFilterContents() =
21 default;
22
23 void DirectionalMorphologyFilterContents::SetRadius(Radius radius) {
24 radius_ = radius;
25 }
26
27 void DirectionalMorphologyFilterContents::SetDirection(Vector2 direction) {
28 direction_ = direction.Normalize();
29 if (direction_.IsZero()) {
30 direction_ = Vector2(0, 1);
31 }
32 }
33
34 void DirectionalMorphologyFilterContents::SetMorphType(MorphType morph_type) {
35 morph_type_ = morph_type;
36 }
37
38 std::optional<Entity> DirectionalMorphologyFilterContents::RenderFilter(
39 const FilterInput::Vector& inputs,
40 const ContentContext& renderer,
41 const Entity& entity,
42 const Matrix& effect_transform,
43 const Rect& coverage,
44 const std::optional<Rect>& coverage_hint) const {
45 using VS = MorphologyFilterPipeline::VertexShader;
46 using FS = MorphologyFilterPipeline::FragmentShader;
47
48 //----------------------------------------------------------------------------
49 /// Handle inputs.
50 ///
51
52 if (inputs.empty()) {
53 return std::nullopt;
54 }
55
56 auto input_snapshot = inputs[0]->GetSnapshot("Morphology", renderer, entity);
57 if (!input_snapshot.has_value()) {
58 return std::nullopt;
59 }
60
61 if (radius_.radius < kEhCloseEnough) {
62 return Entity::FromSnapshot(input_snapshot.value(), entity.GetBlendMode());
63 }
64
65 auto maybe_input_uvs = input_snapshot->GetCoverageUVs(coverage);
66 if (!maybe_input_uvs.has_value()) {
67 return std::nullopt;
68 }
69 auto input_uvs = maybe_input_uvs.value();
70
71 //----------------------------------------------------------------------------
72 /// Render to texture.
73 ///
74
75 ContentContext::SubpassCallback callback = [&](const ContentContext& renderer,
76 RenderPass& pass) {
77 auto& data_host_buffer = renderer.GetTransientsDataBuffer();
78
79 std::array<VS::PerVertexData, 4> vertices = {
80 VS::PerVertexData{Point(0, 0), input_uvs[0]},
81 VS::PerVertexData{Point(1, 0), input_uvs[1]},
82 VS::PerVertexData{Point(0, 1), input_uvs[2]},
83 VS::PerVertexData{Point(1, 1), input_uvs[3]},
84 };
85
86 VS::FrameInfo frame_info;
87 frame_info.mvp = Matrix::MakeOrthographic(ISize(1, 1));
88 frame_info.texture_sampler_y_coord_scale =
89 input_snapshot->texture->GetYCoordScale();
90
91 auto transform = entity.GetTransform() * effect_transform.Basis();
92 auto transformed_radius =
93 transform.TransformDirection(direction_ * radius_.radius);
94 auto transformed_texture_vertices =
95 Rect::MakeSize(input_snapshot->texture->GetSize())
96 .GetTransformedPoints(input_snapshot->transform);
97 auto transformed_texture_width =
98 transformed_texture_vertices[0].GetDistance(
99 transformed_texture_vertices[1]);
100 auto transformed_texture_height =
101 transformed_texture_vertices[0].GetDistance(
102 transformed_texture_vertices[2]);
103
104 FS::FragInfo frag_info;
105 frag_info.radius = std::round(transformed_radius.GetLength());
106 frag_info.morph_type = static_cast<Scalar>(morph_type_);
107 frag_info.uv_offset =
108 input_snapshot->transform.Invert()
109 .TransformDirection(transformed_radius)
110 .Normalize() /
111 Point(transformed_texture_width, transformed_texture_height);
112
113 pass.SetCommandLabel("Morphology Filter");
114 auto options = OptionsFromPass(pass);
115 options.primitive_type = PrimitiveType::kTriangleStrip;
116 options.blend_mode = BlendMode::kSrc;
117 pass.SetPipeline(renderer.GetMorphologyFilterPipeline(options));
118 pass.SetVertexBuffer(CreateVertexBuffer(vertices, data_host_buffer));
119
120 auto sampler_descriptor = input_snapshot->sampler_descriptor;
121 if (renderer.GetDeviceCapabilities().SupportsDecalSamplerAddressMode()) {
122 sampler_descriptor.width_address_mode = SamplerAddressMode::kDecal;
123 sampler_descriptor.height_address_mode = SamplerAddressMode::kDecal;
124 }
125
126 FS::BindTextureSampler(
127 pass, input_snapshot->texture,
128 renderer.GetContext()->GetSamplerLibrary()->GetSampler(
129 sampler_descriptor));
130 VS::BindFrameInfo(pass, data_host_buffer.EmplaceUniform(frame_info));
131 FS::BindFragInfo(pass, data_host_buffer.EmplaceUniform(frag_info));
132
133 return pass.Draw().ok();
134 };
135 std::shared_ptr<CommandBuffer> command_buffer =
136 renderer.GetContext()->CreateCommandBuffer();
137 if (command_buffer == nullptr) {
138 return std::nullopt;
139 }
140
141 fml::StatusOr<RenderTarget> render_target =
142 renderer.MakeSubpass("Directional Morphology Filter", //
143 ISize(coverage.GetSize()), //
144 command_buffer, //
145 callback, //
146 /*msaa_enabled=*/false, //
147 /*depth_stencil_enabled=*/false //
148 );
149 if (!render_target.ok()) {
150 return std::nullopt;
151 }
152
153 if (!renderer.GetContext()->EnqueueCommandBuffer(std::move(command_buffer))) {
154 return std::nullopt;
155 }
156
157 SamplerDescriptor sampler_desc;
158 sampler_desc.min_filter = MinMagFilter::kLinear;
159 sampler_desc.mag_filter = MinMagFilter::kLinear;
160
161 return Entity::FromSnapshot(
162 Snapshot{.texture = render_target.value().GetRenderTargetTexture(),
163 .transform = Matrix::MakeTranslation(coverage.GetOrigin()),
164 .sampler_descriptor = sampler_desc,
165 .opacity = input_snapshot->opacity},
166 entity.GetBlendMode());
167 }
168
169 std::optional<Rect> DirectionalMorphologyFilterContents::GetFilterCoverage(
170 const FilterInput::Vector& inputs,
171 const Entity& entity,
172 const Matrix& effect_transform) const {
173 if (inputs.empty()) {
174 return std::nullopt;
175 }
176
177 auto coverage = inputs[0]->GetCoverage(entity);
178 if (!coverage.has_value()) {
179 return std::nullopt;
180 }
181 auto transform = inputs[0]->GetTransform(entity) * effect_transform.Basis();
182 auto transformed_vector =
183 transform.TransformDirection(direction_ * radius_.radius).Abs();
184
185 auto origin = coverage->GetOrigin();
186 auto size = Vector2(coverage->GetSize());
187 switch (morph_type_) {
188 case FilterContents::MorphType::kDilate:
189 origin -= transformed_vector;
190 size += transformed_vector * 2;
191 break;
192 case FilterContents::MorphType::kErode:
193 origin += transformed_vector;
194 size -= transformed_vector * 2;
195 break;
196 }
197 if (size.x < 0 || size.y < 0) {
198 return Rect::MakeSize(Size(0, 0));
199 }
200 return Rect::MakeOriginSize(origin, Size(size.x, size.y));
201 }
202
203 std::optional<Rect>
204 DirectionalMorphologyFilterContents::GetFilterSourceCoverage(
205 const Matrix& effect_transform,
206 const Rect& output_limit) const {
207 auto transformed_vector =
208 effect_transform.TransformDirection(direction_ * radius_.radius).Abs();
209 switch (morph_type_) {
210 case FilterContents::MorphType::kDilate:
211 return output_limit.Expand(-transformed_vector);
212 case FilterContents::MorphType::kErode:
213 return output_limit.Expand(transformed_vector);
214 }
215 }
216
217 } // namespace impeller
impeller::ContentContext
Definition: content_context.h:138
impeller::ContentContext::SubpassCallback
std::function< bool(const ContentContext &, RenderPass &)> SubpassCallback
Definition: content_context.h:246
impeller::DirectionalMorphologyFilterContents::DirectionalMorphologyFilterContents
DirectionalMorphologyFilterContents()
impeller::DirectionalMorphologyFilterContents::SetRadius
void SetRadius(Radius radius)
Definition: morphology_filter_contents.cc:23
impeller::DirectionalMorphologyFilterContents::GetFilterCoverage
std::optional< Rect > GetFilterCoverage(const FilterInput::Vector &inputs, const Entity &entity, const Matrix &effect_transform) const override
Internal utility method for |GetLocalCoverage| that computes the output coverage of this filter acros...
Definition: morphology_filter_contents.cc:169
impeller::DirectionalMorphologyFilterContents::SetMorphType
void SetMorphType(MorphType morph_type)
Definition: morphology_filter_contents.cc:34
impeller::DirectionalMorphologyFilterContents::GetFilterSourceCoverage
std::optional< Rect > GetFilterSourceCoverage(const Matrix &effect_transform, const Rect &output_limit) const override
Internal utility method for |GetSourceCoverage| that computes the inverse effect of this transform on...
Definition: morphology_filter_contents.cc:204
impeller::DirectionalMorphologyFilterContents::~DirectionalMorphologyFilterContents
~DirectionalMorphologyFilterContents() override
impeller::DirectionalMorphologyFilterContents::SetDirection
void SetDirection(Vector2 direction)
Definition: morphology_filter_contents.cc:27
impeller::Entity
Definition: entity.h:26
impeller::Entity::GetBlendMode
BlendMode GetBlendMode() const
Definition: entity.cc:101
impeller::Entity::GetTransform
const Matrix & GetTransform() const
Get the global transform matrix for this Entity.
Definition: entity.cc:44
impeller::Entity::FromSnapshot
static Entity FromSnapshot(const Snapshot &snapshot, BlendMode blend_mode=BlendMode::kSrcOver)
Create an entity that can be used to render a given snapshot.
Definition: entity.cc:18
impeller::FilterContents::MorphType
MorphType
Definition: filter_contents.h:39
impeller::FilterContents::MorphType::kErode
@ kErode
impeller::FilterContents::MorphType::kDilate
@ kDilate
impeller::FilterInput::Vector
std::vector< FilterInput::Ref > Vector
Definition: filter_input.h:33
impeller::RenderPipelineHandle::VertexShader
VertexShader_ VertexShader
Definition: pipeline.h:163
impeller::RenderPipelineHandle::FragmentShader
FragmentShader_ FragmentShader
Definition: pipeline.h:164
content_context.h
contents.h
formats.h
transform
Matrix transform
Definition: gaussian_blur_filter_contents.cc:214
morphology_filter_contents.h
impeller
Definition: allocation.cc:12
impeller::PrimitiveType::kTriangleStrip
@ kTriangleStrip
impeller::Vector2
Point Vector2
Definition: point.h:331
impeller::Scalar
float Scalar
Definition: scalar.h:19
impeller::SamplerAddressMode::kDecal
@ kDecal
decal sampling mode is only supported on devices that pass the Capabilities.SupportsDecalSamplerAddre...
impeller::kEhCloseEnough
constexpr float kEhCloseEnough
Definition: constants.h:57
impeller::Point
TPoint< Scalar > Point
Definition: point.h:327
impeller::FS
LinePipeline::FragmentShader FS
Definition: line_contents.cc:14
impeller::CreateVertexBuffer
VertexBuffer CreateVertexBuffer(std::array< VertexType, size > input, HostBuffer &data_host_buffer)
Create an index-less vertex buffer from a fixed size array.
Definition: vertex_buffer_builder.h:24
impeller::BlendMode::kSrc
@ kSrc
impeller::Size
TSize< Scalar > Size
Definition: size.h:159
impeller::VS
LinePipeline::VertexShader VS
Definition: line_contents.cc:13
impeller::OptionsFromPass
ContentContextOptions OptionsFromPass(const RenderPass &pass)
Definition: contents.cc:19
impeller::ISize
ISize64 ISize
Definition: size.h:162
impeller::MinMagFilter::kLinear
@ kLinear
render_pass.h
impeller::Matrix
A 4x4 matrix using column-major storage.
Definition: matrix.h:37
impeller::Matrix::MakeOrthographic
static constexpr Matrix MakeOrthographic(TSize< T > size)
Definition: matrix.h:633
impeller::Matrix::MakeTranslation
static constexpr Matrix MakeTranslation(const Vector3 &t)
Definition: matrix.h:95
impeller::Matrix::Basis
constexpr Matrix Basis() const
The Matrix without its w components (without translation).
Definition: matrix.h:239
impeller::Matrix::TransformDirection
constexpr Vector4 TransformDirection(const Vector4 &v) const
Definition: matrix.h:607
impeller::Radius
For convolution filters, the "radius" is the size of the convolution kernel to use on the local space...
Definition: sigma.h:48
impeller::Radius::radius
Scalar radius
Definition: sigma.h:49
impeller::TPoint< Scalar >
impeller::TPoint::Normalize
constexpr TPoint Normalize() const
Definition: point.h:208
impeller::TPoint::IsZero
constexpr bool IsZero() const
Definition: point.h:240
impeller::TRect< Scalar >
impeller::TRect::Expand
constexpr TRect< T > Expand(T left, T top, T right, T bottom) const
Returns a rectangle with expanded edges. Negative expansion results in shrinking.
Definition: rect.h:618
impeller::TRect::GetOrigin
constexpr TPoint< Type > GetOrigin() const
Returns the upper left corner of the rectangle as specified by the left/top or x/y values when it was...
Definition: rect.h:320
impeller::TRect< Scalar >::MakeOriginSize
constexpr static TRect MakeOriginSize(const TPoint< Type > &origin, const TSize< Type > &size)
Definition: rect.h:144
impeller::TRect::GetSize
constexpr TSize< Type > GetSize() const
Returns the size of the rectangle which may be negative in either width or height and may have been c...
Definition: rect.h:327
impeller::TRect::GetTransformedPoints
constexpr std::array< TPoint< T >, 4 > GetTransformedPoints(const Matrix &transform) const
Definition: rect.h:426
impeller::TRect< Scalar >::MakeSize
constexpr static TRect MakeSize(const TSize< U > &size)
Definition: rect.h:150
vertex_buffer_builder.h