Flutter Engine
 
Loading...
Searching...
No Matches
entity_pass_clip_stack.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
6
9
10namespace impeller {
11
12EntityPassClipStack::EntityPassClipStack(const Rect& initial_coverage_rect) {
13 subpass_state_.push_back(SubpassState{
14 .clip_coverage =
15 {
17 .coverage = initial_coverage_rect,
18 .clip_height = 0,
19 }},
20 },
21 });
22}
23
24std::optional<Rect> EntityPassClipStack::CurrentClipCoverage() const {
25 return subpass_state_.back().clip_coverage.back().coverage;
26}
27
29 return !subpass_state_.back().clip_coverage.empty();
30}
31
32void EntityPassClipStack::PushSubpass(std::optional<Rect> subpass_coverage,
33 size_t clip_height) {
34 subpass_state_.push_back(SubpassState{
35 .clip_coverage =
36 {
37 ClipCoverageLayer{.coverage = subpass_coverage,
38 .clip_height = clip_height},
39 },
40 });
41 next_replay_index_ = 0;
42}
43
45 subpass_state_.pop_back();
46 next_replay_index_ = subpass_state_.back().rendered_clip_entities.size();
47}
48
49const std::vector<ClipCoverageLayer>
51 return subpass_state_.back().clip_coverage;
52}
53
55 Point global_pass_position,
56 size_t restore_height) {
57 ClipStateResult result = {.should_render = false, .clip_did_change = false};
58 auto& subpass_state = GetCurrentSubpassState();
59
60 if (subpass_state.clip_coverage.back().clip_height <= restore_height) {
61 // Drop clip restores that will do nothing.
62 return result;
63 }
64
65 auto restoration_index =
66 restore_height - subpass_state.clip_coverage.front().clip_height;
67 FML_DCHECK(restoration_index < subpass_state.clip_coverage.size());
68
69 // We only need to restore the area that covers the coverage of the
70 // clip rect at target height + 1.
71 std::optional<Rect> restore_coverage =
72 (restoration_index + 1 < subpass_state.clip_coverage.size())
73 ? subpass_state.clip_coverage[restoration_index + 1].coverage
74 : std::nullopt;
75 if (restore_coverage.has_value()) {
76 // Make the coverage rectangle relative to the current pass.
77 restore_coverage = restore_coverage->Shift(-global_pass_position);
78 }
79
80 subpass_state.clip_coverage.resize(restoration_index + 1);
81 result.clip_did_change = true;
82
83 if (subpass_state.clip_coverage.back().coverage.has_value()) {
84 FML_DCHECK(next_replay_index_ <=
85 subpass_state.rendered_clip_entities.size());
86 // https://github.com/flutter/flutter/issues/162172
87 // This code is slightly wrong and should be popping more than one clip
88 // entry.
89 if (!subpass_state.rendered_clip_entities.empty()) {
90 subpass_state.rendered_clip_entities.pop_back();
91
92 if (next_replay_index_ > subpass_state.rendered_clip_entities.size()) {
93 next_replay_index_ = subpass_state.rendered_clip_entities.size();
94 }
95 }
96 }
97 return result;
98}
99
101 const ClipContents& clip_contents,
103 Point global_pass_position,
104 uint32_t clip_depth,
105 size_t clip_height_floor,
106 bool is_aa) {
107 ClipStateResult result = {.should_render = false, .clip_did_change = false};
108
109 std::optional<Rect> maybe_clip_coverage = CurrentClipCoverage();
110 // Running this append op won't impact the clip buffer because the
111 // whole screen is already being clipped, so skip it.
112 if (!maybe_clip_coverage.has_value()) {
113 return result;
114 }
115 auto current_clip_coverage = maybe_clip_coverage.value();
116 // Entity transforms are relative to the current pass position, so we need
117 // to check clip coverage in the same space.
118 current_clip_coverage = current_clip_coverage.Shift(-global_pass_position);
119
120 ClipCoverage clip_coverage =
121 clip_contents.GetClipCoverage(current_clip_coverage);
122 if (clip_coverage.coverage.has_value()) {
123 clip_coverage.coverage =
124 clip_coverage.coverage->Shift(global_pass_position);
125 }
126
127 SubpassState& subpass_state = GetCurrentSubpassState();
128
129 // Compute the previous clip height.
130 size_t previous_clip_height = 0;
131 if (!subpass_state.clip_coverage.empty()) {
132 previous_clip_height = subpass_state.clip_coverage.back().clip_height;
133 } else {
134 // If there is no clip coverage, then the previous clip height is the
135 // clip height floor.
136 previous_clip_height = clip_height_floor;
137 }
138
139 // If the new clip coverage is bigger than the existing coverage for
140 // intersect clips, we do not need to change the clip region.
141 if (!clip_coverage.is_difference_or_non_square &&
142 clip_coverage.coverage.has_value() &&
143 clip_coverage.coverage.value().Contains(current_clip_coverage)) {
144 subpass_state.clip_coverage.push_back(ClipCoverageLayer{
145 .coverage = current_clip_coverage, //
146 .clip_height = previous_clip_height + 1 //
147 });
148
149 return result;
150 }
151
152 // If the clip is an axis aligned rect and either is_aa is false or
153 // the clip is very nearly integral, then the depth write can be
154 // skipped for intersect clips. Since we use 4x MSAA, anything within
155 // < ~0.125 of an integral value in either axis can be treated as
156 // approximately the same as an integral value.
157 bool should_render = true;
158 std::optional<Rect> coverage_value = clip_coverage.coverage;
159 if (!clip_coverage.is_difference_or_non_square &&
160 coverage_value.has_value()) {
161 const Rect& coverage = coverage_value.value();
162 constexpr Scalar threshold = 0.124;
163 if (!is_aa ||
164 (std::abs(std::round(coverage.GetLeft()) - coverage.GetLeft()) <=
165 threshold &&
166 std::abs(std::round(coverage.GetTop()) - coverage.GetTop()) <=
167 threshold &&
168 std::abs(std::round(coverage.GetRight()) - coverage.GetRight()) <=
169 threshold &&
170 std::abs(std::round(coverage.GetBottom()) - coverage.GetBottom()) <=
171 threshold)) {
172 coverage_value = Rect::Round(clip_coverage.coverage.value());
173 should_render = false;
174 }
175 }
176
177 subpass_state.clip_coverage.push_back(ClipCoverageLayer{
178 .coverage = coverage_value, //
179 .clip_height = previous_clip_height + 1 //
180
181 });
182 result.clip_did_change = true;
183 result.should_render = should_render;
184
185 FML_DCHECK(subpass_state.clip_coverage.back().clip_height ==
186 subpass_state.clip_coverage.front().clip_height +
187 subpass_state.clip_coverage.size() - 1);
188
189 FML_DCHECK(next_replay_index_ == subpass_state.rendered_clip_entities.size())
190 << "Not all clips have been replayed before appending new clip.";
191
192 subpass_state.rendered_clip_entities.push_back(ReplayResult{
193 .clip_contents = clip_contents, //
194 .transform = transform, //
195 .clip_coverage = coverage_value, //
196 .clip_depth = clip_depth //
197 });
198 next_replay_index_++;
199
200 return result;
201}
202
203EntityPassClipStack::SubpassState&
204EntityPassClipStack::GetCurrentSubpassState() {
205 return subpass_state_.back();
206}
207
208const std::vector<EntityPassClipStack::ReplayResult>&
210 return subpass_state_.back().rendered_clip_entities;
211}
212
213} // namespace impeller
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...
std::optional< Rect > CurrentClipCoverage() const
void PushSubpass(std::optional< Rect > subpass_coverage, size_t clip_height)
const std::vector< ReplayResult > & GetReplayEntities() const
ClipStateResult RecordClip(const ClipContents &clip_contents, Matrix transform, Point global_pass_position, uint32_t clip_depth, size_t clip_height_floor, bool is_aa)
ClipStateResult RecordRestore(Point global_pass_position, size_t restore_height)
EntityPassClipStack(const Rect &initial_coverage_rect)
Create a new [EntityPassClipStack] with an initialized coverage rect.
const std::vector< ClipCoverageLayer > GetClipCoverageLayers() const
#define FML_DCHECK(condition)
Definition logging.h:122
float Scalar
Definition scalar.h:19
std::optional< Rect > coverage
This coverage is the outer coverage of the clip.
A 4x4 matrix using column-major storage.
Definition matrix.h:37
constexpr auto GetBottom() const
Definition rect.h:357
constexpr auto GetTop() const
Definition rect.h:353
constexpr auto GetLeft() const
Definition rect.h:351
Round(const TRect< U > &r)
Definition rect.h:695
constexpr auto GetRight() const
Definition rect.h:355