Flutter Engine
The Flutter Engine
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"
15
16namespace impeller {
17
18static 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
31
33
34void ClipContents::SetGeometry(const std::shared_ptr<Geometry>& geometry) {
35 geometry_ = geometry;
36}
37
39 clip_op_ = clip_op;
40}
41
42std::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 }
72}
73
75 const std::optional<Rect> clip_coverage) const {
76 return true;
77}
78
79bool ClipContents::CanInheritOpacity(const Entity& entity) const {
80 return true;
81}
82
84
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
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
const char * options
static void info(const char *fmt,...) SK_PRINTF_LIKE(1
Definition: DM.cpp:213
static const int points[]
bool ok() const
Definition: status.h:71
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.
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...
void SetInheritedOpacity(Scalar opacity) override
Inherit the provided opacity.
void SetClipOperation(Entity::ClipOperation clip_op)
bool ShouldRender(const Entity &entity, const std::optional< Rect > clip_coverage) const override
bool CanInheritOpacity(const Entity &entity) const override
Whether or not this contents can accept the opacity peephole optimization.
void SetGeometry(const std::shared_ptr< Geometry > &geometry)
bool Render(const ContentContext &renderer, const Entity &entity, RenderPass &pass) const override
bool CanInheritOpacity(const Entity &entity) const override
Whether or not this contents can accept the opacity peephole optimization.
bool Render(const ContentContext &renderer, const Entity &entity, RenderPass &pass) const override
void SetInheritedOpacity(Scalar opacity) override
Inherit the provided opacity.
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...
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...
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.
bool ShouldRender(const Entity &entity, const std::optional< Rect > clip_coverage) const override
void SetRestoreHeight(size_t clip_height)
const Matrix & GetTransform() const
Get the global transform matrix for this Entity.
Definition: entity.cc:46
uint32_t GetClipDepth() const
Definition: entity.cc:102
float GetShaderClipDepth() const
Definition: entity.cc:106
Render passes encode render commands directed as one specific render target into an underlying comman...
Definition: render_pass.h:33
virtual bool SetVertexBuffer(VertexBuffer buffer)
Specify the vertex and index buffer to use for this command.
Definition: render_pass.cc:123
virtual void SetStencilReference(uint32_t value)
Definition: render_pass.cc:103
virtual void SetPipeline(const std::shared_ptr< Pipeline< PipelineDescriptor > > &pipeline)
The pipeline to use for this command.
Definition: render_pass.cc:92
const Matrix & GetOrthographicTransform() const
Definition: render_pass.cc:47
ISize GetRenderTargetSize() const
Definition: render_pass.cc:43
virtual fml::Status Draw()
Record the currently pending command.
Definition: render_pass.cc:127
virtual void SetCommandLabel(std::string_view label)
The debugging label to use for the command.
Definition: render_pass.cc:97
VertexBuffer CreateVertexBuffer(HostBuffer &host_buffer) const
VertexBufferBuilder & AddVertices(std::initializer_list< VertexType_ > vertices)
#define FML_UNREACHABLE()
Definition: logging.h:109
static Scalar GetShaderClipDepth(const Entity &entity)
float Scalar
Definition: scalar.h:18
SolidFillVertexShader VS
TPoint< Scalar > Point
Definition: point.h:322
ContentContextOptions OptionsFromPass(const RenderPass &pass)
Definition: contents.cc:19
@ kNormal
The geometry has no overlapping triangles.
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
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
static constexpr TRect MakeSize(const TSize< U > &size)
Definition: rect.h:146