Flutter Impeller
color_source_contents.h
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 #ifndef FLUTTER_IMPELLER_ENTITY_CONTENTS_COLOR_SOURCE_CONTENTS_H_
6 #define FLUTTER_IMPELLER_ENTITY_CONTENTS_COLOR_SOURCE_CONTENTS_H_
7 
8 #include "fml/logging.h"
17 
18 namespace impeller {
19 
20 //------------------------------------------------------------------------------
21 /// Color sources are geometry-ignostic `Contents` capable of shading any area
22 /// defined by an `impeller::Geometry`. Conceptually,
23 /// `impeller::ColorSourceContents` implement a particular color shading
24 /// behavior.
25 ///
26 /// This separation of concerns between geometry and color source output allows
27 /// Impeller to handle most possible draw combinations in a consistent way.
28 /// For example: There are color sources for handling solid colors, gradients,
29 /// textures, custom runtime effects, and even 3D scenes.
30 ///
31 /// There are some special rendering exceptions that deviate from this pattern
32 /// and cross geometry and color source concerns, such as text atlas and image
33 /// atlas rendering. Special `Contents` exist for rendering these behaviors
34 /// which don't implement `ColorSourceContents`.
35 ///
36 /// @see `impeller::Geometry`
37 ///
38 class ColorSourceContents : public Contents {
39  public:
40  using BindFragmentCallback = std::function<bool(RenderPass& pass)>;
42  std::function<PipelineRef(ContentContextOptions)>;
44  std::function<GeometryResult(const ContentContext& renderer,
45  const Entity& entity,
46  RenderPass& pass,
47  const Geometry* geom)>;
48 
50 
52 
53  //----------------------------------------------------------------------------
54  /// @brief Set the geometry that this contents will use to render.
55  ///
56  void SetGeometry(const Geometry* geometry);
57 
58  //----------------------------------------------------------------------------
59  /// @brief Get the geometry that this contents will use to render.
60  ///
61  const Geometry* GetGeometry() const;
62 
63  //----------------------------------------------------------------------------
64  /// @brief Set the effect transform for this color source.
65  ///
66  /// The effect transform is a transform matrix that is applied to
67  /// the shaded color output and does not impact geometry in any way.
68  ///
69  /// For example: With repeat tiling, any gradient or
70  /// `TiledTextureContents` could be used with an effect transform to
71  /// inexpensively draw an infinite scrolling background pattern.
72  ///
73  void SetEffectTransform(Matrix matrix);
74 
75  //----------------------------------------------------------------------------
76  /// @brief Set the inverted effect transform for this color source.
77  ///
78  /// When the effect transform is set via `SetEffectTransform`, the
79  /// value is inverted upon storage. The reason for this is that most
80  /// color sources internally use the inverted transform.
81  ///
82  /// @return The inverse of the transform set by `SetEffectTransform`.
83  ///
84  /// @see `SetEffectTransform`
85  ///
86  const Matrix& GetInverseEffectTransform() const;
87 
88  //----------------------------------------------------------------------------
89  /// @brief Set the opacity factor for this color source.
90  ///
91  void SetOpacityFactor(Scalar opacity);
92 
93  //----------------------------------------------------------------------------
94  /// @brief Get the opacity factor for this color source.
95  ///
96  /// This value is is factored into the output of the color source in
97  /// addition to opacity information that may be supplied any other
98  /// inputs.
99  ///
100  /// @note If set, the output of this method factors factors in the inherited
101  /// opacity of this `Contents`.
102  Scalar GetOpacityFactor() const;
103 
104  virtual bool IsSolidColor() const;
105 
106  // |Contents|
107  std::optional<Rect> GetCoverage(const Entity& entity) const override;
108 
109  // |Contents|
110  void SetInheritedOpacity(Scalar opacity) override;
111 
112  template <typename VertexShaderT>
113  static bool DrawGeometry(const Contents* contents,
114  const Geometry* geometry,
115  const ContentContext& renderer,
116  const Entity& entity,
117  RenderPass& pass,
118  const PipelineBuilderCallback& pipeline_callback,
119  typename VertexShaderT::FrameInfo frame_info,
120  const BindFragmentCallback& bind_fragment_callback,
121  bool force_stencil = false,
122  const CreateGeometryCallback& create_geom_callback =
124  auto options = OptionsFromPassAndEntity(pass, entity);
125 
126  GeometryResult::Mode geometry_mode = geometry->GetResultMode();
127  bool do_cover_draw = false;
128  Rect cover_area = {};
129 
130  bool is_stencil_then_cover =
131  geometry_mode == GeometryResult::Mode::kNonZero ||
132  geometry_mode == GeometryResult::Mode::kEvenOdd;
133  if (!is_stencil_then_cover && force_stencil) {
134  geometry_mode = GeometryResult::Mode::kNonZero;
135  is_stencil_then_cover = true;
136  }
137 
138  if (is_stencil_then_cover) {
139  pass.SetStencilReference(0);
140 
141  /// Stencil preparation draw.
142 
143  GeometryResult stencil_geometry_result =
144  geometry->GetPositionBuffer(renderer, entity, pass);
145  if (stencil_geometry_result.vertex_buffer.vertex_count == 0u) {
146  return true;
147  }
148  pass.SetVertexBuffer(std::move(stencil_geometry_result.vertex_buffer));
149  options.primitive_type = stencil_geometry_result.type;
150 
151  options.blend_mode = BlendMode::kDst;
152  switch (stencil_geometry_result.mode) {
154  pass.SetCommandLabel("Stencil preparation (NonZero)");
155  options.stencil_mode =
157  break;
159  pass.SetCommandLabel("Stencil preparation (EvenOdd)");
160  options.stencil_mode =
162  break;
163  default:
164  if (force_stencil) {
165  pass.SetCommandLabel("Stencil preparation (NonZero)");
166  options.stencil_mode =
168  break;
169  }
170  FML_UNREACHABLE();
171  }
172  pass.SetPipeline(renderer.GetClipPipeline(options));
173  ClipPipeline::VertexShader::FrameInfo clip_frame_info;
174  clip_frame_info.depth = entity.GetShaderClipDepth();
175  clip_frame_info.mvp = stencil_geometry_result.transform;
176  ClipPipeline::VertexShader::BindFrameInfo(
177  pass,
178  renderer.GetTransientsDataBuffer().EmplaceUniform(clip_frame_info));
179 
180  if (!pass.Draw().ok()) {
181  return false;
182  }
183 
184  /// Cover draw.
185 
186  options.blend_mode = entity.GetBlendMode();
188  std::optional<Rect> maybe_cover_area = geometry->GetCoverage({});
189  if (!maybe_cover_area.has_value()) {
190  return true;
191  }
192  do_cover_draw = true;
193  cover_area = maybe_cover_area.value();
194  }
195 
196  GeometryResult geometry_result;
197  if (do_cover_draw) {
198  FillRectGeometry geom(cover_area);
199  geometry_result = create_geom_callback(renderer, entity, pass, &geom);
200  } else {
201  geometry_result = create_geom_callback(renderer, entity, pass, geometry);
202  }
203 
204  if (geometry_result.vertex_buffer.vertex_count == 0u) {
205  return true;
206  }
207  pass.SetVertexBuffer(std::move(geometry_result.vertex_buffer));
208  options.primitive_type = geometry_result.type;
209 
210  // Enable depth writing for all opaque entities in order to allow
211  // reordering. Opaque entities are coerced to source blending by
212  // `EntityPass::AddEntity`.
213  options.depth_write_enabled = options.blend_mode == BlendMode::kSrc;
214 
215  // Take the pre-populated vertex shader uniform struct and set managed
216  // values.
217  frame_info.mvp = geometry_result.transform;
218 
219  // If overdraw prevention is enabled (like when drawing stroke paths), we
220  // increment the stencil buffer as we draw, preventing overlapping fragments
221  // from drawing. Afterwards, we need to append another draw call to clean up
222  // the stencil buffer (happens below in this method). This can be skipped
223  // for draws that are fully opaque or use src blend mode.
224  if (geometry_result.mode == GeometryResult::Mode::kPreventOverdraw &&
225  options.blend_mode != BlendMode::kSrc) {
226  options.stencil_mode =
228  }
229  pass.SetStencilReference(0);
230 
231  VertexShaderT::BindFrameInfo(
232  pass, renderer.GetTransientsDataBuffer().EmplaceUniform(frame_info));
233 
234  // The reason we need to have a callback mechanism here is that this routine
235  // may insert draw calls before the main draw call below. For example, for
236  // sufficiently complex paths we may opt to use stencil-then-cover to avoid
237  // tessellation.
238  if (!bind_fragment_callback(pass)) {
239  return false;
240  }
241 
242  pass.SetPipeline(pipeline_callback(options));
243 
244  if (!pass.Draw().ok()) {
245  return false;
246  }
247 
248  // If we performed overdraw prevention, a subsection of the clip heightmap
249  // was incremented by 1 in order to self-clip. So simply append a clip
250  // restore to clean it up.
251  if (geometry_result.mode == GeometryResult::Mode::kPreventOverdraw &&
252  options.blend_mode != BlendMode::kSrc) {
253  return RenderClipRestore(renderer, pass, entity.GetClipDepth(),
254  contents->GetCoverage(entity));
255  }
256  return true;
257  }
258 
259  protected:
261  const ContentContext& renderer,
262  const Entity& entity,
263  RenderPass& pass,
264  const Geometry* geom) {
265  return geom->GetPositionBuffer(renderer, entity, pass);
266  }
267 
268  /// @brief Whether the entity should be treated as non-opaque due to stroke
269  /// geometry requiring alpha for coverage.
271 
272  template <typename VertexShaderT>
273  bool DrawGeometry(const ContentContext& renderer,
274  const Entity& entity,
275  RenderPass& pass,
276  const PipelineBuilderCallback& pipeline_callback,
277  typename VertexShaderT::FrameInfo frame_info,
278  const BindFragmentCallback& bind_fragment_callback,
279  bool force_stencil = false,
280  const CreateGeometryCallback& create_geom_callback =
282  //
283  return DrawGeometry<VertexShaderT>(this, //
284  GetGeometry(), //
285  renderer, //
286  entity, //
287  pass, //
288  pipeline_callback, //
289  frame_info, //
290  bind_fragment_callback, //
291  force_stencil, //
292  create_geom_callback);
293  }
294 
295  private:
296  const Geometry* geometry_ = nullptr;
297  Matrix inverse_matrix_;
298  Scalar opacity_ = 1.0;
299  Scalar inherited_opacity_ = 1.0;
300 
301  ColorSourceContents(const ColorSourceContents&) = delete;
302 
303  ColorSourceContents& operator=(const ColorSourceContents&) = delete;
304 };
305 
306 } // namespace impeller
307 
308 #endif // FLUTTER_IMPELLER_ENTITY_CONTENTS_COLOR_SOURCE_CONTENTS_H_
void SetInheritedOpacity(Scalar opacity) override
Inherit the provided opacity.
bool DrawGeometry(const ContentContext &renderer, const Entity &entity, RenderPass &pass, const PipelineBuilderCallback &pipeline_callback, typename VertexShaderT::FrameInfo frame_info, const BindFragmentCallback &bind_fragment_callback, bool force_stencil=false, const CreateGeometryCallback &create_geom_callback=DefaultCreateGeometryCallback) const
const Geometry * GetGeometry() const
Get the geometry that this contents will use to render.
Scalar GetOpacityFactor() const
Get the opacity factor for this color source.
std::optional< Rect > GetCoverage(const Entity &entity) const override
Get the area of the render pass that will be affected when this contents is rendered.
std::function< GeometryResult(const ContentContext &renderer, const Entity &entity, RenderPass &pass, const Geometry *geom)> CreateGeometryCallback
static GeometryResult DefaultCreateGeometryCallback(const ContentContext &renderer, const Entity &entity, RenderPass &pass, const Geometry *geom)
bool AppliesAlphaForStrokeCoverage(const Matrix &transform) const
Whether the entity should be treated as non-opaque due to stroke geometry requiring alpha for coverag...
void SetEffectTransform(Matrix matrix)
Set the effect transform for this color source.
const Matrix & GetInverseEffectTransform() const
Set the inverted effect transform for this color source.
static bool DrawGeometry(const Contents *contents, const Geometry *geometry, const ContentContext &renderer, const Entity &entity, RenderPass &pass, const PipelineBuilderCallback &pipeline_callback, typename VertexShaderT::FrameInfo frame_info, const BindFragmentCallback &bind_fragment_callback, bool force_stencil=false, const CreateGeometryCallback &create_geom_callback=DefaultCreateGeometryCallback)
std::function< PipelineRef(ContentContextOptions)> PipelineBuilderCallback
std::function< bool(RenderPass &pass)> BindFragmentCallback
void SetOpacityFactor(Scalar opacity)
Set the opacity factor for this color source.
void SetGeometry(const Geometry *geometry)
Set the geometry that this contents will use to render.
HostBuffer & GetTransientsDataBuffer() const
Retrieve the current host buffer for transient storage of other non-index data.
PipelineRef GetClipPipeline(ContentContextOptions opts) const
virtual std::optional< Rect > GetCoverage(const Entity &entity) const =0
Get the area of the render pass that will be affected when this contents is rendered.
BlendMode GetBlendMode() const
Definition: entity.cc:101
uint32_t GetClipDepth() const
Definition: entity.cc:84
float GetShaderClipDepth() const
Definition: entity.cc:88
virtual GeometryResult::Mode GetResultMode() const
Definition: geometry.cc:58
virtual GeometryResult GetPositionBuffer(const ContentContext &renderer, const Entity &entity, RenderPass &pass) const =0
virtual std::optional< Rect > GetCoverage(const Matrix &transform) const =0
BufferView EmplaceUniform(const UniformType &uniform)
Emplace uniform data onto the host buffer. Ensure that backend specific uniform alignment requirement...
Definition: host_buffer.h:47
Render passes encode render commands directed as one specific render target into an underlying comman...
Definition: render_pass.h:30
virtual bool SetVertexBuffer(VertexBuffer buffer)
Specify the vertex and index buffer to use for this command.
Definition: render_pass.cc:127
virtual void SetStencilReference(uint32_t value)
Definition: render_pass.cc:103
virtual void SetPipeline(PipelineRef pipeline)
The pipeline to use for this command.
Definition: render_pass.cc:86
virtual fml::Status Draw()
Record the currently pending command.
Definition: render_pass.cc:208
virtual void SetCommandLabel(std::string_view label)
The debugging label to use for the command.
Definition: render_pass.cc:97
float Scalar
Definition: scalar.h:19
raw_ptr< Pipeline< PipelineDescriptor > > PipelineRef
A raw ptr to a pipeline object.
Definition: pipeline.h:88
bool RenderClipRestore(const ContentContext &renderer, RenderPass &pass, uint32_t clip_depth, std::optional< Rect > restore_coverage)
Render a restore clip.
ContentContextOptions OptionsFromPassAndEntity(const RenderPass &pass, const Entity &entity)
Definition: contents.cc:34
PrimitiveType type
Definition: geometry.h:37
VertexBuffer vertex_buffer
Definition: geometry.h:38
A 4x4 matrix using column-major storage.
Definition: matrix.h:37