| Flutter Impeller |

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
5 #include "impeller/entity/entity_pass_clip_stack.h"
6
7 #include "flutter/fml/logging.h"
8 #include "impeller/entity/contents/clip_contents.h"
9 #include "impeller/entity/entity.h"
10
11 namespace impeller {
12
13 EntityPassClipStack::EntityPassClipStack(const Rect& initial_coverage_rect) {
14 subpass_state_.push_back(SubpassState{
15 .clip_coverage =
16 {
17 {ClipCoverageLayer{
18 .coverage = initial_coverage_rect,
19 .clip_height = 0,
20 }},
21 },
22 });
23 }
24
25 std::optional<Rect> EntityPassClipStack::CurrentClipCoverage() const {
26 return subpass_state_.back().clip_coverage.back().coverage;
27 }
28
29 bool EntityPassClipStack::HasCoverage() const {
30 return !subpass_state_.back().clip_coverage.empty();
31 }
32
33 void EntityPassClipStack::PushSubpass(std::optional<Rect> subpass_coverage,
34 size_t clip_height) {
35 subpass_state_.push_back(SubpassState{
36 .clip_coverage =
37 {
38 ClipCoverageLayer{.coverage = subpass_coverage,
39 .clip_height = clip_height},
40 },
41 });
42 next_replay_index_ = 0;
43 }
44
45 void EntityPassClipStack::PopSubpass() {
46 subpass_state_.pop_back();
47 next_replay_index_ = subpass_state_.back().rendered_clip_entities.size();
48 }
49
50 const std::vector<ClipCoverageLayer>
51 EntityPassClipStack::GetClipCoverageLayers() const {
52 return subpass_state_.back().clip_coverage;
53 }
54
55 EntityPassClipStack::ClipStateResult EntityPassClipStack::ApplyClipState(
56 Contents::ClipCoverage global_clip_coverage,
57 Entity& entity,
58 size_t clip_height_floor,
59 Point global_pass_position) {
60 ClipStateResult result = {.should_render = false, .clip_did_change = false};
61
62 auto& subpass_state = GetCurrentSubpassState();
63 switch (global_clip_coverage.type) {
64 case Contents::ClipCoverage::Type::kNoChange:
65 break;
66 case Contents::ClipCoverage::Type::kAppend: {
67 auto maybe_coverage = CurrentClipCoverage();
68
69 // Compute the previous clip height.
70 size_t previous_clip_height = 0;
71 if (!subpass_state.clip_coverage.empty()) {
72 previous_clip_height = subpass_state.clip_coverage.back().clip_height;
73 } else {
74 // If there is no clip coverage, then the previous clip height is the
75 // clip height floor.
76 previous_clip_height = clip_height_floor;
77 }
78
79 if (!maybe_coverage.has_value()) {
80 // Running this append op won't impact the clip buffer because the
81 // whole screen is already being clipped, so skip it.
82 return result;
83 }
84 auto op = maybe_coverage.value();
85
86 // If the new clip coverage is bigger than the existing coverage for
87 // intersect clips, we do not need to change the clip region.
88 if (!global_clip_coverage.is_difference_or_non_square &&
89 global_clip_coverage.coverage.has_value() &&
90 global_clip_coverage.coverage.value().Contains(op)) {
91 subpass_state.clip_coverage.push_back(ClipCoverageLayer{
92 .coverage = op, .clip_height = previous_clip_height + 1});
93
94 return result;
95 }
96
97 subpass_state.clip_coverage.push_back(
98 ClipCoverageLayer{.coverage = global_clip_coverage.coverage,
99 .clip_height = previous_clip_height + 1});
100 result.clip_did_change = true;
101
102 FML_DCHECK(subpass_state.clip_coverage.back().clip_height ==
103 subpass_state.clip_coverage.front().clip_height +
104 subpass_state.clip_coverage.size() - 1);
105
106 } break;
107 case Contents::ClipCoverage::Type::kRestore: {
108 ClipRestoreContents* restore_contents =
109 reinterpret_cast<ClipRestoreContents*>(entity.GetContents().get());
110 size_t restore_height = restore_contents->GetRestoreHeight();
111
112 if (subpass_state.clip_coverage.back().clip_height <= restore_height) {
113 // Drop clip restores that will do nothing.
114 return result;
115 }
116
117 auto restoration_index =
118 restore_height - subpass_state.clip_coverage.front().clip_height;
119 FML_DCHECK(restoration_index < subpass_state.clip_coverage.size());
120
121 // We only need to restore the area that covers the coverage of the
122 // clip rect at target height + 1.
123 std::optional<Rect> restore_coverage =
124 (restoration_index + 1 < subpass_state.clip_coverage.size())
125 ? subpass_state.clip_coverage[restoration_index + 1].coverage
126 : std::nullopt;
127 if (restore_coverage.has_value()) {
128 // Make the coverage rectangle relative to the current pass.
129 restore_coverage = restore_coverage->Shift(-global_pass_position);
130 }
131 subpass_state.clip_coverage.resize(restoration_index + 1);
132 result.clip_did_change = true;
133
134 // Skip all clip restores when stencil-then-cover is enabled.
135 if (subpass_state.clip_coverage.back().coverage.has_value()) {
136 RecordEntity(entity, global_clip_coverage.type, Rect());
137 }
138 return result;
139
140 } break;
141 }
142
143 RecordEntity(entity, global_clip_coverage.type,
144 subpass_state.clip_coverage.back().coverage);
145
146 result.should_render = true;
147 return result;
148 }
149
150 void EntityPassClipStack::RecordEntity(const Entity& entity,
151 Contents::ClipCoverage::Type type,
152 std::optional<Rect> clip_coverage) {
153 auto& subpass_state = GetCurrentSubpassState();
154 switch (type) {
155 case Contents::ClipCoverage::Type::kNoChange:
156 return;
157 case Contents::ClipCoverage::Type::kAppend:
158 FML_DCHECK(next_replay_index_ ==
159 subpass_state.rendered_clip_entities.size())
160 << "Not all clips have been replayed before appending new clip.";
161 subpass_state.rendered_clip_entities.push_back(
162 {.entity = entity.Clone(), .clip_coverage = clip_coverage});
163 next_replay_index_++;
164 break;
165 case Contents::ClipCoverage::Type::kRestore:
166 FML_DCHECK(next_replay_index_ <=
167 subpass_state.rendered_clip_entities.size());
168 if (!subpass_state.rendered_clip_entities.empty()) {
169 subpass_state.rendered_clip_entities.pop_back();
170
171 if (next_replay_index_ > subpass_state.rendered_clip_entities.size()) {
172 next_replay_index_ = subpass_state.rendered_clip_entities.size();
173 }
174 }
175 break;
176 }
177 }
178
179 EntityPassClipStack::SubpassState&
180 EntityPassClipStack::GetCurrentSubpassState() {
181 return subpass_state_.back();
182 }
183
184 const std::vector<EntityPassClipStack::ReplayResult>&
185 EntityPassClipStack::GetReplayEntities() const {
186 return subpass_state_.back().rendered_clip_entities;
187 }
188
189 void EntityPassClipStack::ActivateClipReplay() {
190 next_replay_index_ = 0;
191 }
192
193 const EntityPassClipStack::ReplayResult*
194 EntityPassClipStack::GetNextReplayResult(size_t current_clip_depth) {
195 if (next_replay_index_ >=
196 subpass_state_.back().rendered_clip_entities.size()) {
197 // No clips need to be replayed.
198 return nullptr;
199 }
200 ReplayResult* next_replay =
201 &subpass_state_.back().rendered_clip_entities[next_replay_index_];
202 if (next_replay->entity.GetClipDepth() < current_clip_depth) {
203 // The next replay clip doesn't affect the current entity, so don't replay
204 // it yet.
205 return nullptr;
206 }
207
208 next_replay_index_++;
209 return next_replay;
210 }
211
212 } // namespace impeller
impeller::EntityPassClipStack::ClipStateResult::should_render
bool should_render
Definition: entity_pass_clip_stack.h:34
impeller::EntityPassClipStack::PushSubpass
void PushSubpass(std::optional< Rect > subpass_coverage, size_t clip_height)
Definition: entity_pass_clip_stack.cc:33
impeller::Contents::ClipCoverage::Type
Type
Definition: contents.h:38
entity.h
impeller::EntityPassClipStack::GetClipCoverageLayers
const std::vector< ClipCoverageLayer > GetClipCoverageLayers() const
Definition: entity_pass_clip_stack.cc:51
impeller::EntityPassClipStack::HasCoverage
bool HasCoverage() const
Definition: entity_pass_clip_stack.cc:29
impeller::EntityPassClipStack::EntityPassClipStack
EntityPassClipStack(const Rect &initial_coverage_rect)
Create a new [EntityPassClipStack] with an initialized coverage rect.
Definition: entity_pass_clip_stack.cc:13
impeller::EntityPassClipStack::GetNextReplayResult
const ReplayResult * GetNextReplayResult(size_t current_clip_depth)
Returns the next Entity that should be replayed. If there are no enities to replay,...
Definition: entity_pass_clip_stack.cc:194
impeller::ClipRestoreContents::GetRestoreHeight
size_t GetRestoreHeight() const
Definition: clip_contents.cc:178
impeller::Contents::ClipCoverage::Type::kRestore
@ kRestore
impeller::ClipCoverageLayer::coverage
std::optional< Rect > coverage
Definition: entity_pass_clip_stack.h:15
impeller::ClipCoverageLayer
Definition: entity_pass_clip_stack.h:14
impeller::Entity
Definition: entity.h:20
impeller::EntityPassClipStack::ApplyClipState
ClipStateResult ApplyClipState(Contents::ClipCoverage global_clip_coverage, Entity &entity, size_t clip_height_floor, Point global_pass_position)
Applies the current clip state to an Entity. If the given Entity is a clip operation,...
Definition: entity_pass_clip_stack.cc:55
impeller::EntityPassClipStack::GetReplayEntities
const std::vector< ReplayResult > & GetReplayEntities() const
Definition: entity_pass_clip_stack.cc:185
impeller::EntityPassClipStack::ActivateClipReplay
void ActivateClipReplay()
Definition: entity_pass_clip_stack.cc:189
impeller::Contents::ClipCoverage::coverage
std::optional< Rect > coverage
This coverage is the outer coverage of the clip.
Definition: contents.h:52
impeller::EntityPassClipStack::CurrentClipCoverage
std::optional< Rect > CurrentClipCoverage() const
Definition: entity_pass_clip_stack.cc:25
impeller::Contents::ClipCoverage::type
Type type
Definition: contents.h:40
type
GLenum type
Definition: blit_command_gles.cc:127
impeller::Entity::GetContents
const std::shared_ptr< Contents > & GetContents() const
Definition: entity.cc:87
clip_contents.h
impeller::ClipRestoreContents
Definition: clip_contents.h:49
impeller::EntityPassClipStack::PopSubpass
void PopSubpass()
Definition: entity_pass_clip_stack.cc:45
entity_pass_clip_stack.h
impeller::EntityPassClipStack::ReplayResult::entity
Entity entity
Definition: entity_pass_clip_stack.h:27
impeller::Entity::GetClipDepth
uint32_t GetClipDepth() const
Definition: entity.cc:95
impeller::EntityPassClipStack::RecordEntity
void RecordEntity(const Entity &entity, Contents::ClipCoverage::Type type, std::optional< Rect > clip_coverage)
Definition: entity_pass_clip_stack.cc:150
impeller::EntityPassClipStack::ClipStateResult::clip_did_change
bool clip_did_change
Definition: entity_pass_clip_stack.h:37
impeller::Entity::Clone
Entity Clone() const
Definition: entity.cc:170
impeller::TPoint< Scalar >
impeller::Contents::ClipCoverage
Definition: contents.h:37
impeller::Contents::ClipCoverage::Type::kAppend
@ kAppend
impeller::EntityPassClipStack::ReplayResult
Definition: entity_pass_clip_stack.h:26
impeller::EntityPassClipStack::ClipStateResult
Definition: entity_pass_clip_stack.h:31
impeller
Definition: allocation.cc:12
impeller::TRect< Scalar >
impeller::Contents::ClipCoverage::Type::kNoChange
@ kNoChange
impeller::Contents::ClipCoverage::is_difference_or_non_square
bool is_difference_or_non_square
Definition: contents.h:43