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 
6 
7 #include "flutter/fml/logging.h"
10 
11 namespace impeller {
12 
13 EntityPassClipStack::EntityPassClipStack(const Rect& initial_coverage_rect) {
14  subpass_state_.push_back(SubpassState{
15  .clip_coverage =
16  {
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 
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 
46  subpass_state_.pop_back();
47  next_replay_index_ = subpass_state_.back().rendered_clip_entities.size();
48 }
49 
50 const std::vector<ClipCoverageLayer>
52  return subpass_state_.back().clip_coverage;
53 }
54 
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) {
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 }
149 
152  std::optional<Rect> clip_coverage) {
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 }
178 
179 EntityPassClipStack::SubpassState&
180 EntityPassClipStack::GetCurrentSubpassState() {
181  return subpass_state_.back();
182 }
183 
184 const std::vector<EntityPassClipStack::ReplayResult>&
186  return subpass_state_.back().rendered_clip_entities;
187 }
188 
190  next_replay_index_ = 0;
191 }
192 
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