Flutter Impeller
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< RectCurrentClipCoverage () 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 ReplayResultGetNextReplayResult (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< ClipCoverageLayerGetClipCoverageLayers () 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) {
65  break;
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;
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) {
156  return;
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;
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::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