3
3
// found in the LICENSE file.
4
4
5
5
#include " impeller/entity/entity_pass.h"
6
+ #include < variant>
6
7
8
+ #include " flutter/fml/logging.h"
7
9
#include " flutter/fml/trace_event.h"
8
10
#include " impeller/base/validation.h"
9
11
#include " impeller/entity/contents/content_context.h"
@@ -26,22 +28,20 @@ void EntityPass::SetDelegate(std::unique_ptr<EntityPassDelegate> delegate) {
26
28
}
27
29
28
30
void EntityPass::AddEntity (Entity entity) {
29
- entities_ .emplace_back (std::move (entity));
31
+ elements_ .emplace_back (std::move (entity));
30
32
}
31
33
32
- const std::vector<Entity>& EntityPass::GetEntities () const {
33
- return entities_;
34
- }
35
-
36
- void EntityPass::SetEntities (Entities entities) {
37
- entities_ = std::move (entities);
34
+ void EntityPass::SetElements (std::vector<Element> elements) {
35
+ elements_ = std::move (elements);
38
36
}
39
37
40
38
size_t EntityPass::GetSubpassesDepth () const {
41
39
size_t max_subpass_depth = 0u ;
42
- for (const auto & subpass : subpasses_) {
43
- max_subpass_depth =
44
- std::max (max_subpass_depth, subpass->GetSubpassesDepth ());
40
+ for (const auto & element : elements_) {
41
+ if (auto subpass = std::get_if<std::unique_ptr<EntityPass>>(&element)) {
42
+ max_subpass_depth =
43
+ std::max (max_subpass_depth, subpass->get ()->GetSubpassesDepth ());
44
+ }
45
45
}
46
46
return max_subpass_depth + 1u ;
47
47
}
@@ -50,10 +50,20 @@ const std::shared_ptr<LazyGlyphAtlas>& EntityPass::GetLazyGlyphAtlas() const {
50
50
return lazy_glyph_atlas_;
51
51
}
52
52
53
- std::optional<Rect > EntityPass::GetEntitiesCoverage () const {
53
+ std::optional<Rect > EntityPass::GetElementsCoverage () const {
54
54
std::optional<Rect > result;
55
- for (const auto & entity : entities_) {
56
- auto coverage = entity.GetCoverage ();
55
+ for (const auto & element : elements_) {
56
+ std::optional<Rect > coverage;
57
+
58
+ if (auto entity = std::get_if<Entity>(&element)) {
59
+ coverage = entity->GetCoverage ();
60
+ } else if (auto subpass =
61
+ std::get_if<std::unique_ptr<EntityPass>>(&element)) {
62
+ coverage = subpass->get ()->GetElementsCoverage ();
63
+ } else {
64
+ FML_UNREACHABLE ();
65
+ }
66
+
57
67
if (!result.has_value () && coverage.has_value ()) {
58
68
result = coverage;
59
69
continue ;
@@ -68,7 +78,7 @@ std::optional<Rect> EntityPass::GetEntitiesCoverage() const {
68
78
69
79
std::optional<Rect > EntityPass::GetSubpassCoverage (
70
80
const EntityPass& subpass) const {
71
- auto entities_coverage = subpass.GetEntitiesCoverage ();
81
+ auto entities_coverage = subpass.GetElementsCoverage ();
72
82
// The entities don't cover anything. There is nothing to do.
73
83
if (!entities_coverage.has_value ()) {
74
84
return std::nullopt;
@@ -94,132 +104,149 @@ EntityPass* EntityPass::GetSuperpass() const {
94
104
return superpass_;
95
105
}
96
106
97
- const EntityPass::Subpasses& EntityPass::GetSubpasses () const {
98
- return subpasses_;
99
- }
100
-
101
107
EntityPass* EntityPass::AddSubpass (std::unique_ptr<EntityPass> pass) {
102
108
if (!pass) {
103
109
return nullptr ;
104
110
}
105
111
FML_DCHECK (pass->superpass_ == nullptr );
106
112
pass->superpass_ = this ;
107
- return subpasses_.emplace_back (std::move (pass)).get ();
113
+ auto subpass_pointer = pass.get ();
114
+ elements_.emplace_back (std::move (pass));
115
+ return subpass_pointer;
108
116
}
109
117
110
118
bool EntityPass::Render (ContentContext& renderer,
111
119
RenderPass& parent_pass,
112
120
Point position) const {
113
121
TRACE_EVENT0 (" impeller" , " EntityPass::Render" );
114
122
115
- for (Entity entity : entities_) {
116
- if (!position.IsZero ()) {
117
- // If the pass image is going to be rendered with a non-zero position,
118
- // apply the negative translation to entity copies before rendering them
119
- // so that they'll end up rendering to the correct on-screen position.
120
- entity.SetTransformation (Matrix::MakeTranslation (Vector3 (-position)) *
121
- entity.GetTransformation ());
122
- }
123
- if (!entity.Render (renderer, parent_pass)) {
124
- return false ;
125
- }
126
- }
127
-
128
- for (const auto & subpass : subpasses_) {
129
- if (delegate_->CanElide ()) {
130
- continue ;
131
- }
132
-
133
- if (delegate_->CanCollapseIntoParentPass ()) {
134
- // Directly render into the parent pass and move on.
135
- if (!subpass->Render (renderer, parent_pass, position)) {
123
+ for (const auto & element : elements_) {
124
+ // =========================================================================
125
+ // Entity rendering ========================================================
126
+ // =========================================================================
127
+ if (const auto & entity = std::get_if<Entity>(&element)) {
128
+ Entity e = *entity;
129
+ if (!position.IsZero ()) {
130
+ // If the pass image is going to be rendered with a non-zero position,
131
+ // apply the negative translation to entity copies before rendering them
132
+ // so that they'll end up rendering to the correct on-screen position.
133
+ e.SetTransformation (Matrix::MakeTranslation (Vector3 (-position)) *
134
+ e.GetTransformation ());
135
+ }
136
+ if (!e.Render (renderer, parent_pass)) {
136
137
return false ;
137
138
}
138
139
continue ;
139
140
}
140
141
141
- const auto subpass_coverage = GetSubpassCoverage (*subpass);
142
+ // =========================================================================
143
+ // Subpass rendering =======================================================
144
+ // =========================================================================
145
+ if (const auto & subpass_ptr =
146
+ std::get_if<std::unique_ptr<EntityPass>>(&element)) {
147
+ auto subpass = subpass_ptr->get ();
142
148
143
- if (!subpass_coverage. has_value ()) {
144
- continue ;
145
- }
149
+ if (delegate_-> CanElide ()) {
150
+ continue ;
151
+ }
146
152
147
- if (subpass_coverage->size .IsEmpty ()) {
148
- // It is not an error to have an empty subpass. But subpasses that can't
149
- // create their intermediates must trip errors.
150
- continue ;
151
- }
153
+ if (delegate_->CanCollapseIntoParentPass ()) {
154
+ // Directly render into the parent pass and move on.
155
+ if (!subpass->Render (renderer, parent_pass, position)) {
156
+ return false ;
157
+ }
158
+ continue ;
159
+ }
152
160
153
- auto context = renderer. GetContext ( );
161
+ const auto subpass_coverage = GetSubpassCoverage (*subpass );
154
162
155
- auto subpass_target = RenderTarget::CreateOffscreen (
156
- *context, ISize::Ceil (subpass_coverage->size ));
163
+ if (!subpass_coverage.has_value ()) {
164
+ continue ;
165
+ }
157
166
158
- auto subpass_texture = subpass_target.GetRenderTargetTexture ();
167
+ if (subpass_coverage->size .IsEmpty ()) {
168
+ // It is not an error to have an empty subpass. But subpasses that can't
169
+ // create their intermediates must trip errors.
170
+ continue ;
171
+ }
159
172
160
- if (!subpass_texture) {
161
- return false ;
162
- }
173
+ auto context = renderer.GetContext ();
163
174
164
- auto offscreen_texture_contents =
165
- delegate_->CreateContentsForSubpassTarget (subpass_texture);
166
-
167
- if (!offscreen_texture_contents) {
168
- // This is an error because the subpass delegate said the pass couldn't be
169
- // collapsed into its parent. Yet, when asked how it want's to postprocess
170
- // the offscreen texture, it couldn't give us an answer.
171
- //
172
- // Theoretically, we could collapse the pass now. But that would be
173
- // wasteful as we already have the offscreen texture and we don't want to
174
- // discard it without ever using it. Just make the delegate do the right
175
- // thing.
176
- return false ;
177
- }
175
+ auto subpass_target = RenderTarget::CreateOffscreen (
176
+ *context, ISize::Ceil (subpass_coverage->size ));
178
177
179
- auto sub_command_buffer = context-> CreateRenderCommandBuffer ();
178
+ auto subpass_texture = subpass_target. GetRenderTargetTexture ();
180
179
181
- sub_command_buffer->SetLabel (" Offscreen Command Buffer" );
180
+ if (!subpass_texture) {
181
+ return false ;
182
+ }
182
183
183
- if (!sub_command_buffer) {
184
- return false ;
185
- }
184
+ auto offscreen_texture_contents =
185
+ delegate_->CreateContentsForSubpassTarget (subpass_texture);
186
+
187
+ if (!offscreen_texture_contents) {
188
+ // This is an error because the subpass delegate said the pass couldn't
189
+ // be collapsed into its parent. Yet, when asked how it want's to
190
+ // postprocess the offscreen texture, it couldn't give us an answer.
191
+ //
192
+ // Theoretically, we could collapse the pass now. But that would be
193
+ // wasteful as we already have the offscreen texture and we don't want
194
+ // to discard it without ever using it. Just make the delegate do the
195
+ // right thing.
196
+ return false ;
197
+ }
186
198
187
- auto sub_renderpass = sub_command_buffer-> CreateRenderPass (subpass_target );
199
+ auto sub_command_buffer = context-> CreateRenderCommandBuffer ( );
188
200
189
- if (!sub_renderpass) {
190
- return false ;
191
- }
201
+ sub_command_buffer->SetLabel (" Offscreen Command Buffer" );
202
+
203
+ if (!sub_command_buffer) {
204
+ return false ;
205
+ }
192
206
193
- sub_renderpass->SetLabel (" OffscreenPass" );
207
+ auto sub_renderpass =
208
+ sub_command_buffer->CreateRenderPass (subpass_target);
194
209
195
- if (!subpass-> Render (renderer, * sub_renderpass, subpass_coverage-> origin ) ) {
196
- return false ;
197
- }
210
+ if (!sub_renderpass) {
211
+ return false ;
212
+ }
198
213
199
- if (!sub_renderpass->EncodeCommands (*context->GetTransientsAllocator ())) {
200
- return false ;
201
- }
214
+ sub_renderpass->SetLabel (" OffscreenPass" );
202
215
203
- if (!sub_command_buffer->SubmitCommands ()) {
204
- return false ;
205
- }
216
+ if (!subpass->Render (renderer, *sub_renderpass,
217
+ subpass_coverage->origin )) {
218
+ return false ;
219
+ }
220
+
221
+ if (!sub_renderpass->EncodeCommands (*context->GetTransientsAllocator ())) {
222
+ return false ;
223
+ }
224
+
225
+ if (!sub_command_buffer->SubmitCommands ()) {
226
+ return false ;
227
+ }
228
+
229
+ Entity entity;
230
+ entity.SetPath (PathBuilder{}
231
+ .AddRect (Rect::MakeSize (subpass_coverage->size ))
232
+ .TakePath ());
233
+ entity.SetContents (std::move (offscreen_texture_contents));
234
+ entity.SetStencilDepth (stencil_depth_);
235
+ entity.SetBlendMode (subpass->blend_mode_ );
236
+ // Once we have filters being applied for SaveLayer, some special sauce
237
+ // may be needed here (or in PaintPassDelegate) to ensure the filter
238
+ // parameters are transformed by the `xformation_` matrix, while
239
+ // continuing to apply only the subpass offset to the offscreen texture.
240
+ entity.SetTransformation (Matrix::MakeTranslation (
241
+ Vector3 (subpass_coverage->origin - position)));
242
+ if (!entity.Render (renderer, parent_pass)) {
243
+ return false ;
244
+ }
206
245
207
- Entity entity;
208
- entity.SetPath (PathBuilder{}
209
- .AddRect (Rect::MakeSize (subpass_coverage->size ))
210
- .TakePath ());
211
- entity.SetContents (std::move (offscreen_texture_contents));
212
- entity.SetStencilDepth (stencil_depth_);
213
- entity.SetBlendMode (subpass->blend_mode_ );
214
- // Once we have filters being applied for SaveLayer, some special sauce
215
- // may be needed here (or in PaintPassDelegate) to ensure the filter
216
- // parameters are transformed by the `xformation_` matrix, while continuing
217
- // to apply only the subpass offset to the offscreen texture.
218
- entity.SetTransformation (
219
- Matrix::MakeTranslation (Vector3 (subpass_coverage->origin - position)));
220
- if (!entity.Render (renderer, parent_pass)) {
221
- return false ;
246
+ continue ;
222
247
}
248
+
249
+ FML_UNREACHABLE ();
223
250
}
224
251
225
252
return true ;
@@ -230,23 +257,39 @@ void EntityPass::IterateAllEntities(std::function<bool(Entity&)> iterator) {
230
257
return ;
231
258
}
232
259
233
- for (auto & entity : entities_) {
234
- if (!iterator (entity)) {
235
- return ;
260
+ for (auto & element : elements_) {
261
+ if (auto entity = std::get_if<Entity>(&element)) {
262
+ if (!iterator (*entity)) {
263
+ return ;
264
+ }
265
+ continue ;
236
266
}
237
- }
238
-
239
- for (auto & subpass : subpasses_) {
240
- subpass->IterateAllEntities (iterator);
267
+ if (auto subpass = std::get_if<std::unique_ptr<EntityPass>>(&element)) {
268
+ subpass->get ()->IterateAllEntities (iterator);
269
+ continue ;
270
+ }
271
+ FML_UNREACHABLE ();
241
272
}
242
273
}
243
274
244
275
std::unique_ptr<EntityPass> EntityPass::Clone () const {
245
- auto pass = std::make_unique<EntityPass>();
246
- pass->SetEntities (entities_);
247
- for (const auto & subpass : subpasses_) {
248
- pass->AddSubpass (subpass->Clone ());
276
+ std::vector<Element> new_elements;
277
+ new_elements.reserve (elements_.size ());
278
+
279
+ for (const auto & element : elements_) {
280
+ if (auto entity = std::get_if<Entity>(&element)) {
281
+ new_elements.push_back (*entity);
282
+ continue ;
283
+ }
284
+ if (auto subpass = std::get_if<std::unique_ptr<EntityPass>>(&element)) {
285
+ new_elements.push_back (subpass->get ()->Clone ());
286
+ continue ;
287
+ }
288
+ FML_UNREACHABLE ();
249
289
}
290
+
291
+ auto pass = std::make_unique<EntityPass>();
292
+ pass->SetElements (std::move (new_elements));
250
293
return pass;
251
294
}
252
295
0 commit comments