| 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(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
36 void ClipContents::SetGeometry(GeometryResult clip_geometry) {
37 clip_geometry_ = std::move(clip_geometry);
38 }
39
40 void ClipContents::SetClipOperation(Entity::ClipOperation clip_op) {
41 clip_op_ = clip_op;
42 }
43
44 ClipCoverage ClipContents::GetClipCoverage(
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_) {
50 case Entity::ClipOperation::kDifference:
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 };
57 case Entity::ClipOperation::kIntersect:
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
76 using VS = ClipPipeline::VertexShader;
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) {
92 case GeometryResult::Mode::kNonZero:
93 pass.SetCommandLabel("Clip stencil preparation (NonZero)");
94 options.stencil_mode =
95 ContentContextOptions::StencilMode::kStencilNonZeroFill;
96 break;
97 case GeometryResult::Mode::kEvenOdd:
98 pass.SetCommandLabel("Clip stencil preparation (EvenOdd)");
99 options.stencil_mode =
100 ContentContextOptions::StencilMode::kStencilEvenOddFill;
101 break;
102 case GeometryResult::Mode::kNormal:
103 case GeometryResult::Mode::kPreventOverdraw:
104 pass.SetCommandLabel("Clip stencil preparation (Increment)");
105 options.stencil_mode =
106 ContentContextOptions::StencilMode::kOverdrawPreventionIncrement;
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_) {
124 case Entity::ClipOperation::kIntersect:
125 pass.SetCommandLabel("Intersect Clip");
126 options.stencil_mode =
127 ContentContextOptions::StencilMode::kCoverCompareInverted;
128 cover_area = Rect::MakeSize(pass.GetRenderTargetSize());
129 break;
130 case Entity::ClipOperation::kDifference:
131 pass.SetCommandLabel("Difference Clip");
132 options.stencil_mode = ContentContextOptions::StencilMode::kCoverCompare;
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) {
156 using VS = ClipPipeline::VertexShader;
157
158 pass.SetCommandLabel("Restore Clip");
159 auto options = OptionsFromPass(pass);
160 options.blend_mode = BlendMode::kDestination;
161 options.stencil_mode =
162 ContentContextOptions::StencilMode::kOverdrawPreventionRestore;
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
impeller::ClipCoverage
Definition: clip_contents.h:14
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:88
impeller::Entity::ClipOperation::kDifference
@ kDifference
impeller::Scalar
float Scalar
Definition: scalar.h:18
vertex_buffer.h
entity.h
impeller::ContentContextOptions::StencilMode::kOverdrawPreventionIncrement
@ kOverdrawPreventionIncrement
impeller::GetShaderClipDepth
static Scalar GetShaderClipDepth(uint32_t clip_depth)
Definition: clip_contents.cc:19
impeller::VS
GlyphAtlasPipeline::VertexShader VS
Definition: text_contents.cc:25
impeller::BlendMode::kDestination
@ kDestination
impeller::ClipContents::GetClipCoverage
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...
Definition: clip_contents.cc:44
impeller::RenderClipRestore
bool RenderClipRestore(const ContentContext &renderer, RenderPass &pass, uint32_t clip_depth, std::optional< Rect > restore_coverage)
Render a restore clip.
Definition: clip_contents.cc:152
formats.h
impeller::ClipContents::SetClipOperation
void SetClipOperation(Entity::ClipOperation clip_op)
Definition: clip_contents.cc:40
impeller::RenderPass::SetVertexBuffer
virtual bool SetVertexBuffer(VertexBuffer buffer)
Specify the vertex and index buffer to use for this command.
Definition: render_pass.cc:127
impeller::ContentContextOptions::StencilMode::kStencilEvenOddFill
@ kStencilEvenOddFill
impeller::ContentContext::GetClipPipeline
PipelineRef GetClipPipeline(ContentContextOptions opts) const
Definition: content_context.h:514
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:51
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:418
impeller::RenderPass::Draw
virtual fml::Status Draw()
Record the currently pending command.
Definition: render_pass.cc:208
impeller::TRect::IsEmpty
constexpr bool IsEmpty() const
Returns true if either of the width or height are 0, negative, or NaN.
Definition: rect.h:301
impeller::RenderPass::GetRenderTargetSize
ISize GetRenderTargetSize() const
Definition: render_pass.cc:47
impeller::PrimitiveType::kTriangleStrip
@ kTriangleStrip
impeller::Point
TPoint< Scalar > Point
Definition: point.h:327
impeller::ClipCoverage::coverage
std::optional< Rect > coverage
This coverage is the outer coverage of the clip.
Definition: clip_contents.h:26
render_pass.h
impeller::GeometryResult::type
PrimitiveType type
Definition: geometry.h:37
impeller::ClipContents::SetGeometry
void SetGeometry(GeometryResult geometry)
Set the pre-tessellated clip geometry.
Definition: clip_contents.cc:36
impeller::ClipContents::~ClipContents
~ClipContents()
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::ContentContextOptions::StencilMode::kStencilNonZeroFill
@ kStencilNonZeroFill
impeller::RenderPipelineHandle::VertexShader
VertexShader_ VertexShader
Definition: pipeline.h:113
impeller::GeometryResult
Definition: geometry.h:21
clip_contents.h
impeller::RenderPass::SetStencilReference
virtual void SetStencilReference(uint32_t value)
Definition: render_pass.cc:103
impeller::ClipContents::ClipContents
ClipContents(Rect coverage_rect, bool is_axis_aligned_rect)
Definition: clip_contents.cc:30
impeller::RenderPass
Render passes encode render commands directed as one specific render target into an underlying comman...
Definition: render_pass.h:30
impeller::GeometryResult::transform
Matrix transform
Definition: geometry.h:39
content_context.h
impeller::TRect< Scalar >::MakeSize
constexpr static TRect MakeSize(const TSize< U > &size)
Definition: rect.h:150
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:48
impeller::Entity::ClipOperation
ClipOperation
Definition: entity.h:61
impeller::RenderPass::SetPipeline
virtual void SetPipeline(PipelineRef pipeline)
The pipeline to use for this command.
Definition: render_pass.cc:86
impeller::GeometryResult::Mode::kPreventOverdraw
@ kPreventOverdraw
impeller::ContentContextOptions::StencilMode::kOverdrawPreventionRestore
@ kOverdrawPreventionRestore
impeller::ContentContextOptions::StencilMode::kCoverCompareInverted
@ kCoverCompareInverted
impeller::ContentContextOptions::StencilMode::kCoverCompare
@ kCoverCompare
impeller::GeometryResult::vertex_buffer
VertexBuffer vertex_buffer
Definition: geometry.h:38
impeller
Definition: allocation.cc:12
impeller::ContentContext
Definition: content_context.h:371
impeller::ClipContents::Render
bool Render(const ContentContext &renderer, RenderPass &pass, uint32_t clip_depth) const
Definition: clip_contents.cc:69
impeller::TRect< Scalar >
impeller::GeometryResult::mode
Mode mode
Definition: geometry.h:40
impeller::ContentContext::GetTransientsBuffer
HostBuffer & GetTransientsBuffer() const
Retrieve the currnent host buffer for transient storage.
Definition: content_context.h:866
impeller::GeometryResult::Mode::kNonZero
@ kNonZero
vertex_buffer_builder.h