| Flutter Impeller |

Classes | Public Member Functions | List of all members
impeller::EntityPassClipStack Class Reference

A class that tracks all clips that have been recorded in the current entity pass stencil. More...

`#include <entity_pass_clip_stack.h>`

## Classes
struct | ClipStateResult
struct | ReplayResult

## Public Member Functions
| EntityPassClipStack (const Rect &initial_coverage_rect)
| Create a new [EntityPassClipStack] with an initialized coverage rect. More...
| ~EntityPassClipStack ()=default
std::optional< Rect > | CurrentClipCoverage () const
void | PushSubpass (std::optional< Rect > subpass_coverage, size_t clip_height)
void | PopSubpass ()
bool | HasCoverage () const
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, then the clip state is updated accordingly. More...
void | RecordEntity (const Entity &entity, Contents::ClipCoverage::Type type, std::optional< Rect > clip_coverage)
const std::vector< ReplayResult > & | GetReplayEntities () const
void | ActivateClipReplay ()
const ReplayResult * | GetNextReplayResult (size_t current_clip_depth)
| Returns the next Entity that should be replayed. If there are no enities to replay, then nullptr is returned. More...
const std::vector< ClipCoverageLayer > | GetClipCoverageLayers () const

## Detailed Description

A class that tracks all clips that have been recorded in the current entity pass stencil.

These clips are replayed when restoring the backdrop so that the stencil buffer is left in an identical state.

Definition at line 24 of file entity_pass_clip_stack.h.

## Constructor & Destructor Documentation

## ◆ EntityPassClipStack()

impeller::EntityPassClipStack::EntityPassClipStack | ( | const Rect & | initial_coverage_rect | ) |
| explicit

Create a new [EntityPassClipStack] with an initialized coverage rect.

Definition at line 13 of file entity_pass_clip_stack.cc.

13 {
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 }

References impeller::ClipCoverageLayer::coverage.

## ◆ ~EntityPassClipStack()

impeller::EntityPassClipStack::~EntityPassClipStack | ( |  | ) |
| default

## Member Function Documentation

## ◆ ActivateClipReplay()

void impeller::EntityPassClipStack::ActivateClipReplay | ( |  | ) |

Definition at line 189 of file entity_pass_clip_stack.cc.

189 {
190 next_replay_index_ = 0;
191 }

## ◆ ApplyClipState()

EntityPassClipStack::ClipStateResult impeller::EntityPassClipStack::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, then the clip state is updated accordingly.

Definition at line 55 of file entity_pass_clip_stack.cc.

59 {
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 }

References impeller::EntityPassClipStack::ClipStateResult::clip_did_change, impeller::ClipCoverageLayer::coverage, impeller::Contents::ClipCoverage::coverage, CurrentClipCoverage(), impeller::Entity::GetContents(), impeller::ClipRestoreContents::GetRestoreHeight(), impeller::Contents::ClipCoverage::is_difference_or_non_square, impeller::Contents::ClipCoverage::kAppend, impeller::Contents::ClipCoverage::kNoChange, impeller::Contents::ClipCoverage::kRestore, RecordEntity(), impeller::EntityPassClipStack::ClipStateResult::should_render, and impeller::Contents::ClipCoverage::type.

Referenced by impeller::Canvas::Restore(), and impeller::testing::TEST().

## ◆ CurrentClipCoverage()

std::optional< Rect > impeller::EntityPassClipStack::CurrentClipCoverage | ( |  | ) | const

Definition at line 25 of file entity_pass_clip_stack.cc.

25 {
26 return subpass_state_.back().clip_coverage.back().coverage;
27 }

Referenced by ApplyClipState(), impeller::Canvas::GetLocalCoverageLimit(), impeller::Canvas::Restore(), and impeller::testing::TEST().

## ◆ GetClipCoverageLayers()

const std::vector< ClipCoverageLayer > impeller::EntityPassClipStack::GetClipCoverageLayers | ( |  | ) | const

Definition at line 51 of file entity_pass_clip_stack.cc.

51 {
52 return subpass_state_.back().clip_coverage;
53 }

Referenced by impeller::testing::TEST().

## ◆ GetNextReplayResult()

const EntityPassClipStack::ReplayResult * impeller::EntityPassClipStack::GetNextReplayResult | ( | size_t | current_clip_depth | ) |

Returns the next Entity that should be replayed. If there are no enities to replay, then nullptr is returned.

Definition at line 194 of file entity_pass_clip_stack.cc.

194 {
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 }

References impeller::EntityPassClipStack::ReplayResult::entity, and impeller::Entity::GetClipDepth().

## ◆ GetReplayEntities()

const std::vector< EntityPassClipStack::ReplayResult > & impeller::EntityPassClipStack::GetReplayEntities | ( |  | ) | const

Definition at line 185 of file entity_pass_clip_stack.cc.

185 {
186 return subpass_state_.back().rendered_clip_entities;
187 }

Referenced by impeller::testing::TEST().

## ◆ HasCoverage()

bool impeller::EntityPassClipStack::HasCoverage | ( |  | ) | const

Definition at line 29 of file entity_pass_clip_stack.cc.

29 {
30 return !subpass_state_.back().clip_coverage.empty();
31 }

Referenced by impeller::Canvas::GetLocalCoverageLimit().

## ◆ PopSubpass()

void impeller::EntityPassClipStack::PopSubpass | ( |  | ) |

Definition at line 45 of file entity_pass_clip_stack.cc.

45 {
46 subpass_state_.pop_back();
47 next_replay_index_ = subpass_state_.back().rendered_clip_entities.size();
48 }

Referenced by impeller::Canvas::Restore(), and impeller::testing::TEST().

## ◆ PushSubpass()

void impeller::EntityPassClipStack::PushSubpass | ( | std::optional< Rect > | subpass_coverage,
|  | size_t | clip_height
| ) |  |

Definition at line 33 of file entity_pass_clip_stack.cc.

34 {
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 }

References impeller::ClipCoverageLayer::coverage.

Referenced by impeller::Canvas::SaveLayer(), and impeller::testing::TEST().

## ◆ RecordEntity()

void impeller::EntityPassClipStack::RecordEntity | ( | const Entity & | entity,
|  | Contents::ClipCoverage::Type | type,
|  | std::optional< Rect > | clip_coverage
| ) |  |

Definition at line 150 of file entity_pass_clip_stack.cc.

152 {
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 }

References impeller::Entity::Clone(), impeller::Contents::ClipCoverage::kAppend, impeller::Contents::ClipCoverage::kNoChange, impeller::Contents::ClipCoverage::kRestore, and type.

Referenced by ApplyClipState(), and impeller::testing::TEST().

The documentation for this class was generated from the following files:

- impeller/entity/entity_pass_clip_stack.h
- impeller/entity/entity_pass_clip_stack.cc

impeller::Contents::ClipCoverage::Type::kRestore
@ kRestore
impeller::EntityPassClipStack::CurrentClipCoverage
std::optional< Rect > CurrentClipCoverage() const
Definition: entity_pass_clip_stack.cc:25
type
GLenum type
Definition: blit_command_gles.cc:127
impeller::Rect
TRect< Scalar > Rect
Definition: rect.h:776
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::Contents::ClipCoverage::Type::kAppend
@ kAppend
impeller::Contents::ClipCoverage::Type::kNoChange
@ kNoChange