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, renderer.GetTransientsBuffer().EmplaceUniform(clip_frame_info));
178 
179  if (!pass.Draw().ok()) {
180  return false;
181  }
182 
183  /// Cover draw.
184 
185  options.blend_mode = entity.GetBlendMode();
187  std::optional<Rect> maybe_cover_area = geometry->GetCoverage({});
188  if (!maybe_cover_area.has_value()) {
189  return true;
190  }
191  do_cover_draw = true;
192  cover_area = maybe_cover_area.value();
193  }
194 
195  GeometryResult geometry_result;
196  if (do_cover_draw) {
197  FillRectGeometry geom(cover_area);
198  geometry_result = create_geom_callback(renderer, entity, pass, &geom);
199  } else {
200  geometry_result = create_geom_callback(renderer, entity, pass, geometry);
201  }
202 
203  if (geometry_result.vertex_buffer.vertex_count == 0u) {
204  return true;
205  }
206  pass.SetVertexBuffer(std::move(geometry_result.vertex_buffer));
207  options.primitive_type = geometry_result.type;
208 
209  // Enable depth writing for all opaque entities in order to allow
210  // reordering. Opaque entities are coerced to source blending by
211  // `EntityPass::AddEntity`.
212  options.depth_write_enabled = options.blend_mode == BlendMode::kSrc;
213 
214  // Take the pre-populated vertex shader uniform struct and set managed
215  // values.
216  frame_info.mvp = geometry_result.transform;
217 
218  // If overdraw prevention is enabled (like when drawing stroke paths), we
219  // increment the stencil buffer as we draw, preventing overlapping fragments
220  // from drawing. Afterwards, we need to append another draw call to clean up
221  // the stencil buffer (happens below in this method). This can be skipped
222  // for draws that are fully opaque or use src blend mode.
223  if (geometry_result.mode == GeometryResult::Mode::kPreventOverdraw &&
224  options.blend_mode != BlendMode::kSrc) {
225  options.stencil_mode =
227  }
228  pass.SetStencilReference(0);
229 
230  VertexShaderT::BindFrameInfo(
231  pass, renderer.GetTransientsBuffer().EmplaceUniform(frame_info));
232 
233  // The reason we need to have a callback mechanism here is that this routine
234  // may insert draw calls before the main draw call below. For example, for
235  // sufficiently complex paths we may opt to use stencil-then-cover to avoid
236  // tessellation.
237  if (!bind_fragment_callback(pass)) {
238  return false;
239  }
240 
241  pass.SetPipeline(pipeline_callback(options));
242 
243  if (!pass.Draw().ok()) {
244  return false;
245  }
246 
247  // If we performed overdraw prevention, a subsection of the clip heightmap
248  // was incremented by 1 in order to self-clip. So simply append a clip
249  // restore to clean it up.
250  if (geometry_result.mode == GeometryResult::Mode::kPreventOverdraw &&
251  options.blend_mode != BlendMode::kSrc) {
252  return RenderClipRestore(renderer, pass, entity.GetClipDepth(),
253  contents->GetCoverage(entity));
254  }
255  return true;
256  }
257 
258  protected:
260  const ContentContext& renderer,
261  const Entity& entity,
262  RenderPass& pass,
263  const Geometry* geom) {
264  return geom->GetPositionBuffer(renderer, entity, pass);
265  }
266 
267  /// @brief Whether the entity should be treated as non-opaque due to stroke
268  /// geometry requiring alpha for coverage.
270 
271  template <typename VertexShaderT>
272  bool DrawGeometry(const ContentContext& renderer,
273  const Entity& entity,
274  RenderPass& pass,
275  const PipelineBuilderCallback& pipeline_callback,
276  typename VertexShaderT::FrameInfo frame_info,
277  const BindFragmentCallback& bind_fragment_callback,
278  bool force_stencil = false,
279  const CreateGeometryCallback& create_geom_callback =
281  //
282  return DrawGeometry<VertexShaderT>(this, //
283  GetGeometry(), //
284  renderer, //
285  entity, //
286  pass, //
287  pipeline_callback, //
288  frame_info, //
289  bind_fragment_callback, //
290  force_stencil, //
291  create_geom_callback);
292  }
293 
294  private:
295  const Geometry* geometry_ = nullptr;
296  Matrix inverse_matrix_;
297  Scalar opacity_ = 1.0;
298  Scalar inherited_opacity_ = 1.0;
299 
300  ColorSourceContents(const ColorSourceContents&) = delete;
301 
302  ColorSourceContents& operator=(const ColorSourceContents&) = delete;
303 };
304 
305 } // namespace impeller
306 
307 #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 & GetTransientsBuffer() const
Retrieve the currnent host buffer for transient storage.
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