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