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"
13 #include "impeller/entity/entity.h"
16 
17 namespace impeller {
18 
19 static Scalar GetShaderClipDepth(uint32_t clip_depth) {
20  // Draw the clip at the max of the clip entity's depth slice, so that other
21  // draw calls with this same depth value will be culled even if they have a
22  // perspective transform.
23  return std::nextafterf(Entity::GetShaderClipDepth(clip_depth + 1), 0.0f);
24 }
25 
26 /*******************************************************************************
27  ******* ClipContents
28  ******************************************************************************/
29 
30 ClipContents::ClipContents(Rect coverage_rect, bool is_axis_aligned_rect)
31  : coverage_rect_(coverage_rect),
32  is_axis_aligned_rect_(is_axis_aligned_rect) {}
33 
34 ClipContents::~ClipContents() = default;
35 
37  clip_geometry_ = std::move(clip_geometry);
38 }
39 
41  clip_op_ = clip_op;
42 }
43 
45  const std::optional<Rect>& current_clip_coverage) const {
46  if (!current_clip_coverage.has_value()) {
47  return {.coverage = std::nullopt};
48  }
49  switch (clip_op_) {
51  // This can be optimized further by considering cases when the bounds of
52  // the current stencil will shrink.
53  return {
54  .is_difference_or_non_square = true, //
55  .coverage = current_clip_coverage //
56  };
58  if (coverage_rect_.IsEmpty() || !current_clip_coverage.has_value()) {
59  return {.coverage = std::nullopt};
60  }
61  return {
62  .is_difference_or_non_square = !is_axis_aligned_rect_, //
63  .coverage = current_clip_coverage->Intersection(coverage_rect_), //
64  };
65  }
66  FML_UNREACHABLE();
67 }
68 
69 bool ClipContents::Render(const ContentContext& renderer,
70  RenderPass& pass,
71  uint32_t clip_depth) const {
72  if (!clip_geometry_.vertex_buffer) {
73  return true;
74  }
75 
77 
78  VS::FrameInfo info;
79  info.depth = GetShaderClipDepth(clip_depth);
80 
81  auto options = OptionsFromPass(pass);
82  options.blend_mode = BlendMode::kDestination;
83 
84  pass.SetStencilReference(0);
85 
86  /// Stencil preparation draw.
87 
88  options.depth_write_enabled = false;
89  options.primitive_type = clip_geometry_.type;
90  pass.SetVertexBuffer(clip_geometry_.vertex_buffer);
91  switch (clip_geometry_.mode) {
93  pass.SetCommandLabel("Clip stencil preparation (NonZero)");
94  options.stencil_mode =
96  break;
98  pass.SetCommandLabel("Clip stencil preparation (EvenOdd)");
99  options.stencil_mode =
101  break;
104  pass.SetCommandLabel("Clip stencil preparation (Increment)");
105  options.stencil_mode =
107  break;
108  }
109  pass.SetPipeline(renderer.GetClipPipeline(options));
110 
111  info.mvp = clip_geometry_.transform;
112  VS::BindFrameInfo(pass, renderer.GetTransientsBuffer().EmplaceUniform(info));
113 
114  if (!pass.Draw().ok()) {
115  return false;
116  }
117 
118  /// Write depth.
119 
120  options.depth_write_enabled = true;
121  options.primitive_type = PrimitiveType::kTriangleStrip;
122  Rect cover_area;
123  switch (clip_op_) {
125  pass.SetCommandLabel("Intersect Clip");
126  options.stencil_mode =
128  cover_area = Rect::MakeSize(pass.GetRenderTargetSize());
129  break;
131  pass.SetCommandLabel("Difference Clip");
133  cover_area = coverage_rect_;
134  break;
135  }
136  auto points = cover_area.GetPoints();
137  pass.SetVertexBuffer(
138  CreateVertexBuffer(points, renderer.GetTransientsBuffer()));
139 
140  pass.SetPipeline(renderer.GetClipPipeline(options));
141 
142  info.mvp = pass.GetOrthographicTransform();
143  VS::BindFrameInfo(pass, renderer.GetTransientsBuffer().EmplaceUniform(info));
144 
145  return pass.Draw().ok();
146 }
147 
148 /*******************************************************************************
149  ******* ClipRestoreContents
150  ******************************************************************************/
151 
152 bool RenderClipRestore(const ContentContext& renderer,
153  RenderPass& pass,
154  uint32_t clip_depth,
155  std::optional<Rect> restore_coverage) {
157 
158  pass.SetCommandLabel("Restore Clip");
159  auto options = OptionsFromPass(pass);
160  options.blend_mode = BlendMode::kDestination;
161  options.stencil_mode =
163  options.primitive_type = PrimitiveType::kTriangleStrip;
164  pass.SetPipeline(renderer.GetClipPipeline(options));
165  pass.SetStencilReference(0);
166 
167  // Create a rect that covers either the given restore area, or the whole
168  // render target texture.
169  auto ltrb =
170  restore_coverage.value_or(Rect::MakeSize(pass.GetRenderTargetSize()))
171  .GetLTRB();
172 
173  std::array<VS::PerVertexData, 4> vertices = {
174  VS::PerVertexData{Point(ltrb[0], ltrb[1])},
175  VS::PerVertexData{Point(ltrb[2], ltrb[1])},
176  VS::PerVertexData{Point(ltrb[0], ltrb[3])},
177  VS::PerVertexData{Point(ltrb[2], ltrb[3])},
178  };
179  pass.SetVertexBuffer(
180  CreateVertexBuffer(vertices, renderer.GetTransientsBuffer()));
181 
182  VS::FrameInfo info;
183  info.depth = GetShaderClipDepth(clip_depth);
184  info.mvp = pass.GetOrthographicTransform();
185  VS::BindFrameInfo(pass, renderer.GetTransientsBuffer().EmplaceUniform(info));
186 
187  return pass.Draw().ok();
188 }
189 
190 } // namespace impeller
ClipContents(Rect coverage_rect, bool is_axis_aligned_rect)
void SetGeometry(GeometryResult geometry)
Set the pre-tessellated clip geometry.
ClipCoverage GetClipCoverage(const std::optional< Rect > &current_clip_coverage) const
Given the current pass space bounding rectangle of the clip buffer, return the expected clip coverage...
void SetClipOperation(Entity::ClipOperation clip_op)
bool Render(const ContentContext &renderer, RenderPass &pass, uint32_t clip_depth) const
HostBuffer & GetTransientsBuffer() const
Retrieve the currnent host buffer for transient storage.
PipelineRef GetClipPipeline(ContentContextOptions opts) const
float GetShaderClipDepth() const
Definition: entity.cc:88
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
const Matrix & GetOrthographicTransform() const
Definition: render_pass.cc:51
virtual void SetPipeline(PipelineRef pipeline)
The pipeline to use for this command.
Definition: render_pass.cc:86
ISize GetRenderTargetSize() const
Definition: render_pass.cc:47
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
static Scalar GetShaderClipDepth(uint32_t clip_depth)
GlyphAtlasPipeline::VertexShader VS
TPoint< Scalar > Point
Definition: point.h:327
bool RenderClipRestore(const ContentContext &renderer, RenderPass &pass, uint32_t clip_depth, std::optional< Rect > restore_coverage)
Render a restore clip.
VertexBuffer CreateVertexBuffer(std::array< VertexType, size > input, HostBuffer &host_buffer)
Create an index-less vertex buffer from a fixed size array.
ContentContextOptions OptionsFromPass(const RenderPass &pass)
Definition: contents.cc:19
std::optional< Rect > coverage
This coverage is the outer coverage of the clip.
Definition: clip_contents.h:26
PrimitiveType type
Definition: geometry.h:37
@ kNormal
The geometry has no overlapping triangles.
VertexBuffer vertex_buffer
Definition: geometry.h:38
constexpr bool IsEmpty() const
Returns true if either of the width or height are 0, negative, or NaN.
Definition: rect.h:301
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:418
constexpr static TRect MakeSize(const TSize< U > &size)
Definition: rect.h:150