33// found in the LICENSE file.
44
55#include " impeller/entity/entity_pass.h"
6+ #include < variant>
67
8+ #include " flutter/fml/logging.h"
79#include " flutter/fml/trace_event.h"
810#include " impeller/base/validation.h"
911#include " impeller/entity/contents/content_context.h"
@@ -26,22 +28,20 @@ void EntityPass::SetDelegate(std::unique_ptr<EntityPassDelegate> delegate) {
2628}
2729
2830void EntityPass::AddEntity (Entity entity) {
29- entities_ .emplace_back (std::move (entity));
31+ elements_ .emplace_back (std::move (entity));
3032}
3133
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);
3836}
3937
4038size_t EntityPass::GetSubpassesDepth () const {
4139 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+ }
4545 }
4646 return max_subpass_depth + 1u ;
4747}
@@ -50,10 +50,20 @@ const std::shared_ptr<LazyGlyphAtlas>& EntityPass::GetLazyGlyphAtlas() const {
5050 return lazy_glyph_atlas_;
5151}
5252
53- std::optional<Rect> EntityPass::GetEntitiesCoverage () const {
53+ std::optional<Rect> EntityPass::GetElementsCoverage () const {
5454 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+
5767 if (!result.has_value () && coverage.has_value ()) {
5868 result = coverage;
5969 continue ;
@@ -68,7 +78,7 @@ std::optional<Rect> EntityPass::GetEntitiesCoverage() const {
6878
6979std::optional<Rect> EntityPass::GetSubpassCoverage (
7080 const EntityPass& subpass) const {
71- auto entities_coverage = subpass.GetEntitiesCoverage ();
81+ auto entities_coverage = subpass.GetElementsCoverage ();
7282 // The entities don't cover anything. There is nothing to do.
7383 if (!entities_coverage.has_value ()) {
7484 return std::nullopt ;
@@ -94,132 +104,149 @@ EntityPass* EntityPass::GetSuperpass() const {
94104 return superpass_;
95105}
96106
97- const EntityPass::Subpasses& EntityPass::GetSubpasses () const {
98- return subpasses_;
99- }
100-
101107EntityPass* EntityPass::AddSubpass (std::unique_ptr<EntityPass> pass) {
102108 if (!pass) {
103109 return nullptr ;
104110 }
105111 FML_DCHECK (pass->superpass_ == nullptr );
106112 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;
108116}
109117
110118bool EntityPass::Render (ContentContext& renderer,
111119 RenderPass& parent_pass,
112120 Point position) const {
113121 TRACE_EVENT0 (" impeller" , " EntityPass::Render" );
114122
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)) {
136137 return false ;
137138 }
138139 continue ;
139140 }
140141
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 ();
142148
143- if (!subpass_coverage. has_value ()) {
144- continue ;
145- }
149+ if (delegate_-> CanElide ()) {
150+ continue ;
151+ }
146152
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+ }
152160
153- auto context = renderer. GetContext ( );
161+ const auto subpass_coverage = GetSubpassCoverage (*subpass );
154162
155- auto subpass_target = RenderTarget::CreateOffscreen (
156- *context, ISize::Ceil (subpass_coverage->size ));
163+ if (!subpass_coverage.has_value ()) {
164+ continue ;
165+ }
157166
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+ }
159172
160- if (!subpass_texture) {
161- return false ;
162- }
173+ auto context = renderer.GetContext ();
163174
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 ));
178177
179- auto sub_command_buffer = context-> CreateRenderCommandBuffer ();
178+ auto subpass_texture = subpass_target. GetRenderTargetTexture ();
180179
181- sub_command_buffer->SetLabel (" Offscreen Command Buffer" );
180+ if (!subpass_texture) {
181+ return false ;
182+ }
182183
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+ }
186198
187- auto sub_renderpass = sub_command_buffer-> CreateRenderPass (subpass_target );
199+ auto sub_command_buffer = context-> CreateRenderCommandBuffer ( );
188200
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+ }
192206
193- sub_renderpass->SetLabel (" OffscreenPass" );
207+ auto sub_renderpass =
208+ sub_command_buffer->CreateRenderPass (subpass_target);
194209
195- if (!subpass-> Render (renderer, * sub_renderpass, subpass_coverage-> origin ) ) {
196- return false ;
197- }
210+ if (!sub_renderpass) {
211+ return false ;
212+ }
198213
199- if (!sub_renderpass->EncodeCommands (*context->GetTransientsAllocator ())) {
200- return false ;
201- }
214+ sub_renderpass->SetLabel (" OffscreenPass" );
202215
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+ }
206245
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 ;
222247 }
248+
249+ FML_UNREACHABLE ();
223250 }
224251
225252 return true ;
@@ -230,23 +257,39 @@ void EntityPass::IterateAllEntities(std::function<bool(Entity&)> iterator) {
230257 return ;
231258 }
232259
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 ;
236266 }
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 ();
241272 }
242273}
243274
244275std::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 ();
249289 }
290+
291+ auto pass = std::make_unique<EntityPass>();
292+ pass->SetElements (std::move (new_elements));
250293 return pass;
251294}
252295
0 commit comments