| Flutter Impeller |

clip_contents.cc
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 #include <cmath>
6 #include <optional>
7
8 #include "fml/logging.h"
9 #include "impeller/core/formats.h"
10 #include "impeller/entity/contents/clip_contents.h"
11 #include "impeller/entity/contents/content_context.h"
12 #include "impeller/entity/entity.h"
13 #include "impeller/renderer/render_pass.h"
14 #include "impeller/renderer/vertex_buffer_builder.h"
15
16 namespace impeller {
17
18 static Scalar GetShaderClipDepth(const Entity& entity) {
19 // Draw the clip at the max of the clip entity's depth slice, so that other
20 // draw calls with this same depth value will be culled even if they have a
21 // perspective transform.
22 return std::nextafterf(
23 Entity::GetShaderClipDepth(entity.GetNewClipDepth() + 1), 0.0f);
24 }
25
26 /*******************************************************************************
27 ******* ClipContents
28 ******************************************************************************/
29
30 ClipContents::ClipContents() = default;
31
32 ClipContents::~ClipContents() = default;
33
34 void ClipContents::SetGeometry(const std::shared_ptr<Geometry>& geometry) {
35 geometry_ = geometry;
36 }
37
38 void ClipContents::SetClipOperation(Entity::ClipOperation clip_op) {
39 clip_op_ = clip_op;
40 }
41
42 std::optional<Rect> ClipContents::GetCoverage(const Entity& entity) const {
43 return std::nullopt;
44 };
45
46 Contents::ClipCoverage ClipContents::GetClipCoverage(
47 const Entity& entity,
48 const std::optional<Rect>& current_clip_coverage) const {
49 if (!current_clip_coverage.has_value()) {
50 return {.type = ClipCoverage::Type::kAppend, .coverage = std::nullopt};
51 }
52 switch (clip_op_) {
53 case Entity::ClipOperation::kDifference:
54 // This can be optimized further by considering cases when the bounds of
55 // the current stencil will shrink.
56 return {.type = ClipCoverage::Type::kAppend,
57 .coverage = current_clip_coverage};
58 case Entity::ClipOperation::kIntersect:
59 if (!geometry_) {
60 return {.type = ClipCoverage::Type::kAppend, .coverage = std::nullopt};
61 }
62 auto coverage = geometry_->GetCoverage(entity.GetTransform());
63 if (!coverage.has_value() || !current_clip_coverage.has_value()) {
64 return {.type = ClipCoverage::Type::kAppend, .coverage = std::nullopt};
65 }
66 return {
67 .type = ClipCoverage::Type::kAppend,
68 .coverage = current_clip_coverage->Intersection(coverage.value()),
69 };
70 }
71 FML_UNREACHABLE();
72 }
73
74 bool ClipContents::ShouldRender(const Entity& entity,
75 const std::optional<Rect> clip_coverage) const {
76 return true;
77 }
78
79 bool ClipContents::CanInheritOpacity(const Entity& entity) const {
80 return true;
81 }
82
83 void ClipContents::SetInheritedOpacity(Scalar opacity) {}
84
85 bool ClipContents::RenderDepthClip(const ContentContext& renderer,
86 const Entity& entity,
87 RenderPass& pass,
88 Entity::ClipOperation clip_op,
89 const Geometry& geometry) const {
90 using VS = ClipPipeline::VertexShader;
91
92 VS::FrameInfo info;
93 info.depth = GetShaderClipDepth(entity);
94
95 auto geometry_result = geometry.GetPositionBuffer(renderer, entity, pass);
96 auto options = OptionsFromPass(pass);
97 options.blend_mode = BlendMode::kDestination;
98
99 pass.SetStencilReference(0);
100
101 /// Stencil preparation draw.
102
103 options.depth_write_enabled = false;
104 options.primitive_type = geometry_result.type;
105 pass.SetVertexBuffer(std::move(geometry_result.vertex_buffer));
106 switch (geometry_result.mode) {
107 case GeometryResult::Mode::kNonZero:
108 pass.SetCommandLabel("Clip stencil preparation (NonZero)");
109 options.stencil_mode =
110 ContentContextOptions::StencilMode::kStencilNonZeroFill;
111 break;
112 case GeometryResult::Mode::kEvenOdd:
113 pass.SetCommandLabel("Clip stencil preparation (EvenOdd)");
114 options.stencil_mode =
115 ContentContextOptions::StencilMode::kStencilEvenOddFill;
116 break;
117 case GeometryResult::Mode::kNormal:
118 case GeometryResult::Mode::kPreventOverdraw:
119 pass.SetCommandLabel("Clip stencil preparation (Increment)");
120 options.stencil_mode =
121 ContentContextOptions::StencilMode::kLegacyClipIncrement;
122 break;
123 }
124 pass.SetPipeline(renderer.GetClipPipeline(options));
125
126 info.mvp = geometry_result.transform;
127 VS::BindFrameInfo(pass, renderer.GetTransientsBuffer().EmplaceUniform(info));
128
129 if (!pass.Draw().ok()) {
130 return false;
131 }
132
133 /// Write depth.
134
135 options.depth_write_enabled = true;
136 options.primitive_type = PrimitiveType::kTriangleStrip;
137 Rect cover_area;
138 switch (clip_op) {
139 case Entity::ClipOperation::kIntersect:
140 pass.SetCommandLabel("Intersect Clip");
141 options.stencil_mode =
142 ContentContextOptions::StencilMode::kCoverCompareInverted;
143 cover_area = Rect::MakeSize(pass.GetRenderTargetSize());
144 break;
145 case Entity::ClipOperation::kDifference:
146 pass.SetCommandLabel("Difference Clip");
147 options.stencil_mode = ContentContextOptions::StencilMode::kCoverCompare;
148 std::optional<Rect> maybe_cover_area =
149 geometry.GetCoverage(entity.GetTransform());
150 if (!maybe_cover_area.has_value()) {
151 return true;
152 }
153 cover_area = maybe_cover_area.value();
154 break;
155 }
156 auto points = cover_area.GetPoints();
157 auto vertices =
158 VertexBufferBuilder<VS::PerVertexData>{}
159 .AddVertices({{points[0]}, {points[1]}, {points[2]}, {points[3]}})
160 .CreateVertexBuffer(renderer.GetTransientsBuffer());
161 pass.SetVertexBuffer(std::move(vertices));
162
163 pass.SetPipeline(renderer.GetClipPipeline(options));
164
165 info.mvp = pass.GetOrthographicTransform();
166 VS::BindFrameInfo(pass, renderer.GetTransientsBuffer().EmplaceUniform(info));
167
168 return pass.Draw().ok();
169 }
170
171 bool ClipContents::RenderStencilClip(const ContentContext& renderer,
172 const Entity& entity,
173 RenderPass& pass,
174 Entity::ClipOperation clip_op,
175 const Geometry& geometry) const {
176 using VS = ClipPipeline::VertexShader;
177
178 VS::FrameInfo info;
179 info.depth = GetShaderClipDepth(entity);
180
181 auto options = OptionsFromPass(pass);
182 options.blend_mode = BlendMode::kDestination;
183 pass.SetStencilReference(entity.GetClipDepth());
184
185 if (clip_op == Entity::ClipOperation::kDifference) {
186 {
187 pass.SetCommandLabel("Difference Clip (Increment)");
188
189 options.stencil_mode =
190 ContentContextOptions::StencilMode::kLegacyClipIncrement;
191
192 auto points = Rect::MakeSize(pass.GetRenderTargetSize()).GetPoints();
193 auto vertices =
194 VertexBufferBuilder<VS::PerVertexData>{}
195 .AddVertices({{points[0]}, {points[1]}, {points[2]}, {points[3]}})
196 .CreateVertexBuffer(renderer.GetTransientsBuffer());
197
198 pass.SetVertexBuffer(std::move(vertices));
199
200 info.mvp = pass.GetOrthographicTransform();
201 VS::BindFrameInfo(pass,
202 renderer.GetTransientsBuffer().EmplaceUniform(info));
203
204 options.primitive_type = PrimitiveType::kTriangleStrip;
205 pass.SetPipeline(renderer.GetClipPipeline(options));
206 pass.Draw();
207 }
208
209 {
210 pass.SetCommandLabel("Difference Clip (Punch)");
211 pass.SetStencilReference(entity.GetClipDepth() + 1);
212
213 options.stencil_mode =
214 ContentContextOptions::StencilMode::kLegacyClipDecrement;
215 }
216 } else {
217 pass.SetCommandLabel("Intersect Clip");
218
219 options.stencil_mode =
220 ContentContextOptions::StencilMode::kLegacyClipIncrement;
221 }
222
223 auto geometry_result = geometry.GetPositionBuffer(renderer, entity, pass);
224 options.primitive_type = geometry_result.type;
225 pass.SetPipeline(renderer.GetClipPipeline(options));
226
227 pass.SetVertexBuffer(std::move(geometry_result.vertex_buffer));
228
229 info.mvp = geometry_result.transform;
230 VS::BindFrameInfo(pass, renderer.GetTransientsBuffer().EmplaceUniform(info));
231
232 return pass.Draw().ok();
233 }
234
235 bool ClipContents::Render(const ContentContext& renderer,
236 const Entity& entity,
237 RenderPass& pass) const {
238 if (!geometry_) {
239 return true;
240 }
241 if constexpr (ContentContext::kEnableStencilThenCover) {
242 return RenderDepthClip(renderer, entity, pass, clip_op_, *geometry_);
243 } else {
244 return RenderStencilClip(renderer, entity, pass, clip_op_, *geometry_);
245 }
246 }
247
248 /*******************************************************************************
249 ******* ClipRestoreContents
250 ******************************************************************************/
251
252 ClipRestoreContents::ClipRestoreContents() = default;
253
254 ClipRestoreContents::~ClipRestoreContents() = default;
255
256 void ClipRestoreContents::SetRestoreCoverage(
257 std::optional<Rect> restore_coverage) {
258 restore_coverage_ = restore_coverage;
259 }
260
261 std::optional<Rect> ClipRestoreContents::GetCoverage(
262 const Entity& entity) const {
263 return std::nullopt;
264 };
265
266 Contents::ClipCoverage ClipRestoreContents::GetClipCoverage(
267 const Entity& entity,
268 const std::optional<Rect>& current_clip_coverage) const {
269 return {.type = ClipCoverage::Type::kRestore, .coverage = std::nullopt};
270 }
271
272 bool ClipRestoreContents::ShouldRender(
273 const Entity& entity,
274 const std::optional<Rect> clip_coverage) const {
275 return true;
276 }
277
278 bool ClipRestoreContents::CanInheritOpacity(const Entity& entity) const {
279 return true;
280 }
281
282 void ClipRestoreContents::SetInheritedOpacity(Scalar opacity) {}
283
284 bool ClipRestoreContents::Render(const ContentContext& renderer,
285 const Entity& entity,
286 RenderPass& pass) const {
287 using VS = ClipPipeline::VertexShader;
288
289 pass.SetCommandLabel("Restore Clip");
290 auto options = OptionsFromPass(pass);
291 options.blend_mode = BlendMode::kDestination;
292 options.stencil_mode = ContentContextOptions::StencilMode::kLegacyClipRestore;
293 options.primitive_type = PrimitiveType::kTriangleStrip;
294 pass.SetPipeline(renderer.GetClipPipeline(options));
295 pass.SetStencilReference(entity.GetClipDepth());
296
297 // Create a rect that covers either the given restore area, or the whole
298 // render target texture.
299 auto ltrb =
300 restore_coverage_.value_or(Rect::MakeSize(pass.GetRenderTargetSize()))
301 .GetLTRB();
302 VertexBufferBuilder<VS::PerVertexData> vtx_builder;
303 vtx_builder.AddVertices({
304 {Point(ltrb[0], ltrb[1])},
305 {Point(ltrb[2], ltrb[1])},
306 {Point(ltrb[0], ltrb[3])},
307 {Point(ltrb[2], ltrb[3])},
308 });
309 pass.SetVertexBuffer(
310 vtx_builder.CreateVertexBuffer(renderer.GetTransientsBuffer()));
311
312 VS::FrameInfo info;
313 info.depth = GetShaderClipDepth(entity);
314 info.mvp = pass.GetOrthographicTransform();
315 VS::BindFrameInfo(pass, renderer.GetTransientsBuffer().EmplaceUniform(info));
316
317 return pass.Draw().ok();
318 }
319
320 } // namespace impeller
impeller::GeometryResult::Mode::kNormal
@ kNormal
The geometry has no overlapping triangles.
impeller::Entity::ClipOperation::kIntersect
@ kIntersect
impeller::OptionsFromPass
ContentContextOptions OptionsFromPass(const RenderPass &pass)
Definition: contents.cc:20
impeller::Entity::GetShaderClipDepth
float GetShaderClipDepth() const
Definition: entity.cc:117
impeller::Entity::GetNewClipDepth
uint32_t GetNewClipDepth() const
Definition: entity.cc:113
impeller::ClipRestoreContents::ClipRestoreContents
ClipRestoreContents()
impeller::Entity::ClipOperation::kDifference
@ kDifference
impeller::Scalar
float Scalar
Definition: scalar.h:18
impeller::Entity::GetTransform
const Matrix & GetTransform() const
Get the global transform matrix for this Entity.
Definition: entity.cc:49
impeller::ClipRestoreContents::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: clip_contents.cc:261
entity.h
impeller::ClipRestoreContents::CanInheritOpacity
bool CanInheritOpacity(const Entity &entity) const override
Whether or not this contents can accept the opacity peephole optimization.
Definition: clip_contents.cc:278
impeller::Geometry::GetCoverage
virtual std::optional< Rect > GetCoverage(const Matrix &transform) const =0
impeller::BlendMode::kDestination
@ kDestination
formats.h
impeller::ContentContext::GetClipPipeline
std::shared_ptr< Pipeline< PipelineDescriptor > > GetClipPipeline(ContentContextOptions opts) const
Definition: content_context.h:566
impeller::ClipContents::SetClipOperation
void SetClipOperation(Entity::ClipOperation clip_op)
Definition: clip_contents.cc:38
impeller::RenderPass::SetVertexBuffer
virtual bool SetVertexBuffer(VertexBuffer buffer)
Specify the vertex and index buffer to use for this command.
Definition: render_pass.cc:123
impeller::ClipRestoreContents::SetRestoreCoverage
void SetRestoreCoverage(std::optional< Rect > coverage)
The area on the pass texture where this clip restore will be applied. If unset, the entire pass textu...
Definition: clip_contents.cc:256
impeller::VertexBufferBuilder::AddVertices
VertexBufferBuilder & AddVertices(std::initializer_list< VertexType_ > vertices)
Definition: vertex_buffer_builder.h:70
impeller::ClipRestoreContents::~ClipRestoreContents
~ClipRestoreContents()
impeller::ContentContextOptions::StencilMode::kStencilEvenOddFill
@ kStencilEvenOddFill
impeller::GeometryResult::Mode::kEvenOdd
@ kEvenOdd
impeller::RenderPass::SetCommandLabel
virtual void SetCommandLabel(std::string_view label)
The debugging label to use for the command.
Definition: render_pass.cc:97
impeller::RenderPass::GetOrthographicTransform
const Matrix & GetOrthographicTransform() const
Definition: render_pass.cc:47
impeller::ContentContextOptions::StencilMode::kLegacyClipDecrement
@ kLegacyClipDecrement
Decrement the stencil heightmap (used for difference clipping only).
impeller::ClipContents::ShouldRender
bool ShouldRender(const Entity &entity, const std::optional< Rect > clip_coverage) const override
Definition: clip_contents.cc:74
impeller::TRect::GetPoints
constexpr std::array< TPoint< T >, 4 > GetPoints() const
Get the points that represent the 4 corners of this rectangle in a Z order that is compatible with tr...
Definition: rect.h:382
impeller::ClipContents::GetClipCoverage
ClipCoverage GetClipCoverage(const Entity &entity, const std::optional< Rect > &current_clip_coverage) const override
Given the current pass space bounding rectangle of the clip buffer, return the expected clip coverage...
Definition: clip_contents.cc:46
impeller::RenderPass::Draw
virtual fml::Status Draw()
Record the currently pending command.
Definition: render_pass.cc:127
impeller::ContentContext::kEnableStencilThenCover
static constexpr bool kEnableStencilThenCover
Definition: content_context.h:411
impeller::GetShaderClipDepth
static Scalar GetShaderClipDepth(const Entity &entity)
Definition: clip_contents.cc:18
impeller::VS
SolidFillVertexShader VS
Definition: stroke_path_geometry.cc:15
impeller::Entity
Definition: entity.h:21
impeller::RenderPass::GetRenderTargetSize
ISize GetRenderTargetSize() const
Definition: render_pass.cc:43
impeller::ClipContents::SetGeometry
void SetGeometry(const std::shared_ptr< Geometry > &geometry)
Definition: clip_contents.cc:34
impeller::ClipContents::ClipContents
ClipContents()
impeller::PrimitiveType::kTriangleStrip
@ kTriangleStrip
impeller::Point
TPoint< Scalar > Point
Definition: point.h:316
impeller::ContentContextOptions::StencilMode::kLegacyClipIncrement
@ kLegacyClipIncrement
Increment the stencil heightmap.
render_pass.h
impeller::ClipRestoreContents::Render
bool Render(const ContentContext &renderer, const Entity &entity, RenderPass &pass) const override
Definition: clip_contents.cc:284
impeller::Geometry::GetPositionBuffer
virtual GeometryResult GetPositionBuffer(const ContentContext &renderer, const Entity &entity, RenderPass &pass) const =0
impeller::ClipContents::~ClipContents
~ClipContents()
impeller::ClipContents::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: clip_contents.cc:42
impeller::VertexBufferBuilder
Definition: vertex_buffer_builder.h:24
impeller::ContentContextOptions::StencilMode::kStencilNonZeroFill
@ kStencilNonZeroFill
impeller::Contents::ClipCoverage::type
Type type
Definition: contents.h:43
impeller::ClipRestoreContents::SetInheritedOpacity
void SetInheritedOpacity(Scalar opacity) override
Inherit the provided opacity.
Definition: clip_contents.cc:282
clip_contents.h
impeller::Rect
TRect< Scalar > Rect
Definition: rect.h:661
impeller::RenderPass::SetStencilReference
virtual void SetStencilReference(uint32_t value)
Definition: render_pass.cc:103
impeller::ClipContents::Render
bool Render(const ContentContext &renderer, const Entity &entity, RenderPass &pass) const override
Definition: clip_contents.cc:235
impeller::VertexBufferBuilder::CreateVertexBuffer
VertexBuffer CreateVertexBuffer(HostBuffer &host_buffer) const
Definition: vertex_buffer_builder.h:84
impeller::RenderPass
Render passes encode render commands directed as one specific render target into an underlying comman...
Definition: render_pass.h:33
impeller::Entity::GetClipDepth
uint32_t GetClipDepth() const
Definition: entity.cc:105
content_context.h
impeller::Geometry
Definition: geometry.h:83
impeller::ClipRestoreContents::ShouldRender
bool ShouldRender(const Entity &entity, const std::optional< Rect > clip_coverage) const override
Definition: clip_contents.cc:272
impeller::TRect< Scalar >::MakeSize
constexpr static TRect MakeSize(const TSize< U > &size)
Definition: rect.h:146
impeller::ClipRestoreContents::GetClipCoverage
ClipCoverage GetClipCoverage(const Entity &entity, const std::optional< Rect > &current_clip_coverage) const override
Given the current pass space bounding rectangle of the clip buffer, return the expected clip coverage...
Definition: clip_contents.cc:266
impeller::Contents::ClipCoverage
Definition: contents.h:40
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:50
impeller::ClipContents::CanInheritOpacity
bool CanInheritOpacity(const Entity &entity) const override
Whether or not this contents can accept the opacity peephole optimization.
Definition: clip_contents.cc:79
impeller::Entity::ClipOperation
ClipOperation
Definition: entity.h:61
impeller::ClipContents::SetInheritedOpacity
void SetInheritedOpacity(Scalar opacity) override
Inherit the provided opacity.
Definition: clip_contents.cc:83
impeller::GeometryResult::Mode::kPreventOverdraw
@ kPreventOverdraw
impeller::RenderPass::SetPipeline
virtual void SetPipeline(const std::shared_ptr< Pipeline< PipelineDescriptor >> &pipeline)
The pipeline to use for this command.
Definition: render_pass.cc:92
impeller::ContentContextOptions::StencilMode::kCoverCompareInverted
@ kCoverCompareInverted
impeller::ContentContextOptions::StencilMode::kCoverCompare
@ kCoverCompare
impeller::RenderPipelineT::VertexShader
VertexShader_ VertexShader
Definition: pipeline.h:93
impeller::ContentContextOptions::StencilMode::kLegacyClipRestore
@ kLegacyClipRestore
Slice the clip heightmap to a new maximum height.
impeller
Definition: aiks_blur_unittests.cc:20
impeller::kRestore
@ kRestore
Definition: canvas_recorder.h:23
impeller::ContentContext
Definition: content_context.h:392
impeller::ContentContext::GetTransientsBuffer
HostBuffer & GetTransientsBuffer() const
Retrieve the currnent host buffer for transient storage.
Definition: content_context.h:833
impeller::GeometryResult::Mode::kNonZero
@ kNonZero
vertex_buffer_builder.h