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 
8 
9 namespace impeller {
10 
11 EntityPassClipStack::EntityPassClipStack(const Rect& initial_coverage_rect) {
12  subpass_state_.push_back(SubpassState{
13  .clip_coverage =
14  {
16  .coverage = initial_coverage_rect,
17  .clip_height = 0,
18  }},
19  },
20  });
21 }
22 
23 std::optional<Rect> EntityPassClipStack::CurrentClipCoverage() const {
24  return subpass_state_.back().clip_coverage.back().coverage;
25 }
26 
28  return !subpass_state_.back().clip_coverage.empty();
29 }
30 
31 void EntityPassClipStack::PushSubpass(std::optional<Rect> subpass_coverage,
32  size_t clip_height) {
33  subpass_state_.push_back(SubpassState{
34  .clip_coverage =
35  {
36  ClipCoverageLayer{.coverage = subpass_coverage,
37  .clip_height = clip_height},
38  },
39  });
40 }
41 
43  subpass_state_.pop_back();
44 }
45 
46 const std::vector<ClipCoverageLayer>
48  return subpass_state_.back().clip_coverage;
49 }
50 
52  Contents::ClipCoverage global_clip_coverage,
53  Entity& entity,
54  size_t clip_height_floor,
55  Point global_pass_position) {
56  ClipStateResult result = {.should_render = false, .clip_did_change = false};
57 
58  auto& subpass_state = GetCurrentSubpassState();
59  switch (global_clip_coverage.type) {
61  break;
63  auto op = CurrentClipCoverage();
64 
65  // Compute the previous clip height.
66  size_t previous_clip_height = 0;
67  if (!subpass_state.clip_coverage.empty()) {
68  previous_clip_height = subpass_state.clip_coverage.back().clip_height;
69  } else {
70  // If there is no clip coverage, then the previous clip height is the
71  // clip height floor.
72  previous_clip_height = clip_height_floor;
73  }
74 
75  subpass_state.clip_coverage.push_back(
76  ClipCoverageLayer{.coverage = global_clip_coverage.coverage,
77  .clip_height = previous_clip_height + 1});
78  result.clip_did_change = true;
79 
80  FML_DCHECK(subpass_state.clip_coverage.back().clip_height ==
81  subpass_state.clip_coverage.front().clip_height +
82  subpass_state.clip_coverage.size() - 1);
83 
84  if (!op.has_value()) {
85  // Running this append op won't impact the clip buffer because the
86  // whole screen is already being clipped, so skip it.
87  return result;
88  }
89  } break;
91  ClipRestoreContents* restore_contents =
92  reinterpret_cast<ClipRestoreContents*>(entity.GetContents().get());
93  size_t restore_height = restore_contents->GetRestoreHeight();
94 
95  if (subpass_state.clip_coverage.back().clip_height <= restore_height) {
96  // Drop clip restores that will do nothing.
97  return result;
98  }
99 
100  auto restoration_index =
101  restore_height - subpass_state.clip_coverage.front().clip_height;
102  FML_DCHECK(restoration_index < subpass_state.clip_coverage.size());
103 
104  // We only need to restore the area that covers the coverage of the
105  // clip rect at target height + 1.
106  std::optional<Rect> restore_coverage =
107  (restoration_index + 1 < subpass_state.clip_coverage.size())
108  ? subpass_state.clip_coverage[restoration_index + 1].coverage
109  : std::nullopt;
110  if (restore_coverage.has_value()) {
111  // Make the coverage rectangle relative to the current pass.
112  restore_coverage = restore_coverage->Shift(-global_pass_position);
113  }
114  subpass_state.clip_coverage.resize(restoration_index + 1);
115  result.clip_did_change = true;
116 
117  // Skip all clip restores when stencil-then-cover is enabled.
118  if (subpass_state.clip_coverage.back().coverage.has_value()) {
119  RecordEntity(entity, global_clip_coverage.type, Rect());
120  }
121  return result;
122 
123  } break;
124  }
125 
126  RecordEntity(entity, global_clip_coverage.type,
127  subpass_state.clip_coverage.back().coverage);
128 
129  result.should_render = true;
130  return result;
131 }
132 
135  std::optional<Rect> clip_coverage) {
136  auto& subpass_state = GetCurrentSubpassState();
137  switch (type) {
139  return;
141  subpass_state.rendered_clip_entities.push_back(
142  {.entity = entity.Clone(), .clip_coverage = clip_coverage});
143  break;
145  if (!subpass_state.rendered_clip_entities.empty()) {
146  subpass_state.rendered_clip_entities.pop_back();
147  }
148  break;
149  }
150 }
151 
152 EntityPassClipStack::SubpassState&
153 EntityPassClipStack::GetCurrentSubpassState() {
154  return subpass_state_.back();
155 }
156 
157 const std::vector<EntityPassClipStack::ReplayResult>&
159  return subpass_state_.back().rendered_clip_entities;
160 }
161 
162 } // 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:31
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:47
impeller::EntityPassClipStack::HasCoverage
bool HasCoverage() const
Definition: entity_pass_clip_stack.cc:27
impeller::EntityPassClipStack::EntityPassClipStack
EntityPassClipStack(const Rect &initial_coverage_rect)
Create a new [EntityPassClipStack] with an initialized coverage rect.
Definition: entity_pass_clip_stack.cc:11
impeller::ClipRestoreContents::GetRestoreHeight
size_t GetRestoreHeight() const
Definition: clip_contents.cc:198
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:51
impeller::EntityPassClipStack::GetReplayEntities
const std::vector< ReplayResult > & GetReplayEntities() const
Definition: entity_pass_clip_stack.cc:158
impeller::Contents::ClipCoverage::coverage
std::optional< Rect > coverage
Definition: contents.h:41
impeller::EntityPassClipStack::CurrentClipCoverage
std::optional< Rect > CurrentClipCoverage() const
Definition: entity_pass_clip_stack.cc:23
impeller::Contents::ClipCoverage::type
Type type
Definition: contents.h:40
type
GLenum type
Definition: blit_command_gles.cc:126
impeller::Entity::GetContents
const std::shared_ptr< Contents > & GetContents() const
Definition: entity.cc:94
clip_contents.h
impeller::ClipRestoreContents
Definition: clip_contents.h:59
impeller::EntityPassClipStack::PopSubpass
void PopSubpass()
Definition: entity_pass_clip_stack.cc:42
entity_pass_clip_stack.h
impeller::EntityPassClipStack::RecordEntity
void RecordEntity(const Entity &entity, Contents::ClipCoverage::Type type, std::optional< Rect > clip_coverage)
Definition: entity_pass_clip_stack.cc:133
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:191
impeller::TPoint< Scalar >
impeller::Contents::ClipCoverage
Definition: contents.h:37
impeller::Contents::ClipCoverage::Type::kAppend
@ kAppend
impeller::EntityPassClipStack::ClipStateResult
Definition: entity_pass_clip_stack.h:31
impeller
Definition: aiks_blend_unittests.cc:18
impeller::TRect< Scalar >
impeller::Contents::ClipCoverage::Type::kNoChange
@ kNoChange