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