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"
12 #include "impeller/entity/entity.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(Entity::GetShaderClipDepth(entity.GetClipDepth() + 1),
23  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 
39  clip_op_ = clip_op;
40 }
41 
42 std::optional<Rect> ClipContents::GetCoverage(const Entity& entity) const {
43  return std::nullopt;
44 };
45 
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_) {
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};
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 
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 
84 
85 bool ClipContents::Render(const ContentContext& renderer,
86  const Entity& entity,
87  RenderPass& pass) const {
88  if (!geometry_) {
89  return true;
90  }
91 
93 
94  if (clip_op_ == Entity::ClipOperation::kIntersect &&
95  geometry_->IsAxisAlignedRect() &&
97  std::optional<Rect> coverage =
98  geometry_->GetCoverage(entity.GetTransform());
99  if (coverage.has_value() &&
100  coverage->Contains(Rect::MakeSize(pass.GetRenderTargetSize()))) {
101  // Skip axis-aligned intersect clips that cover the whole render target
102  // since they won't draw anything to the depth buffer.
103  return true;
104  }
105  }
106 
107  VS::FrameInfo info;
108  info.depth = GetShaderClipDepth(entity);
109 
110  auto geometry_result = geometry_->GetPositionBuffer(renderer, entity, pass);
111  auto options = OptionsFromPass(pass);
112  options.blend_mode = BlendMode::kDestination;
113 
114  pass.SetStencilReference(0);
115 
116  /// Stencil preparation draw.
117 
118  options.depth_write_enabled = false;
119  options.primitive_type = geometry_result.type;
120  pass.SetVertexBuffer(std::move(geometry_result.vertex_buffer));
121  switch (geometry_result.mode) {
123  pass.SetCommandLabel("Clip stencil preparation (NonZero)");
124  options.stencil_mode =
126  break;
128  pass.SetCommandLabel("Clip stencil preparation (EvenOdd)");
129  options.stencil_mode =
131  break;
134  pass.SetCommandLabel("Clip stencil preparation (Increment)");
135  options.stencil_mode =
137  break;
138  }
139  pass.SetPipeline(renderer.GetClipPipeline(options));
140 
141  info.mvp = geometry_result.transform;
142  VS::BindFrameInfo(pass, renderer.GetTransientsBuffer().EmplaceUniform(info));
143 
144  if (!pass.Draw().ok()) {
145  return false;
146  }
147 
148  /// Write depth.
149 
150  options.depth_write_enabled = true;
151  options.primitive_type = PrimitiveType::kTriangleStrip;
152  Rect cover_area;
153  switch (clip_op_) {
155  pass.SetCommandLabel("Intersect Clip");
156  options.stencil_mode =
158  cover_area = Rect::MakeSize(pass.GetRenderTargetSize());
159  break;
161  pass.SetCommandLabel("Difference Clip");
163  std::optional<Rect> maybe_cover_area =
164  geometry_->GetCoverage(entity.GetTransform());
165  if (!maybe_cover_area.has_value()) {
166  return true;
167  }
168  cover_area = maybe_cover_area.value();
169  break;
170  }
171  auto points = cover_area.GetPoints();
172  auto vertices =
174  .AddVertices({{points[0]}, {points[1]}, {points[2]}, {points[3]}})
175  .CreateVertexBuffer(renderer.GetTransientsBuffer());
176  pass.SetVertexBuffer(std::move(vertices));
177 
178  pass.SetPipeline(renderer.GetClipPipeline(options));
179 
180  info.mvp = pass.GetOrthographicTransform();
181  VS::BindFrameInfo(pass, renderer.GetTransientsBuffer().EmplaceUniform(info));
182 
183  return pass.Draw().ok();
184 }
185 
186 /*******************************************************************************
187  ******* ClipRestoreContents
188  ******************************************************************************/
189 
191 
193 
194 void ClipRestoreContents::SetRestoreHeight(size_t clip_height) {
195  restore_height_ = clip_height;
196 }
197 
199  return restore_height_;
200 }
201 
203  std::optional<Rect> restore_coverage) {
204  restore_coverage_ = restore_coverage;
205 }
206 
208  const Entity& entity) const {
209  return std::nullopt;
210 };
211 
213  const Entity& entity,
214  const std::optional<Rect>& current_clip_coverage) const {
215  return {.type = ClipCoverage::Type::kRestore, .coverage = std::nullopt};
216 }
217 
219  const Entity& entity,
220  const std::optional<Rect> clip_coverage) const {
221  return true;
222 }
223 
225  return true;
226 }
227 
229 
231  const Entity& entity,
232  RenderPass& pass) const {
234 
235  pass.SetCommandLabel("Restore Clip");
236  auto options = OptionsFromPass(pass);
237  options.blend_mode = BlendMode::kDestination;
238  options.stencil_mode =
240  options.primitive_type = PrimitiveType::kTriangleStrip;
241  pass.SetPipeline(renderer.GetClipPipeline(options));
242  pass.SetStencilReference(0);
243 
244  // Create a rect that covers either the given restore area, or the whole
245  // render target texture.
246  auto ltrb =
247  restore_coverage_.value_or(Rect::MakeSize(pass.GetRenderTargetSize()))
248  .GetLTRB();
250  vtx_builder.AddVertices({
251  {Point(ltrb[0], ltrb[1])},
252  {Point(ltrb[2], ltrb[1])},
253  {Point(ltrb[0], ltrb[3])},
254  {Point(ltrb[2], ltrb[3])},
255  });
256  pass.SetVertexBuffer(
257  vtx_builder.CreateVertexBuffer(renderer.GetTransientsBuffer()));
258 
259  VS::FrameInfo info;
260  info.depth = GetShaderClipDepth(entity);
261  info.mvp = pass.GetOrthographicTransform();
262  VS::BindFrameInfo(pass, renderer.GetTransientsBuffer().EmplaceUniform(info));
263 
264  return pass.Draw().ok();
265 }
266 
267 } // 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:19
impeller::Entity::GetShaderClipDepth
float GetShaderClipDepth() const
Definition: entity.cc:106
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:46
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:207
entity.h
impeller::ContentContextOptions::StencilMode::kOverdrawPreventionIncrement
@ kOverdrawPreventionIncrement
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:224
impeller::BlendMode::kDestination
@ kDestination
formats.h
impeller::ContentContext::GetClipPipeline
std::shared_ptr< Pipeline< PipelineDescriptor > > GetClipPipeline(ContentContextOptions opts) const
Definition: content_context.h:496
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:202
impeller::VertexBufferBuilder::AddVertices
VertexBufferBuilder & AddVertices(std::initializer_list< VertexType_ > vertices)
Definition: vertex_buffer_builder.h:67
impeller::ClipRestoreContents::GetRestoreHeight
size_t GetRestoreHeight() const
Definition: clip_contents.cc:198
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::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:405
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::GetShaderClipDepth
static Scalar GetShaderClipDepth(const Entity &entity)
Definition: clip_contents.cc:18
impeller::VS
SolidFillVertexShader VS
Definition: stroke_path_geometry.cc:16
impeller::Entity
Definition: entity.h:20
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:322
render_pass.h
impeller::ClipRestoreContents::Render
bool Render(const ContentContext &renderer, const Entity &entity, RenderPass &pass) const override
Definition: clip_contents.cc:230
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:21
impeller::ContentContextOptions::StencilMode::kStencilNonZeroFill
@ kStencilNonZeroFill
impeller::Contents::ClipCoverage::type
Type type
Definition: contents.h:40
impeller::Matrix::IsTranslationScaleOnly
constexpr bool IsTranslationScaleOnly() const
Returns true if the matrix has a scale-only basis and is non-projective. Note that an identity matrix...
Definition: matrix.h:392
impeller::RenderPipelineHandle::VertexShader
VertexShader_ VertexShader
Definition: pipeline.h:106
impeller::ClipRestoreContents::SetInheritedOpacity
void SetInheritedOpacity(Scalar opacity) override
Inherit the provided opacity.
Definition: clip_contents.cc:228
clip_contents.h
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:85
impeller::VertexBufferBuilder::CreateVertexBuffer
VertexBuffer CreateVertexBuffer(HostBuffer &host_buffer) const
Definition: vertex_buffer_builder.h:81
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:102
content_context.h
impeller::ClipRestoreContents::ShouldRender
bool ShouldRender(const Entity &entity, const std::optional< Rect > clip_coverage) const override
Definition: clip_contents.cc:218
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:212
impeller::Contents::ClipCoverage
Definition: contents.h:37
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::ClipRestoreContents::SetRestoreHeight
void SetRestoreHeight(size_t clip_height)
Definition: clip_contents.cc:194
impeller::GeometryResult::Mode::kPreventOverdraw
@ kPreventOverdraw
impeller::ContentContextOptions::StencilMode::kOverdrawPreventionRestore
@ kOverdrawPreventionRestore
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
Definition: aiks_blend_unittests.cc:18
impeller::ContentContext
Definition: content_context.h:366
impeller::TRect< Scalar >
impeller::ContentContext::GetTransientsBuffer
HostBuffer & GetTransientsBuffer() const
Retrieve the currnent host buffer for transient storage.
Definition: content_context.h:752
impeller::GeometryResult::Mode::kNonZero
@ kNonZero
vertex_buffer_builder.h