Flutter Engine
The Flutter Engine
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 RecordEntity(entity, global_clip_coverage.type,
128 subpass_state.clip_coverage.back().coverage);
129
130 result.should_render = true;
131 return result;
132}
133
136 std::optional<Rect> clip_coverage) {
137 auto& subpass_state = GetCurrentSubpassState();
138 switch (type) {
140 return;
142 subpass_state.rendered_clip_entities.push_back(
143 {.entity = entity.Clone(), .clip_coverage = clip_coverage});
144 break;
146 if (!subpass_state.rendered_clip_entities.empty()) {
147 subpass_state.rendered_clip_entities.pop_back();
148 }
149 break;
150 }
151}
152
153EntityPassClipStack::SubpassState&
154EntityPassClipStack::GetCurrentSubpassState() {
155 return subpass_state_.back();
156}
157
158const std::vector<EntityPassClipStack::ReplayResult>&
160 return subpass_state_.back().rendered_clip_entities;
161}
162
163} // namespace impeller
GLenum type
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)
const std::shared_ptr< Contents > & GetContents() const
Definition: entity.cc:94
Entity Clone() const
Definition: entity.cc:191
if(end==-1)
GAsyncResult * result
#define FML_DCHECK(condition)
Definition: logging.h:103
std::optional< Rect > coverage
Definition: contents.h:41