| 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
5 #include "impeller/entity/entity_pass_clip_stack.h"
6 #include "impeller/entity/contents/clip_contents.h"
7 #include "impeller/entity/contents/content_context.h"
8 #include "impeller/entity/entity.h"
9
10 namespace impeller {
11
12 EntityPassClipStack::EntityPassClipStack(const Rect& initial_coverage_rect) {
13 subpass_state_.push_back(SubpassState{
14 .clip_coverage =
15 {
16 {ClipCoverageLayer{
17 .coverage = initial_coverage_rect,
18 .clip_depth = 0,
19 }},
20 },
21 });
22 }
23
24 std::optional<Rect> EntityPassClipStack::CurrentClipCoverage() const {
25 return subpass_state_.back().clip_coverage.back().coverage;
26 }
27
28 bool EntityPassClipStack::HasCoverage() const {
29 return !subpass_state_.back().clip_coverage.empty();
30 }
31
32 void EntityPassClipStack::PushSubpass(std::optional<Rect> subpass_coverage,
33 size_t clip_depth) {
34 subpass_state_.push_back(SubpassState{
35 .clip_coverage =
36 {
37 ClipCoverageLayer{.coverage = subpass_coverage,
38 .clip_depth = clip_depth},
39 },
40 });
41 }
42
43 void EntityPassClipStack::PopSubpass() {
44 subpass_state_.pop_back();
45 }
46
47 const std::vector<ClipCoverageLayer>
48 EntityPassClipStack::GetClipCoverageLayers() const {
49 return subpass_state_.back().clip_coverage;
50 }
51
52 EntityPassClipStack::ClipStateResult EntityPassClipStack::ApplyClipState(
53 Contents::ClipCoverage global_clip_coverage,
54 Entity& entity,
55 size_t clip_depth_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) {
61 case Contents::ClipCoverage::Type::kNoChange:
62 break;
63 case Contents::ClipCoverage::Type::kAppend: {
64 auto op = CurrentClipCoverage();
65 subpass_state.clip_coverage.push_back(
66 ClipCoverageLayer{.coverage = global_clip_coverage.coverage,
67 .clip_depth = entity.GetClipDepth() + 1});
68 result.clip_did_change = true;
69
70 FML_DCHECK(subpass_state.clip_coverage.back().clip_depth ==
71 subpass_state.clip_coverage.front().clip_depth +
72 subpass_state.clip_coverage.size() - 1);
73
74 if (!op.has_value()) {
75 // Running this append op won't impact the clip buffer because the
76 // whole screen is already being clipped, so skip it.
77 return result;
78 }
79 } break;
80 case Contents::ClipCoverage::Type::kRestore: {
81 if (subpass_state.clip_coverage.back().clip_depth <=
82 entity.GetClipDepth()) {
83 // Drop clip restores that will do nothing.
84 return result;
85 }
86
87 auto restoration_index = entity.GetClipDepth() -
88 subpass_state.clip_coverage.front().clip_depth;
89 FML_DCHECK(restoration_index < subpass_state.clip_coverage.size());
90
91 // We only need to restore the area that covers the coverage of the
92 // clip rect at target depth + 1.
93 std::optional<Rect> restore_coverage =
94 (restoration_index + 1 < subpass_state.clip_coverage.size())
95 ? subpass_state.clip_coverage[restoration_index + 1].coverage
96 : std::nullopt;
97 if (restore_coverage.has_value()) {
98 // Make the coverage rectangle relative to the current pass.
99 restore_coverage = restore_coverage->Shift(-global_pass_position);
100 }
101 subpass_state.clip_coverage.resize(restoration_index + 1);
102 result.clip_did_change = true;
103
104 if constexpr (ContentContext::kEnableStencilThenCover) {
105 // Skip all clip restores when stencil-then-cover is enabled.
106 if (subpass_state.clip_coverage.back().coverage.has_value()) {
107 RecordEntity(entity, global_clip_coverage.type, Rect());
108 }
109 return result;
110 }
111
112 if (!subpass_state.clip_coverage.back().coverage.has_value()) {
113 // Running this restore op won't make anything renderable, so skip it.
114 return result;
115 }
116
117 auto restore_contents =
118 static_cast<ClipRestoreContents*>(entity.GetContents().get());
119 restore_contents->SetRestoreCoverage(restore_coverage);
120
121 } break;
122 }
123
124 #ifdef IMPELLER_ENABLE_CAPTURE
125 {
126 auto element_entity_coverage = entity.GetCoverage();
127 if (element_entity_coverage.has_value()) {
128 element_entity_coverage =
129 element_entity_coverage->Shift(global_pass_position);
130 entity.GetCapture().AddRect("Coverage", *element_entity_coverage,
131 {.readonly = true});
132 }
133 }
134 #endif
135
136 entity.SetClipDepth(entity.GetClipDepth() - clip_depth_floor);
137 RecordEntity(entity, global_clip_coverage.type,
138 subpass_state.clip_coverage.back().coverage);
139
140 result.should_render = true;
141 return result;
142 }
143
144 void EntityPassClipStack::RecordEntity(const Entity& entity,
145 Contents::ClipCoverage::Type type,
146 std::optional<Rect> clip_coverage) {
147 auto& subpass_state = GetCurrentSubpassState();
148 switch (type) {
149 case Contents::ClipCoverage::Type::kNoChange:
150 return;
151 case Contents::ClipCoverage::Type::kAppend:
152 subpass_state.rendered_clip_entities.push_back(
153 {.entity = entity.Clone(), .clip_coverage = clip_coverage});
154 break;
155 case Contents::ClipCoverage::Type::kRestore:
156 if (!subpass_state.rendered_clip_entities.empty()) {
157 subpass_state.rendered_clip_entities.pop_back();
158 }
159 break;
160 }
161 }
162
163 EntityPassClipStack::SubpassState&
164 EntityPassClipStack::GetCurrentSubpassState() {
165 return subpass_state_.back();
166 }
167
168 const std::vector<EntityPassClipStack::ReplayResult>&
169 EntityPassClipStack::GetReplayEntities() const {
170 return subpass_state_.back().rendered_clip_entities;
171 }
172
173 } // namespace impeller
impeller::Entity::SetClipDepth
void SetClipDepth(uint32_t clip_depth)
Definition: entity.cc:101
impeller::EntityPassClipStack::ClipStateResult::should_render
bool should_render
Definition: entity_pass_clip_stack.h:34
impeller::Entity::GetCapture
Capture & GetCapture() const
Definition: entity.cc:206
impeller::Contents::ClipCoverage::Type
Type
Definition: contents.h:41
entity.h
impeller::EntityPassClipStack::GetClipCoverageLayers
const std::vector< ClipCoverageLayer > GetClipCoverageLayers() const
Definition: entity_pass_clip_stack.cc:48
impeller::EntityPassClipStack::HasCoverage
bool HasCoverage() const
Definition: entity_pass_clip_stack.cc:28
impeller::EntityPassClipStack::EntityPassClipStack
EntityPassClipStack(const Rect &initial_coverage_rect)
Create a new [EntityPassClipStack] with an initialized coverage rect.
Definition: entity_pass_clip_stack.cc:12
impeller::ClipRestoreContents::SetRestoreCoverage
void SetRestoreCoverage(std::optional< Rect > coverage)
The area on the pass texture where this clip restore will be applied. If unset, the entire pass textu...
Definition: clip_contents.cc:256
impeller::Contents::ClipCoverage::Type::kRestore
@ kRestore
impeller::ClipCoverageLayer::coverage
std::optional< Rect > coverage
Definition: entity_pass_clip_stack.h:15
impeller::ContentContext::kEnableStencilThenCover
static constexpr bool kEnableStencilThenCover
Definition: content_context.h:411
impeller::ClipCoverageLayer
Definition: entity_pass_clip_stack.h:14
impeller::Entity
Definition: entity.h:21
impeller::EntityPassClipStack::GetReplayEntities
const std::vector< ReplayResult > & GetReplayEntities() const
Definition: entity_pass_clip_stack.cc:169
impeller::EntityPassClipStack::ApplyClipState
ClipStateResult ApplyClipState(Contents::ClipCoverage global_clip_coverage, Entity &entity, size_t clip_depth_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:52
impeller::Contents::ClipCoverage::coverage
std::optional< Rect > coverage
Definition: contents.h:44
impeller::EntityPassClipStack::CurrentClipCoverage
std::optional< Rect > CurrentClipCoverage() const
Definition: entity_pass_clip_stack.cc:24
impeller::Contents::ClipCoverage::type
Type type
Definition: contents.h:43
impeller::Entity::GetContents
const std::shared_ptr< Contents > & GetContents() const
Definition: entity.cc:97
impeller::EntityPassClipStack::PushSubpass
void PushSubpass(std::optional< Rect > subpass_coverage, size_t clip_depth)
Definition: entity_pass_clip_stack.cc:32
clip_contents.h
impeller::ClipRestoreContents
Definition: clip_contents.h:71
impeller::EntityPassClipStack::PopSubpass
void PopSubpass()
Definition: entity_pass_clip_stack.cc:43
entity_pass_clip_stack.h
impeller::Entity::GetClipDepth
uint32_t GetClipDepth() const
Definition: entity.cc:105
content_context.h
impeller::EntityPassClipStack::RecordEntity
void RecordEntity(const Entity &entity, Contents::ClipCoverage::Type type, std::optional< Rect > clip_coverage)
Definition: entity_pass_clip_stack.cc:144
impeller::Entity::GetCoverage
std::optional< Rect > GetCoverage() const
Definition: entity.cc:69
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:210
impeller::TPoint< Scalar >
impeller::Contents::ClipCoverage
Definition: contents.h:40
impeller::Contents::ClipCoverage::Type::kAppend
@ kAppend
impeller::EntityPassClipStack::ClipStateResult
Definition: entity_pass_clip_stack.h:31
impeller
Definition: aiks_blur_unittests.cc:20
impeller::TRect< Scalar >
impeller::Contents::ClipCoverage::Type::kNoChange
@ kNoChange