| 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"
9 #include "impeller/entity/contents/clip_contents.h"
10 #include "impeller/entity/contents/content_context.h"
11 #include "impeller/entity/contents/contents.h"
12 #include "impeller/entity/contents/pipelines.h"
13 #include "impeller/entity/geometry/geometry.h"
14 #include "impeller/entity/geometry/rect_geometry.h"
15 #include "impeller/geometry/matrix.h"
16 #include "impeller/renderer/render_pass.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)>;
41 using PipelineBuilderCallback =
42 std::function<PipelineRef(ContentContextOptions)>;
43 using CreateGeometryCallback =
44 std::function<GeometryResult(const ContentContext& renderer,
45 const Entity& entity,
46 RenderPass& pass,
47 const Geometry* geom)>;
48
49 ColorSourceContents();
50
51 ~ColorSourceContents() override;
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 =
123 DefaultCreateGeometryCallback) {
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) {
153 case GeometryResult::Mode::kNonZero:
154 pass.SetCommandLabel("Stencil preparation (NonZero)");
155 options.stencil_mode =
156 ContentContextOptions::StencilMode::kStencilNonZeroFill;
157 break;
158 case GeometryResult::Mode::kEvenOdd:
159 pass.SetCommandLabel("Stencil preparation (EvenOdd)");
160 options.stencil_mode =
161 ContentContextOptions::StencilMode::kStencilEvenOddFill;
162 break;
163 default:
164 if (force_stencil) {
165 pass.SetCommandLabel("Stencil preparation (NonZero)");
166 options.stencil_mode =
167 ContentContextOptions::StencilMode::kStencilNonZeroFill;
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();
186 options.stencil_mode = ContentContextOptions::StencilMode::kCoverCompare;
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 RectGeometry 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 =
226 ContentContextOptions::StencilMode::kOverdrawPreventionIncrement;
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:
259 static GeometryResult DefaultCreateGeometryCallback(
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.
269 bool AppliesAlphaForStrokeCoverage(const Matrix& transform) const;
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 =
280 DefaultCreateGeometryCallback) const {
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_
impeller::ColorSourceContents
Definition: color_source_contents.h:38
impeller::ColorSourceContents::SetInheritedOpacity
void SetInheritedOpacity(Scalar opacity) override
Inherit the provided opacity.
Definition: color_source_contents.cc:49
impeller::ColorSourceContents::DrawGeometry
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
Definition: color_source_contents.h:272
impeller::ColorSourceContents::GetGeometry
const Geometry * GetGeometry() const
Get the geometry that this contents will use to render.
Definition: color_source_contents.cc:20
impeller::ColorSourceContents::GetOpacityFactor
Scalar GetOpacityFactor() const
Get the opacity factor for this color source.
Definition: color_source_contents.cc:28
impeller::ColorSourceContents::GetCoverage
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.
Definition: color_source_contents.cc:44
impeller::ColorSourceContents::CreateGeometryCallback
std::function< GeometryResult(const ContentContext &renderer, const Entity &entity, RenderPass &pass, const Geometry *geom)> CreateGeometryCallback
Definition: color_source_contents.h:47
impeller::ColorSourceContents::DefaultCreateGeometryCallback
static GeometryResult DefaultCreateGeometryCallback(const ContentContext &renderer, const Entity &entity, RenderPass &pass, const Geometry *geom)
Definition: color_source_contents.h:259
impeller::ColorSourceContents::AppliesAlphaForStrokeCoverage
bool AppliesAlphaForStrokeCoverage(const Matrix &transform) const
Whether the entity should be treated as non-opaque due to stroke geometry requiring alpha for coverag...
Definition: color_source_contents.cc:53
impeller::ColorSourceContents::ColorSourceContents
ColorSourceContents()
impeller::ColorSourceContents::~ColorSourceContents
~ColorSourceContents() override
impeller::ColorSourceContents::SetEffectTransform
void SetEffectTransform(Matrix matrix)
Set the effect transform for this color source.
Definition: color_source_contents.cc:32
impeller::ColorSourceContents::GetInverseEffectTransform
const Matrix & GetInverseEffectTransform() const
Set the inverted effect transform for this color source.
Definition: color_source_contents.cc:36
impeller::ColorSourceContents::IsSolidColor
virtual bool IsSolidColor() const
Definition: color_source_contents.cc:40
impeller::ColorSourceContents::DrawGeometry
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)
Definition: color_source_contents.h:113
impeller::ColorSourceContents::PipelineBuilderCallback
std::function< PipelineRef(ContentContextOptions)> PipelineBuilderCallback
Definition: color_source_contents.h:42
impeller::ColorSourceContents::BindFragmentCallback
std::function< bool(RenderPass &pass)> BindFragmentCallback
Definition: color_source_contents.h:40
impeller::ColorSourceContents::SetOpacityFactor
void SetOpacityFactor(Scalar opacity)
Set the opacity factor for this color source.
Definition: color_source_contents.cc:24
impeller::ColorSourceContents::SetGeometry
void SetGeometry(const Geometry *geometry)
Set the geometry that this contents will use to render.
Definition: color_source_contents.cc:16
impeller::ContentContext
Definition: content_context.h:138
impeller::ContentContext::GetTransientsBuffer
HostBuffer & GetTransientsBuffer() const
Retrieve the currnent host buffer for transient storage.
Definition: content_context.h:296
impeller::ContentContext::GetClipPipeline
PipelineRef GetClipPipeline(ContentContextOptions opts) const
Definition: content_context.cc:1115
impeller::Contents
Definition: contents.h:31
impeller::Contents::GetCoverage
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.
impeller::Entity
Definition: entity.h:20
impeller::Entity::GetBlendMode
BlendMode GetBlendMode() const
Definition: entity.cc:101
impeller::Entity::GetClipDepth
uint32_t GetClipDepth() const
Definition: entity.cc:84
impeller::Entity::GetShaderClipDepth
float GetShaderClipDepth() const
Definition: entity.cc:88
impeller::Geometry
Definition: geometry.h:50
impeller::Geometry::GetResultMode
virtual GeometryResult::Mode GetResultMode() const
Definition: geometry.cc:57
impeller::Geometry::GetPositionBuffer
virtual GeometryResult GetPositionBuffer(const ContentContext &renderer, const Entity &entity, RenderPass &pass) const =0
impeller::Geometry::GetCoverage
virtual std::optional< Rect > GetCoverage(const Matrix &transform) const =0
impeller::HostBuffer::EmplaceUniform
BufferView EmplaceUniform(const UniformType &uniform)
Emplace uniform data onto the host buffer. Ensure that backend specific uniform alignment requirement...
Definition: host_buffer.h:48
impeller::RectGeometry
Definition: rect_geometry.h:12
impeller::RenderPass
Render passes encode render commands directed as one specific render target into an underlying comman...
Definition: render_pass.h:30
impeller::RenderPass::SetVertexBuffer
virtual bool SetVertexBuffer(VertexBuffer buffer)
Specify the vertex and index buffer to use for this command.
Definition: render_pass.cc:127
impeller::RenderPass::SetStencilReference
virtual void SetStencilReference(uint32_t value)
Definition: render_pass.cc:103
impeller::RenderPass::SetPipeline
virtual void SetPipeline(PipelineRef pipeline)
The pipeline to use for this command.
Definition: render_pass.cc:86
impeller::RenderPass::Draw
virtual fml::Status Draw()
Record the currently pending command.
Definition: render_pass.cc:208
impeller::RenderPass::SetCommandLabel
virtual void SetCommandLabel(std::string_view label)
The debugging label to use for the command.
Definition: render_pass.cc:97
clip_contents.h
content_context.h
contents.h
transform
Matrix transform
Definition: gaussian_blur_filter_contents.cc:214
geometry.h
matrix.h
impeller
Definition: allocation.cc:12
impeller::Scalar
float Scalar
Definition: scalar.h:18
impeller::PipelineRef
raw_ptr< Pipeline< PipelineDescriptor > > PipelineRef
A raw ptr to a pipeline object.
Definition: pipeline.h:88
impeller::RenderClipRestore
bool RenderClipRestore(const ContentContext &renderer, RenderPass &pass, uint32_t clip_depth, std::optional< Rect > restore_coverage)
Render a restore clip.
Definition: clip_contents.cc:153
impeller::BlendMode::kDst
@ kDst
impeller::BlendMode::kSrc
@ kSrc
impeller::OptionsFromPassAndEntity
ContentContextOptions OptionsFromPassAndEntity(const RenderPass &pass, const Entity &entity)
Definition: contents.cc:34
pipelines.h
rect_geometry.h
render_pass.h
impeller::ContentContextOptions
Definition: content_context.h:40
impeller::ContentContextOptions::StencilMode::kStencilEvenOddFill
@ kStencilEvenOddFill
impeller::ContentContextOptions::StencilMode::kOverdrawPreventionIncrement
@ kOverdrawPreventionIncrement
impeller::ContentContextOptions::StencilMode::kStencilNonZeroFill
@ kStencilNonZeroFill
impeller::ContentContextOptions::StencilMode::kCoverCompare
@ kCoverCompare
impeller::GeometryResult
Definition: geometry.h:21
impeller::GeometryResult::type
PrimitiveType type
Definition: geometry.h:37
impeller::GeometryResult::Mode
Mode
Definition: geometry.h:22
impeller::GeometryResult::Mode::kEvenOdd
@ kEvenOdd
impeller::GeometryResult::Mode::kPreventOverdraw
@ kPreventOverdraw
impeller::GeometryResult::Mode::kNonZero
@ kNonZero
impeller::GeometryResult::transform
Matrix transform
Definition: geometry.h:39
impeller::GeometryResult::vertex_buffer
VertexBuffer vertex_buffer
Definition: geometry.h:38
impeller::GeometryResult::mode
Mode mode
Definition: geometry.h:40
impeller::Matrix
A 4x4 matrix using column-major storage.
Definition: matrix.h:37
impeller::TRect< Scalar >
impeller::VertexBuffer::vertex_count
size_t vertex_count
Definition: vertex_buffer.h:25