| 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/core/vertex_buffer.h"
11 #include "impeller/entity/contents/clip_contents.h"
12 #include "impeller/entity/contents/content_context.h"
13 #include "impeller/entity/entity.h"
14 #include "impeller/renderer/render_pass.h"
15 #include "impeller/renderer/vertex_buffer_builder.h"
16
17 namespace impeller {
18
19 static Scalar GetShaderClipDepth(const Entity& entity) {
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(entity.GetClipDepth() + 1),
24 0.0f);
25 }
26
27 /*******************************************************************************
28 ******* ClipContents
29 ******************************************************************************/
30
31 ClipContents::ClipContents() = default;
32
33 ClipContents::~ClipContents() = default;
34
35 void ClipContents::SetGeometry(const Geometry* geometry) {
36 geometry_ = geometry;
37 }
38
39 void ClipContents::SetClipOperation(Entity::ClipOperation clip_op) {
40 clip_op_ = clip_op;
41 }
42
43 std::optional<Rect> ClipContents::GetCoverage(const Entity& entity) const {
44 return std::nullopt;
45 };
46
47 Contents::ClipCoverage ClipContents::GetClipCoverage(
48 const Entity& entity,
49 const std::optional<Rect>& current_clip_coverage) const {
50 if (!current_clip_coverage.has_value()) {
51 return {.type = ClipCoverage::Type::kAppend, .coverage = std::nullopt};
52 }
53 switch (clip_op_) {
54 case Entity::ClipOperation::kDifference:
55 // This can be optimized further by considering cases when the bounds of
56 // the current stencil will shrink.
57 return {
58 .type = ClipCoverage::Type::kAppend, //
59 .is_difference_or_non_square = true, //
60 .coverage = current_clip_coverage //
61 };
62 case Entity::ClipOperation::kIntersect:
63 if (!geometry_) {
64 return {.type = ClipCoverage::Type::kAppend, .coverage = std::nullopt};
65 }
66 auto coverage = geometry_->GetCoverage(entity.GetTransform());
67 if (!coverage.has_value() || !current_clip_coverage.has_value()) {
68 return {.type = ClipCoverage::Type::kAppend, .coverage = std::nullopt};
69 }
70 return {
71 .type = ClipCoverage::Type::kAppend, //
72 .is_difference_or_non_square = !geometry_->IsAxisAlignedRect(), //
73 .coverage = current_clip_coverage->Intersection(coverage.value()), //
74 };
75 }
76 FML_UNREACHABLE();
77 }
78
79 void ClipContents::SetInheritedOpacity(Scalar opacity) {}
80
81 bool ClipContents::Render(const ContentContext& renderer,
82 const Entity& entity,
83 RenderPass& pass) const {
84 if (!geometry_) {
85 return true;
86 }
87
88 using VS = ClipPipeline::VertexShader;
89
90 VS::FrameInfo info;
91 info.depth = GetShaderClipDepth(entity);
92
93 auto geometry_result = geometry_->GetPositionBuffer(renderer, entity, pass);
94 auto options = OptionsFromPass(pass);
95 options.blend_mode = BlendMode::kDestination;
96
97 pass.SetStencilReference(0);
98
99 /// Stencil preparation draw.
100
101 options.depth_write_enabled = false;
102 options.primitive_type = geometry_result.type;
103 pass.SetVertexBuffer(std::move(geometry_result.vertex_buffer));
104 switch (geometry_result.mode) {
105 case GeometryResult::Mode::kNonZero:
106 pass.SetCommandLabel("Clip stencil preparation (NonZero)");
107 options.stencil_mode =
108 ContentContextOptions::StencilMode::kStencilNonZeroFill;
109 break;
110 case GeometryResult::Mode::kEvenOdd:
111 pass.SetCommandLabel("Clip stencil preparation (EvenOdd)");
112 options.stencil_mode =
113 ContentContextOptions::StencilMode::kStencilEvenOddFill;
114 break;
115 case GeometryResult::Mode::kNormal:
116 case GeometryResult::Mode::kPreventOverdraw:
117 pass.SetCommandLabel("Clip stencil preparation (Increment)");
118 options.stencil_mode =
119 ContentContextOptions::StencilMode::kOverdrawPreventionIncrement;
120 break;
121 }
122 pass.SetPipeline(renderer.GetClipPipeline(options));
123
124 info.mvp = geometry_result.transform;
125 VS::BindFrameInfo(pass, renderer.GetTransientsBuffer().EmplaceUniform(info));
126
127 if (!pass.Draw().ok()) {
128 return false;
129 }
130
131 /// Write depth.
132
133 options.depth_write_enabled = true;
134 options.primitive_type = PrimitiveType::kTriangleStrip;
135 Rect cover_area;
136 switch (clip_op_) {
137 case Entity::ClipOperation::kIntersect:
138 pass.SetCommandLabel("Intersect Clip");
139 options.stencil_mode =
140 ContentContextOptions::StencilMode::kCoverCompareInverted;
141 cover_area = Rect::MakeSize(pass.GetRenderTargetSize());
142 break;
143 case Entity::ClipOperation::kDifference:
144 pass.SetCommandLabel("Difference Clip");
145 options.stencil_mode = ContentContextOptions::StencilMode::kCoverCompare;
146 std::optional<Rect> maybe_cover_area =
147 geometry_->GetCoverage(entity.GetTransform());
148 if (!maybe_cover_area.has_value()) {
149 return true;
150 }
151 cover_area = maybe_cover_area.value();
152 break;
153 }
154 auto points = cover_area.GetPoints();
155 pass.SetVertexBuffer(
156 CreateVertexBuffer(points, renderer.GetTransientsBuffer()));
157
158 pass.SetPipeline(renderer.GetClipPipeline(options));
159
160 info.mvp = pass.GetOrthographicTransform();
161 VS::BindFrameInfo(pass, renderer.GetTransientsBuffer().EmplaceUniform(info));
162
163 return pass.Draw().ok();
164 }
165
166 /*******************************************************************************
167 ******* ClipRestoreContents
168 ******************************************************************************/
169
170 ClipRestoreContents::ClipRestoreContents() = default;
171
172 ClipRestoreContents::~ClipRestoreContents() = default;
173
174 void ClipRestoreContents::SetRestoreHeight(size_t clip_height) {
175 restore_height_ = clip_height;
176 }
177
178 size_t ClipRestoreContents::GetRestoreHeight() const {
179 return restore_height_;
180 }
181
182 void ClipRestoreContents::SetRestoreCoverage(
183 std::optional<Rect> restore_coverage) {
184 restore_coverage_ = restore_coverage;
185 }
186
187 std::optional<Rect> ClipRestoreContents::GetCoverage(
188 const Entity& entity) const {
189 return std::nullopt;
190 };
191
192 Contents::ClipCoverage ClipRestoreContents::GetClipCoverage(
193 const Entity& entity,
194 const std::optional<Rect>& current_clip_coverage) const {
195 return {.type = ClipCoverage::Type::kRestore, .coverage = std::nullopt};
196 }
197
198 void ClipRestoreContents::SetInheritedOpacity(Scalar opacity) {}
199
200 bool ClipRestoreContents::Render(const ContentContext& renderer,
201 const Entity& entity,
202 RenderPass& pass) const {
203 using VS = ClipPipeline::VertexShader;
204
205 pass.SetCommandLabel("Restore Clip");
206 auto options = OptionsFromPass(pass);
207 options.blend_mode = BlendMode::kDestination;
208 options.stencil_mode =
209 ContentContextOptions::StencilMode::kOverdrawPreventionRestore;
210 options.primitive_type = PrimitiveType::kTriangleStrip;
211 pass.SetPipeline(renderer.GetClipPipeline(options));
212 pass.SetStencilReference(0);
213
214 // Create a rect that covers either the given restore area, or the whole
215 // render target texture.
216 auto ltrb =
217 restore_coverage_.value_or(Rect::MakeSize(pass.GetRenderTargetSize()))
218 .GetLTRB();
219
220 std::array<VS::PerVertexData, 4> vertices = {
221 VS::PerVertexData{Point(ltrb[0], ltrb[1])},
222 VS::PerVertexData{Point(ltrb[2], ltrb[1])},
223 VS::PerVertexData{Point(ltrb[0], ltrb[3])},
224 VS::PerVertexData{Point(ltrb[2], ltrb[3])},
225 };
226 pass.SetVertexBuffer(
227 CreateVertexBuffer(vertices, renderer.GetTransientsBuffer()));
228
229 VS::FrameInfo info;
230 info.depth = GetShaderClipDepth(entity);
231 info.mvp = pass.GetOrthographicTransform();
232 VS::BindFrameInfo(pass, renderer.GetTransientsBuffer().EmplaceUniform(info));
233
234 return pass.Draw().ok();
235 }
236
237 } // 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:99
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:47
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:187
vertex_buffer.h
entity.h
impeller::ContentContextOptions::StencilMode::kOverdrawPreventionIncrement
@ kOverdrawPreventionIncrement
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:492
impeller::ClipContents::SetClipOperation
void SetClipOperation(Entity::ClipOperation clip_op)
Definition: clip_contents.cc:39
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:182
impeller::ClipRestoreContents::GetRestoreHeight
size_t GetRestoreHeight() const
Definition: clip_contents.cc:178
impeller::Geometry::IsAxisAlignedRect
virtual bool IsAxisAlignedRect() const
Definition: geometry.cc:124
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::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:408
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:47
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:19
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::ClipContents
ClipContents()
impeller::PrimitiveType::kTriangleStrip
@ kTriangleStrip
impeller::Point
TPoint< Scalar > Point
Definition: point.h:327
render_pass.h
impeller::ClipRestoreContents::Render
bool Render(const ContentContext &renderer, const Entity &entity, RenderPass &pass) const override
Definition: clip_contents.cc:200
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:43
impeller::CreateVertexBuffer
VertexBuffer CreateVertexBuffer(std::array< VertexType, size > input, HostBuffer &host_buffer)
Create an index-less vertex buffer from a fixed size array.
Definition: vertex_buffer_builder.h:24
impeller::ClipContents::SetGeometry
void SetGeometry(const Geometry *geometry)
Definition: clip_contents.cc:35
impeller::ContentContextOptions::StencilMode::kStencilNonZeroFill
@ kStencilNonZeroFill
impeller::Contents::ClipCoverage::type
Type type
Definition: contents.h:40
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:198
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: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:95
content_context.h
impeller::Geometry
Definition: geometry.h:55
impeller::TRect< Scalar >::MakeSize
constexpr static TRect MakeSize(const TSize< U > &size)
Definition: rect.h:150
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:192
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::Entity::ClipOperation
ClipOperation
Definition: entity.h:61
impeller::ClipContents::SetInheritedOpacity
void SetInheritedOpacity(Scalar opacity) override
Inherit the provided opacity.
Definition: clip_contents.cc:79
impeller::ClipRestoreContents::SetRestoreHeight
void SetRestoreHeight(size_t clip_height)
Definition: clip_contents.cc:174
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: allocation.cc:12
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:753
impeller::GeometryResult::Mode::kNonZero
@ kNonZero
vertex_buffer_builder.h