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 Get the geometry that this contents will use to render.
55  ///
56  virtual const Geometry* GetGeometry() const = 0;
57 
58  //----------------------------------------------------------------------------
59  /// @brief Set the effect transform for this color source.
60  ///
61  /// The effect transform is a transform matrix that is applied to
62  /// the shaded color output and does not impact geometry in any way.
63  ///
64  /// For example: With repeat tiling, any gradient or
65  /// `TiledTextureContents` could be used with an effect transform to
66  /// inexpensively draw an infinite scrolling background pattern.
67  ///
68  void SetEffectTransform(Matrix matrix);
69 
70  //----------------------------------------------------------------------------
71  /// @brief Set the inverted effect transform for this color source.
72  ///
73  /// When the effect transform is set via `SetEffectTransform`, the
74  /// value is inverted upon storage. The reason for this is that most
75  /// color sources internally use the inverted transform.
76  ///
77  /// @return The inverse of the transform set by `SetEffectTransform`.
78  ///
79  /// @see `SetEffectTransform`
80  ///
81  const Matrix& GetInverseEffectTransform() const;
82 
83  //----------------------------------------------------------------------------
84  /// @brief Set the opacity factor for this color source.
85  ///
86  void SetOpacityFactor(Scalar opacity);
87 
88  //----------------------------------------------------------------------------
89  /// @brief Get the opacity factor for this color source.
90  ///
91  /// This value is is factored into the output of the color source in
92  /// addition to opacity information that may be supplied any other
93  /// inputs.
94  ///
95  /// @note If set, the output of this method factors factors in the inherited
96  /// opacity of this `Contents`.
97  Scalar GetOpacityFactor() const;
98 
99  virtual bool IsSolidColor() const;
100 
101  // |Contents|
102  std::optional<Rect> GetCoverage(const Entity& entity) const override;
103 
104  // |Contents|
105  void SetInheritedOpacity(Scalar opacity) override;
106 
107  template <typename VertexShaderT>
108  static bool DrawGeometry(const Contents* contents,
109  const Geometry* geometry,
110  const ContentContext& renderer,
111  const Entity& entity,
112  RenderPass& pass,
113  const PipelineBuilderCallback& pipeline_callback,
114  typename VertexShaderT::FrameInfo frame_info,
115  const BindFragmentCallback& bind_fragment_callback,
116  bool force_stencil = false,
117  const CreateGeometryCallback& create_geom_callback =
119  auto options = OptionsFromPassAndEntity(pass, entity);
120 
121  GeometryResult::Mode geometry_mode = geometry->GetResultMode();
122  bool do_cover_draw = false;
123  Rect cover_area = {};
124 
125  bool is_stencil_then_cover =
126  geometry_mode == GeometryResult::Mode::kNonZero ||
127  geometry_mode == GeometryResult::Mode::kEvenOdd;
128  if (!is_stencil_then_cover && force_stencil) {
129  geometry_mode = GeometryResult::Mode::kNonZero;
130  is_stencil_then_cover = true;
131  }
132 
133  if (is_stencil_then_cover) {
134  pass.SetStencilReference(0);
135 
136  /// Stencil preparation draw.
137 
138  GeometryResult stencil_geometry_result =
139  geometry->GetPositionBuffer(renderer, entity, pass);
140  if (stencil_geometry_result.vertex_buffer.vertex_count == 0u) {
141  return true;
142  }
143  pass.SetVertexBuffer(std::move(stencil_geometry_result.vertex_buffer));
144  options.primitive_type = stencil_geometry_result.type;
145 
146  options.blend_mode = BlendMode::kDst;
147  switch (stencil_geometry_result.mode) {
149  pass.SetCommandLabel("Stencil preparation (NonZero)");
150  options.stencil_mode =
152  break;
154  pass.SetCommandLabel("Stencil preparation (EvenOdd)");
155  options.stencil_mode =
157  break;
158  default:
159  if (force_stencil) {
160  pass.SetCommandLabel("Stencil preparation (NonZero)");
161  options.stencil_mode =
163  break;
164  }
165  FML_UNREACHABLE();
166  }
167  pass.SetPipeline(renderer.GetClipPipeline(options));
168  ClipPipeline::VertexShader::FrameInfo clip_frame_info;
169  clip_frame_info.depth = entity.GetShaderClipDepth();
170  clip_frame_info.mvp = stencil_geometry_result.transform;
171  ClipPipeline::VertexShader::BindFrameInfo(
172  pass,
173  renderer.GetTransientsDataBuffer().EmplaceUniform(clip_frame_info));
174 
175  if (!pass.Draw().ok()) {
176  return false;
177  }
178 
179  /// Cover draw.
180 
181  options.blend_mode = entity.GetBlendMode();
183  std::optional<Rect> maybe_cover_area = geometry->GetCoverage({});
184  if (!maybe_cover_area.has_value()) {
185  return true;
186  }
187  do_cover_draw = true;
188  cover_area = maybe_cover_area.value();
189  }
190 
191  GeometryResult geometry_result;
192  if (do_cover_draw) {
193  FillRectGeometry geom(cover_area);
194  geometry_result = create_geom_callback(renderer, entity, pass, &geom);
195  } else {
196  geometry_result = create_geom_callback(renderer, entity, pass, geometry);
197  }
198 
199  if (geometry_result.vertex_buffer.vertex_count == 0u) {
200  return true;
201  }
202  pass.SetVertexBuffer(std::move(geometry_result.vertex_buffer));
203  options.primitive_type = geometry_result.type;
204 
205  // Enable depth writing for all opaque entities in order to allow
206  // reordering. Opaque entities are coerced to source blending by
207  // `EntityPass::AddEntity`.
208  options.depth_write_enabled = options.blend_mode == BlendMode::kSrc;
209 
210  // Take the pre-populated vertex shader uniform struct and set managed
211  // values.
212  frame_info.mvp = geometry_result.transform;
213 
214  // If overdraw prevention is requested (like when drawing stroke paths), set
215  // up the depth buffer and depth comparison function to prevent the same
216  // pixel from being painted multiple times.
217  if (geometry_result.mode == GeometryResult::Mode::kPreventOverdraw) {
218  options.depth_write_enabled = true;
219  options.depth_compare = CompareFunction::kGreater;
220  }
221  pass.SetStencilReference(0);
222 
223  VertexShaderT::BindFrameInfo(
224  pass, renderer.GetTransientsDataBuffer().EmplaceUniform(frame_info));
225 
226  // The reason we need to have a callback mechanism here is that this routine
227  // may insert draw calls before the main draw call below. For example, for
228  // sufficiently complex paths we may opt to use stencil-then-cover to avoid
229  // tessellation.
230  if (!bind_fragment_callback(pass)) {
231  return false;
232  }
233 
234  pass.SetPipeline(pipeline_callback(options));
235 
236  return pass.Draw().ok();
237  }
238 
239  protected:
241  const ContentContext& renderer,
242  const Entity& entity,
243  RenderPass& pass,
244  const Geometry* geom) {
245  return geom->GetPositionBuffer(renderer, entity, pass);
246  }
247 
248  /// @brief Whether the entity should be treated as non-opaque due to stroke
249  /// geometry requiring alpha for coverage.
251 
252  template <typename VertexShaderT>
253  bool DrawGeometry(const ContentContext& renderer,
254  const Entity& entity,
255  RenderPass& pass,
256  const PipelineBuilderCallback& pipeline_callback,
257  typename VertexShaderT::FrameInfo frame_info,
258  const BindFragmentCallback& bind_fragment_callback,
259  bool force_stencil = false,
260  const CreateGeometryCallback& create_geom_callback =
262  //
263  return DrawGeometry<VertexShaderT>(this, //
264  GetGeometry(), //
265  renderer, //
266  entity, //
267  pass, //
268  pipeline_callback, //
269  frame_info, //
270  bind_fragment_callback, //
271  force_stencil, //
272  create_geom_callback);
273  }
274 
275  private:
276  Matrix inverse_matrix_;
277  Scalar opacity_ = 1.0;
278  Scalar inherited_opacity_ = 1.0;
279 
280  ColorSourceContents(const ColorSourceContents&) = delete;
281 
282  ColorSourceContents& operator=(const ColorSourceContents&) = delete;
283 };
284 
285 } // namespace impeller
286 
287 #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
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)
virtual const Geometry * GetGeometry() const =0
Get the geometry that this contents will use to render.
std::function< PipelineRef(ContentContextOptions)> PipelineBuilderCallback
std::function< bool(RenderPass &pass)> BindFragmentCallback
void SetOpacityFactor(Scalar opacity)
Set the opacity factor for this color source.
HostBuffer & GetTransientsDataBuffer() const
Retrieve the current host buffer for transient storage of other non-index data.
PipelineRef GetClipPipeline(ContentContextOptions opts) const
BlendMode GetBlendMode() const
Definition: entity.cc:102
float GetShaderClipDepth() const
Definition: entity.cc:90
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:89
@ kGreater
Comparison test passes if new_value > current_value.
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