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 
6 
7 #include <cmath>
8 
14 
15 namespace impeller {
16 
18  default;
19 
21  default;
22 
24  radius_ = radius;
25 }
26 
28  direction_ = direction.Normalize();
29  if (direction_.IsZero()) {
30  direction_ = Vector2(0, 1);
31  }
32 }
33 
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 {
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& host_buffer = renderer.GetTransientsBuffer();
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, 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, host_buffer.EmplaceUniform(frame_info));
131  FS::BindFragInfo(pass, 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(),
164  .sampler_descriptor = sampler_desc,
165  .opacity = input_snapshot->opacity},
166  entity.GetBlendMode());
167 }
168 
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_) {
189  origin -= transformed_vector;
190  size += transformed_vector * 2;
191  break;
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>
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_) {
211  return output_limit.Expand(-transformed_vector);
213  return output_limit.Expand(transformed_vector);
214  }
215 }
216 
217 } // namespace impeller
std::function< bool(const ContentContext &, RenderPass &)> SubpassCallback
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...
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...
BlendMode GetBlendMode() const
Definition: entity.cc:101
const Matrix & GetTransform() const
Get the global transform matrix for this Entity.
Definition: entity.cc:44
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
std::vector< FilterInput::Ref > Vector
Definition: filter_input.h:33
FragmentShader_ FragmentShader
Definition: pipeline.h:164
Point Vector2
Definition: point.h:331
float Scalar
Definition: scalar.h:19
@ kDecal
decal sampling mode is only supported on devices that pass the Capabilities.SupportsDecalSamplerAddre...
constexpr float kEhCloseEnough
Definition: constants.h:57
TPoint< Scalar > Point
Definition: point.h:327
LinePipeline::FragmentShader FS
VertexBuffer CreateVertexBuffer(std::array< VertexType, size > input, HostBuffer &host_buffer)
Create an index-less vertex buffer from a fixed size array.
TSize< Scalar > Size
Definition: size.h:159
LinePipeline::VertexShader VS
ContentContextOptions OptionsFromPass(const RenderPass &pass)
Definition: contents.cc:19
ISize64 ISize
Definition: size.h:162
A 4x4 matrix using column-major storage.
Definition: matrix.h:37
static constexpr Matrix MakeOrthographic(TSize< T > size)
Definition: matrix.h:566
static constexpr Matrix MakeTranslation(const Vector3 &t)
Definition: matrix.h:95
constexpr Matrix Basis() const
The Matrix without its w components (without translation).
Definition: matrix.h:239
constexpr Vector4 TransformDirection(const Vector4 &v) const
Definition: matrix.h:540
For convolution filters, the "radius" is the size of the convolution kernel to use on the local space...
Definition: sigma.h:48
Scalar radius
Definition: sigma.h:49
constexpr TPoint Normalize() const
Definition: point.h:208
constexpr bool IsZero() const
Definition: point.h:240
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:622
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:324
constexpr static TRect MakeOriginSize(const TPoint< Type > &origin, const TSize< Type > &size)
Definition: rect.h:144
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:331
constexpr std::array< TPoint< T >, 4 > GetTransformedPoints(const Matrix &transform) const
Definition: rect.h:430
constexpr static TRect MakeSize(const TSize< U > &size)
Definition: rect.h:150